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