[{"data":1,"prerenderedAt":2346},["ShallowReactive",2],{"navigation_docs":3,"-use-cases-telemetry-ingest":576,"-use-cases-telemetry-ingest-surround":2341},[4,35,85,138,318,453,512,551],{"title":5,"path":6,"stem":7,"children":8,"page":34},"Start","\u002Fstart","1.start",[9,14,19,24,29],{"title":10,"path":11,"stem":12,"icon":13},"Introduction","\u002Fstart\u002Fintroduction","1.start\u002F1.introduction","i-lucide-info",{"title":15,"path":16,"stem":17,"icon":18},"Why start with evlog","\u002Fstart\u002Fwhy-evlog","1.start\u002F2.why-evlog","i-lucide-rocket",{"title":20,"path":21,"stem":22,"icon":23},"Installation","\u002Fstart\u002Finstallation","1.start\u002F3.installation","i-lucide-download",{"title":25,"path":26,"stem":27,"icon":28},"Quick Start","\u002Fstart\u002Fquick-start","1.start\u002F4.quick-start","i-lucide-zap",{"title":30,"path":31,"stem":32,"icon":33},"Choose your logger","\u002Fstart\u002Ftypescript-logging-library","1.start\u002F5.typescript-logging-library","i-lucide-file-code",false,{"title":36,"path":37,"stem":38,"children":39,"page":34},"Learn","\u002Flearn","2.learn",[40,45,50,55,60,65,70,75,80],{"title":41,"path":42,"stem":43,"icon":44},"Overview","\u002Flearn\u002Foverview","2.learn\u002F0.overview","i-lucide-list",{"title":46,"path":47,"stem":48,"icon":49},"Simple Logging","\u002Flearn\u002Fsimple-logging","2.learn\u002F1.simple-logging","i-lucide-terminal",{"title":51,"path":52,"stem":53,"icon":54},"Wide Events","\u002Flearn\u002Fwide-events","2.learn\u002F2.wide-events","i-lucide-layers",{"title":56,"path":57,"stem":58,"icon":59},"Structured Errors","\u002Flearn\u002Fstructured-errors","2.learn\u002F3.structured-errors","i-lucide-shield-alert",{"title":61,"path":62,"stem":63,"icon":64},"Lifecycle","\u002Flearn\u002Flifecycle","2.learn\u002F4.lifecycle","i-lucide-arrow-right-left",{"title":66,"path":67,"stem":68,"icon":69},"Sampling","\u002Flearn\u002Fsampling","2.learn\u002F5.sampling","i-lucide-filter",{"title":71,"path":72,"stem":73,"icon":74},"Auto-Redaction","\u002Flearn\u002Fredaction","2.learn\u002F6.redaction","i-lucide-eye-off",{"title":76,"path":77,"stem":78,"icon":79},"Typed Fields","\u002Flearn\u002Ftyped-fields","2.learn\u002F7.typed-fields","i-simple-icons-typescript",{"title":81,"path":82,"stem":83,"icon":84},"Catalogs","\u002Flearn\u002Fcatalogs","2.learn\u002F8.catalogs","i-lucide-book-open",{"title":86,"path":87,"stem":88,"children":89,"page":34},"CLI","\u002Fcli","3.cli",[90,93,98,103,108,113,118,123,128,133],{"title":41,"path":91,"stem":92,"icon":49},"\u002Fcli\u002Foverview","3.cli\u002F0.overview",{"title":94,"path":95,"stem":96,"icon":97},"init","\u002Fcli\u002Finit","3.cli\u002F1.init","i-lucide-wand-sparkles",{"title":99,"path":100,"stem":101,"icon":102},"map","\u002Fcli\u002Fmap","3.cli\u002F2.map","i-lucide-radar",{"title":104,"path":105,"stem":106,"icon":107},"Rules","\u002Fcli\u002Frules","3.cli\u002F3.rules","i-lucide-list-checks",{"title":109,"path":110,"stem":111,"icon":112},"Scoring","\u002Fcli\u002Fscoring","3.cli\u002F4.scoring","i-lucide-gauge",{"title":114,"path":115,"stem":116,"icon":117},"CI","\u002Fcli\u002Fci","3.cli\u002F5.ci","i-lucide-git-pull-request",{"title":119,"path":120,"stem":121,"icon":122},"doctor","\u002Fcli\u002Fdoctor","3.cli\u002F6.doctor","i-lucide-stethoscope",{"title":124,"path":125,"stem":126,"icon":127},"telemetry","\u002Fcli\u002Ftelemetry","3.cli\u002F7.telemetry","i-lucide-bar-chart-3",{"title":129,"path":130,"stem":131,"icon":132},"agents","\u002Fcli\u002Fagents","3.cli\u002F8.agents","i-lucide-bot",{"title":134,"path":135,"stem":136,"icon":137},"Observability Score","\u002Fcli\u002Fobservability-score","3.cli\u002F9.observability-score","i-lucide-activity",{"title":139,"path":140,"stem":141,"children":142,"page":34},"Integrate","\u002Fintegrate","4.integrate",[143,147,230],{"title":41,"path":144,"stem":145,"icon":146},"\u002Fintegrate\u002Foverview","4.integrate\u002F0.overview","i-lucide-plug",{"title":148,"path":149,"stem":150,"children":151,"page":34},"Adapters","\u002Fintegrate\u002Fadapters","4.integrate\u002Fadapters",[152,155,185,210],{"title":41,"path":153,"stem":154,"icon":44},"\u002Fintegrate\u002Fadapters\u002Foverview","4.integrate\u002Fadapters\u002F01.overview",{"title":156,"path":157,"stem":158,"children":159,"page":34},"Cloud","\u002Fintegrate\u002Fadapters\u002Fcloud","4.integrate\u002Fadapters\u002Fcloud",[160,165,170,175,180],{"title":161,"path":162,"stem":163,"icon":164},"Axiom","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Faxiom","4.integrate\u002Fadapters\u002Fcloud\u002F01.axiom","i-custom-axiom",{"title":166,"path":167,"stem":168,"icon":169},"PostHog","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fposthog","4.integrate\u002Fadapters\u002Fcloud\u002F02.posthog","i-simple-icons-posthog",{"title":171,"path":172,"stem":173,"icon":174},"Sentry","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fsentry","4.integrate\u002Fadapters\u002Fcloud\u002F03.sentry","i-simple-icons-sentry",{"title":176,"path":177,"stem":178,"icon":179},"Better Stack","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fbetter-stack","4.integrate\u002Fadapters\u002Fcloud\u002F04.better-stack","i-simple-icons-betterstack",{"title":181,"path":182,"stem":183,"icon":184},"Datadog","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fdatadog","4.integrate\u002Fadapters\u002Fcloud\u002F05.datadog","i-simple-icons-datadog",{"title":186,"path":187,"stem":188,"children":189,"page":34},"Cloud or Self-Hosted","\u002Fintegrate\u002Fadapters\u002Fhybrid","4.integrate\u002Fadapters\u002Fhybrid",[190,195,200,205],{"title":191,"path":192,"stem":193,"icon":194},"Grafana Loki","\u002Fintegrate\u002Fadapters\u002Fhybrid\u002Floki","4.integrate\u002Fadapters\u002Fhybrid\u002F01.loki","i-simple-icons-grafana",{"title":196,"path":197,"stem":198,"icon":199},"ClickHouse","\u002Fintegrate\u002Fadapters\u002Fhybrid\u002Fclickhouse","4.integrate\u002Fadapters\u002Fhybrid\u002F02.clickhouse","i-simple-icons-clickhouse",{"title":201,"path":202,"stem":203,"icon":204},"OTLP","\u002Fintegrate\u002Fadapters\u002Fhybrid\u002Fotlp","4.integrate\u002Fadapters\u002Fhybrid\u002F03.otlp","i-simple-icons-opentelemetry",{"title":206,"path":207,"stem":208,"icon":209},"HyperDX","\u002Fintegrate\u002Fadapters\u002Fhybrid\u002Fhyperdx","4.integrate\u002Fadapters\u002Fhybrid\u002F04.hyperdx","i-custom-hyperdx",{"title":211,"path":212,"stem":213,"children":214,"page":34},"Self-Hosted","\u002Fintegrate\u002Fadapters\u002Fself-hosted","4.integrate\u002Fadapters\u002Fself-hosted",[215,220,225],{"title":216,"path":217,"stem":218,"icon":219},"File System","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Ffs","4.integrate\u002Fadapters\u002Fself-hosted\u002F01.fs","i-lucide-hard-drive",{"title":221,"path":222,"stem":223,"icon":224},"NuxtHub","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Fnuxthub","4.integrate\u002Fadapters\u002Fself-hosted\u002F02.nuxthub","i-simple-icons-nuxt",{"title":226,"path":227,"stem":228,"icon":229},"Memory","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Fmemory","4.integrate\u002Fadapters\u002Fself-hosted\u002F03.memory","i-lucide-cpu",{"title":231,"path":232,"stem":233,"children":234,"page":34},"Frameworks","\u002Fintegrate\u002Fframeworks","4.integrate\u002Fframeworks",[235,239,244,249,254,259,264,269,274,279,284,289,294,299,303,308,313],{"title":41,"path":236,"stem":237,"icon":238},"\u002Fintegrate\u002Fframeworks\u002Foverview","4.integrate\u002Fframeworks\u002F00.overview","i-lucide-layout-grid",{"title":240,"path":241,"stem":242,"icon":243},"Nuxt","\u002Fintegrate\u002Fframeworks\u002Fnuxt","4.integrate\u002Fframeworks\u002F01.nuxt","i-simple-icons-nuxtdotjs",{"title":245,"path":246,"stem":247,"icon":248},"Next.js","\u002Fintegrate\u002Fframeworks\u002Fnextjs","4.integrate\u002Fframeworks\u002F02.nextjs","i-simple-icons-nextdotjs",{"title":250,"path":251,"stem":252,"icon":253},"SvelteKit","\u002Fintegrate\u002Fframeworks\u002Fsveltekit","4.integrate\u002Fframeworks\u002F03.sveltekit","i-simple-icons-svelte",{"title":255,"path":256,"stem":257,"icon":258},"Nitro","\u002Fintegrate\u002Fframeworks\u002Fnitro","4.integrate\u002Fframeworks\u002F04.nitro","i-custom-nitro",{"title":260,"path":261,"stem":262,"icon":263},"TanStack Start","\u002Fintegrate\u002Fframeworks\u002Ftanstack-start","4.integrate\u002Fframeworks\u002F05.tanstack-start","i-custom-tanstack",{"title":265,"path":266,"stem":267,"icon":268},"NestJS","\u002Fintegrate\u002Fframeworks\u002Fnestjs","4.integrate\u002Fframeworks\u002F06.nestjs","i-simple-icons-nestjs",{"title":270,"path":271,"stem":272,"icon":273},"Express","\u002Fintegrate\u002Fframeworks\u002Fexpress","4.integrate\u002Fframeworks\u002F07.express","i-simple-icons-express",{"title":275,"path":276,"stem":277,"icon":278},"Hono","\u002Fintegrate\u002Fframeworks\u002Fhono","4.integrate\u002Fframeworks\u002F08.hono","i-simple-icons-hono",{"title":280,"path":281,"stem":282,"icon":283},"Fastify","\u002Fintegrate\u002Fframeworks\u002Ffastify","4.integrate\u002Fframeworks\u002F09.fastify","i-simple-icons-fastify",{"title":285,"path":286,"stem":287,"icon":288},"Elysia","\u002Fintegrate\u002Fframeworks\u002Felysia","4.integrate\u002Fframeworks\u002F10.elysia","i-custom-elysia",{"title":290,"path":291,"stem":292,"icon":293},"React Router","\u002Fintegrate\u002Fframeworks\u002Freact-router","4.integrate\u002Fframeworks\u002F11.react-router","i-custom-reactrouter",{"title":295,"path":296,"stem":297,"icon":298},"Cloudflare Workers","\u002Fintegrate\u002Fframeworks\u002Fcloudflare-workers","4.integrate\u002Fframeworks\u002F12.cloudflare-workers","i-simple-icons-cloudflare",{"title":300,"path":301,"stem":302,"icon":79},"Standalone","\u002Fintegrate\u002Fframeworks\u002Fstandalone","4.integrate\u002Fframeworks\u002F13.standalone",{"title":304,"path":305,"stem":306,"icon":307},"Astro","\u002Fintegrate\u002Fframeworks\u002Fastro","4.integrate\u002Fframeworks\u002F14.astro","i-simple-icons-astro",{"title":309,"path":310,"stem":311,"icon":312},"oRPC","\u002Fintegrate\u002Fframeworks\u002Forpc","4.integrate\u002Fframeworks\u002F15.orpc","i-lucide-network",{"title":314,"path":315,"stem":316,"icon":317},"AWS Lambda","\u002Fintegrate\u002Fframeworks\u002Faws-lambda","4.integrate\u002Fframeworks\u002F16.aws-lambda","i-custom-lambda",{"title":319,"path":320,"stem":321,"children":322,"page":34},"Use Cases","\u002Fuse-cases","5.use-cases",[323,326,331,359,386,418,439,444,449],{"title":41,"path":324,"stem":325,"icon":107},"\u002Fuse-cases\u002Foverview","5.use-cases\u002F0.overview",{"title":327,"path":328,"stem":329,"icon":330},"Client Logging","\u002Fuse-cases\u002Fclient-logging","5.use-cases\u002F1.client-logging","i-lucide-monitor",{"title":332,"icon":333,"path":334,"stem":335,"children":336,"page":34},"AI SDK","i-simple-icons-vercel","\u002Fuse-cases\u002Fai-sdk","5.use-cases\u002F2.ai-sdk",[337,340,345,350,355],{"title":41,"path":338,"stem":339,"icon":44},"\u002Fuse-cases\u002Fai-sdk\u002Foverview","5.use-cases\u002F2.ai-sdk\u002F01.overview",{"title":341,"path":342,"stem":343,"icon":344},"Usage","\u002Fuse-cases\u002Fai-sdk\u002Fusage","5.use-cases\u002F2.ai-sdk\u002F02.usage","i-lucide-code",{"title":346,"path":347,"stem":348,"icon":349},"Options","\u002Fuse-cases\u002Fai-sdk\u002Foptions","5.use-cases\u002F2.ai-sdk\u002F03.options","i-lucide-sliders",{"title":351,"path":352,"stem":353,"icon":354},"Metadata","\u002Fuse-cases\u002Fai-sdk\u002Fmetadata","5.use-cases\u002F2.ai-sdk\u002F04.metadata","i-lucide-database",{"title":356,"path":357,"stem":358,"icon":137},"Telemetry","\u002Fuse-cases\u002Fai-sdk\u002Ftelemetry","5.use-cases\u002F2.ai-sdk\u002F05.telemetry",{"title":360,"icon":361,"path":362,"stem":363,"children":364,"page":34},"Better Auth","i-simple-icons-betterauth","\u002Fuse-cases\u002Fbetter-auth","5.use-cases\u002F3.better-auth",[365,368,373,378,382],{"title":41,"path":366,"stem":367,"icon":44},"\u002Fuse-cases\u002Fbetter-auth\u002Foverview","5.use-cases\u002F3.better-auth\u002F01.overview",{"title":369,"path":370,"stem":371,"icon":372},"Identify User","\u002Fuse-cases\u002Fbetter-auth\u002Fidentify-user","5.use-cases\u002F3.better-auth\u002F02.identify-user","i-lucide-user-check",{"title":374,"path":375,"stem":376,"icon":377},"Middleware","\u002Fuse-cases\u002Fbetter-auth\u002Fmiddleware","5.use-cases\u002F3.better-auth\u002F03.middleware","i-lucide-shield",{"title":379,"path":380,"stem":381,"icon":330},"Client Sync","\u002Fuse-cases\u002Fbetter-auth\u002Fclient-sync","5.use-cases\u002F3.better-auth\u002F04.client-sync",{"title":383,"path":384,"stem":385,"icon":112},"Performance","\u002Fuse-cases\u002Fbetter-auth\u002Fperformance","5.use-cases\u002F3.better-auth\u002F05.performance",{"title":387,"icon":388,"path":389,"stem":390,"children":391,"page":34},"Audit Logs","i-lucide-shield-check","\u002Fuse-cases\u002Faudit","5.use-cases\u002F4.audit",[392,395,400,405,410,414],{"title":41,"path":393,"stem":394,"icon":44},"\u002Fuse-cases\u002Faudit\u002Foverview","5.use-cases\u002F4.audit\u002F01.overview",{"title":396,"path":397,"stem":398,"icon":399},"Schema","\u002Fuse-cases\u002Faudit\u002Fschema","5.use-cases\u002F4.audit\u002F02.schema","i-lucide-file-text",{"title":401,"path":402,"stem":403,"icon":404},"Recording","\u002Fuse-cases\u002Faudit\u002Frecording","5.use-cases\u002F4.audit\u002F03.recording","i-lucide-pen-line",{"title":406,"path":407,"stem":408,"icon":409},"Drains","\u002Fuse-cases\u002Faudit\u002Fpipeline","5.use-cases\u002F4.audit\u002F04.pipeline","i-lucide-link",{"title":411,"path":412,"stem":413,"icon":388},"Compliance","\u002Fuse-cases\u002Faudit\u002Fcompliance","5.use-cases\u002F4.audit\u002F05.compliance",{"title":415,"path":416,"stem":417,"icon":84},"Recipes","\u002Fuse-cases\u002Faudit\u002Frecipes","5.use-cases\u002F4.audit\u002F06.recipes",{"title":356,"icon":112,"path":419,"stem":420,"children":421,"page":34},"\u002Fuse-cases\u002Ftelemetry","5.use-cases\u002F4.telemetry",[422,425,430,435],{"title":41,"path":423,"stem":424,"icon":44},"\u002Fuse-cases\u002Ftelemetry\u002Foverview","5.use-cases\u002F4.telemetry\u002F01.overview",{"title":426,"path":427,"stem":428,"icon":429},"Setup","\u002Fuse-cases\u002Ftelemetry\u002Fsetup","5.use-cases\u002F4.telemetry\u002F02.setup","i-lucide-wrench",{"title":431,"path":432,"stem":433,"icon":434},"Ingest","\u002Fuse-cases\u002Ftelemetry\u002Fingest","5.use-cases\u002F4.telemetry\u002F03.ingest","i-lucide-server",{"title":436,"path":437,"stem":438,"icon":84},"Reference","\u002Fuse-cases\u002Ftelemetry\u002Freference","5.use-cases\u002F4.telemetry\u002F04.reference",{"title":440,"path":441,"stem":442,"icon":443},"Enrichers","\u002Fuse-cases\u002Fenrichers","5.use-cases\u002F5.enrichers","i-lucide-sparkles",{"title":445,"path":446,"stem":447,"icon":448},"eve","\u002Fuse-cases\u002Feve","5.use-cases\u002F5.eve","i-custom-eve",{"title":450,"path":451,"stem":452,"icon":434},"Node.js request logging","\u002Fuse-cases\u002Fstructured-logging-nodejs","5.use-cases\u002F6.structured-logging-nodejs",{"title":454,"path":455,"stem":456,"children":457,"page":34},"Extend","\u002Fextend","6.extend",[458,462,467,472,476,481,485,489,493,497,502,507],{"title":41,"path":459,"stem":460,"icon":461},"\u002Fextend\u002Foverview","6.extend\u002F0.overview","i-lucide-blocks",{"title":463,"path":464,"stem":465,"icon":466},"Stream","\u002Fextend\u002Fstream","6.extend\u002F1.stream","i-lucide-radio-tower",{"title":468,"path":469,"stem":470,"icon":471},"Custom framework","\u002Fextend\u002Fcustom-framework","6.extend\u002F10.custom-framework","i-lucide-puzzle",{"title":473,"path":474,"stem":475,"icon":466},"Diagnostics channel","\u002Fextend\u002Fdiagnostics-channel","6.extend\u002F11.diagnostics-channel",{"title":477,"path":478,"stem":479,"icon":480},"FS reader","\u002Fextend\u002Ffs-reader","6.extend\u002F2.fs-reader","i-lucide-folder-search",{"title":415,"path":482,"stem":483,"icon":484},"\u002Fextend\u002Fconsumer-recipes","6.extend\u002F3.consumer-recipes","i-lucide-chef-hat",{"title":486,"path":487,"stem":488,"icon":461},"Plugins","\u002Fextend\u002Fplugins","6.extend\u002F4.plugins",{"title":490,"path":491,"stem":492,"icon":443},"Custom enrichers","\u002Fextend\u002Fcustom-enrichers","6.extend\u002F5.custom-enrichers",{"title":494,"path":495,"stem":496,"icon":69},"Tail sampling","\u002Fextend\u002Ftail-sampling","6.extend\u002F6.tail-sampling",{"title":498,"path":499,"stem":500,"icon":501},"Identity headers","\u002Fextend\u002Fidentity-headers","6.extend\u002F7.identity-headers","i-lucide-fingerprint",{"title":503,"path":504,"stem":505,"icon":506},"Custom drains","\u002Fextend\u002Fcustom-drains","6.extend\u002F8.custom-drains","i-lucide-share-2",{"title":508,"path":509,"stem":510,"icon":511},"Drain pipeline","\u002Fextend\u002Fdrain-pipeline","6.extend\u002F9.drain-pipeline","i-lucide-workflow",{"title":436,"path":513,"stem":514,"children":515,"page":34},"\u002Freference","7.reference",[516,520,525,528,533,537,542,546],{"title":41,"path":517,"stem":518,"icon":519},"\u002Freference\u002Foverview","7.reference\u002F0.overview","i-lucide-book-marked",{"title":521,"path":522,"stem":523,"icon":524},"Configuration","\u002Freference\u002Fconfiguration","7.reference\u002F1.configuration","i-lucide-settings",{"title":383,"path":526,"stem":527,"icon":112},"\u002Freference\u002Fperformance","7.reference\u002F2.performance",{"title":529,"path":530,"stem":531,"icon":532},"Vite Plugin","\u002Freference\u002Fvite-plugin","7.reference\u002F3.vite-plugin","i-custom-vite",{"title":534,"path":535,"stem":536,"icon":388},"Best Practices","\u002Freference\u002Fbest-practices","7.reference\u002F4.best-practices",{"title":538,"path":539,"stem":540,"icon":541},"vs Other Loggers","\u002Freference\u002Fvs-other-loggers","7.reference\u002F5.vs-other-loggers","i-lucide-scale",{"title":543,"path":544,"stem":545,"icon":443},"Agent Skills","\u002Freference\u002Fagent-skills","7.reference\u002F6.agent-skills",{"title":547,"path":548,"stem":549,"icon":550},"Cost","\u002Freference\u002Fcost","7.reference\u002F7.cost","i-lucide-receipt",{"title":552,"path":553,"stem":554,"children":555,"page":34},"Compare","\u002Fcompare","8.compare",[556,560,564,568,572],{"title":557,"path":558,"stem":559,"icon":541},"evlog vs Pino","\u002Fcompare\u002Fpino","8.compare\u002F1.pino",{"title":561,"path":562,"stem":563,"icon":204},"evlog vs OpenTelemetry","\u002Fcompare\u002Fopentelemetry","8.compare\u002F2.opentelemetry",{"title":565,"path":566,"stem":567,"icon":541},"evlog vs LogTape","\u002Fcompare\u002Flogtape","8.compare\u002F3.logtape",{"title":569,"path":570,"stem":571,"icon":541},"evlog vs Winston: formats and request events","\u002Fcompare\u002Fwinston","8.compare\u002F4.winston",{"title":573,"path":574,"stem":575,"icon":541},"evlog vs Consola: reporters and request context","\u002Fcompare\u002Fconsola","8.compare\u002F5.consola",{"id":577,"title":578,"body":579,"description":2329,"extension":2330,"links":2331,"meta":2337,"navigation":2338,"path":432,"seo":2339,"stem":433,"__hash__":2340},"docs\u002F5.use-cases\u002F4.telemetry\u002F03.ingest.md","Telemetry Ingest",{"type":580,"value":581,"toc":2321},"minimark",[582,596,604,609,616,621,632,637,648,743,749,763,769,781,1010,1029,1033,1040,1976,1980,1986,2294,2298,2307,2317],[583,584,585,586,590,591,595],"p",{},"You ship a CLI. Users run it on their machines. You want to know ",[587,588,589],"em",{},"which commands run, how often they fail, and which versions are out there",", without building a separate analytics SDK or reading raw ",[592,593,594],"code",{},"argv",".",[583,597,598,599,603],{},"That means a ",[600,601,602],"strong",{},"server endpoint"," your CLI POSTs to. The local outbox is only there so short CI jobs and offline runs do not lose data before the POST succeeds.",[605,606,608],"h2",{"id":607},"the-security-question-read-this-first","The security question (read this first)",[610,611,612,615],"tip",{},[600,613,614],{},"CLI telemetry is not a vault."," You are collecting anonymous usage counters (command name, duration, outcome, a few numbers), not passwords, not file paths, not tokens. Design for that threat model and you do not need impossible client-side secrets.",[583,617,618],{},[600,619,620],{},"\"I put the ingest URL in my CLI. Isn't that a secret?\"",[583,622,623,624,627,628,631],{},"No. The URL lives in your npm package or binary. Anyone can read it with ",[592,625,626],{},"strings",", by installing the package, or by watching network traffic. The same applies to an API key or ",[592,629,630],{},"Authorization"," header baked into the CLI is extractable, not a real barrier.",[583,633,634],{},[600,635,636],{},"\"So can't anyone send fake events?\"",[583,638,639,640,643,644,647],{},"In theory, yes: someone could ",[592,641,642],{},"curl"," your endpoint with forged JSON. That is why you treat the endpoint as ",[600,645,646],{},"semi-public"," (like a browser analytics key) and defend on the server:",[649,650,651,664],"table",{},[652,653,654],"thead",{},[655,656,657,661],"tr",{},[658,659,660],"th",{},"What you might worry about",[658,662,663],{},"Practical answer",[665,666,667,679,690,701,716,728],"tbody",{},[655,668,669,673],{},[670,671,672],"td",{},"Random internet bots",[670,674,675,676],{},"Validate the payload shape; reject garbage with ",[592,677,678],{},"400",[655,680,681,687],{},[670,682,683,684,686],{},"Someone spamming fake ",[592,685,119],{}," runs",[670,688,689],{},"Rate-limit by IP; data is low-value counters, not money",[655,691,692,698],{},[670,693,694,695],{},"Forged ",[592,696,697],{},"tool.name",[670,699,700],{},"Allowlist only your published tool names server-side",[655,702,703,709],{},[670,704,705,706],{},"Unexpected fields in ",[592,707,708],{},"custom",[670,710,711,712,715],{},"Filter to the keys you declared — same list as ",[592,713,714],{},"collect"," on the CLI",[655,717,718,721],{},[670,719,720],{},"Double-counting on retry",[670,722,723,724,727],{},"Dedupe on ",[592,725,726],{},"idempotencyKey"," when storing",[655,729,730,733],{},[670,731,732],{},"Leaking user secrets",[670,734,735,736,738,739,742],{},"CLI never reads raw ",[592,737,594],{},"; you only allowlisted flags and ",[592,740,741],{},"telemetry.set()"," counters",[583,744,745,748],{},[600,746,747],{},"What \"good enough\" looks like:"," validate every POST, store idempotently, rate-limit at the edge (CDN, API gateway, or middleware), and keep the payload boring (no PII by design). That is the same playbook as client-side analytics: not banking-grade auth, but reliable product insight.",[750,751,753,756,757,762],"callout",{"color":752,"icon":388},"info",[592,754,755],{},"@evlog\u002Ftelemetry"," ships ",[600,758,759],{},[592,760,761],{},"parseIngestBody()"," for your server, with the same validation rules documented here, so you do not copy-paste a validator from the docs. Pair it with your framework route and your database or evlog drain.",[605,764,766,767],{"id":765},"step-1-validate-with-parseingestbody","Step 1: Validate with ",[592,768,761],{},[583,770,771,772,775,776,778,779,595],{},"Mirror the CLI config on the server: same ",[592,773,774],{},"name",", same custom keys you allow via ",[592,777,714],{}," \u002F ",[592,780,741],{},[782,783,789],"pre",{"className":784,"code":785,"filename":786,"language":787,"meta":788,"style":788},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { parseIngestBody } from '@evlog\u002Ftelemetry\u002Fingest'\n\nexport const ingestOptions = {\n  allowedTools: ['my-tool'],\n  allowedCustomKeys: {\n    'my-tool': ['checksFailed', 'checksWarn', 'itemsSynced'],\n  },\n} as const\n\nexport function parseTelemetryBody(raw: string) {\n  return parseIngestBody(raw, ingestOptions)\n}\n","lib\u002Ftelemetry-ingest.ts","ts","",[592,790,791,824,831,850,877,887,931,937,949,954,984,1004],{"__ignoreMap":788},[792,793,796,800,804,808,811,814,817,821],"span",{"class":794,"line":795},"line",1,[792,797,799],{"class":798},"s7zQu","import",[792,801,803],{"class":802},"sMK4o"," {",[792,805,807],{"class":806},"sTEyZ"," parseIngestBody",[792,809,810],{"class":802}," }",[792,812,813],{"class":798}," from",[792,815,816],{"class":802}," '",[792,818,820],{"class":819},"sfazB","@evlog\u002Ftelemetry\u002Fingest",[792,822,823],{"class":802},"'\n",[792,825,827],{"class":794,"line":826},2,[792,828,830],{"emptyLinePlaceholder":829},true,"\n",[792,832,834,837,841,844,847],{"class":794,"line":833},3,[792,835,836],{"class":798},"export",[792,838,840],{"class":839},"spNyl"," const",[792,842,843],{"class":806}," ingestOptions ",[792,845,846],{"class":802},"=",[792,848,849],{"class":802}," {\n",[792,851,853,857,860,863,866,869,871,874],{"class":794,"line":852},4,[792,854,856],{"class":855},"swJcz","  allowedTools",[792,858,859],{"class":802},":",[792,861,862],{"class":806}," [",[792,864,865],{"class":802},"'",[792,867,868],{"class":819},"my-tool",[792,870,865],{"class":802},[792,872,873],{"class":806},"]",[792,875,876],{"class":802},",\n",[792,878,880,883,885],{"class":794,"line":879},5,[792,881,882],{"class":855},"  allowedCustomKeys",[792,884,859],{"class":802},[792,886,849],{"class":802},[792,888,890,893,895,897,899,901,903,906,908,911,913,916,918,920,922,925,927,929],{"class":794,"line":889},6,[792,891,892],{"class":802},"    '",[792,894,868],{"class":855},[792,896,865],{"class":802},[792,898,859],{"class":802},[792,900,862],{"class":806},[792,902,865],{"class":802},[792,904,905],{"class":819},"checksFailed",[792,907,865],{"class":802},[792,909,910],{"class":802},",",[792,912,816],{"class":802},[792,914,915],{"class":819},"checksWarn",[792,917,865],{"class":802},[792,919,910],{"class":802},[792,921,816],{"class":802},[792,923,924],{"class":819},"itemsSynced",[792,926,865],{"class":802},[792,928,873],{"class":806},[792,930,876],{"class":802},[792,932,934],{"class":794,"line":933},7,[792,935,936],{"class":802},"  },\n",[792,938,940,943,946],{"class":794,"line":939},8,[792,941,942],{"class":802},"}",[792,944,945],{"class":798}," as",[792,947,948],{"class":839}," const\n",[792,950,952],{"class":794,"line":951},9,[792,953,830],{"emptyLinePlaceholder":829},[792,955,957,959,962,966,969,973,975,979,982],{"class":794,"line":956},10,[792,958,836],{"class":798},[792,960,961],{"class":839}," function",[792,963,965],{"class":964},"s2Zo4"," parseTelemetryBody",[792,967,968],{"class":802},"(",[792,970,972],{"class":971},"sHdIc","raw",[792,974,859],{"class":802},[792,976,978],{"class":977},"sBMFI"," string",[792,980,981],{"class":802},")",[792,983,849],{"class":802},[792,985,987,990,992,994,996,998,1001],{"class":794,"line":986},11,[792,988,989],{"class":798},"  return",[792,991,807],{"class":964},[792,993,968],{"class":855},[792,995,972],{"class":806},[792,997,910],{"class":802},[792,999,1000],{"class":806}," ingestOptions",[792,1002,1003],{"class":855},")\n",[792,1005,1007],{"class":794,"line":1006},12,[792,1008,1009],{"class":802},"}\n",[583,1011,1012,1014,1015,1018,1019,1021,1022,1025,1026,1028],{},[592,1013,761],{}," checks batch size, JSON shape, ",[592,1016,1017],{},"event: 'run'",", tool allowlist, envelope types, ISO timestamp, and strips ",[592,1020,708],{}," keys you did not declare. Throws ",[592,1023,1024],{},"IngestValidationError"," on failure, so return ",[592,1027,678],{}," from your route.",[605,1030,1032],{"id":1031},"step-2-wire-your-route","Step 2: Wire your route",[583,1034,1035,1036,1039],{},"Same contract for any framework: read the raw body, validate, store, return ",[600,1037,1038],{},"204"," so the CLI clears its outbox:",[1041,1042,1043,1413,1670],"code-group",{},[782,1044,1047],{"className":784,"code":1045,"filename":1046,"language":787,"meta":788,"style":788},"import { defineEventHandler, readRawBody, setResponseStatus } from 'h3'\nimport { IngestValidationError } from '@evlog\u002Ftelemetry\u002Fingest'\nimport { parseTelemetryBody } from '~\u002Flib\u002Ftelemetry-ingest'\nimport { storeRunEvents } from '~\u002Flib\u002Ftelemetry-store'\n\nexport default defineEventHandler(async (event) => {\n  const raw = await readRawBody(event, 'utf8')\n  if (!raw) {\n    setResponseStatus(event, 400)\n    return { error: 'empty body' }\n  }\n\n  try {\n    const events = parseTelemetryBody(raw)\n    await storeRunEvents(events)\n    setResponseStatus(event, 204)\n    return null\n  } catch (err) {\n    setResponseStatus(event, err instanceof IngestValidationError ? 400 : 500)\n    return { error: 'invalid payload' }\n  }\n})\n","server\u002Fapi\u002Ftelemetry\u002Fingest.post.ts (Nitro)",[592,1048,1049,1079,1098,1117,1137,1141,1168,1199,1217,1234,1256,1261,1265,1273,1292,1307,1323,1331,1349,1381,1401,1406],{"__ignoreMap":788},[792,1050,1051,1053,1055,1058,1060,1063,1065,1068,1070,1072,1074,1077],{"class":794,"line":795},[792,1052,799],{"class":798},[792,1054,803],{"class":802},[792,1056,1057],{"class":806}," defineEventHandler",[792,1059,910],{"class":802},[792,1061,1062],{"class":806}," readRawBody",[792,1064,910],{"class":802},[792,1066,1067],{"class":806}," setResponseStatus",[792,1069,810],{"class":802},[792,1071,813],{"class":798},[792,1073,816],{"class":802},[792,1075,1076],{"class":819},"h3",[792,1078,823],{"class":802},[792,1080,1081,1083,1085,1088,1090,1092,1094,1096],{"class":794,"line":826},[792,1082,799],{"class":798},[792,1084,803],{"class":802},[792,1086,1087],{"class":806}," IngestValidationError",[792,1089,810],{"class":802},[792,1091,813],{"class":798},[792,1093,816],{"class":802},[792,1095,820],{"class":819},[792,1097,823],{"class":802},[792,1099,1100,1102,1104,1106,1108,1110,1112,1115],{"class":794,"line":833},[792,1101,799],{"class":798},[792,1103,803],{"class":802},[792,1105,965],{"class":806},[792,1107,810],{"class":802},[792,1109,813],{"class":798},[792,1111,816],{"class":802},[792,1113,1114],{"class":819},"~\u002Flib\u002Ftelemetry-ingest",[792,1116,823],{"class":802},[792,1118,1119,1121,1123,1126,1128,1130,1132,1135],{"class":794,"line":852},[792,1120,799],{"class":798},[792,1122,803],{"class":802},[792,1124,1125],{"class":806}," storeRunEvents",[792,1127,810],{"class":802},[792,1129,813],{"class":798},[792,1131,816],{"class":802},[792,1133,1134],{"class":819},"~\u002Flib\u002Ftelemetry-store",[792,1136,823],{"class":802},[792,1138,1139],{"class":794,"line":879},[792,1140,830],{"emptyLinePlaceholder":829},[792,1142,1143,1145,1148,1150,1152,1155,1158,1161,1163,1166],{"class":794,"line":889},[792,1144,836],{"class":798},[792,1146,1147],{"class":798}," default",[792,1149,1057],{"class":964},[792,1151,968],{"class":806},[792,1153,1154],{"class":839},"async",[792,1156,1157],{"class":802}," (",[792,1159,1160],{"class":971},"event",[792,1162,981],{"class":802},[792,1164,1165],{"class":839}," =>",[792,1167,849],{"class":802},[792,1169,1170,1173,1176,1179,1182,1184,1186,1188,1190,1192,1195,1197],{"class":794,"line":933},[792,1171,1172],{"class":839},"  const",[792,1174,1175],{"class":806}," raw",[792,1177,1178],{"class":802}," =",[792,1180,1181],{"class":798}," await",[792,1183,1062],{"class":964},[792,1185,968],{"class":855},[792,1187,1160],{"class":806},[792,1189,910],{"class":802},[792,1191,816],{"class":802},[792,1193,1194],{"class":819},"utf8",[792,1196,865],{"class":802},[792,1198,1003],{"class":855},[792,1200,1201,1204,1206,1209,1211,1214],{"class":794,"line":939},[792,1202,1203],{"class":798},"  if",[792,1205,1157],{"class":855},[792,1207,1208],{"class":802},"!",[792,1210,972],{"class":806},[792,1212,1213],{"class":855},") ",[792,1215,1216],{"class":802},"{\n",[792,1218,1219,1222,1224,1226,1228,1232],{"class":794,"line":951},[792,1220,1221],{"class":964},"    setResponseStatus",[792,1223,968],{"class":855},[792,1225,1160],{"class":806},[792,1227,910],{"class":802},[792,1229,1231],{"class":1230},"sbssI"," 400",[792,1233,1003],{"class":855},[792,1235,1236,1239,1241,1244,1246,1248,1251,1253],{"class":794,"line":956},[792,1237,1238],{"class":798},"    return",[792,1240,803],{"class":802},[792,1242,1243],{"class":855}," error",[792,1245,859],{"class":802},[792,1247,816],{"class":802},[792,1249,1250],{"class":819},"empty body",[792,1252,865],{"class":802},[792,1254,1255],{"class":802}," }\n",[792,1257,1258],{"class":794,"line":986},[792,1259,1260],{"class":802},"  }\n",[792,1262,1263],{"class":794,"line":1006},[792,1264,830],{"emptyLinePlaceholder":829},[792,1266,1268,1271],{"class":794,"line":1267},13,[792,1269,1270],{"class":798},"  try",[792,1272,849],{"class":802},[792,1274,1276,1279,1282,1284,1286,1288,1290],{"class":794,"line":1275},14,[792,1277,1278],{"class":839},"    const",[792,1280,1281],{"class":806}," events",[792,1283,1178],{"class":802},[792,1285,965],{"class":964},[792,1287,968],{"class":855},[792,1289,972],{"class":806},[792,1291,1003],{"class":855},[792,1293,1295,1298,1300,1302,1305],{"class":794,"line":1294},15,[792,1296,1297],{"class":798},"    await",[792,1299,1125],{"class":964},[792,1301,968],{"class":855},[792,1303,1304],{"class":806},"events",[792,1306,1003],{"class":855},[792,1308,1310,1312,1314,1316,1318,1321],{"class":794,"line":1309},16,[792,1311,1221],{"class":964},[792,1313,968],{"class":855},[792,1315,1160],{"class":806},[792,1317,910],{"class":802},[792,1319,1320],{"class":1230}," 204",[792,1322,1003],{"class":855},[792,1324,1326,1328],{"class":794,"line":1325},17,[792,1327,1238],{"class":798},[792,1329,1330],{"class":802}," null\n",[792,1332,1334,1337,1340,1342,1345,1347],{"class":794,"line":1333},18,[792,1335,1336],{"class":802},"  }",[792,1338,1339],{"class":798}," catch",[792,1341,1157],{"class":855},[792,1343,1344],{"class":806},"err",[792,1346,1213],{"class":855},[792,1348,1216],{"class":802},[792,1350,1352,1354,1356,1358,1360,1363,1366,1368,1371,1373,1376,1379],{"class":794,"line":1351},19,[792,1353,1221],{"class":964},[792,1355,968],{"class":855},[792,1357,1160],{"class":806},[792,1359,910],{"class":802},[792,1361,1362],{"class":806}," err",[792,1364,1365],{"class":802}," instanceof",[792,1367,1087],{"class":977},[792,1369,1370],{"class":802}," ?",[792,1372,1231],{"class":1230},[792,1374,1375],{"class":802}," :",[792,1377,1378],{"class":1230}," 500",[792,1380,1003],{"class":855},[792,1382,1384,1386,1388,1390,1392,1394,1397,1399],{"class":794,"line":1383},20,[792,1385,1238],{"class":798},[792,1387,803],{"class":802},[792,1389,1243],{"class":855},[792,1391,859],{"class":802},[792,1393,816],{"class":802},[792,1395,1396],{"class":819},"invalid payload",[792,1398,865],{"class":802},[792,1400,1255],{"class":802},[792,1402,1404],{"class":794,"line":1403},21,[792,1405,1260],{"class":802},[792,1407,1409,1411],{"class":794,"line":1408},22,[792,1410,942],{"class":802},[792,1412,1003],{"class":806},[782,1414,1417],{"className":784,"code":1415,"filename":1416,"language":787,"meta":788,"style":788},"import { IngestValidationError } from '@evlog\u002Ftelemetry\u002Fingest'\nimport { parseTelemetryBody } from '@\u002Flib\u002Ftelemetry-ingest'\nimport { storeRunEvents } from '@\u002Flib\u002Ftelemetry-store'\n\nexport async function POST(request: Request) {\n  const raw = await request.text()\n  try {\n    const events = parseTelemetryBody(raw)\n    await storeRunEvents(events)\n    return new Response(null, { status: 204 })\n  } catch (err) {\n    const status = err instanceof IngestValidationError ? 400 : 500\n    return Response.json({ error: 'invalid payload' }, { status })\n  }\n}\n","app\u002Fapi\u002Ftelemetry\u002Fingest\u002Froute.ts (Next.js App Router)",[592,1418,1419,1437,1456,1475,1479,1505,1526,1532,1548,1560,1588,1602,1625,1662,1666],{"__ignoreMap":788},[792,1420,1421,1423,1425,1427,1429,1431,1433,1435],{"class":794,"line":795},[792,1422,799],{"class":798},[792,1424,803],{"class":802},[792,1426,1087],{"class":806},[792,1428,810],{"class":802},[792,1430,813],{"class":798},[792,1432,816],{"class":802},[792,1434,820],{"class":819},[792,1436,823],{"class":802},[792,1438,1439,1441,1443,1445,1447,1449,1451,1454],{"class":794,"line":826},[792,1440,799],{"class":798},[792,1442,803],{"class":802},[792,1444,965],{"class":806},[792,1446,810],{"class":802},[792,1448,813],{"class":798},[792,1450,816],{"class":802},[792,1452,1453],{"class":819},"@\u002Flib\u002Ftelemetry-ingest",[792,1455,823],{"class":802},[792,1457,1458,1460,1462,1464,1466,1468,1470,1473],{"class":794,"line":833},[792,1459,799],{"class":798},[792,1461,803],{"class":802},[792,1463,1125],{"class":806},[792,1465,810],{"class":802},[792,1467,813],{"class":798},[792,1469,816],{"class":802},[792,1471,1472],{"class":819},"@\u002Flib\u002Ftelemetry-store",[792,1474,823],{"class":802},[792,1476,1477],{"class":794,"line":852},[792,1478,830],{"emptyLinePlaceholder":829},[792,1480,1481,1483,1486,1488,1491,1493,1496,1498,1501,1503],{"class":794,"line":879},[792,1482,836],{"class":798},[792,1484,1485],{"class":839}," async",[792,1487,961],{"class":839},[792,1489,1490],{"class":964}," POST",[792,1492,968],{"class":802},[792,1494,1495],{"class":971},"request",[792,1497,859],{"class":802},[792,1499,1500],{"class":977}," Request",[792,1502,981],{"class":802},[792,1504,849],{"class":802},[792,1506,1507,1509,1511,1513,1515,1518,1520,1523],{"class":794,"line":889},[792,1508,1172],{"class":839},[792,1510,1175],{"class":806},[792,1512,1178],{"class":802},[792,1514,1181],{"class":798},[792,1516,1517],{"class":806}," request",[792,1519,595],{"class":802},[792,1521,1522],{"class":964},"text",[792,1524,1525],{"class":855},"()\n",[792,1527,1528,1530],{"class":794,"line":933},[792,1529,1270],{"class":798},[792,1531,849],{"class":802},[792,1533,1534,1536,1538,1540,1542,1544,1546],{"class":794,"line":939},[792,1535,1278],{"class":839},[792,1537,1281],{"class":806},[792,1539,1178],{"class":802},[792,1541,965],{"class":964},[792,1543,968],{"class":855},[792,1545,972],{"class":806},[792,1547,1003],{"class":855},[792,1549,1550,1552,1554,1556,1558],{"class":794,"line":951},[792,1551,1297],{"class":798},[792,1553,1125],{"class":964},[792,1555,968],{"class":855},[792,1557,1304],{"class":806},[792,1559,1003],{"class":855},[792,1561,1562,1564,1567,1570,1572,1575,1577,1580,1582,1584,1586],{"class":794,"line":956},[792,1563,1238],{"class":798},[792,1565,1566],{"class":802}," new",[792,1568,1569],{"class":964}," Response",[792,1571,968],{"class":855},[792,1573,1574],{"class":802},"null,",[792,1576,803],{"class":802},[792,1578,1579],{"class":855}," status",[792,1581,859],{"class":802},[792,1583,1320],{"class":1230},[792,1585,810],{"class":802},[792,1587,1003],{"class":855},[792,1589,1590,1592,1594,1596,1598,1600],{"class":794,"line":986},[792,1591,1336],{"class":802},[792,1593,1339],{"class":798},[792,1595,1157],{"class":855},[792,1597,1344],{"class":806},[792,1599,1213],{"class":855},[792,1601,1216],{"class":802},[792,1603,1604,1606,1608,1610,1612,1614,1616,1618,1620,1622],{"class":794,"line":1006},[792,1605,1278],{"class":839},[792,1607,1579],{"class":806},[792,1609,1178],{"class":802},[792,1611,1362],{"class":806},[792,1613,1365],{"class":802},[792,1615,1087],{"class":977},[792,1617,1370],{"class":802},[792,1619,1231],{"class":1230},[792,1621,1375],{"class":802},[792,1623,1624],{"class":1230}," 500\n",[792,1626,1627,1629,1631,1633,1636,1638,1641,1643,1645,1647,1649,1651,1654,1656,1658,1660],{"class":794,"line":1267},[792,1628,1238],{"class":798},[792,1630,1569],{"class":806},[792,1632,595],{"class":802},[792,1634,1635],{"class":964},"json",[792,1637,968],{"class":855},[792,1639,1640],{"class":802},"{",[792,1642,1243],{"class":855},[792,1644,859],{"class":802},[792,1646,816],{"class":802},[792,1648,1396],{"class":819},[792,1650,865],{"class":802},[792,1652,1653],{"class":802}," },",[792,1655,803],{"class":802},[792,1657,1579],{"class":806},[792,1659,810],{"class":802},[792,1661,1003],{"class":855},[792,1663,1664],{"class":794,"line":1275},[792,1665,1260],{"class":802},[792,1667,1668],{"class":794,"line":1294},[792,1669,1009],{"class":802},[782,1671,1674],{"className":784,"code":1672,"filename":1673,"language":787,"meta":788,"style":788},"import { Hono } from 'hono'\nimport { IngestValidationError } from '@evlog\u002Ftelemetry\u002Fingest'\nimport { parseTelemetryBody } from '..\u002Flib\u002Ftelemetry-ingest'\nimport { storeRunEvents } from '..\u002Flib\u002Ftelemetry-store'\n\nconst app = new Hono()\n\napp.post('\u002Fapi\u002Ftelemetry\u002Fingest', async (c) => {\n  const raw = await c.req.text()\n  try {\n    const events = parseTelemetryBody(raw)\n    await storeRunEvents(events)\n    return c.body(null, 204)\n  } catch (err) {\n    const status = err instanceof IngestValidationError ? 400 : 500\n    return c.json({ error: 'invalid payload' }, status)\n  }\n})\n\nexport default app\n","src\u002Froutes\u002Ftelemetry.ts (Hono)",[592,1675,1676,1696,1714,1733,1752,1756,1772,1776,1810,1834,1840,1856,1868,1887,1901,1923,1953,1957,1963,1967],{"__ignoreMap":788},[792,1677,1678,1680,1682,1685,1687,1689,1691,1694],{"class":794,"line":795},[792,1679,799],{"class":798},[792,1681,803],{"class":802},[792,1683,1684],{"class":806}," Hono",[792,1686,810],{"class":802},[792,1688,813],{"class":798},[792,1690,816],{"class":802},[792,1692,1693],{"class":819},"hono",[792,1695,823],{"class":802},[792,1697,1698,1700,1702,1704,1706,1708,1710,1712],{"class":794,"line":826},[792,1699,799],{"class":798},[792,1701,803],{"class":802},[792,1703,1087],{"class":806},[792,1705,810],{"class":802},[792,1707,813],{"class":798},[792,1709,816],{"class":802},[792,1711,820],{"class":819},[792,1713,823],{"class":802},[792,1715,1716,1718,1720,1722,1724,1726,1728,1731],{"class":794,"line":833},[792,1717,799],{"class":798},[792,1719,803],{"class":802},[792,1721,965],{"class":806},[792,1723,810],{"class":802},[792,1725,813],{"class":798},[792,1727,816],{"class":802},[792,1729,1730],{"class":819},"..\u002Flib\u002Ftelemetry-ingest",[792,1732,823],{"class":802},[792,1734,1735,1737,1739,1741,1743,1745,1747,1750],{"class":794,"line":852},[792,1736,799],{"class":798},[792,1738,803],{"class":802},[792,1740,1125],{"class":806},[792,1742,810],{"class":802},[792,1744,813],{"class":798},[792,1746,816],{"class":802},[792,1748,1749],{"class":819},"..\u002Flib\u002Ftelemetry-store",[792,1751,823],{"class":802},[792,1753,1754],{"class":794,"line":879},[792,1755,830],{"emptyLinePlaceholder":829},[792,1757,1758,1761,1764,1766,1768,1770],{"class":794,"line":889},[792,1759,1760],{"class":839},"const",[792,1762,1763],{"class":806}," app ",[792,1765,846],{"class":802},[792,1767,1566],{"class":802},[792,1769,1684],{"class":964},[792,1771,1525],{"class":806},[792,1773,1774],{"class":794,"line":933},[792,1775,830],{"emptyLinePlaceholder":829},[792,1777,1778,1781,1783,1786,1788,1790,1793,1795,1797,1799,1801,1804,1806,1808],{"class":794,"line":939},[792,1779,1780],{"class":806},"app",[792,1782,595],{"class":802},[792,1784,1785],{"class":964},"post",[792,1787,968],{"class":806},[792,1789,865],{"class":802},[792,1791,1792],{"class":819},"\u002Fapi\u002Ftelemetry\u002Fingest",[792,1794,865],{"class":802},[792,1796,910],{"class":802},[792,1798,1485],{"class":839},[792,1800,1157],{"class":802},[792,1802,1803],{"class":971},"c",[792,1805,981],{"class":802},[792,1807,1165],{"class":839},[792,1809,849],{"class":802},[792,1811,1812,1814,1816,1818,1820,1823,1825,1828,1830,1832],{"class":794,"line":951},[792,1813,1172],{"class":839},[792,1815,1175],{"class":806},[792,1817,1178],{"class":802},[792,1819,1181],{"class":798},[792,1821,1822],{"class":806}," c",[792,1824,595],{"class":802},[792,1826,1827],{"class":806},"req",[792,1829,595],{"class":802},[792,1831,1522],{"class":964},[792,1833,1525],{"class":855},[792,1835,1836,1838],{"class":794,"line":956},[792,1837,1270],{"class":798},[792,1839,849],{"class":802},[792,1841,1842,1844,1846,1848,1850,1852,1854],{"class":794,"line":986},[792,1843,1278],{"class":839},[792,1845,1281],{"class":806},[792,1847,1178],{"class":802},[792,1849,965],{"class":964},[792,1851,968],{"class":855},[792,1853,972],{"class":806},[792,1855,1003],{"class":855},[792,1857,1858,1860,1862,1864,1866],{"class":794,"line":1006},[792,1859,1297],{"class":798},[792,1861,1125],{"class":964},[792,1863,968],{"class":855},[792,1865,1304],{"class":806},[792,1867,1003],{"class":855},[792,1869,1870,1872,1874,1876,1879,1881,1883,1885],{"class":794,"line":1267},[792,1871,1238],{"class":798},[792,1873,1822],{"class":806},[792,1875,595],{"class":802},[792,1877,1878],{"class":964},"body",[792,1880,968],{"class":855},[792,1882,1574],{"class":802},[792,1884,1320],{"class":1230},[792,1886,1003],{"class":855},[792,1888,1889,1891,1893,1895,1897,1899],{"class":794,"line":1275},[792,1890,1336],{"class":802},[792,1892,1339],{"class":798},[792,1894,1157],{"class":855},[792,1896,1344],{"class":806},[792,1898,1213],{"class":855},[792,1900,1216],{"class":802},[792,1902,1903,1905,1907,1909,1911,1913,1915,1917,1919,1921],{"class":794,"line":1294},[792,1904,1278],{"class":839},[792,1906,1579],{"class":806},[792,1908,1178],{"class":802},[792,1910,1362],{"class":806},[792,1912,1365],{"class":802},[792,1914,1087],{"class":977},[792,1916,1370],{"class":802},[792,1918,1231],{"class":1230},[792,1920,1375],{"class":802},[792,1922,1624],{"class":1230},[792,1924,1925,1927,1929,1931,1933,1935,1937,1939,1941,1943,1945,1947,1949,1951],{"class":794,"line":1309},[792,1926,1238],{"class":798},[792,1928,1822],{"class":806},[792,1930,595],{"class":802},[792,1932,1635],{"class":964},[792,1934,968],{"class":855},[792,1936,1640],{"class":802},[792,1938,1243],{"class":855},[792,1940,859],{"class":802},[792,1942,816],{"class":802},[792,1944,1396],{"class":819},[792,1946,865],{"class":802},[792,1948,1653],{"class":802},[792,1950,1579],{"class":806},[792,1952,1003],{"class":855},[792,1954,1955],{"class":794,"line":1325},[792,1956,1260],{"class":802},[792,1958,1959,1961],{"class":794,"line":1333},[792,1960,942],{"class":802},[792,1962,1003],{"class":806},[792,1964,1965],{"class":794,"line":1351},[792,1966,830],{"emptyLinePlaceholder":829},[792,1968,1969,1971,1973],{"class":794,"line":1383},[792,1970,836],{"class":798},[792,1972,1147],{"class":798},[792,1974,1975],{"class":806}," app\n",[605,1977,1979],{"id":1978},"step-3-store-idempotently","Step 3: Store idempotently",[583,1981,1982,1983,1985],{},"Retries and backlog drains can POST the same ",[592,1984,726],{}," twice. Upsert (or skip) so metrics stay correct:",[782,1987,1990],{"className":784,"code":1988,"filename":1989,"language":787,"meta":788,"style":788},"import type { RunEvent } from '@evlog\u002Ftelemetry'\n\nexport async function storeRunEvents(events: RunEvent[]): Promise\u003Cvoid> {\n  for (const run of events) {\n    await db.telemetryRun.upsert({\n      where: { idempotencyKey: run.idempotencyKey },\n      create: {\n        tool: run.tool.name,\n        version: run.tool.version,\n        command: run.command,\n        outcome: run.outcome,\n        durationMs: run.durationMs,\n        custom: run.custom,\n        recordedAt: run.timestamp,\n      },\n      update: {},\n    })\n  }\n\n  \u002F\u002F Or forward into evlog's drain pipeline for Axiom \u002F Datadog \u002F OTLP:\n  \u002F\u002F await ingestWideEvents(events.map(run => ({ source: 'telemetry', ...run })))\n}\n","lib\u002Ftelemetry-store.ts",[592,1991,1992,2014,2018,2056,2077,2098,2121,2130,2150,2170,2186,2202,2218,2233,2249,2254,2264,2271,2275,2279,2285,2290],{"__ignoreMap":788},[792,1993,1994,1996,1999,2001,2004,2006,2008,2010,2012],{"class":794,"line":795},[792,1995,799],{"class":798},[792,1997,1998],{"class":798}," type",[792,2000,803],{"class":802},[792,2002,2003],{"class":806}," RunEvent",[792,2005,810],{"class":802},[792,2007,813],{"class":798},[792,2009,816],{"class":802},[792,2011,755],{"class":819},[792,2013,823],{"class":802},[792,2015,2016],{"class":794,"line":826},[792,2017,830],{"emptyLinePlaceholder":829},[792,2019,2020,2022,2024,2026,2028,2030,2032,2034,2036,2039,2042,2045,2048,2051,2054],{"class":794,"line":833},[792,2021,836],{"class":798},[792,2023,1485],{"class":839},[792,2025,961],{"class":839},[792,2027,1125],{"class":964},[792,2029,968],{"class":802},[792,2031,1304],{"class":971},[792,2033,859],{"class":802},[792,2035,2003],{"class":977},[792,2037,2038],{"class":806},"[]",[792,2040,2041],{"class":802},"):",[792,2043,2044],{"class":977}," Promise",[792,2046,2047],{"class":802},"\u003C",[792,2049,2050],{"class":977},"void",[792,2052,2053],{"class":802},">",[792,2055,849],{"class":802},[792,2057,2058,2061,2063,2065,2068,2071,2073,2075],{"class":794,"line":852},[792,2059,2060],{"class":798},"  for",[792,2062,1157],{"class":855},[792,2064,1760],{"class":839},[792,2066,2067],{"class":806}," run",[792,2069,2070],{"class":802}," of",[792,2072,1281],{"class":806},[792,2074,1213],{"class":855},[792,2076,1216],{"class":802},[792,2078,2079,2081,2084,2086,2089,2091,2094,2096],{"class":794,"line":879},[792,2080,1297],{"class":798},[792,2082,2083],{"class":806}," db",[792,2085,595],{"class":802},[792,2087,2088],{"class":806},"telemetryRun",[792,2090,595],{"class":802},[792,2092,2093],{"class":964},"upsert",[792,2095,968],{"class":855},[792,2097,1216],{"class":802},[792,2099,2100,2103,2105,2107,2110,2112,2114,2116,2118],{"class":794,"line":889},[792,2101,2102],{"class":855},"      where",[792,2104,859],{"class":802},[792,2106,803],{"class":802},[792,2108,2109],{"class":855}," idempotencyKey",[792,2111,859],{"class":802},[792,2113,2067],{"class":806},[792,2115,595],{"class":802},[792,2117,726],{"class":806},[792,2119,2120],{"class":802}," },\n",[792,2122,2123,2126,2128],{"class":794,"line":933},[792,2124,2125],{"class":855},"      create",[792,2127,859],{"class":802},[792,2129,849],{"class":802},[792,2131,2132,2135,2137,2139,2141,2144,2146,2148],{"class":794,"line":939},[792,2133,2134],{"class":855},"        tool",[792,2136,859],{"class":802},[792,2138,2067],{"class":806},[792,2140,595],{"class":802},[792,2142,2143],{"class":806},"tool",[792,2145,595],{"class":802},[792,2147,774],{"class":806},[792,2149,876],{"class":802},[792,2151,2152,2155,2157,2159,2161,2163,2165,2168],{"class":794,"line":951},[792,2153,2154],{"class":855},"        version",[792,2156,859],{"class":802},[792,2158,2067],{"class":806},[792,2160,595],{"class":802},[792,2162,2143],{"class":806},[792,2164,595],{"class":802},[792,2166,2167],{"class":806},"version",[792,2169,876],{"class":802},[792,2171,2172,2175,2177,2179,2181,2184],{"class":794,"line":956},[792,2173,2174],{"class":855},"        command",[792,2176,859],{"class":802},[792,2178,2067],{"class":806},[792,2180,595],{"class":802},[792,2182,2183],{"class":806},"command",[792,2185,876],{"class":802},[792,2187,2188,2191,2193,2195,2197,2200],{"class":794,"line":986},[792,2189,2190],{"class":855},"        outcome",[792,2192,859],{"class":802},[792,2194,2067],{"class":806},[792,2196,595],{"class":802},[792,2198,2199],{"class":806},"outcome",[792,2201,876],{"class":802},[792,2203,2204,2207,2209,2211,2213,2216],{"class":794,"line":1006},[792,2205,2206],{"class":855},"        durationMs",[792,2208,859],{"class":802},[792,2210,2067],{"class":806},[792,2212,595],{"class":802},[792,2214,2215],{"class":806},"durationMs",[792,2217,876],{"class":802},[792,2219,2220,2223,2225,2227,2229,2231],{"class":794,"line":1267},[792,2221,2222],{"class":855},"        custom",[792,2224,859],{"class":802},[792,2226,2067],{"class":806},[792,2228,595],{"class":802},[792,2230,708],{"class":806},[792,2232,876],{"class":802},[792,2234,2235,2238,2240,2242,2244,2247],{"class":794,"line":1275},[792,2236,2237],{"class":855},"        recordedAt",[792,2239,859],{"class":802},[792,2241,2067],{"class":806},[792,2243,595],{"class":802},[792,2245,2246],{"class":806},"timestamp",[792,2248,876],{"class":802},[792,2250,2251],{"class":794,"line":1294},[792,2252,2253],{"class":802},"      },\n",[792,2255,2256,2259,2261],{"class":794,"line":1309},[792,2257,2258],{"class":855},"      update",[792,2260,859],{"class":802},[792,2262,2263],{"class":802}," {},\n",[792,2265,2266,2269],{"class":794,"line":1325},[792,2267,2268],{"class":802},"    }",[792,2270,1003],{"class":855},[792,2272,2273],{"class":794,"line":1333},[792,2274,1260],{"class":802},[792,2276,2277],{"class":794,"line":1351},[792,2278,830],{"emptyLinePlaceholder":829},[792,2280,2281],{"class":794,"line":1383},[792,2282,2284],{"class":2283},"sHwdD","  \u002F\u002F Or forward into evlog's drain pipeline for Axiom \u002F Datadog \u002F OTLP:\n",[792,2286,2287],{"class":794,"line":1403},[792,2288,2289],{"class":2283},"  \u002F\u002F await ingestWideEvents(events.map(run => ({ source: 'telemetry', ...run })))\n",[792,2291,2292],{"class":794,"line":1408},[792,2293,1009],{"class":802},[605,2295,2297],{"id":2296},"step-4-rate-limit-at-the-edge","Step 4: Rate-limit at the edge",[583,2299,2300,2302,2303,2306],{},[592,2301,761],{}," is your last line of schema defense, not your only one. Add rate limits where traffic enters (CDN, API gateway, or middleware), especially per IP. Optional: also bucket by ",[592,2304,2305],{},"machineId"," hash inside the handler if you need tighter control.",[583,2308,2309,2310,2312,2313,2316],{},"Non-2xx responses keep events in the user's outbox; they will retry on the next CLI invocation. Return ",[600,2311,1038],{}," (or any ",[592,2314,2315],{},"2xx",") only when storage succeeded.",[2318,2319,2320],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":788,"searchDepth":826,"depth":826,"links":2322},[2323,2324,2326,2327,2328],{"id":607,"depth":826,"text":608},{"id":765,"depth":826,"text":2325},"Step 1: Validate with parseIngestBody()",{"id":1031,"depth":826,"text":1032},{"id":1978,"depth":826,"text":1979},{"id":2296,"depth":826,"text":2297},"Build the ingestion endpoint for @evlog\u002Ftelemetry: the threat model, parseIngestBody validation, framework routes, storage, and rate limiting.","md",[2332,2335,2336],{"label":41,"icon":44,"to":423,"color":2333,"variant":2334},"neutral","subtle",{"label":426,"icon":429,"to":427,"color":2333,"variant":2334},{"label":436,"icon":84,"to":437,"color":2333,"variant":2334},{},{"title":431,"icon":434},{"title":578,"description":2329},"rFp9uwlFbw94P_AK3Grez6dlVtWQc2B56C4Go2gQXgc",[2342,2344],{"title":426,"path":427,"stem":428,"description":2343,"icon":429,"children":-1},"Wire @evlog\u002Ftelemetry into citty CLIs, standalone scripts, and GitHub Actions — delivery config, automatic flag capture, telemetry.set(), and debug mode.",{"title":436,"path":437,"stem":438,"description":2345,"icon":84,"children":-1},"RunEvent envelope, extending the schema with collect and custom fields, privacy rules, TELEMETRY.md disclosure, and consent \u002F outbox reliability.",1789915916460]