[{"data":1,"prerenderedAt":1317},["ShallowReactive",2],{"navigation_docs":3,"-use-cases-audit-pipeline":429,"-use-cases-audit-pipeline-surround":1312},[4,30,80,235,343,398],{"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},"Integrate","\u002Fintegrate","3.integrate",[85,89,152],{"title":36,"path":86,"stem":87,"icon":88},"\u002Fintegrate\u002Foverview","3.integrate\u002F0.overview","i-lucide-plug",{"title":90,"path":91,"stem":92,"children":93,"page":29},"Adapters","\u002Fintegrate\u002Fadapters","3.integrate\u002Fadapters",[94,97,137],{"title":36,"path":95,"stem":96,"icon":39},"\u002Fintegrate\u002Fadapters\u002Foverview","3.integrate\u002Fadapters\u002F01.overview",{"title":98,"path":99,"stem":100,"children":101,"page":29},"Cloud","\u002Fintegrate\u002Fadapters\u002Fcloud","3.integrate\u002Fadapters\u002Fcloud",[102,107,112,117,122,127,132],{"title":103,"path":104,"stem":105,"icon":106},"Axiom","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Faxiom","3.integrate\u002Fadapters\u002Fcloud\u002F01.axiom","i-custom-axiom",{"title":108,"path":109,"stem":110,"icon":111},"OTLP","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fotlp","3.integrate\u002Fadapters\u002Fcloud\u002F02.otlp","i-simple-icons-opentelemetry",{"title":113,"path":114,"stem":115,"icon":116},"PostHog","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fposthog","3.integrate\u002Fadapters\u002Fcloud\u002F03.posthog","i-simple-icons-posthog",{"title":118,"path":119,"stem":120,"icon":121},"Sentry","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fsentry","3.integrate\u002Fadapters\u002Fcloud\u002F04.sentry","i-simple-icons-sentry",{"title":123,"path":124,"stem":125,"icon":126},"Better Stack","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fbetter-stack","3.integrate\u002Fadapters\u002Fcloud\u002F05.better-stack","i-simple-icons-betterstack",{"title":128,"path":129,"stem":130,"icon":131},"Datadog","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fdatadog","3.integrate\u002Fadapters\u002Fcloud\u002F06.datadog","i-simple-icons-datadog",{"title":133,"path":134,"stem":135,"icon":136},"HyperDX","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fhyperdx","3.integrate\u002Fadapters\u002Fcloud\u002F07.hyperdx","i-custom-hyperdx",{"title":138,"path":139,"stem":140,"children":141,"page":29},"Self-Hosted","\u002Fintegrate\u002Fadapters\u002Fself-hosted","3.integrate\u002Fadapters\u002Fself-hosted",[142,147],{"title":143,"path":144,"stem":145,"icon":146},"File System","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Ffs","3.integrate\u002Fadapters\u002Fself-hosted\u002F01.fs","i-lucide-hard-drive",{"title":148,"path":149,"stem":150,"icon":151},"NuxtHub","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Fnuxthub","3.integrate\u002Fadapters\u002Fself-hosted\u002F02.nuxthub","i-simple-icons-nuxt",{"title":153,"path":154,"stem":155,"children":156,"page":29},"Frameworks","\u002Fintegrate\u002Fframeworks","3.integrate\u002Fframeworks",[157,161,166,171,176,181,186,191,196,201,206,211,216,221,225,230],{"title":36,"path":158,"stem":159,"icon":160},"\u002Fintegrate\u002Fframeworks\u002Foverview","3.integrate\u002Fframeworks\u002F00.overview","i-lucide-layout-grid",{"title":162,"path":163,"stem":164,"icon":165},"Nuxt","\u002Fintegrate\u002Fframeworks\u002Fnuxt","3.integrate\u002Fframeworks\u002F01.nuxt","i-simple-icons-nuxtdotjs",{"title":167,"path":168,"stem":169,"icon":170},"Next.js","\u002Fintegrate\u002Fframeworks\u002Fnextjs","3.integrate\u002Fframeworks\u002F02.nextjs","i-simple-icons-nextdotjs",{"title":172,"path":173,"stem":174,"icon":175},"SvelteKit","\u002Fintegrate\u002Fframeworks\u002Fsveltekit","3.integrate\u002Fframeworks\u002F03.sveltekit","i-simple-icons-svelte",{"title":177,"path":178,"stem":179,"icon":180},"Nitro","\u002Fintegrate\u002Fframeworks\u002Fnitro","3.integrate\u002Fframeworks\u002F04.nitro","i-custom-nitro",{"title":182,"path":183,"stem":184,"icon":185},"TanStack Start","\u002Fintegrate\u002Fframeworks\u002Ftanstack-start","3.integrate\u002Fframeworks\u002F05.tanstack-start","i-custom-tanstack",{"title":187,"path":188,"stem":189,"icon":190},"NestJS","\u002Fintegrate\u002Fframeworks\u002Fnestjs","3.integrate\u002Fframeworks\u002F06.nestjs","i-simple-icons-nestjs",{"title":192,"path":193,"stem":194,"icon":195},"Express","\u002Fintegrate\u002Fframeworks\u002Fexpress","3.integrate\u002Fframeworks\u002F07.express","i-simple-icons-express",{"title":197,"path":198,"stem":199,"icon":200},"Hono","\u002Fintegrate\u002Fframeworks\u002Fhono","3.integrate\u002Fframeworks\u002F08.hono","i-simple-icons-hono",{"title":202,"path":203,"stem":204,"icon":205},"Fastify","\u002Fintegrate\u002Fframeworks\u002Ffastify","3.integrate\u002Fframeworks\u002F09.fastify","i-simple-icons-fastify",{"title":207,"path":208,"stem":209,"icon":210},"Elysia","\u002Fintegrate\u002Fframeworks\u002Felysia","3.integrate\u002Fframeworks\u002F10.elysia","i-custom-elysia",{"title":212,"path":213,"stem":214,"icon":215},"React Router","\u002Fintegrate\u002Fframeworks\u002Freact-router","3.integrate\u002Fframeworks\u002F11.react-router","i-custom-reactrouter",{"title":217,"path":218,"stem":219,"icon":220},"Cloudflare Workers","\u002Fintegrate\u002Fframeworks\u002Fcloudflare-workers","3.integrate\u002Fframeworks\u002F12.cloudflare-workers","i-simple-icons-cloudflare",{"title":222,"path":223,"stem":224,"icon":74},"Standalone","\u002Fintegrate\u002Fframeworks\u002Fstandalone","3.integrate\u002Fframeworks\u002F13.standalone",{"title":226,"path":227,"stem":228,"icon":229},"Astro","\u002Fintegrate\u002Fframeworks\u002Fastro","3.integrate\u002Fframeworks\u002F14.astro","i-simple-icons-astro",{"title":231,"path":232,"stem":233,"icon":234},"AWS Lambda","\u002Fintegrate\u002Fframeworks\u002Faws-lambda","3.integrate\u002Fframeworks\u002F16.aws-lambda","i-custom-lambda",{"title":236,"path":237,"stem":238,"children":239,"page":29},"Use Cases","\u002Fuse-cases","4.use-cases",[240,244,249,278,306,338],{"title":36,"path":241,"stem":242,"icon":243},"\u002Fuse-cases\u002Foverview","4.use-cases\u002F0.overview","i-lucide-list-checks",{"title":245,"path":246,"stem":247,"icon":248},"Client Logging","\u002Fuse-cases\u002Fclient-logging","4.use-cases\u002F1.client-logging","i-lucide-monitor",{"title":250,"icon":251,"path":252,"stem":253,"children":254,"page":29},"AI SDK","i-simple-icons-vercel","\u002Fuse-cases\u002Fai-sdk","4.use-cases\u002F2.ai-sdk",[255,258,263,268,273],{"title":36,"path":256,"stem":257,"icon":39},"\u002Fuse-cases\u002Fai-sdk\u002Foverview","4.use-cases\u002F2.ai-sdk\u002F01.overview",{"title":259,"path":260,"stem":261,"icon":262},"Usage","\u002Fuse-cases\u002Fai-sdk\u002Fusage","4.use-cases\u002F2.ai-sdk\u002F02.usage","i-lucide-code",{"title":264,"path":265,"stem":266,"icon":267},"Options","\u002Fuse-cases\u002Fai-sdk\u002Foptions","4.use-cases\u002F2.ai-sdk\u002F03.options","i-lucide-sliders",{"title":269,"path":270,"stem":271,"icon":272},"Metadata","\u002Fuse-cases\u002Fai-sdk\u002Fmetadata","4.use-cases\u002F2.ai-sdk\u002F04.metadata","i-lucide-database",{"title":274,"path":275,"stem":276,"icon":277},"Telemetry","\u002Fuse-cases\u002Fai-sdk\u002Ftelemetry","4.use-cases\u002F2.ai-sdk\u002F05.telemetry","i-lucide-activity",{"title":279,"icon":280,"path":281,"stem":282,"children":283,"page":29},"Better Auth","i-simple-icons-betterauth","\u002Fuse-cases\u002Fbetter-auth","4.use-cases\u002F3.better-auth",[284,287,292,297,301],{"title":36,"path":285,"stem":286,"icon":39},"\u002Fuse-cases\u002Fbetter-auth\u002Foverview","4.use-cases\u002F3.better-auth\u002F01.overview",{"title":288,"path":289,"stem":290,"icon":291},"Identify User","\u002Fuse-cases\u002Fbetter-auth\u002Fidentify-user","4.use-cases\u002F3.better-auth\u002F02.identify-user","i-lucide-user-check",{"title":293,"path":294,"stem":295,"icon":296},"Middleware","\u002Fuse-cases\u002Fbetter-auth\u002Fmiddleware","4.use-cases\u002F3.better-auth\u002F03.middleware","i-lucide-shield",{"title":298,"path":299,"stem":300,"icon":248},"Client Sync","\u002Fuse-cases\u002Fbetter-auth\u002Fclient-sync","4.use-cases\u002F3.better-auth\u002F04.client-sync",{"title":302,"path":303,"stem":304,"icon":305},"Performance","\u002Fuse-cases\u002Fbetter-auth\u002Fperformance","4.use-cases\u002F3.better-auth\u002F05.performance","i-lucide-gauge",{"title":307,"icon":308,"path":309,"stem":310,"children":311,"page":29},"Audit Logs","i-lucide-shield-check","\u002Fuse-cases\u002Faudit","4.use-cases\u002F4.audit",[312,315,320,325,330,334],{"title":36,"path":313,"stem":314,"icon":39},"\u002Fuse-cases\u002Faudit\u002Foverview","4.use-cases\u002F4.audit\u002F01.overview",{"title":316,"path":317,"stem":318,"icon":319},"Schema","\u002Fuse-cases\u002Faudit\u002Fschema","4.use-cases\u002F4.audit\u002F02.schema","i-lucide-file-text",{"title":321,"path":322,"stem":323,"icon":324},"Recording","\u002Fuse-cases\u002Faudit\u002Frecording","4.use-cases\u002F4.audit\u002F03.recording","i-lucide-pen-line",{"title":326,"path":327,"stem":328,"icon":329},"Drains","\u002Fuse-cases\u002Faudit\u002Fpipeline","4.use-cases\u002F4.audit\u002F04.pipeline","i-lucide-link",{"title":331,"path":332,"stem":333,"icon":308},"Compliance","\u002Fuse-cases\u002Faudit\u002Fcompliance","4.use-cases\u002F4.audit\u002F05.compliance",{"title":335,"path":336,"stem":337,"icon":79},"Recipes","\u002Fuse-cases\u002Faudit\u002Frecipes","4.use-cases\u002F4.audit\u002F06.recipes",{"title":339,"path":340,"stem":341,"icon":342},"Enrichers","\u002Fuse-cases\u002Fenrichers","4.use-cases\u002F5.enrichers","i-lucide-sparkles",{"title":344,"path":345,"stem":346,"children":347,"page":29},"Extend","\u002Fextend","5.extend",[348,352,357,362,367,371,375,379,383,388,393],{"title":36,"path":349,"stem":350,"icon":351},"\u002Fextend\u002Foverview","5.extend\u002F0.overview","i-lucide-blocks",{"title":353,"path":354,"stem":355,"icon":356},"Stream","\u002Fextend\u002Fstream","5.extend\u002F1.stream","i-lucide-radio-tower",{"title":358,"path":359,"stem":360,"icon":361},"Custom framework","\u002Fextend\u002Fcustom-framework","5.extend\u002F10.custom-framework","i-lucide-puzzle",{"title":363,"path":364,"stem":365,"icon":366},"FS reader","\u002Fextend\u002Ffs-reader","5.extend\u002F2.fs-reader","i-lucide-folder-search",{"title":335,"path":368,"stem":369,"icon":370},"\u002Fextend\u002Fconsumer-recipes","5.extend\u002F3.consumer-recipes","i-lucide-chef-hat",{"title":372,"path":373,"stem":374,"icon":351},"Plugins","\u002Fextend\u002Fplugins","5.extend\u002F4.plugins",{"title":376,"path":377,"stem":378,"icon":342},"Custom enrichers","\u002Fextend\u002Fcustom-enrichers","5.extend\u002F5.custom-enrichers",{"title":380,"path":381,"stem":382,"icon":64},"Tail sampling","\u002Fextend\u002Ftail-sampling","5.extend\u002F6.tail-sampling",{"title":384,"path":385,"stem":386,"icon":387},"Identity headers","\u002Fextend\u002Fidentity-headers","5.extend\u002F7.identity-headers","i-lucide-fingerprint",{"title":389,"path":390,"stem":391,"icon":392},"Custom drains","\u002Fextend\u002Fcustom-drains","5.extend\u002F8.custom-drains","i-lucide-share-2",{"title":394,"path":395,"stem":396,"icon":397},"Drain pipeline","\u002Fextend\u002Fdrain-pipeline","5.extend\u002F9.drain-pipeline","i-lucide-workflow",{"title":399,"path":400,"stem":401,"children":402,"page":29},"Reference","\u002Freference","6.reference",[403,408,411,416,420,425],{"title":404,"path":405,"stem":406,"icon":407},"Configuration","\u002Freference\u002Fconfiguration","6.reference\u002F1.configuration","i-lucide-settings",{"title":302,"path":409,"stem":410,"icon":305},"\u002Freference\u002Fperformance","6.reference\u002F2.performance",{"title":412,"path":413,"stem":414,"icon":415},"Vite Plugin","\u002Freference\u002Fvite-plugin","6.reference\u002F3.vite-plugin","i-custom-vite",{"title":417,"path":418,"stem":419,"icon":308},"Best Practices","\u002Freference\u002Fbest-practices","6.reference\u002F4.best-practices",{"title":421,"path":422,"stem":423,"icon":424},"vs Other Loggers","\u002Freference\u002Fvs-other-loggers","6.reference\u002F5.vs-other-loggers","i-lucide-scale",{"title":426,"path":427,"stem":428,"icon":342},"Agent Skills","\u002Freference\u002Fagent-skills","6.reference\u002F6.agent-skills",{"id":430,"title":431,"body":432,"description":1301,"extension":1302,"links":1303,"meta":1308,"navigation":1309,"path":327,"seo":1310,"stem":328,"__hash__":1311},"docs\u002F4.use-cases\u002F4.audit\u002F04.pipeline.md","Drains & Integrity",{"type":433,"value":434,"toc":1293},"minimark",[435,452,459,468,555,558,681,699,705,725,739,876,883,935,941,946,952,1009,1026,1031,1034,1109,1113,1116,1265,1271,1274,1289],[436,437,438,439,443,444,447,448,451],"p",{},"Three building blocks: ",[440,441,442],"code",{},"auditEnricher"," fills context, ",[440,445,446],{},"auditOnly"," routes audits to a dedicated drain, and ",[440,449,450],{},"signed"," adds tamper-evident integrity. Each is opt-in and replaceable.",[453,454,456],"h2",{"id":455},"auditenricher",[440,457,458],{},"auditEnricher()",[436,460,461,463,464,467],{},[440,462,458],{}," populates ",[440,465,466],{},"event.audit.context.{requestId, traceId, ip, userAgent, tenantId}",". Skip it and ship a custom enricher if your strategy differs.",[469,470,476],"pre",{"className":471,"code":472,"filename":473,"language":474,"meta":475,"style":475},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { auditEnricher } from 'evlog'\n\nnitro.hooks.hook('evlog:enrich', auditEnricher())\n","server\u002Fplugins\u002Fevlog.ts","typescript","",[440,477,478,511,518],{"__ignoreMap":475},[479,480,483,487,491,495,498,501,504,508],"span",{"class":481,"line":482},"line",1,[479,484,486],{"class":485},"s7zQu","import",[479,488,490],{"class":489},"sMK4o"," {",[479,492,494],{"class":493},"sTEyZ"," auditEnricher",[479,496,497],{"class":489}," }",[479,499,500],{"class":485}," from",[479,502,503],{"class":489}," '",[479,505,507],{"class":506},"sfazB","evlog",[479,509,510],{"class":489},"'\n",[479,512,514],{"class":481,"line":513},2,[479,515,517],{"emptyLinePlaceholder":516},true,"\n",[479,519,521,524,527,530,532,536,539,542,545,547,550,552],{"class":481,"line":520},3,[479,522,523],{"class":493},"nitro",[479,525,526],{"class":489},".",[479,528,529],{"class":493},"hooks",[479,531,526],{"class":489},[479,533,535],{"class":534},"s2Zo4","hook",[479,537,538],{"class":493},"(",[479,540,541],{"class":489},"'",[479,543,544],{"class":506},"evlog:enrich",[479,546,541],{"class":489},[479,548,549],{"class":489},",",[479,551,494],{"class":534},[479,553,554],{"class":493},"())\n",[436,556,557],{},"For multi-tenant apps and custom session bridges, pass options:",[469,559,561],{"className":471,"code":560,"language":474,"meta":475,"style":475},"nitro.hooks.hook('evlog:enrich', auditEnricher({\n  tenantId: ctx => ctx.event.tenant as string | undefined,\n  bridge: { getSession: async ctx => readSessionActor(ctx.headers) },\n}))\n",[440,562,563,592,636,672],{"__ignoreMap":475},[479,564,565,567,569,571,573,575,577,579,581,583,585,587,589],{"class":481,"line":482},[479,566,523],{"class":493},[479,568,526],{"class":489},[479,570,529],{"class":493},[479,572,526],{"class":489},[479,574,535],{"class":534},[479,576,538],{"class":493},[479,578,541],{"class":489},[479,580,544],{"class":506},[479,582,541],{"class":489},[479,584,549],{"class":489},[479,586,494],{"class":534},[479,588,538],{"class":493},[479,590,591],{"class":489},"{\n",[479,593,594,597,600,604,608,610,612,615,617,620,623,627,630,633],{"class":481,"line":513},[479,595,596],{"class":534},"  tenantId",[479,598,599],{"class":489},":",[479,601,603],{"class":602},"sHdIc"," ctx",[479,605,607],{"class":606},"spNyl"," =>",[479,609,603],{"class":493},[479,611,526],{"class":489},[479,613,614],{"class":493},"event",[479,616,526],{"class":489},[479,618,619],{"class":493},"tenant ",[479,621,622],{"class":485},"as",[479,624,626],{"class":625},"sBMFI"," string",[479,628,629],{"class":489}," |",[479,631,632],{"class":625}," undefined",[479,634,635],{"class":489},",\n",[479,637,638,642,644,646,649,651,654,656,658,661,664,666,669],{"class":481,"line":520},[479,639,641],{"class":640},"swJcz","  bridge",[479,643,599],{"class":489},[479,645,490],{"class":489},[479,647,648],{"class":534}," getSession",[479,650,599],{"class":489},[479,652,653],{"class":606}," async",[479,655,603],{"class":602},[479,657,607],{"class":606},[479,659,660],{"class":534}," readSessionActor",[479,662,663],{"class":493},"(ctx",[479,665,526],{"class":489},[479,667,668],{"class":493},"headers) ",[479,670,671],{"class":489},"},\n",[479,673,675,678],{"class":481,"line":674},4,[479,676,677],{"class":489},"}",[479,679,680],{"class":493},"))\n",[436,682,683,684,686,687,690,691,694,695,698],{},"Without ",[440,685,442],{},", ",[440,688,689],{},"audit.context"," stays empty — auditors and incident responders need at least ",[440,692,693],{},"requestId"," and ",[440,696,697],{},"ip"," to triangulate a recorded action.",[453,700,702],{"id":701},"auditonly",[440,703,704],{},"auditOnly()",[706,707,708,712,713,716,717,720,721,724],"tip",{},[709,710,711],"strong",{},"Why filter audits to a separate sink?"," Three reasons: ",[709,714,715],{},"cost"," (audit volume is tiny next to product telemetry — keep them separate so retention costs don't explode), ",[709,718,719],{},"permissions"," (the audit dataset should be read-only for engineers and write-only for the app), and ",[709,722,723],{},"retention"," (audits often live 7+ years; product logs rarely live more than 90 days).",[436,726,727,730,731,734,735,738],{},[440,728,729],{},"auditOnly(drain)"," only forwards events with an ",[440,732,733],{},"audit"," field. Compose with ",[709,736,737],{},"any"," drain:",[469,740,742],{"className":471,"code":741,"language":474,"meta":475,"style":475},"import { auditOnly } from 'evlog'\nimport { createAxiomDrain } from 'evlog\u002Faxiom'\n\n\u002F\u002F Send audits to a dedicated Axiom dataset:\nnitro.hooks.hook('evlog:drain', auditOnly(\n  createAxiomDrain({ dataset: 'audit', token: process.env.AXIOM_AUDIT_TOKEN }),\n))\n",[440,743,744,763,783,787,793,822,871],{"__ignoreMap":475},[479,745,746,748,750,753,755,757,759,761],{"class":481,"line":482},[479,747,486],{"class":485},[479,749,490],{"class":489},[479,751,752],{"class":493}," auditOnly",[479,754,497],{"class":489},[479,756,500],{"class":485},[479,758,503],{"class":489},[479,760,507],{"class":506},[479,762,510],{"class":489},[479,764,765,767,769,772,774,776,778,781],{"class":481,"line":513},[479,766,486],{"class":485},[479,768,490],{"class":489},[479,770,771],{"class":493}," createAxiomDrain",[479,773,497],{"class":489},[479,775,500],{"class":485},[479,777,503],{"class":489},[479,779,780],{"class":506},"evlog\u002Faxiom",[479,782,510],{"class":489},[479,784,785],{"class":481,"line":520},[479,786,517],{"emptyLinePlaceholder":516},[479,788,789],{"class":481,"line":674},[479,790,792],{"class":791},"sHwdD","\u002F\u002F Send audits to a dedicated Axiom dataset:\n",[479,794,796,798,800,802,804,806,808,810,813,815,817,819],{"class":481,"line":795},5,[479,797,523],{"class":493},[479,799,526],{"class":489},[479,801,529],{"class":493},[479,803,526],{"class":489},[479,805,535],{"class":534},[479,807,538],{"class":493},[479,809,541],{"class":489},[479,811,812],{"class":506},"evlog:drain",[479,814,541],{"class":489},[479,816,549],{"class":489},[479,818,752],{"class":534},[479,820,821],{"class":493},"(\n",[479,823,825,828,830,833,836,838,840,842,844,846,849,851,854,856,859,861,864,866,869],{"class":481,"line":824},6,[479,826,827],{"class":534},"  createAxiomDrain",[479,829,538],{"class":493},[479,831,832],{"class":489},"{",[479,834,835],{"class":640}," dataset",[479,837,599],{"class":489},[479,839,503],{"class":489},[479,841,733],{"class":506},[479,843,541],{"class":489},[479,845,549],{"class":489},[479,847,848],{"class":640}," token",[479,850,599],{"class":489},[479,852,853],{"class":493}," process",[479,855,526],{"class":489},[479,857,858],{"class":493},"env",[479,860,526],{"class":489},[479,862,863],{"class":493},"AXIOM_AUDIT_TOKEN ",[479,865,677],{"class":489},[479,867,868],{"class":493},")",[479,870,635],{"class":489},[479,872,874],{"class":481,"line":873},7,[479,875,680],{"class":493},[436,877,878,879,882],{},"Set ",[440,880,881],{},"await: true"," to make audit writes synchronous (no fire-and-forget for audits — crash-safe by default):",[469,884,886],{"className":471,"code":885,"language":474,"meta":475,"style":475},"auditOnly(createFsDrain({ dir: '.audit' }), { await: true })\n",[440,887,888],{"__ignoreMap":475},[479,889,890,892,894,897,899,901,904,906,908,911,913,915,917,919,921,924,926,930,932],{"class":481,"line":482},[479,891,446],{"class":534},[479,893,538],{"class":493},[479,895,896],{"class":534},"createFsDrain",[479,898,538],{"class":493},[479,900,832],{"class":489},[479,902,903],{"class":640}," dir",[479,905,599],{"class":489},[479,907,503],{"class":489},[479,909,910],{"class":506},".audit",[479,912,541],{"class":489},[479,914,497],{"class":489},[479,916,868],{"class":493},[479,918,549],{"class":489},[479,920,490],{"class":489},[479,922,923],{"class":640}," await",[479,925,599],{"class":489},[479,927,929],{"class":928},"sfNiH"," true",[479,931,497],{"class":489},[479,933,934],{"class":493},")\n",[436,936,937,938,940],{},"The ",[440,939,881],{}," flag costs you a small bit of latency per request that records an audit (one synchronous drain call), but guarantees the audit hits disk before the response is sent. For compliance-grade audits, the trade-off is always worth it.",[453,942,943],{"id":450},[440,944,945],{},"signed()",[436,947,948,951],{},[440,949,950],{},"signed(drain, opts)"," adds tamper-evident integrity. Two strategies:",[953,954,955,971],"table",{},[956,957,958],"thead",{},[959,960,961,965,968],"tr",{},[962,963,964],"th",{},"Strategy",[962,966,967],{},"What it adds",[962,969,970],{},"Use case",[972,973,974,991],"tbody",{},[959,975,976,982,988],{},[977,978,979],"td",{},[440,980,981],{},"'hmac'",[977,983,984,987],{},[440,985,986],{},"event.audit.signature"," (HMAC of the canonical event)",[977,989,990],{},"Single-event integrity check (any later mutation fails verification).",[959,992,993,998,1006],{},[977,994,995],{},[440,996,997],{},"'hash-chain'",[977,999,1000,694,1003],{},[440,1001,1002],{},"event.audit.prevHash",[440,1004,1005],{},"event.audit.hash",[977,1007,1008],{},"A verifiable chain — deletions and reordering also become detectable.",[706,1010,1011,1017,1018,1022,1023,1025],{},[709,1012,1013,1014,1016],{},"What ",[440,1015,945],{}," actually buys you."," Detection, not prevention. Anyone with write access to the underlying sink can still nuke the file or table — but the chain proves ",[1019,1020,1021],"em",{},"which"," events were dropped or modified after the fact. Skip ",[440,1024,945],{}," if you already write to an append-only \u002F WORM store (S3 Object Lock, Postgres with row-level immutability, BigQuery append-only tables); doubling integrity layers just adds latency without raising the bar.",[1027,1028,1030],"h3",{"id":1029},"hmac","HMAC",[436,1032,1033],{},"Each event gets a signature. Tampering with one row breaks that row's verification, but doesn't break later rows.",[469,1035,1037],{"className":471,"code":1036,"language":474,"meta":475,"style":475},"import { signed } from 'evlog'\n\nsigned(drain, { strategy: 'hmac', secret: process.env.AUDIT_SECRET! })\n",[440,1038,1039,1058,1062],{"__ignoreMap":475},[479,1040,1041,1043,1045,1048,1050,1052,1054,1056],{"class":481,"line":482},[479,1042,486],{"class":485},[479,1044,490],{"class":489},[479,1046,1047],{"class":493}," signed",[479,1049,497],{"class":489},[479,1051,500],{"class":485},[479,1053,503],{"class":489},[479,1055,507],{"class":506},[479,1057,510],{"class":489},[479,1059,1060],{"class":481,"line":513},[479,1061,517],{"emptyLinePlaceholder":516},[479,1063,1064,1066,1069,1071,1073,1076,1078,1080,1082,1084,1086,1089,1091,1093,1095,1097,1099,1102,1105,1107],{"class":481,"line":520},[479,1065,450],{"class":534},[479,1067,1068],{"class":493},"(drain",[479,1070,549],{"class":489},[479,1072,490],{"class":489},[479,1074,1075],{"class":640}," strategy",[479,1077,599],{"class":489},[479,1079,503],{"class":489},[479,1081,1029],{"class":506},[479,1083,541],{"class":489},[479,1085,549],{"class":489},[479,1087,1088],{"class":640}," secret",[479,1090,599],{"class":489},[479,1092,853],{"class":493},[479,1094,526],{"class":489},[479,1096,858],{"class":493},[479,1098,526],{"class":489},[479,1100,1101],{"class":493},"AUDIT_SECRET",[479,1103,1104],{"class":489},"!",[479,1106,497],{"class":489},[479,1108,934],{"class":493},[1027,1110,1112],{"id":1111},"hash-chain","Hash-chain",[436,1114,1115],{},"Each event references the previous event's hash. Deleting any row breaks the chain forward of that point, so the verifier can pinpoint the exact row that was tampered with.",[469,1117,1119],{"className":471,"code":1118,"language":474,"meta":475,"style":475},"signed(drain, {\n  strategy: 'hash-chain',\n  state: {\n    load: () => fs.readFile('.audit\u002Fhead', 'utf8').catch(() => null),\n    save: (h) => fs.writeFile('.audit\u002Fhead', h),\n  },\n})\n",[440,1120,1121,1132,1147,1156,1215,1254,1259],{"__ignoreMap":475},[479,1122,1123,1125,1127,1129],{"class":481,"line":482},[479,1124,450],{"class":534},[479,1126,1068],{"class":493},[479,1128,549],{"class":489},[479,1130,1131],{"class":489}," {\n",[479,1133,1134,1137,1139,1141,1143,1145],{"class":481,"line":513},[479,1135,1136],{"class":640},"  strategy",[479,1138,599],{"class":489},[479,1140,503],{"class":489},[479,1142,1111],{"class":506},[479,1144,541],{"class":489},[479,1146,635],{"class":489},[479,1148,1149,1152,1154],{"class":481,"line":520},[479,1150,1151],{"class":640},"  state",[479,1153,599],{"class":489},[479,1155,1131],{"class":489},[479,1157,1158,1161,1163,1166,1168,1171,1173,1176,1178,1180,1183,1185,1187,1189,1192,1194,1196,1198,1201,1203,1206,1208,1211,1213],{"class":481,"line":674},[479,1159,1160],{"class":534},"    load",[479,1162,599],{"class":489},[479,1164,1165],{"class":489}," ()",[479,1167,607],{"class":606},[479,1169,1170],{"class":493}," fs",[479,1172,526],{"class":489},[479,1174,1175],{"class":534},"readFile",[479,1177,538],{"class":493},[479,1179,541],{"class":489},[479,1181,1182],{"class":506},".audit\u002Fhead",[479,1184,541],{"class":489},[479,1186,549],{"class":489},[479,1188,503],{"class":489},[479,1190,1191],{"class":506},"utf8",[479,1193,541],{"class":489},[479,1195,868],{"class":493},[479,1197,526],{"class":489},[479,1199,1200],{"class":534},"catch",[479,1202,538],{"class":493},[479,1204,1205],{"class":489},"()",[479,1207,607],{"class":606},[479,1209,1210],{"class":489}," null",[479,1212,868],{"class":493},[479,1214,635],{"class":489},[479,1216,1217,1220,1222,1225,1228,1230,1232,1234,1236,1239,1241,1243,1245,1247,1249,1252],{"class":481,"line":795},[479,1218,1219],{"class":534},"    save",[479,1221,599],{"class":489},[479,1223,1224],{"class":489}," (",[479,1226,1227],{"class":602},"h",[479,1229,868],{"class":489},[479,1231,607],{"class":606},[479,1233,1170],{"class":493},[479,1235,526],{"class":489},[479,1237,1238],{"class":534},"writeFile",[479,1240,538],{"class":493},[479,1242,541],{"class":489},[479,1244,1182],{"class":506},[479,1246,541],{"class":489},[479,1248,549],{"class":489},[479,1250,1251],{"class":493}," h)",[479,1253,635],{"class":489},[479,1255,1256],{"class":481,"line":824},[479,1257,1258],{"class":489},"  },\n",[479,1260,1261,1263],{"class":481,"line":873},[479,1262,677],{"class":489},[479,1264,934],{"class":493},[436,1266,937,1267,1270],{},[440,1268,1269],{},"state"," config is required for cross-process or durable chains: load the previous head hash from your own store (Redis, Postgres, file) before each event, save the new head after.",[1272,1273],"hash-chain-tamper",{},[1275,1276,1277,1278,1281,1282,1285,1286,526],"note",{},"A CLI to walk and verify the chain (",[440,1279,1280],{},"evlog audit verify",") is on the roadmap. Until then, validate by recomputing the hashes of stored events and comparing each ",[440,1283,1284],{},"prevHash"," against the previous event's ",[440,1287,1288],{},"hash",[1290,1291,1292],"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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":475,"searchDepth":513,"depth":513,"links":1294},[1295,1296,1297],{"id":455,"depth":513,"text":458},{"id":701,"depth":513,"text":704},{"id":450,"depth":513,"text":945,"children":1298},[1299,1300],{"id":1029,"depth":520,"text":1030},{"id":1111,"depth":520,"text":1112},"auditEnricher to auto-fill request context, auditOnly to route audits to a dedicated sink, and signed for tamper-evident HMAC or hash-chain integrity.","md",[1304,1307],{"label":321,"icon":324,"to":322,"color":1305,"variant":1306},"neutral","subtle",{"label":331,"icon":308,"to":332,"color":1305,"variant":1306},{},{"title":326,"icon":329},{"title":431,"description":1301},"LSIG7lYQpD2WWwt5mxihPEgrxDkMPCXYx3ekIMTwyWk",[1313,1315],{"title":321,"path":322,"stem":323,"description":1314,"icon":324,"children":-1},"log.audit, log.audit.deny, standalone audit(), withAudit auto-instrumentation, defineAuditAction and defineAuditCatalog registries, and auditDiff change patches.",{"title":331,"path":332,"stem":333,"description":1316,"icon":308,"children":-1},"Integrity, redact presets, GDPR vs append-only, retention windows, and the most common pitfalls when shipping audit logs to production.",1778440153061]