[{"data":1,"prerenderedAt":3866},["ShallowReactive",2],{"navigation_docs":3,"-logging-catalogs":547,"-logging-catalogs-surround":3861},[4,35,159,201,289,446,531],{"title":5,"path":6,"stem":7,"children":8,"page":34},"Getting Started","\u002Fgetting-started","1.getting-started",[9,14,19,24,29],{"title":10,"path":11,"stem":12,"icon":13},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-info",{"title":15,"path":16,"stem":17,"icon":18},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":20,"path":21,"stem":22,"icon":23},"Quick Start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start","i-lucide-zap",{"title":25,"path":26,"stem":27,"icon":28},"Agent Skills","\u002Fgetting-started\u002Fagent-skills","1.getting-started\u002F4.agent-skills","i-lucide-sparkles",{"title":30,"path":31,"stem":32,"icon":33},"vs Other Loggers","\u002Fgetting-started\u002Fvs-other-loggers","1.getting-started\u002F5.vs-other-loggers","i-lucide-scale",false,{"title":36,"path":37,"stem":38,"children":39,"page":34},"Logging","\u002Flogging","2.logging",[40,45,50,55,60,65,70,99,127],{"title":41,"path":42,"stem":43,"icon":44},"Overview","\u002Flogging\u002Foverview","2.logging\u002F0.overview","i-lucide-list",{"title":46,"path":47,"stem":48,"icon":49},"Simple Logging","\u002Flogging\u002Fsimple-logging","2.logging\u002F1.simple-logging","i-lucide-terminal",{"title":51,"path":52,"stem":53,"icon":54},"Wide Events","\u002Flogging\u002Fwide-events","2.logging\u002F2.wide-events","i-lucide-layers",{"title":56,"path":57,"stem":58,"icon":59},"Structured Errors","\u002Flogging\u002Fstructured-errors","2.logging\u002F3.structured-errors","i-lucide-shield-alert",{"title":61,"path":62,"stem":63,"icon":64},"Catalogs","\u002Flogging\u002Fcatalogs","2.logging\u002F4.catalogs","i-lucide-book-open",{"title":66,"path":67,"stem":68,"icon":69},"Client Logging","\u002Flogging\u002Fclient-logging","2.logging\u002F5.client-logging","i-lucide-monitor",{"title":71,"icon":72,"path":73,"stem":74,"children":75,"page":34},"AI SDK","i-simple-icons-vercel","\u002Flogging\u002Fai-sdk","2.logging\u002F6.ai-sdk",[76,79,84,89,94],{"title":41,"path":77,"stem":78,"icon":44},"\u002Flogging\u002Fai-sdk\u002Foverview","2.logging\u002F6.ai-sdk\u002F01.overview",{"title":80,"path":81,"stem":82,"icon":83},"Usage","\u002Flogging\u002Fai-sdk\u002Fusage","2.logging\u002F6.ai-sdk\u002F02.usage","i-lucide-code",{"title":85,"path":86,"stem":87,"icon":88},"Options","\u002Flogging\u002Fai-sdk\u002Foptions","2.logging\u002F6.ai-sdk\u002F03.options","i-lucide-sliders",{"title":90,"path":91,"stem":92,"icon":93},"Metadata","\u002Flogging\u002Fai-sdk\u002Fmetadata","2.logging\u002F6.ai-sdk\u002F04.metadata","i-lucide-database",{"title":95,"path":96,"stem":97,"icon":98},"Telemetry","\u002Flogging\u002Fai-sdk\u002Ftelemetry","2.logging\u002F6.ai-sdk\u002F05.telemetry","i-lucide-activity",{"title":100,"icon":101,"path":102,"stem":103,"children":104,"page":34},"Better Auth","i-simple-icons-betterauth","\u002Flogging\u002Fbetter-auth","2.logging\u002F7.better-auth",[105,108,113,118,122],{"title":41,"path":106,"stem":107,"icon":44},"\u002Flogging\u002Fbetter-auth\u002Foverview","2.logging\u002F7.better-auth\u002F01.overview",{"title":109,"path":110,"stem":111,"icon":112},"Identify User","\u002Flogging\u002Fbetter-auth\u002Fidentify-user","2.logging\u002F7.better-auth\u002F02.identify-user","i-lucide-user-check",{"title":114,"path":115,"stem":116,"icon":117},"Middleware","\u002Flogging\u002Fbetter-auth\u002Fmiddleware","2.logging\u002F7.better-auth\u002F03.middleware","i-lucide-shield",{"title":119,"path":120,"stem":121,"icon":69},"Client Sync","\u002Flogging\u002Fbetter-auth\u002Fclient-sync","2.logging\u002F7.better-auth\u002F04.client-sync",{"title":123,"path":124,"stem":125,"icon":126},"Performance","\u002Flogging\u002Fbetter-auth\u002Fperformance","2.logging\u002F7.better-auth\u002F05.performance","i-lucide-gauge",{"title":128,"icon":129,"path":130,"stem":131,"children":132,"page":34},"Audit Logs","i-lucide-shield-check","\u002Flogging\u002Faudit","2.logging\u002F8.audit",[133,136,141,146,151,155],{"title":41,"path":134,"stem":135,"icon":44},"\u002Flogging\u002Faudit\u002Foverview","2.logging\u002F8.audit\u002F01.overview",{"title":137,"path":138,"stem":139,"icon":140},"Schema","\u002Flogging\u002Faudit\u002Fschema","2.logging\u002F8.audit\u002F02.schema","i-lucide-file-text",{"title":142,"path":143,"stem":144,"icon":145},"Recording","\u002Flogging\u002Faudit\u002Frecording","2.logging\u002F8.audit\u002F03.recording","i-lucide-pen-line",{"title":147,"path":148,"stem":149,"icon":150},"Drains","\u002Flogging\u002Faudit\u002Fpipeline","2.logging\u002F8.audit\u002F04.pipeline","i-lucide-link",{"title":152,"path":153,"stem":154,"icon":129},"Compliance","\u002Flogging\u002Faudit\u002Fcompliance","2.logging\u002F8.audit\u002F05.compliance",{"title":156,"path":157,"stem":158,"icon":64},"Recipes","\u002Flogging\u002Faudit\u002Frecipes","2.logging\u002F8.audit\u002F06.recipes",{"title":160,"path":161,"stem":162,"children":163,"page":34},"Core Concepts","\u002Fcore-concepts","3.core-concepts",[164,169,174,179,184,188,191,196],{"title":165,"path":166,"stem":167,"icon":168},"Lifecycle","\u002Fcore-concepts\u002Flifecycle","3.core-concepts\u002F0.lifecycle","i-lucide-arrow-right-left",{"title":170,"path":171,"stem":172,"icon":173},"Configuration","\u002Fcore-concepts\u002Fconfiguration","3.core-concepts\u002F1.configuration","i-lucide-settings",{"title":175,"path":176,"stem":177,"icon":178},"Sampling","\u002Fcore-concepts\u002Fsampling","3.core-concepts\u002F2.sampling","i-lucide-filter",{"title":180,"path":181,"stem":182,"icon":183},"Typed Fields","\u002Fcore-concepts\u002Ftyped-fields","3.core-concepts\u002F3.typed-fields","i-simple-icons-typescript",{"title":185,"path":186,"stem":187,"icon":129},"Best Practices","\u002Fcore-concepts\u002Fbest-practices","3.core-concepts\u002F4.best-practices",{"title":123,"path":189,"stem":190,"icon":126},"\u002Fcore-concepts\u002Fperformance","3.core-concepts\u002F5.performance",{"title":192,"path":193,"stem":194,"icon":195},"Vite Plugin","\u002Fcore-concepts\u002Fvite-plugin","3.core-concepts\u002F6.vite-plugin","i-custom-vite",{"title":197,"path":198,"stem":199,"icon":200},"Auto-Redaction","\u002Fcore-concepts\u002Fredaction","3.core-concepts\u002F7.redaction","i-lucide-eye-off",{"title":202,"path":203,"stem":204,"children":205,"page":34},"Frameworks","\u002Fframeworks","4.frameworks",[206,210,215,220,225,230,235,240,245,250,255,260,265,270,274,279,284],{"title":41,"path":207,"stem":208,"icon":209},"\u002Fframeworks\u002Foverview","4.frameworks\u002F00.overview","i-lucide-layout-grid",{"title":211,"path":212,"stem":213,"icon":214},"Nuxt","\u002Fframeworks\u002Fnuxt","4.frameworks\u002F01.nuxt","i-simple-icons-nuxtdotjs",{"title":216,"path":217,"stem":218,"icon":219},"Next.js","\u002Fframeworks\u002Fnextjs","4.frameworks\u002F02.nextjs","i-simple-icons-nextdotjs",{"title":221,"path":222,"stem":223,"icon":224},"SvelteKit","\u002Fframeworks\u002Fsveltekit","4.frameworks\u002F03.sveltekit","i-simple-icons-svelte",{"title":226,"path":227,"stem":228,"icon":229},"Nitro","\u002Fframeworks\u002Fnitro","4.frameworks\u002F04.nitro","i-custom-nitro",{"title":231,"path":232,"stem":233,"icon":234},"TanStack Start","\u002Fframeworks\u002Ftanstack-start","4.frameworks\u002F05.tanstack-start","i-custom-tanstack",{"title":236,"path":237,"stem":238,"icon":239},"NestJS","\u002Fframeworks\u002Fnestjs","4.frameworks\u002F06.nestjs","i-simple-icons-nestjs",{"title":241,"path":242,"stem":243,"icon":244},"Express","\u002Fframeworks\u002Fexpress","4.frameworks\u002F07.express","i-simple-icons-express",{"title":246,"path":247,"stem":248,"icon":249},"Hono","\u002Fframeworks\u002Fhono","4.frameworks\u002F08.hono","i-simple-icons-hono",{"title":251,"path":252,"stem":253,"icon":254},"Fastify","\u002Fframeworks\u002Ffastify","4.frameworks\u002F09.fastify","i-simple-icons-fastify",{"title":256,"path":257,"stem":258,"icon":259},"Elysia","\u002Fframeworks\u002Felysia","4.frameworks\u002F10.elysia","i-custom-elysia",{"title":261,"path":262,"stem":263,"icon":264},"React Router","\u002Fframeworks\u002Freact-router","4.frameworks\u002F11.react-router","i-custom-reactrouter",{"title":266,"path":267,"stem":268,"icon":269},"Cloudflare Workers","\u002Fframeworks\u002Fcloudflare-workers","4.frameworks\u002F12.cloudflare-workers","i-simple-icons-cloudflare",{"title":271,"path":272,"stem":273,"icon":183},"Standalone","\u002Fframeworks\u002Fstandalone","4.frameworks\u002F13.standalone",{"title":275,"path":276,"stem":277,"icon":278},"Astro","\u002Fframeworks\u002Fastro","4.frameworks\u002F14.astro","i-simple-icons-astro",{"title":280,"path":281,"stem":282,"icon":283},"AWS Lambda","\u002Fframeworks\u002Faws-lambda","4.frameworks\u002F16.aws-lambda","i-custom-lambda",{"title":285,"path":286,"stem":287,"icon":288},"Custom Integration","\u002Fframeworks\u002Fcustom-integration","4.frameworks\u002F17.custom-integration","i-lucide-puzzle",{"title":290,"path":291,"stem":292,"children":293,"page":34},"Build on top","\u002Fbuild-on-top","5.build-on-top",[294,297,325,346,373,400,428],{"title":41,"path":295,"stem":296,"icon":54},"\u002Fbuild-on-top\u002Foverview","5.build-on-top\u002F0.overview",{"title":298,"path":299,"stem":300,"children":301,"page":34},"Observers","\u002Fbuild-on-top\u002Fobservers","5.build-on-top\u002Fobservers",[302,306,311,316,321],{"title":41,"path":303,"stem":304,"icon":305},"\u002Fbuild-on-top\u002Fobservers\u002Foverview","5.build-on-top\u002Fobservers\u002F1.overview","i-lucide-eye",{"title":307,"path":308,"stem":309,"icon":310},"Stream API","\u002Fbuild-on-top\u002Fobservers\u002Fin-process-stream","5.build-on-top\u002Fobservers\u002F2.in-process-stream","i-lucide-radio-tower",{"title":312,"path":313,"stem":314,"icon":315},"Stream server","\u002Fbuild-on-top\u002Fobservers\u002Fstream-server","5.build-on-top\u002Fobservers\u002F3.stream-server","i-lucide-radio",{"title":317,"path":318,"stem":319,"icon":320},"FS reader","\u002Fbuild-on-top\u002Fobservers\u002Ffs-reader","5.build-on-top\u002Fobservers\u002F4.fs-reader","i-lucide-folder-search",{"title":156,"path":322,"stem":323,"icon":324},"\u002Fbuild-on-top\u002Fobservers\u002Fconsumer-recipes","5.build-on-top\u002Fobservers\u002F5.consumer-recipes","i-lucide-chef-hat",{"title":326,"path":327,"stem":328,"children":329,"page":34},"Pipeline","\u002Fbuild-on-top\u002Fpipeline","5.build-on-top\u002Fpipeline",[330,334,338,342],{"title":41,"path":331,"stem":332,"icon":333},"\u002Fbuild-on-top\u002Fpipeline\u002Foverview","5.build-on-top\u002Fpipeline\u002F1.overview","i-lucide-workflow",{"title":335,"path":336,"stem":337,"icon":288},"Plugins","\u002Fbuild-on-top\u002Fpipeline\u002Fplugins","5.build-on-top\u002Fpipeline\u002F2.plugins",{"title":339,"path":340,"stem":341,"icon":28},"Custom enrichers","\u002Fbuild-on-top\u002Fpipeline\u002Fcustom-enrichers","5.build-on-top\u002Fpipeline\u002F3.custom-enrichers",{"title":343,"path":344,"stem":345,"icon":178},"Tail sampling","\u002Fbuild-on-top\u002Fpipeline\u002Ftail-sampling","5.build-on-top\u002Fpipeline\u002F4.tail-sampling",{"title":347,"path":348,"stem":349,"children":350,"page":34},"Scenarios","\u002Fbuild-on-top\u002Fscenarios","5.build-on-top\u002Fscenarios",[351,355,359,364,368],{"title":41,"path":352,"stem":353,"icon":354},"\u002Fbuild-on-top\u002Fscenarios\u002Foverview","5.build-on-top\u002Fscenarios\u002F0.overview","i-lucide-clipboard-list",{"title":356,"path":357,"stem":358,"icon":49},"Local debugging toolkit","\u002Fbuild-on-top\u002Fscenarios\u002Flocal-debugging-toolkit","5.build-on-top\u002Fscenarios\u002F1.local-debugging-toolkit",{"title":360,"path":361,"stem":362,"icon":363},"Tenant-aware logging","\u002Fbuild-on-top\u002Fscenarios\u002Ftenant-aware-logging","5.build-on-top\u002Fscenarios\u002F2.tenant-aware-logging","i-lucide-users",{"title":365,"path":366,"stem":367,"icon":129},"Compliance audit","\u002Fbuild-on-top\u002Fscenarios\u002Fcompliance-audit","5.build-on-top\u002Fscenarios\u002F3.compliance-audit",{"title":369,"path":370,"stem":371,"icon":372},"Cross-app error vocab","\u002Fbuild-on-top\u002Fscenarios\u002Fcross-app-error-vocab","5.build-on-top\u002Fscenarios\u002F4.cross-app-error-vocab","i-lucide-book",{"title":374,"path":375,"stem":376,"children":377,"page":34},"Shared packages","\u002Fbuild-on-top\u002Fshared","5.build-on-top\u002Fshared",[378,382,386,391,395],{"title":41,"path":379,"stem":380,"icon":381},"\u002Fbuild-on-top\u002Fshared\u002Foverview","5.build-on-top\u002Fshared\u002F1.overview","i-lucide-package",{"title":383,"path":384,"stem":385,"icon":381},"Catalogs as packages","\u002Fbuild-on-top\u002Fshared\u002Fcatalogs-as-packages","5.build-on-top\u002Fshared\u002F2.catalogs-as-packages",{"title":387,"path":388,"stem":389,"icon":390},"Drains as packages","\u002Fbuild-on-top\u002Fshared\u002Fdrains-as-packages","5.build-on-top\u002Fshared\u002F3.drains-as-packages","i-lucide-package-2",{"title":392,"path":393,"stem":394,"icon":28},"Enrichers as packages","\u002Fbuild-on-top\u002Fshared\u002Fenrichers-as-packages","5.build-on-top\u002Fshared\u002F4.enrichers-as-packages",{"title":396,"path":397,"stem":398,"icon":399},"Integration as package","\u002Fbuild-on-top\u002Fshared\u002Fintegration-as-package","5.build-on-top\u002Fshared\u002F5.integration-as-package","i-lucide-package-check",{"title":401,"path":402,"stem":403,"children":404,"page":34},"Sinks","\u002Fbuild-on-top\u002Fsinks","5.build-on-top\u002Fsinks",[405,409,414,418,423],{"title":41,"path":406,"stem":407,"icon":408},"\u002Fbuild-on-top\u002Fsinks\u002Foverview","5.build-on-top\u002Fsinks\u002F1.overview","i-lucide-arrow-up-from-line",{"title":410,"path":411,"stem":412,"icon":413},"Custom drains","\u002Fbuild-on-top\u002Fsinks\u002Fcustom-drains","5.build-on-top\u002Fsinks\u002F2.custom-drains","i-lucide-code-2",{"title":415,"path":416,"stem":417,"icon":333},"Drain pipeline","\u002Fbuild-on-top\u002Fsinks\u002Fdrain-pipeline","5.build-on-top\u002Fsinks\u002F3.drain-pipeline",{"title":419,"path":420,"stem":421,"icon":422},"Identity headers","\u002Fbuild-on-top\u002Fsinks\u002Fidentity-headers","5.build-on-top\u002Fsinks\u002F4.identity-headers","i-lucide-fingerprint",{"title":424,"path":425,"stem":426,"icon":427},"Fanout","\u002Fbuild-on-top\u002Fsinks\u002Ffanout-and-multi-drain","5.build-on-top\u002Fsinks\u002F5.fanout-and-multi-drain","i-lucide-share-2",{"title":429,"path":430,"stem":431,"children":432,"page":34},"Sources","\u002Fbuild-on-top\u002Fsources","5.build-on-top\u002Fsources",[433,437,441],{"title":41,"path":434,"stem":435,"icon":436},"\u002Fbuild-on-top\u002Fsources\u002Foverview","5.build-on-top\u002Fsources\u002F1.overview","i-lucide-arrow-down-to-line",{"title":438,"path":439,"stem":440,"icon":288},"Custom framework","\u002Fbuild-on-top\u002Fsources\u002Fcustom-framework","5.build-on-top\u002Fsources\u002F2.custom-framework",{"title":442,"path":443,"stem":444,"icon":445},"Middleware toolkit","\u002Fbuild-on-top\u002Fsources\u002Fmiddleware-toolkit","5.build-on-top\u002Fsources\u002F3.middleware-toolkit","i-lucide-wrench",{"title":447,"path":448,"stem":449,"children":450,"page":34},"Adapters","\u002Fadapters","6.adapters",[451,454,494,509],{"title":41,"path":452,"stem":453,"icon":44},"\u002Fadapters\u002Foverview","6.adapters\u002F01.overview",{"title":455,"path":456,"stem":457,"children":458,"page":34},"Cloud destinations","\u002Fadapters\u002Fcloud","6.adapters\u002F02.cloud",[459,464,469,474,479,484,489],{"title":460,"path":461,"stem":462,"icon":463},"Axiom","\u002Fadapters\u002Fcloud\u002Faxiom","6.adapters\u002F02.cloud\u002F01.axiom","i-custom-axiom",{"title":465,"path":466,"stem":467,"icon":468},"OTLP","\u002Fadapters\u002Fcloud\u002Fotlp","6.adapters\u002F02.cloud\u002F02.otlp","i-simple-icons-opentelemetry",{"title":470,"path":471,"stem":472,"icon":473},"PostHog","\u002Fadapters\u002Fcloud\u002Fposthog","6.adapters\u002F02.cloud\u002F03.posthog","i-simple-icons-posthog",{"title":475,"path":476,"stem":477,"icon":478},"Sentry","\u002Fadapters\u002Fcloud\u002Fsentry","6.adapters\u002F02.cloud\u002F04.sentry","i-simple-icons-sentry",{"title":480,"path":481,"stem":482,"icon":483},"Better Stack","\u002Fadapters\u002Fcloud\u002Fbetter-stack","6.adapters\u002F02.cloud\u002F05.better-stack","i-simple-icons-betterstack",{"title":485,"path":486,"stem":487,"icon":488},"Datadog","\u002Fadapters\u002Fcloud\u002Fdatadog","6.adapters\u002F02.cloud\u002F06.datadog","i-simple-icons-datadog",{"title":490,"path":491,"stem":492,"icon":493},"HyperDX","\u002Fadapters\u002Fcloud\u002Fhyperdx","6.adapters\u002F02.cloud\u002F07.hyperdx","i-custom-hyperdx",{"title":495,"path":496,"stem":497,"children":498,"page":34},"Self-hosted","\u002Fadapters\u002Fself-hosted","6.adapters\u002F03.self-hosted",[499,504],{"title":500,"path":501,"stem":502,"icon":503},"File System","\u002Fadapters\u002Fself-hosted\u002Ffs","6.adapters\u002F03.self-hosted\u002F01.fs","i-lucide-hard-drive",{"title":505,"path":506,"stem":507,"icon":508},"NuxtHub","\u002Fadapters\u002Fself-hosted\u002Fnuxthub","6.adapters\u002F03.self-hosted\u002F02.nuxthub","i-simple-icons-nuxt",{"title":510,"path":511,"stem":512,"children":513,"page":34},"Building blocks","\u002Fadapters\u002Fbuilding-blocks","6.adapters\u002F04.building-blocks",[514,517,522,526],{"title":326,"path":515,"stem":516,"icon":333},"\u002Fadapters\u002Fbuilding-blocks\u002Fpipeline","6.adapters\u002F04.building-blocks\u002F01.pipeline",{"title":518,"path":519,"stem":520,"icon":521},"HTTP","\u002Fadapters\u002Fbuilding-blocks\u002Fhttp","6.adapters\u002F04.building-blocks\u002F02.http","i-lucide-globe",{"title":523,"path":524,"stem":525,"icon":83},"Custom Adapters","\u002Fadapters\u002Fbuilding-blocks\u002Fcustom","6.adapters\u002F04.building-blocks\u002F03.custom",{"title":527,"path":528,"stem":529,"icon":530},"Toolkit","\u002Fadapters\u002Fbuilding-blocks\u002Ftoolkit","6.adapters\u002F04.building-blocks\u002F04.toolkit","i-lucide-blocks",{"title":532,"path":533,"stem":534,"children":535,"page":34},"Enrichers","\u002Fenrichers","7.enrichers",[536,539,543],{"title":41,"path":537,"stem":538,"icon":28},"\u002Fenrichers\u002Foverview","7.enrichers\u002F1.overview",{"title":540,"path":541,"stem":542,"icon":288},"Built-in","\u002Fenrichers\u002Fbuilt-in","7.enrichers\u002F2.built-in",{"title":544,"path":545,"stem":546,"icon":83},"Custom","\u002Fenrichers\u002Fcustom","7.enrichers\u002F3.custom",{"id":548,"title":61,"body":549,"description":3851,"extension":3852,"links":3853,"meta":3857,"navigation":3858,"path":62,"seo":3859,"stem":63,"__hash__":3860},"docs\u002F2.logging\u002F4.catalogs.md",{"type":550,"value":551,"toc":3824},"minimark",[552,571,722,735,740,743,846,852,856,859,864,875,1228,1232,1246,1254,1467,1478,1482,1494,1500,1680,1690,1694,1704,1710,1714,1720,1726,1977,1981,2271,2284,2288,2360,2417,2566,2586,2590,2594,2604,2832,2836,2839,2884,3006,3010,3034,3171,3175,3194,3198,3257,3263,3267,3270,3316,3399,3408,3412,3532,3539,3543,3559,3572,3588,3665,3669,3777,3783,3787,3820],[553,554,555,556,560,561,560,564,560,567,570],"p",{},"The catalog primitives (",[557,558,559],"code",{},"defineError",", ",[557,562,563],{},"defineErrorCatalog",[557,565,566],{},"defineAuditAction",[557,568,569],{},"defineAuditCatalog",") are the same regardless of project size. What changes is how you organise them. This page is the deep-dive: conventions, scaling recipes from one file to a published npm package, composition patterns, and the opt-in type augmentation.",[572,573,576,582,713],"prompt",{":actions":574,"description":575,"icon":64},"[\"copy\",\"cursor\",\"windsurf\"]","Set up typed error and audit catalogs in my app",[553,577,578,579,581],{},"Group errors and audit actions in typed catalogs to eliminate magic strings, get autocomplete on ",[557,580,557],{}," everywhere, and ship them as npm packages in a monorepo.",[583,584,585,597,607,621,630,640,647,654,672,679,693,703],"ul",{},[586,587,588,589,592,593,596],"li",{},"Use ",[557,590,591],{},"defineErrorCatalog(prefix, map)"," for error bundles, ",[557,594,595],{},"defineAuditCatalog(prefix, map)"," for audit bundles",[586,598,588,599,602,603,606],{},[557,600,601],{},"defineError(code, options)"," and ",[557,604,605],{},"defineAuditAction(action, opts?)"," for one-off factories that don't fit a catalog",[586,608,609,610,613,614,560,617,620],{},"Convention: UPPER_SNAKE_CASE keys, lower.dot.case prefix, wire format is ",[557,611,612],{},"${prefix}.${KEY}"," (e.g. ",[557,615,616],{},"billing.PAYMENT_DECLINED",[557,618,619],{},"billing.INVOICE_REFUND",")",[586,622,623,624,560,627,620],{},"One catalog = one bounded context = one prefix = one file (e.g. ",[557,625,626],{},"errors\u002Fbilling.ts",[557,628,629],{},"audit\u002Fbilling.ts",[586,631,632,633,636,637],{},"Throw with ",[557,634,635],{},"billingErrors.PAYMENT_DECLINED({ cause, internal })",", audit with ",[557,638,639],{},"log.audit(billingAudit.INVOICE_REFUND({ actor, target }))",[586,641,642,643,646],{},"Use templated messages (",[557,644,645],{},"message: ({ id }) => \\","User ${id} not found``) when params are dynamic and required",[586,648,649,650,653],{},"Catalog defaults for ",[557,651,652],{},"internal"," are shallow-merged with call-site values (call-site wins)",[586,655,656,657,660,661,560,664,667,668,671],{},"Add the opt-in ",[557,658,659],{},"declare module 'evlog' { interface RegisteredErrorCatalogs { billing: typeof billingErrors } }"," augmentation to surface autocomplete on ",[557,662,663],{},"createError({ code })",[557,665,666],{},"parseError(err).code",", and ",[557,669,670],{},"throwError(code)"," everywhere",[586,673,674,675,678],{},"Scale by sharding: single file → folder per domain → sub-prefixes (",[557,676,677],{},"billing.payment",") → one npm package per bounded context (each owns its prefix, no conflicts possible)",[586,680,681,682,685,686,689,690],{},"Each shared package ships its own ",[557,683,684],{},"declare module 'evlog'"," block in ",[557,687,688],{},"src\u002Findex.ts"," so the type augmentation propagates to consumers via the published ",[557,691,692],{},".d.ts",[586,694,695,696,699,700],{},"Compare on ",[557,697,698],{},"factory.code"," in tests instead of string literals so renames are TS errors, not silent breaks: ",[557,701,702],{},"expect(err.code).toBe(billingErrors.PAYMENT_DECLINED.code)",[586,704,705,706,708,709,712],{},"Never override ",[557,707,557],{}," at the call site (the catalog defines the code identity); never put ",[557,710,711],{},"declare module"," blocks in test files (they leak into the main type-checker)",[553,714,715,716],{},"Docs: ",[717,718,719],"a",{"href":719,"rel":720},"https:\u002F\u002Fwww.evlog.dev\u002Flogging\u002Fcatalogs",[721],"nofollow",[723,724,725,726,602,730,734],"tip",{},"If you haven't yet, start with ",[717,727,729],{"href":728},"\u002Flogging\u002Fstructured-errors#error-catalogs","Structured Errors → Error Catalogs",[717,731,733],{"href":732},"\u002Flogging\u002Faudit\u002Frecording#defineauditcatalog","Audit → defineAuditCatalog"," for the basics. This page assumes you've used the primitives at least once.",[736,737,739],"h2",{"id":738},"conventions","Conventions",[553,741,742],{},"A single set of conventions covers both error and audit catalogs.",[744,745,746,761],"table",{},[747,748,749],"thead",{},[750,751,752,755,758],"tr",{},[753,754],"th",{},[753,756,757],{},"Convention",[753,759,760],{},"Example",[762,763,764,787,811,830],"tbody",{},[750,765,766,773,779],{},[767,768,769],"td",{},[770,771,772],"strong",{},"Catalog key",[767,774,775,778],{},[557,776,777],{},"UPPER_SNAKE_CASE"," (enum-style, scales to hundreds of entries)",[767,780,781,560,784],{},[557,782,783],{},"PAYMENT_DECLINED",[557,785,786],{},"INVOICE_REFUND",[750,788,789,794,800],{},[767,790,791],{},[770,792,793],{},"Prefix",[767,795,796,799],{},[557,797,798],{},"lower.dot.case",", can be hierarchical",[767,801,802,560,805,560,808],{},[557,803,804],{},"'billing'",[557,806,807],{},"'billing.payment'",[557,809,810],{},"'auth.session'",[750,812,813,818,823],{},[767,814,815],{},[770,816,817],{},"Wire format",[767,819,820,822],{},[557,821,612],{}," (preserved casing)",[767,824,825,560,827],{},[557,826,616],{},[557,828,829],{},"auth.INVALID_TOKEN",[750,831,832,837,840],{},[767,833,834],{},[770,835,836],{},"One catalog =",[767,838,839],{},"One bounded context, one prefix, one file",[767,841,842,560,844],{},[557,843,626],{},[557,845,629],{},[553,847,848,849,851],{},"The wire format ends up in HTTP responses, wide events, drains, and dashboards. Stick to it across services so a ",[557,850,557],{}," from one service is recognisable in another.",[736,853,855],{"id":854},"scaling-story","Scaling story",[553,857,858],{},"The same primitives cover four scales without API change.",[860,861,863],"h3",{"id":862},"_1-file-small-repo","1 file — small repo",[553,865,866,867,870,871,874],{},"One ",[557,868,869],{},"errors.ts",", one ",[557,872,873],{},"audit.ts",". Done.",[876,877,878,1124],"code-group",{},[879,880,886],"pre",{"className":881,"code":882,"filename":883,"language":884,"meta":885,"style":885},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { defineErrorCatalog } from 'evlog'\n\nexport const errors = defineErrorCatalog('app', {\n  USER_NOT_FOUND: { status: 404, message: 'User not found' },\n  FORBIDDEN: { status: 403, message: 'Forbidden' },\n  VALIDATION_FAILED: {\n    status: 400,\n    message: ({ field }: { field: string }) => `Invalid ${field}`,\n  },\n})\n","src\u002Ferrors.ts","typescript","",[557,887,888,921,928,964,1002,1034,1044,1058,1109,1115],{"__ignoreMap":885},[889,890,893,897,901,905,908,911,914,918],"span",{"class":891,"line":892},"line",1,[889,894,896],{"class":895},"s7zQu","import",[889,898,900],{"class":899},"sMK4o"," {",[889,902,904],{"class":903},"sTEyZ"," defineErrorCatalog",[889,906,907],{"class":899}," }",[889,909,910],{"class":895}," from",[889,912,913],{"class":899}," '",[889,915,917],{"class":916},"sfazB","evlog",[889,919,920],{"class":899},"'\n",[889,922,924],{"class":891,"line":923},2,[889,925,927],{"emptyLinePlaceholder":926},true,"\n",[889,929,931,934,938,941,944,947,950,953,956,958,961],{"class":891,"line":930},3,[889,932,933],{"class":895},"export",[889,935,937],{"class":936},"spNyl"," const",[889,939,940],{"class":903}," errors ",[889,942,943],{"class":899},"=",[889,945,904],{"class":946},"s2Zo4",[889,948,949],{"class":903},"(",[889,951,952],{"class":899},"'",[889,954,955],{"class":916},"app",[889,957,952],{"class":899},[889,959,960],{"class":899},",",[889,962,963],{"class":899}," {\n",[889,965,967,971,974,976,979,981,985,987,990,992,994,997,999],{"class":891,"line":966},4,[889,968,970],{"class":969},"swJcz","  USER_NOT_FOUND",[889,972,973],{"class":899},":",[889,975,900],{"class":899},[889,977,978],{"class":969}," status",[889,980,973],{"class":899},[889,982,984],{"class":983},"sbssI"," 404",[889,986,960],{"class":899},[889,988,989],{"class":969}," message",[889,991,973],{"class":899},[889,993,913],{"class":899},[889,995,996],{"class":916},"User not found",[889,998,952],{"class":899},[889,1000,1001],{"class":899}," },\n",[889,1003,1005,1008,1010,1012,1014,1016,1019,1021,1023,1025,1027,1030,1032],{"class":891,"line":1004},5,[889,1006,1007],{"class":969},"  FORBIDDEN",[889,1009,973],{"class":899},[889,1011,900],{"class":899},[889,1013,978],{"class":969},[889,1015,973],{"class":899},[889,1017,1018],{"class":983}," 403",[889,1020,960],{"class":899},[889,1022,989],{"class":969},[889,1024,973],{"class":899},[889,1026,913],{"class":899},[889,1028,1029],{"class":916},"Forbidden",[889,1031,952],{"class":899},[889,1033,1001],{"class":899},[889,1035,1037,1040,1042],{"class":891,"line":1036},6,[889,1038,1039],{"class":969},"  VALIDATION_FAILED",[889,1041,973],{"class":899},[889,1043,963],{"class":899},[889,1045,1047,1050,1052,1055],{"class":891,"line":1046},7,[889,1048,1049],{"class":969},"    status",[889,1051,973],{"class":899},[889,1053,1054],{"class":983}," 400",[889,1056,1057],{"class":899},",\n",[889,1059,1061,1064,1066,1069,1073,1076,1078,1080,1082,1086,1089,1092,1095,1098,1101,1104,1107],{"class":891,"line":1060},8,[889,1062,1063],{"class":946},"    message",[889,1065,973],{"class":899},[889,1067,1068],{"class":899}," ({",[889,1070,1072],{"class":1071},"sHdIc"," field",[889,1074,1075],{"class":899}," }:",[889,1077,900],{"class":899},[889,1079,1072],{"class":969},[889,1081,973],{"class":899},[889,1083,1085],{"class":1084},"sBMFI"," string",[889,1087,1088],{"class":899}," })",[889,1090,1091],{"class":936}," =>",[889,1093,1094],{"class":899}," `",[889,1096,1097],{"class":916},"Invalid ",[889,1099,1100],{"class":899},"${",[889,1102,1103],{"class":903},"field",[889,1105,1106],{"class":899},"}`",[889,1108,1057],{"class":899},[889,1110,1112],{"class":891,"line":1111},9,[889,1113,1114],{"class":899},"  },\n",[889,1116,1118,1121],{"class":891,"line":1117},10,[889,1119,1120],{"class":899},"}",[889,1122,1123],{"class":903},")\n",[879,1125,1128],{"className":881,"code":1126,"filename":1127,"language":884,"meta":885,"style":885},"import { defineAuditCatalog } from 'evlog'\n\nexport const audit = defineAuditCatalog('app', {\n  USER_LOGIN: { target: 'user' },\n  USER_DELETE: { target: 'user' },\n})\n","src\u002Faudit.ts",[557,1129,1130,1149,1153,1178,1201,1222],{"__ignoreMap":885},[889,1131,1132,1134,1136,1139,1141,1143,1145,1147],{"class":891,"line":892},[889,1133,896],{"class":895},[889,1135,900],{"class":899},[889,1137,1138],{"class":903}," defineAuditCatalog",[889,1140,907],{"class":899},[889,1142,910],{"class":895},[889,1144,913],{"class":899},[889,1146,917],{"class":916},[889,1148,920],{"class":899},[889,1150,1151],{"class":891,"line":923},[889,1152,927],{"emptyLinePlaceholder":926},[889,1154,1155,1157,1159,1162,1164,1166,1168,1170,1172,1174,1176],{"class":891,"line":930},[889,1156,933],{"class":895},[889,1158,937],{"class":936},[889,1160,1161],{"class":903}," audit ",[889,1163,943],{"class":899},[889,1165,1138],{"class":946},[889,1167,949],{"class":903},[889,1169,952],{"class":899},[889,1171,955],{"class":916},[889,1173,952],{"class":899},[889,1175,960],{"class":899},[889,1177,963],{"class":899},[889,1179,1180,1183,1185,1187,1190,1192,1194,1197,1199],{"class":891,"line":966},[889,1181,1182],{"class":969},"  USER_LOGIN",[889,1184,973],{"class":899},[889,1186,900],{"class":899},[889,1188,1189],{"class":969}," target",[889,1191,973],{"class":899},[889,1193,913],{"class":899},[889,1195,1196],{"class":916},"user",[889,1198,952],{"class":899},[889,1200,1001],{"class":899},[889,1202,1203,1206,1208,1210,1212,1214,1216,1218,1220],{"class":891,"line":1004},[889,1204,1205],{"class":969},"  USER_DELETE",[889,1207,973],{"class":899},[889,1209,900],{"class":899},[889,1211,1189],{"class":969},[889,1213,973],{"class":899},[889,1215,913],{"class":899},[889,1217,1196],{"class":916},[889,1219,952],{"class":899},[889,1221,1001],{"class":899},[889,1223,1224,1226],{"class":891,"line":1036},[889,1225,1120],{"class":899},[889,1227,1123],{"class":903},[860,1229,1231],{"id":1230},"_1-folder-1-file-per-domain-medium-repo","1 folder, 1 file per domain — medium repo",[553,1233,1234,1235,602,1238,1241,1242,1245],{},"Group by bounded context. One file per domain in ",[557,1236,1237],{},"src\u002Ferrors\u002F",[557,1239,1240],{},"src\u002Faudit\u002F",". An ",[557,1243,1244],{},"index.ts"," re-exports for ergonomic imports and centralises the type augmentation.",[879,1247,1252],{"className":1248,"code":1250,"language":1251},[1249],"language-text","src\u002F\n├── errors\u002F\n│   ├── billing.ts        → billingErrors (prefix: 'billing')\n│   ├── auth.ts           → authErrors    (prefix: 'auth')\n│   ├── user.ts           → userErrors    (prefix: 'user')\n│   └── index.ts          → re-export + declare module\n├── audit\u002F\n│   ├── billing.ts        → billingAudit\n│   ├── auth.ts           → authAudit\n│   └── index.ts\n","text",[557,1253,1250],{"__ignoreMap":885},[879,1255,1258],{"className":881,"code":1256,"filename":1257,"language":884,"meta":885,"style":885},"import type { authErrors } from '.\u002Fauth'\nimport type { billingErrors } from '.\u002Fbilling'\nimport type { userErrors } from '.\u002Fuser'\n\nexport { authErrors } from '.\u002Fauth'\nexport { billingErrors } from '.\u002Fbilling'\nexport { userErrors } from '.\u002Fuser'\n\ndeclare module 'evlog' {\n  interface RegisteredErrorCatalogs {\n    auth: typeof authErrors\n    billing: typeof billingErrors\n    user: typeof userErrors\n  }\n}\n","src\u002Ferrors\u002Findex.ts",[557,1259,1260,1283,1305,1327,1331,1349,1367,1385,1389,1405,1415,1429,1442,1455,1461],{"__ignoreMap":885},[889,1261,1262,1264,1267,1269,1272,1274,1276,1278,1281],{"class":891,"line":892},[889,1263,896],{"class":895},[889,1265,1266],{"class":895}," type",[889,1268,900],{"class":899},[889,1270,1271],{"class":903}," authErrors",[889,1273,907],{"class":899},[889,1275,910],{"class":895},[889,1277,913],{"class":899},[889,1279,1280],{"class":916},".\u002Fauth",[889,1282,920],{"class":899},[889,1284,1285,1287,1289,1291,1294,1296,1298,1300,1303],{"class":891,"line":923},[889,1286,896],{"class":895},[889,1288,1266],{"class":895},[889,1290,900],{"class":899},[889,1292,1293],{"class":903}," billingErrors",[889,1295,907],{"class":899},[889,1297,910],{"class":895},[889,1299,913],{"class":899},[889,1301,1302],{"class":916},".\u002Fbilling",[889,1304,920],{"class":899},[889,1306,1307,1309,1311,1313,1316,1318,1320,1322,1325],{"class":891,"line":930},[889,1308,896],{"class":895},[889,1310,1266],{"class":895},[889,1312,900],{"class":899},[889,1314,1315],{"class":903}," userErrors",[889,1317,907],{"class":899},[889,1319,910],{"class":895},[889,1321,913],{"class":899},[889,1323,1324],{"class":916},".\u002Fuser",[889,1326,920],{"class":899},[889,1328,1329],{"class":891,"line":966},[889,1330,927],{"emptyLinePlaceholder":926},[889,1332,1333,1335,1337,1339,1341,1343,1345,1347],{"class":891,"line":1004},[889,1334,933],{"class":895},[889,1336,900],{"class":899},[889,1338,1271],{"class":903},[889,1340,907],{"class":899},[889,1342,910],{"class":895},[889,1344,913],{"class":899},[889,1346,1280],{"class":916},[889,1348,920],{"class":899},[889,1350,1351,1353,1355,1357,1359,1361,1363,1365],{"class":891,"line":1036},[889,1352,933],{"class":895},[889,1354,900],{"class":899},[889,1356,1293],{"class":903},[889,1358,907],{"class":899},[889,1360,910],{"class":895},[889,1362,913],{"class":899},[889,1364,1302],{"class":916},[889,1366,920],{"class":899},[889,1368,1369,1371,1373,1375,1377,1379,1381,1383],{"class":891,"line":1046},[889,1370,933],{"class":895},[889,1372,900],{"class":899},[889,1374,1315],{"class":903},[889,1376,907],{"class":899},[889,1378,910],{"class":895},[889,1380,913],{"class":899},[889,1382,1324],{"class":916},[889,1384,920],{"class":899},[889,1386,1387],{"class":891,"line":1060},[889,1388,927],{"emptyLinePlaceholder":926},[889,1390,1391,1394,1397,1399,1401,1403],{"class":891,"line":1111},[889,1392,1393],{"class":936},"declare",[889,1395,1396],{"class":936}," module",[889,1398,913],{"class":899},[889,1400,917],{"class":916},[889,1402,952],{"class":899},[889,1404,963],{"class":899},[889,1406,1407,1410,1413],{"class":891,"line":1117},[889,1408,1409],{"class":936},"  interface",[889,1411,1412],{"class":1084}," RegisteredErrorCatalogs",[889,1414,963],{"class":899},[889,1416,1418,1421,1423,1426],{"class":891,"line":1417},11,[889,1419,1420],{"class":969},"    auth",[889,1422,973],{"class":899},[889,1424,1425],{"class":899}," typeof",[889,1427,1428],{"class":903}," authErrors\n",[889,1430,1432,1435,1437,1439],{"class":891,"line":1431},12,[889,1433,1434],{"class":969},"    billing",[889,1436,973],{"class":899},[889,1438,1425],{"class":899},[889,1440,1441],{"class":903}," billingErrors\n",[889,1443,1445,1448,1450,1452],{"class":891,"line":1444},13,[889,1446,1447],{"class":969},"    user",[889,1449,973],{"class":899},[889,1451,1425],{"class":899},[889,1453,1454],{"class":903}," userErrors\n",[889,1456,1458],{"class":891,"line":1457},14,[889,1459,1460],{"class":899},"  }\n",[889,1462,1464],{"class":891,"line":1463},15,[889,1465,1466],{"class":899},"}\n",[553,1468,1469,1470,1473,1474,1477],{},"The augmentation is purely type-level: there is no ",[557,1471,1472],{},"init"," step, no runtime registration. Importing ",[557,1475,1476],{},"~\u002Ferrors"," once anywhere in your app is enough for TypeScript to pick up the merged type.",[860,1479,1481],{"id":1480},"sub-prefixes-very-large-repo","Sub-prefixes — very large repo",[553,1483,1484,1485,560,1487,560,1490,1493],{},"Hierarchical prefixes (",[557,1486,677],{},[557,1488,1489],{},"billing.subscription",[557,1491,1492],{},"auth.session",") keep keys short while preserving namespace clarity. One catalog per sub-domain.",[879,1495,1498],{"className":1496,"code":1497,"language":1251},[1249],"src\u002Ffeatures\u002F\n├── billing\u002F\n│   └── errors\u002F\n│       ├── payment.ts        → billingPaymentErrors (prefix: 'billing.payment')\n│       ├── subscription.ts   → billingSubscriptionErrors\n│       └── invoice.ts        → billingInvoiceErrors\n├── auth\u002F\n│   └── errors\u002F\n│       ├── session.ts        → authSessionErrors (prefix: 'auth.session')\n│       ├── oauth.ts          → authOAuthErrors\n│       └── mfa.ts            → authMfaErrors\n",[557,1499,1497],{"__ignoreMap":885},[879,1501,1504],{"className":881,"code":1502,"filename":1503,"language":884,"meta":885,"style":885},"import { defineErrorCatalog } from 'evlog'\n\nexport const billingPaymentErrors = defineErrorCatalog('billing.payment', {\n  DECLINED: { status: 402, message: 'Card declined' },\n  INSUFFICIENT_FUNDS: { status: 402, message: 'Insufficient funds' },\n  EXPIRED_CARD: { status: 402, message: 'Card expired' },\n  CVV_MISMATCH: { status: 402, message: 'CVV mismatch' },\n})\n","src\u002Ffeatures\u002Fbilling\u002Ferrors\u002Fpayment.ts",[557,1505,1506,1524,1528,1553,1584,1614,1644,1674],{"__ignoreMap":885},[889,1507,1508,1510,1512,1514,1516,1518,1520,1522],{"class":891,"line":892},[889,1509,896],{"class":895},[889,1511,900],{"class":899},[889,1513,904],{"class":903},[889,1515,907],{"class":899},[889,1517,910],{"class":895},[889,1519,913],{"class":899},[889,1521,917],{"class":916},[889,1523,920],{"class":899},[889,1525,1526],{"class":891,"line":923},[889,1527,927],{"emptyLinePlaceholder":926},[889,1529,1530,1532,1534,1537,1539,1541,1543,1545,1547,1549,1551],{"class":891,"line":930},[889,1531,933],{"class":895},[889,1533,937],{"class":936},[889,1535,1536],{"class":903}," billingPaymentErrors ",[889,1538,943],{"class":899},[889,1540,904],{"class":946},[889,1542,949],{"class":903},[889,1544,952],{"class":899},[889,1546,677],{"class":916},[889,1548,952],{"class":899},[889,1550,960],{"class":899},[889,1552,963],{"class":899},[889,1554,1555,1558,1560,1562,1564,1566,1569,1571,1573,1575,1577,1580,1582],{"class":891,"line":966},[889,1556,1557],{"class":969},"  DECLINED",[889,1559,973],{"class":899},[889,1561,900],{"class":899},[889,1563,978],{"class":969},[889,1565,973],{"class":899},[889,1567,1568],{"class":983}," 402",[889,1570,960],{"class":899},[889,1572,989],{"class":969},[889,1574,973],{"class":899},[889,1576,913],{"class":899},[889,1578,1579],{"class":916},"Card declined",[889,1581,952],{"class":899},[889,1583,1001],{"class":899},[889,1585,1586,1589,1591,1593,1595,1597,1599,1601,1603,1605,1607,1610,1612],{"class":891,"line":1004},[889,1587,1588],{"class":969},"  INSUFFICIENT_FUNDS",[889,1590,973],{"class":899},[889,1592,900],{"class":899},[889,1594,978],{"class":969},[889,1596,973],{"class":899},[889,1598,1568],{"class":983},[889,1600,960],{"class":899},[889,1602,989],{"class":969},[889,1604,973],{"class":899},[889,1606,913],{"class":899},[889,1608,1609],{"class":916},"Insufficient funds",[889,1611,952],{"class":899},[889,1613,1001],{"class":899},[889,1615,1616,1619,1621,1623,1625,1627,1629,1631,1633,1635,1637,1640,1642],{"class":891,"line":1036},[889,1617,1618],{"class":969},"  EXPIRED_CARD",[889,1620,973],{"class":899},[889,1622,900],{"class":899},[889,1624,978],{"class":969},[889,1626,973],{"class":899},[889,1628,1568],{"class":983},[889,1630,960],{"class":899},[889,1632,989],{"class":969},[889,1634,973],{"class":899},[889,1636,913],{"class":899},[889,1638,1639],{"class":916},"Card expired",[889,1641,952],{"class":899},[889,1643,1001],{"class":899},[889,1645,1646,1649,1651,1653,1655,1657,1659,1661,1663,1665,1667,1670,1672],{"class":891,"line":1046},[889,1647,1648],{"class":969},"  CVV_MISMATCH",[889,1650,973],{"class":899},[889,1652,900],{"class":899},[889,1654,978],{"class":969},[889,1656,973],{"class":899},[889,1658,1568],{"class":983},[889,1660,960],{"class":899},[889,1662,989],{"class":969},[889,1664,973],{"class":899},[889,1666,913],{"class":899},[889,1668,1669],{"class":916},"CVV mismatch",[889,1671,952],{"class":899},[889,1673,1001],{"class":899},[889,1675,1676,1678],{"class":891,"line":1060},[889,1677,1120],{"class":899},[889,1679,1123],{"class":903},[553,1681,1682,1683,560,1686,1689],{},"Wire codes become ",[557,1684,1685],{},"billing.payment.DECLINED",[557,1687,1688],{},"billing.payment.INSUFFICIENT_FUNDS",", etc. The convention scales to hundreds of entries without collisions.",[860,1691,1693],{"id":1692},"npm-packages-monorepo","npm packages — monorepo",[553,1695,1696,1697,1699,1700,1703],{},"In a monorepo, each bounded context can ship as its own npm package. Type augmentation propagates through the published ",[557,1698,692],{},", so consumers get autocomplete just by ",[557,1701,1702],{},"pnpm add @acme\u002Ferrors-billing",".",[879,1705,1708],{"className":1706,"code":1707,"language":1251},[1249],"acme-monorepo\u002F\n├── packages\u002F\n│   ├── errors-billing\u002F         → @acme\u002Ferrors-billing\n│   │   └── src\u002Findex.ts\n│   ├── errors-auth\u002F            → @acme\u002Ferrors-auth\n│   │   └── src\u002Findex.ts\n│   └── audit-billing\u002F          → @acme\u002Faudit-billing\n│       └── src\u002Findex.ts\n└── apps\u002F\n    ├── api\u002F                    → imports + re-exports the catalogs\n    └── worker\u002F\n",[557,1709,1707],{"__ignoreMap":885},[736,1711,1713],{"id":1712},"publishing-a-catalog-as-an-npm-package","Publishing a catalog as an npm package",[553,1715,1716,1717,1719],{},"A catalog is just regular TypeScript that depends on ",[557,1718,917],{}," as a peer dep. Here is the minimal recipe.",[860,1721,1723],{"id":1722},"packagejson",[557,1724,1725],{},"package.json",[879,1727,1732],{"className":1728,"code":1729,"filename":1730,"language":1731,"meta":885,"style":885},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"name\": \"@acme\u002Ferrors-billing\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"main\": \".\u002Fdist\u002Findex.mjs\",\n  \"types\": \".\u002Fdist\u002Findex.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"import\": \".\u002Fdist\u002Findex.mjs\",\n      \"types\": \".\u002Fdist\u002Findex.d.ts\"\n    }\n  },\n  \"peerDependencies\": {\n    \"evlog\": \"^3.0.0\"\n  },\n  \"files\": [\"dist\"]\n}\n","packages\u002Ferrors-billing\u002Fpackage.json","json",[557,1733,1734,1739,1762,1782,1802,1822,1842,1855,1868,1887,1904,1909,1913,1926,1943,1947,1972],{"__ignoreMap":885},[889,1735,1736],{"class":891,"line":892},[889,1737,1738],{"class":899},"{\n",[889,1740,1741,1744,1747,1750,1752,1755,1758,1760],{"class":891,"line":923},[889,1742,1743],{"class":899},"  \"",[889,1745,1746],{"class":936},"name",[889,1748,1749],{"class":899},"\"",[889,1751,973],{"class":899},[889,1753,1754],{"class":899}," \"",[889,1756,1757],{"class":916},"@acme\u002Ferrors-billing",[889,1759,1749],{"class":899},[889,1761,1057],{"class":899},[889,1763,1764,1766,1769,1771,1773,1775,1778,1780],{"class":891,"line":930},[889,1765,1743],{"class":899},[889,1767,1768],{"class":936},"version",[889,1770,1749],{"class":899},[889,1772,973],{"class":899},[889,1774,1754],{"class":899},[889,1776,1777],{"class":916},"1.0.0",[889,1779,1749],{"class":899},[889,1781,1057],{"class":899},[889,1783,1784,1786,1789,1791,1793,1795,1798,1800],{"class":891,"line":966},[889,1785,1743],{"class":899},[889,1787,1788],{"class":936},"type",[889,1790,1749],{"class":899},[889,1792,973],{"class":899},[889,1794,1754],{"class":899},[889,1796,1797],{"class":916},"module",[889,1799,1749],{"class":899},[889,1801,1057],{"class":899},[889,1803,1804,1806,1809,1811,1813,1815,1818,1820],{"class":891,"line":1004},[889,1805,1743],{"class":899},[889,1807,1808],{"class":936},"main",[889,1810,1749],{"class":899},[889,1812,973],{"class":899},[889,1814,1754],{"class":899},[889,1816,1817],{"class":916},".\u002Fdist\u002Findex.mjs",[889,1819,1749],{"class":899},[889,1821,1057],{"class":899},[889,1823,1824,1826,1829,1831,1833,1835,1838,1840],{"class":891,"line":1036},[889,1825,1743],{"class":899},[889,1827,1828],{"class":936},"types",[889,1830,1749],{"class":899},[889,1832,973],{"class":899},[889,1834,1754],{"class":899},[889,1836,1837],{"class":916},".\u002Fdist\u002Findex.d.ts",[889,1839,1749],{"class":899},[889,1841,1057],{"class":899},[889,1843,1844,1846,1849,1851,1853],{"class":891,"line":1046},[889,1845,1743],{"class":899},[889,1847,1848],{"class":936},"exports",[889,1850,1749],{"class":899},[889,1852,973],{"class":899},[889,1854,963],{"class":899},[889,1856,1857,1860,1862,1864,1866],{"class":891,"line":1060},[889,1858,1859],{"class":899},"    \"",[889,1861,1703],{"class":1084},[889,1863,1749],{"class":899},[889,1865,973],{"class":899},[889,1867,963],{"class":899},[889,1869,1870,1873,1875,1877,1879,1881,1883,1885],{"class":891,"line":1111},[889,1871,1872],{"class":899},"      \"",[889,1874,896],{"class":983},[889,1876,1749],{"class":899},[889,1878,973],{"class":899},[889,1880,1754],{"class":899},[889,1882,1817],{"class":916},[889,1884,1749],{"class":899},[889,1886,1057],{"class":899},[889,1888,1889,1891,1893,1895,1897,1899,1901],{"class":891,"line":1117},[889,1890,1872],{"class":899},[889,1892,1828],{"class":983},[889,1894,1749],{"class":899},[889,1896,973],{"class":899},[889,1898,1754],{"class":899},[889,1900,1837],{"class":916},[889,1902,1903],{"class":899},"\"\n",[889,1905,1906],{"class":891,"line":1417},[889,1907,1908],{"class":899},"    }\n",[889,1910,1911],{"class":891,"line":1431},[889,1912,1114],{"class":899},[889,1914,1915,1917,1920,1922,1924],{"class":891,"line":1444},[889,1916,1743],{"class":899},[889,1918,1919],{"class":936},"peerDependencies",[889,1921,1749],{"class":899},[889,1923,973],{"class":899},[889,1925,963],{"class":899},[889,1927,1928,1930,1932,1934,1936,1938,1941],{"class":891,"line":1457},[889,1929,1859],{"class":899},[889,1931,917],{"class":1084},[889,1933,1749],{"class":899},[889,1935,973],{"class":899},[889,1937,1754],{"class":899},[889,1939,1940],{"class":916},"^3.0.0",[889,1942,1903],{"class":899},[889,1944,1945],{"class":891,"line":1463},[889,1946,1114],{"class":899},[889,1948,1950,1952,1955,1957,1959,1962,1964,1967,1969],{"class":891,"line":1949},16,[889,1951,1743],{"class":899},[889,1953,1954],{"class":936},"files",[889,1956,1749],{"class":899},[889,1958,973],{"class":899},[889,1960,1961],{"class":899}," [",[889,1963,1749],{"class":899},[889,1965,1966],{"class":916},"dist",[889,1968,1749],{"class":899},[889,1970,1971],{"class":899},"]\n",[889,1973,1975],{"class":891,"line":1974},17,[889,1976,1466],{"class":899},[860,1978,1980],{"id":1979},"source-catalog-augmentation-in-the-same-file","Source — catalog + augmentation in the same file",[879,1982,1985],{"className":881,"code":1983,"filename":1984,"language":884,"meta":885,"style":885},"import { defineErrorCatalog } from 'evlog'\n\nexport const billingErrors = defineErrorCatalog('billing', {\n  PAYMENT_DECLINED: {\n    status: 402,\n    message: 'Card declined',\n    why: 'Issuer declined the charge',\n    fix: 'Try a different payment method',\n    link: 'https:\u002F\u002Fdocs.example.com\u002Ferrors\u002Fbilling.payment_declined',\n  },\n  INSUFFICIENT_FUNDS: {\n    status: 402,\n    message: ({ available, required }: { available: number, required: number }) =>\n      `Insufficient funds: $${available}\u002F$${required}`,\n  },\n  \u002F\u002F ...\n})\n\ndeclare module 'evlog' {\n  interface RegisteredErrorCatalogs {\n    billing: typeof billingErrors\n  }\n}\n","packages\u002Ferrors-billing\u002Fsrc\u002Findex.ts",[557,1986,1987,2005,2009,2035,2044,2054,2068,2084,2100,2116,2120,2128,2138,2178,2205,2209,2215,2221,2226,2241,2250,2261,2266],{"__ignoreMap":885},[889,1988,1989,1991,1993,1995,1997,1999,2001,2003],{"class":891,"line":892},[889,1990,896],{"class":895},[889,1992,900],{"class":899},[889,1994,904],{"class":903},[889,1996,907],{"class":899},[889,1998,910],{"class":895},[889,2000,913],{"class":899},[889,2002,917],{"class":916},[889,2004,920],{"class":899},[889,2006,2007],{"class":891,"line":923},[889,2008,927],{"emptyLinePlaceholder":926},[889,2010,2011,2013,2015,2018,2020,2022,2024,2026,2029,2031,2033],{"class":891,"line":930},[889,2012,933],{"class":895},[889,2014,937],{"class":936},[889,2016,2017],{"class":903}," billingErrors ",[889,2019,943],{"class":899},[889,2021,904],{"class":946},[889,2023,949],{"class":903},[889,2025,952],{"class":899},[889,2027,2028],{"class":916},"billing",[889,2030,952],{"class":899},[889,2032,960],{"class":899},[889,2034,963],{"class":899},[889,2036,2037,2040,2042],{"class":891,"line":966},[889,2038,2039],{"class":969},"  PAYMENT_DECLINED",[889,2041,973],{"class":899},[889,2043,963],{"class":899},[889,2045,2046,2048,2050,2052],{"class":891,"line":1004},[889,2047,1049],{"class":969},[889,2049,973],{"class":899},[889,2051,1568],{"class":983},[889,2053,1057],{"class":899},[889,2055,2056,2058,2060,2062,2064,2066],{"class":891,"line":1036},[889,2057,1063],{"class":969},[889,2059,973],{"class":899},[889,2061,913],{"class":899},[889,2063,1579],{"class":916},[889,2065,952],{"class":899},[889,2067,1057],{"class":899},[889,2069,2070,2073,2075,2077,2080,2082],{"class":891,"line":1046},[889,2071,2072],{"class":969},"    why",[889,2074,973],{"class":899},[889,2076,913],{"class":899},[889,2078,2079],{"class":916},"Issuer declined the charge",[889,2081,952],{"class":899},[889,2083,1057],{"class":899},[889,2085,2086,2089,2091,2093,2096,2098],{"class":891,"line":1060},[889,2087,2088],{"class":969},"    fix",[889,2090,973],{"class":899},[889,2092,913],{"class":899},[889,2094,2095],{"class":916},"Try a different payment method",[889,2097,952],{"class":899},[889,2099,1057],{"class":899},[889,2101,2102,2105,2107,2109,2112,2114],{"class":891,"line":1111},[889,2103,2104],{"class":969},"    link",[889,2106,973],{"class":899},[889,2108,913],{"class":899},[889,2110,2111],{"class":916},"https:\u002F\u002Fdocs.example.com\u002Ferrors\u002Fbilling.payment_declined",[889,2113,952],{"class":899},[889,2115,1057],{"class":899},[889,2117,2118],{"class":891,"line":1117},[889,2119,1114],{"class":899},[889,2121,2122,2124,2126],{"class":891,"line":1417},[889,2123,1588],{"class":969},[889,2125,973],{"class":899},[889,2127,963],{"class":899},[889,2129,2130,2132,2134,2136],{"class":891,"line":1431},[889,2131,1049],{"class":969},[889,2133,973],{"class":899},[889,2135,1568],{"class":983},[889,2137,1057],{"class":899},[889,2139,2140,2142,2144,2146,2149,2151,2154,2156,2158,2160,2162,2165,2167,2169,2171,2173,2175],{"class":891,"line":1444},[889,2141,1063],{"class":946},[889,2143,973],{"class":899},[889,2145,1068],{"class":899},[889,2147,2148],{"class":1071}," available",[889,2150,960],{"class":899},[889,2152,2153],{"class":1071}," required",[889,2155,1075],{"class":899},[889,2157,900],{"class":899},[889,2159,2148],{"class":969},[889,2161,973],{"class":899},[889,2163,2164],{"class":1084}," number",[889,2166,960],{"class":899},[889,2168,2153],{"class":969},[889,2170,973],{"class":899},[889,2172,2164],{"class":1084},[889,2174,1088],{"class":899},[889,2176,2177],{"class":936}," =>\n",[889,2179,2180,2183,2186,2188,2191,2193,2196,2198,2201,2203],{"class":891,"line":1457},[889,2181,2182],{"class":899},"      `",[889,2184,2185],{"class":916},"Insufficient funds: $",[889,2187,1100],{"class":899},[889,2189,2190],{"class":903},"available",[889,2192,1120],{"class":899},[889,2194,2195],{"class":916},"\u002F$",[889,2197,1100],{"class":899},[889,2199,2200],{"class":903},"required",[889,2202,1106],{"class":899},[889,2204,1057],{"class":899},[889,2206,2207],{"class":891,"line":1463},[889,2208,1114],{"class":899},[889,2210,2211],{"class":891,"line":1949},[889,2212,2214],{"class":2213},"sHwdD","  \u002F\u002F ...\n",[889,2216,2217,2219],{"class":891,"line":1974},[889,2218,1120],{"class":899},[889,2220,1123],{"class":903},[889,2222,2224],{"class":891,"line":2223},18,[889,2225,927],{"emptyLinePlaceholder":926},[889,2227,2229,2231,2233,2235,2237,2239],{"class":891,"line":2228},19,[889,2230,1393],{"class":936},[889,2232,1396],{"class":936},[889,2234,913],{"class":899},[889,2236,917],{"class":916},[889,2238,952],{"class":899},[889,2240,963],{"class":899},[889,2242,2244,2246,2248],{"class":891,"line":2243},20,[889,2245,1409],{"class":936},[889,2247,1412],{"class":1084},[889,2249,963],{"class":899},[889,2251,2253,2255,2257,2259],{"class":891,"line":2252},21,[889,2254,1434],{"class":969},[889,2256,973],{"class":899},[889,2258,1425],{"class":899},[889,2260,1441],{"class":903},[889,2262,2264],{"class":891,"line":2263},22,[889,2265,1460],{"class":899},[889,2267,2269],{"class":891,"line":2268},23,[889,2270,1466],{"class":899},[553,2272,2273,2274,2276,2277,2280,2281,2283],{},"The ",[557,2275,711],{}," block lives inside the source file so the bundler emits it into the ",[557,2278,2279],{},"dist\u002Findex.d.ts",". Any consumer that imports from ",[557,2282,1757],{}," gets the augmentation transitively — no extra setup required on their side.",[860,2285,2287],{"id":2286},"consumption","Consumption",[879,2289,2292],{"className":881,"code":2290,"filename":2291,"language":884,"meta":885,"style":885},"\u002F\u002F Importing the package activates both the runtime catalog and the type augmentation.\nimport { billingErrors } from '@acme\u002Ferrors-billing'\nimport { authErrors } from '@acme\u002Ferrors-auth'\n\n\u002F\u002F Re-export from a central place so the rest of the app has one import path.\nexport { billingErrors, authErrors }\n","apps\u002Fapi\u002Fsrc\u002Finit.ts",[557,2293,2294,2299,2317,2336,2340,2345],{"__ignoreMap":885},[889,2295,2296],{"class":891,"line":892},[889,2297,2298],{"class":2213},"\u002F\u002F Importing the package activates both the runtime catalog and the type augmentation.\n",[889,2300,2301,2303,2305,2307,2309,2311,2313,2315],{"class":891,"line":923},[889,2302,896],{"class":895},[889,2304,900],{"class":899},[889,2306,1293],{"class":903},[889,2308,907],{"class":899},[889,2310,910],{"class":895},[889,2312,913],{"class":899},[889,2314,1757],{"class":916},[889,2316,920],{"class":899},[889,2318,2319,2321,2323,2325,2327,2329,2331,2334],{"class":891,"line":930},[889,2320,896],{"class":895},[889,2322,900],{"class":899},[889,2324,1271],{"class":903},[889,2326,907],{"class":899},[889,2328,910],{"class":895},[889,2330,913],{"class":899},[889,2332,2333],{"class":916},"@acme\u002Ferrors-auth",[889,2335,920],{"class":899},[889,2337,2338],{"class":891,"line":966},[889,2339,927],{"emptyLinePlaceholder":926},[889,2341,2342],{"class":891,"line":1004},[889,2343,2344],{"class":2213},"\u002F\u002F Re-export from a central place so the rest of the app has one import path.\n",[889,2346,2347,2349,2351,2353,2355,2357],{"class":891,"line":1036},[889,2348,933],{"class":895},[889,2350,900],{"class":899},[889,2352,1293],{"class":903},[889,2354,960],{"class":899},[889,2356,1271],{"class":903},[889,2358,2359],{"class":899}," }\n",[879,2361,2364],{"className":881,"code":2362,"filename":2363,"language":884,"meta":885,"style":885},"import { billingErrors } from '~\u002Finit'\n\nthrow billingErrors.PAYMENT_DECLINED({ cause: stripeErr })\n","apps\u002Fapi\u002Fsrc\u002Froutes\u002Fcheckout.post.ts",[557,2365,2366,2385,2389],{"__ignoreMap":885},[889,2367,2368,2370,2372,2374,2376,2378,2380,2383],{"class":891,"line":892},[889,2369,896],{"class":895},[889,2371,900],{"class":899},[889,2373,1293],{"class":903},[889,2375,907],{"class":899},[889,2377,910],{"class":895},[889,2379,913],{"class":899},[889,2381,2382],{"class":916},"~\u002Finit",[889,2384,920],{"class":899},[889,2386,2387],{"class":891,"line":923},[889,2388,927],{"emptyLinePlaceholder":926},[889,2390,2391,2394,2396,2398,2400,2402,2405,2408,2410,2413,2415],{"class":891,"line":930},[889,2392,2393],{"class":895},"throw",[889,2395,1293],{"class":903},[889,2397,1703],{"class":899},[889,2399,783],{"class":946},[889,2401,949],{"class":903},[889,2403,2404],{"class":899},"{",[889,2406,2407],{"class":969}," cause",[889,2409,973],{"class":899},[889,2411,2412],{"class":903}," stripeErr ",[889,2414,1120],{"class":899},[889,2416,1123],{"class":903},[879,2418,2421],{"className":881,"code":2419,"filename":2420,"language":884,"meta":885,"style":885},"import { createError, parseError } from 'evlog'\n\nthrow createError({\n  code: 'billing.PAYMENT_DECLINED', \u002F\u002F ← autocomplete from the registered catalog\n  message: 'Card declined',\n  status: 402,\n})\n\nconst err = parseError(caught)\nif (err.code === 'billing.PAYMENT_DECLINED') retry()\n\u002F\u002F                ↑ TypeScript knows the union of all registered codes\n","Anywhere in the app — autocomplete works",[557,2422,2423,2447,2451,2461,2479,2494,2505,2511,2515,2530,2561],{"__ignoreMap":885},[889,2424,2425,2427,2429,2432,2434,2437,2439,2441,2443,2445],{"class":891,"line":892},[889,2426,896],{"class":895},[889,2428,900],{"class":899},[889,2430,2431],{"class":903}," createError",[889,2433,960],{"class":899},[889,2435,2436],{"class":903}," parseError",[889,2438,907],{"class":899},[889,2440,910],{"class":895},[889,2442,913],{"class":899},[889,2444,917],{"class":916},[889,2446,920],{"class":899},[889,2448,2449],{"class":891,"line":923},[889,2450,927],{"emptyLinePlaceholder":926},[889,2452,2453,2455,2457,2459],{"class":891,"line":930},[889,2454,2393],{"class":895},[889,2456,2431],{"class":946},[889,2458,949],{"class":903},[889,2460,1738],{"class":899},[889,2462,2463,2466,2468,2470,2472,2474,2476],{"class":891,"line":966},[889,2464,2465],{"class":969},"  code",[889,2467,973],{"class":899},[889,2469,913],{"class":899},[889,2471,616],{"class":916},[889,2473,952],{"class":899},[889,2475,960],{"class":899},[889,2477,2478],{"class":2213}," \u002F\u002F ← autocomplete from the registered catalog\n",[889,2480,2481,2484,2486,2488,2490,2492],{"class":891,"line":1004},[889,2482,2483],{"class":969},"  message",[889,2485,973],{"class":899},[889,2487,913],{"class":899},[889,2489,1579],{"class":916},[889,2491,952],{"class":899},[889,2493,1057],{"class":899},[889,2495,2496,2499,2501,2503],{"class":891,"line":1036},[889,2497,2498],{"class":969},"  status",[889,2500,973],{"class":899},[889,2502,1568],{"class":983},[889,2504,1057],{"class":899},[889,2506,2507,2509],{"class":891,"line":1046},[889,2508,1120],{"class":899},[889,2510,1123],{"class":903},[889,2512,2513],{"class":891,"line":1060},[889,2514,927],{"emptyLinePlaceholder":926},[889,2516,2517,2520,2523,2525,2527],{"class":891,"line":1111},[889,2518,2519],{"class":936},"const",[889,2521,2522],{"class":903}," err ",[889,2524,943],{"class":899},[889,2526,2436],{"class":946},[889,2528,2529],{"class":903},"(caught)\n",[889,2531,2532,2535,2538,2540,2543,2546,2548,2550,2552,2555,2558],{"class":891,"line":1117},[889,2533,2534],{"class":895},"if",[889,2536,2537],{"class":903}," (err",[889,2539,1703],{"class":899},[889,2541,2542],{"class":903},"code ",[889,2544,2545],{"class":899},"===",[889,2547,913],{"class":899},[889,2549,616],{"class":916},[889,2551,952],{"class":899},[889,2553,2554],{"class":903},") ",[889,2556,2557],{"class":946},"retry",[889,2559,2560],{"class":903},"()\n",[889,2562,2563],{"class":891,"line":1417},[889,2564,2565],{"class":2213},"\u002F\u002F                ↑ TypeScript knows the union of all registered codes\n",[2567,2568,2570,2573,2574,2576,2577,560,2580,2576,2582,2585],"callout",{"color":2569,"icon":381},"neutral",[770,2571,2572],{},"Each shared package owns its prefix."," ",[557,2575,1757],{}," owns ",[557,2578,2579],{},"billing.*",[557,2581,2333],{},[557,2583,2584],{},"auth.*",". Conflicts are impossible by construction. Bumping a catalog to a new minor (adding entries) propagates to consumers via the regular semver upgrade path — no codegen, no migration step.",[736,2587,2589],{"id":2588},"composition-patterns","Composition patterns",[860,2591,2593],{"id":2592},"mix-catalogs-and-standalone-factories","Mix catalogs and standalone factories",[553,2595,2596,602,2598,2600,2601,2603],{},[557,2597,559],{},[557,2599,563],{}," produce identical call-site shapes. Use catalogs for grouped errors, ",[557,2602,559],{}," for one-offs (e.g. cross-cutting concerns like rate-limiting that don't belong to a specific domain).",[879,2605,2607],{"className":881,"code":2606,"filename":1257,"language":884,"meta":885,"style":885},"import { defineError, defineErrorCatalog } from 'evlog'\n\nexport const billingErrors = defineErrorCatalog('billing', {\n  PAYMENT_DECLINED: { status: 402, message: 'Card declined' },\n})\n\nexport const rateLimited = defineError('app.RATE_LIMITED', {\n  status: 429,\n  message: ({ retryAfter }: { retryAfter: number }) =>\n    `Rate limited: retry in ${retryAfter}s`,\n})\n\n\u002F\u002F Both look identical at the call site:\nthrow billingErrors.PAYMENT_DECLINED()\nthrow rateLimited({ retryAfter: 30 })\n",[557,2608,2609,2632,2636,2660,2688,2694,2698,2724,2735,2760,2783,2789,2793,2798,2810],{"__ignoreMap":885},[889,2610,2611,2613,2615,2618,2620,2622,2624,2626,2628,2630],{"class":891,"line":892},[889,2612,896],{"class":895},[889,2614,900],{"class":899},[889,2616,2617],{"class":903}," defineError",[889,2619,960],{"class":899},[889,2621,904],{"class":903},[889,2623,907],{"class":899},[889,2625,910],{"class":895},[889,2627,913],{"class":899},[889,2629,917],{"class":916},[889,2631,920],{"class":899},[889,2633,2634],{"class":891,"line":923},[889,2635,927],{"emptyLinePlaceholder":926},[889,2637,2638,2640,2642,2644,2646,2648,2650,2652,2654,2656,2658],{"class":891,"line":930},[889,2639,933],{"class":895},[889,2641,937],{"class":936},[889,2643,2017],{"class":903},[889,2645,943],{"class":899},[889,2647,904],{"class":946},[889,2649,949],{"class":903},[889,2651,952],{"class":899},[889,2653,2028],{"class":916},[889,2655,952],{"class":899},[889,2657,960],{"class":899},[889,2659,963],{"class":899},[889,2661,2662,2664,2666,2668,2670,2672,2674,2676,2678,2680,2682,2684,2686],{"class":891,"line":966},[889,2663,2039],{"class":969},[889,2665,973],{"class":899},[889,2667,900],{"class":899},[889,2669,978],{"class":969},[889,2671,973],{"class":899},[889,2673,1568],{"class":983},[889,2675,960],{"class":899},[889,2677,989],{"class":969},[889,2679,973],{"class":899},[889,2681,913],{"class":899},[889,2683,1579],{"class":916},[889,2685,952],{"class":899},[889,2687,1001],{"class":899},[889,2689,2690,2692],{"class":891,"line":1004},[889,2691,1120],{"class":899},[889,2693,1123],{"class":903},[889,2695,2696],{"class":891,"line":1036},[889,2697,927],{"emptyLinePlaceholder":926},[889,2699,2700,2702,2704,2707,2709,2711,2713,2715,2718,2720,2722],{"class":891,"line":1046},[889,2701,933],{"class":895},[889,2703,937],{"class":936},[889,2705,2706],{"class":903}," rateLimited ",[889,2708,943],{"class":899},[889,2710,2617],{"class":946},[889,2712,949],{"class":903},[889,2714,952],{"class":899},[889,2716,2717],{"class":916},"app.RATE_LIMITED",[889,2719,952],{"class":899},[889,2721,960],{"class":899},[889,2723,963],{"class":899},[889,2725,2726,2728,2730,2733],{"class":891,"line":1060},[889,2727,2498],{"class":969},[889,2729,973],{"class":899},[889,2731,2732],{"class":983}," 429",[889,2734,1057],{"class":899},[889,2736,2737,2739,2741,2743,2746,2748,2750,2752,2754,2756,2758],{"class":891,"line":1111},[889,2738,2483],{"class":946},[889,2740,973],{"class":899},[889,2742,1068],{"class":899},[889,2744,2745],{"class":1071}," retryAfter",[889,2747,1075],{"class":899},[889,2749,900],{"class":899},[889,2751,2745],{"class":969},[889,2753,973],{"class":899},[889,2755,2164],{"class":1084},[889,2757,1088],{"class":899},[889,2759,2177],{"class":936},[889,2761,2762,2765,2768,2770,2773,2775,2778,2781],{"class":891,"line":1117},[889,2763,2764],{"class":899},"    `",[889,2766,2767],{"class":916},"Rate limited: retry in ",[889,2769,1100],{"class":899},[889,2771,2772],{"class":903},"retryAfter",[889,2774,1120],{"class":899},[889,2776,2777],{"class":916},"s",[889,2779,2780],{"class":899},"`",[889,2782,1057],{"class":899},[889,2784,2785,2787],{"class":891,"line":1417},[889,2786,1120],{"class":899},[889,2788,1123],{"class":903},[889,2790,2791],{"class":891,"line":1431},[889,2792,927],{"emptyLinePlaceholder":926},[889,2794,2795],{"class":891,"line":1444},[889,2796,2797],{"class":2213},"\u002F\u002F Both look identical at the call site:\n",[889,2799,2800,2802,2804,2806,2808],{"class":891,"line":1457},[889,2801,2393],{"class":895},[889,2803,1293],{"class":903},[889,2805,1703],{"class":899},[889,2807,783],{"class":946},[889,2809,2560],{"class":903},[889,2811,2812,2814,2817,2819,2821,2823,2825,2828,2830],{"class":891,"line":1463},[889,2813,2393],{"class":895},[889,2815,2816],{"class":946}," rateLimited",[889,2818,949],{"class":903},[889,2820,2404],{"class":899},[889,2822,2745],{"class":969},[889,2824,973],{"class":899},[889,2826,2827],{"class":983}," 30",[889,2829,907],{"class":899},[889,2831,1123],{"class":903},[860,2833,2835],{"id":2834},"re-export-from-one-entry-per-domain","Re-export from one entry per domain",[553,2837,2838],{},"If a feature ships errors and audits together, give it a single re-export module so call sites only import once.",[879,2840,2843],{"className":881,"code":2841,"filename":2842,"language":884,"meta":885,"style":885},"export { billingErrors } from '.\u002Ferrors\u002Fbilling'\nexport { billingAudit } from '.\u002Faudit\u002Fbilling'\n","src\u002Ffeatures\u002Fbilling\u002Findex.ts",[557,2844,2845,2864],{"__ignoreMap":885},[889,2846,2847,2849,2851,2853,2855,2857,2859,2862],{"class":891,"line":892},[889,2848,933],{"class":895},[889,2850,900],{"class":899},[889,2852,1293],{"class":903},[889,2854,907],{"class":899},[889,2856,910],{"class":895},[889,2858,913],{"class":899},[889,2860,2861],{"class":916},".\u002Ferrors\u002Fbilling",[889,2863,920],{"class":899},[889,2865,2866,2868,2870,2873,2875,2877,2879,2882],{"class":891,"line":923},[889,2867,933],{"class":895},[889,2869,900],{"class":899},[889,2871,2872],{"class":903}," billingAudit",[889,2874,907],{"class":899},[889,2876,910],{"class":895},[889,2878,913],{"class":899},[889,2880,2881],{"class":916},".\u002Faudit\u002Fbilling",[889,2883,920],{"class":899},[879,2885,2888],{"className":881,"code":2886,"filename":2887,"language":884,"meta":885,"style":885},"import { billingErrors, billingAudit } from '~\u002Ffeatures\u002Fbilling'\n\nif (!cart.items.length) throw billingErrors.CART_EMPTY()\n\nlog.audit(billingAudit.INVOICE_REFUND({ actor, target: { id: 'inv_889' } }))\n","server\u002Fapi\u002Frefund.post.ts",[557,2889,2890,2913,2917,2951,2955],{"__ignoreMap":885},[889,2891,2892,2894,2896,2898,2900,2902,2904,2906,2908,2911],{"class":891,"line":892},[889,2893,896],{"class":895},[889,2895,900],{"class":899},[889,2897,1293],{"class":903},[889,2899,960],{"class":899},[889,2901,2872],{"class":903},[889,2903,907],{"class":899},[889,2905,910],{"class":895},[889,2907,913],{"class":899},[889,2909,2910],{"class":916},"~\u002Ffeatures\u002Fbilling",[889,2912,920],{"class":899},[889,2914,2915],{"class":891,"line":923},[889,2916,927],{"emptyLinePlaceholder":926},[889,2918,2919,2921,2924,2927,2930,2932,2935,2937,2940,2942,2944,2946,2949],{"class":891,"line":930},[889,2920,2534],{"class":895},[889,2922,2923],{"class":903}," (",[889,2925,2926],{"class":899},"!",[889,2928,2929],{"class":903},"cart",[889,2931,1703],{"class":899},[889,2933,2934],{"class":903},"items",[889,2936,1703],{"class":899},[889,2938,2939],{"class":903},"length) ",[889,2941,2393],{"class":895},[889,2943,1293],{"class":903},[889,2945,1703],{"class":899},[889,2947,2948],{"class":946},"CART_EMPTY",[889,2950,2560],{"class":903},[889,2952,2953],{"class":891,"line":966},[889,2954,927],{"emptyLinePlaceholder":926},[889,2956,2957,2960,2962,2965,2968,2970,2972,2974,2976,2979,2981,2983,2985,2987,2990,2992,2994,2997,2999,3001,3003],{"class":891,"line":1004},[889,2958,2959],{"class":903},"log",[889,2961,1703],{"class":899},[889,2963,2964],{"class":946},"audit",[889,2966,2967],{"class":903},"(billingAudit",[889,2969,1703],{"class":899},[889,2971,786],{"class":946},[889,2973,949],{"class":903},[889,2975,2404],{"class":899},[889,2977,2978],{"class":903}," actor",[889,2980,960],{"class":899},[889,2982,1189],{"class":969},[889,2984,973],{"class":899},[889,2986,900],{"class":899},[889,2988,2989],{"class":969}," id",[889,2991,973],{"class":899},[889,2993,913],{"class":899},[889,2995,2996],{"class":916},"inv_889",[889,2998,952],{"class":899},[889,3000,907],{"class":899},[889,3002,907],{"class":899},[889,3004,3005],{"class":903},"))\n",[860,3007,3009],{"id":3008},"override-catalog-defaults-at-the-call-site","Override catalog defaults at the call site",[553,3011,3012,3013,560,3016,560,3019,560,3022,560,3025,560,3028,3030,3031,3033],{},"Every entry's defaults (",[557,3014,3015],{},"message",[557,3017,3018],{},"status",[557,3020,3021],{},"why",[557,3023,3024],{},"fix",[557,3026,3027],{},"link",[557,3029,652],{},") are overridable per call. ",[557,3032,652],{}," is shallow-merged (call-site wins on conflict).",[879,3035,3037],{"className":881,"code":3036,"language":884,"meta":885,"style":885},"\u002F\u002F Catalog default:\n\u002F\u002F message: 'Card declined'\n\u002F\u002F internal: { category: 'gateway' }\n\nthrow billingErrors.PAYMENT_DECLINED({\n  message: 'Custom message for this specific call',\n  internal: { stripeRef: 'ch_x', category: 'gateway-overridden' },\n  cause: stripeErr,\n})\n\n\u002F\u002F Resulting EvlogError:\n\u002F\u002F - message: 'Custom message for this specific call' (override)\n\u002F\u002F - status: 402 (catalog default)\n\u002F\u002F - why: 'Issuer declined the charge' (catalog default)\n\u002F\u002F - internal: { category: 'gateway-overridden', stripeRef: 'ch_x' }\n",[557,3038,3039,3044,3049,3054,3058,3072,3087,3124,3136,3142,3146,3151,3156,3161,3166],{"__ignoreMap":885},[889,3040,3041],{"class":891,"line":892},[889,3042,3043],{"class":2213},"\u002F\u002F Catalog default:\n",[889,3045,3046],{"class":891,"line":923},[889,3047,3048],{"class":2213},"\u002F\u002F message: 'Card declined'\n",[889,3050,3051],{"class":891,"line":930},[889,3052,3053],{"class":2213},"\u002F\u002F internal: { category: 'gateway' }\n",[889,3055,3056],{"class":891,"line":966},[889,3057,927],{"emptyLinePlaceholder":926},[889,3059,3060,3062,3064,3066,3068,3070],{"class":891,"line":1004},[889,3061,2393],{"class":895},[889,3063,1293],{"class":903},[889,3065,1703],{"class":899},[889,3067,783],{"class":946},[889,3069,949],{"class":903},[889,3071,1738],{"class":899},[889,3073,3074,3076,3078,3080,3083,3085],{"class":891,"line":1036},[889,3075,2483],{"class":969},[889,3077,973],{"class":899},[889,3079,913],{"class":899},[889,3081,3082],{"class":916},"Custom message for this specific call",[889,3084,952],{"class":899},[889,3086,1057],{"class":899},[889,3088,3089,3092,3094,3096,3099,3101,3103,3106,3108,3110,3113,3115,3117,3120,3122],{"class":891,"line":1046},[889,3090,3091],{"class":969},"  internal",[889,3093,973],{"class":899},[889,3095,900],{"class":899},[889,3097,3098],{"class":969}," stripeRef",[889,3100,973],{"class":899},[889,3102,913],{"class":899},[889,3104,3105],{"class":916},"ch_x",[889,3107,952],{"class":899},[889,3109,960],{"class":899},[889,3111,3112],{"class":969}," category",[889,3114,973],{"class":899},[889,3116,913],{"class":899},[889,3118,3119],{"class":916},"gateway-overridden",[889,3121,952],{"class":899},[889,3123,1001],{"class":899},[889,3125,3126,3129,3131,3134],{"class":891,"line":1060},[889,3127,3128],{"class":969},"  cause",[889,3130,973],{"class":899},[889,3132,3133],{"class":903}," stripeErr",[889,3135,1057],{"class":899},[889,3137,3138,3140],{"class":891,"line":1111},[889,3139,1120],{"class":899},[889,3141,1123],{"class":903},[889,3143,3144],{"class":891,"line":1117},[889,3145,927],{"emptyLinePlaceholder":926},[889,3147,3148],{"class":891,"line":1417},[889,3149,3150],{"class":2213},"\u002F\u002F Resulting EvlogError:\n",[889,3152,3153],{"class":891,"line":1431},[889,3154,3155],{"class":2213},"\u002F\u002F - message: 'Custom message for this specific call' (override)\n",[889,3157,3158],{"class":891,"line":1444},[889,3159,3160],{"class":2213},"\u002F\u002F - status: 402 (catalog default)\n",[889,3162,3163],{"class":891,"line":1457},[889,3164,3165],{"class":2213},"\u002F\u002F - why: 'Issuer declined the charge' (catalog default)\n",[889,3167,3168],{"class":891,"line":1463},[889,3169,3170],{"class":2213},"\u002F\u002F - internal: { category: 'gateway-overridden', stripeRef: 'ch_x' }\n",[736,3172,3174],{"id":3173},"type-augmentation-deep-dive","Type augmentation — deep dive",[553,3176,3177,3178,3180,3181,560,3183,3185,3186,3189,3190,3193],{},"The opt-in ",[557,3179,684],{}," block is what surfaces autocomplete on ",[557,3182,663],{},[557,3184,666],{},", and the typed ",[557,3187,3188],{},"ErrorCode"," \u002F ",[557,3191,3192],{},"AuditAction"," exports.",[860,3195,3197],{"id":3196},"where-to-put-the-augmentation","Where to put the augmentation",[744,3199,3200,3210],{},[747,3201,3202],{},[750,3203,3204,3207],{},[753,3205,3206],{},"Repo shape",[753,3208,3209],{},"Recommended location",[762,3211,3212,3222,3236,3249],{},[750,3213,3214,3219],{},[767,3215,3216,3217,620],{},"Single file (",[557,3218,883],{},[767,3220,3221],{},"At the bottom of the same file",[750,3223,3224,3230],{},[767,3225,3226,3227,620],{},"Folder (",[557,3228,3229],{},"src\u002Ferrors\u002F*.ts",[767,3231,3232,3233,3235],{},"In ",[557,3234,1257],{}," (centralised) or each catalog file (decentralised)",[750,3237,3238,3241],{},[767,3239,3240],{},"npm package",[767,3242,3243,3244,3246,3247],{},"At the bottom of the package's main ",[557,3245,688],{}," so it ships in the published ",[557,3248,692],{},[750,3250,3251,3254],{},[767,3252,3253],{},"Monorepo",[767,3255,3256],{},"One augmentation per package, no central registry needed",[553,3258,3259,3260,3262],{},"Both centralised and decentralised work — TypeScript merges multiple ",[557,3261,684],{}," blocks across files automatically.",[860,3264,3266],{"id":3265},"how-to-add-custom-domains","How to add custom domains",[553,3268,3269],{},"Each augmentation key is the namespace name. Multiple catalogs sharing a prefix can either be merged into one key or split:",[879,3271,3274],{"className":881,"code":3272,"filename":3273,"language":884,"meta":885,"style":885},"declare module 'evlog' {\n  interface RegisteredErrorCatalogs {\n    billing: typeof billingErrors\n  }\n}\n","Centralised — one key per package",[557,3275,3276,3290,3298,3308,3312],{"__ignoreMap":885},[889,3277,3278,3280,3282,3284,3286,3288],{"class":891,"line":892},[889,3279,1393],{"class":936},[889,3281,1396],{"class":936},[889,3283,913],{"class":899},[889,3285,917],{"class":916},[889,3287,952],{"class":899},[889,3289,963],{"class":899},[889,3291,3292,3294,3296],{"class":891,"line":923},[889,3293,1409],{"class":936},[889,3295,1412],{"class":1084},[889,3297,963],{"class":899},[889,3299,3300,3302,3304,3306],{"class":891,"line":930},[889,3301,1434],{"class":969},[889,3303,973],{"class":899},[889,3305,1425],{"class":899},[889,3307,1441],{"class":903},[889,3309,3310],{"class":891,"line":966},[889,3311,1460],{"class":899},[889,3313,3314],{"class":891,"line":1004},[889,3315,1466],{"class":899},[879,3317,3320],{"className":881,"code":3318,"filename":3319,"language":884,"meta":885,"style":885},"declare module 'evlog' {\n  interface RegisteredErrorCatalogs {\n    'billing.payment': typeof billingPaymentErrors\n    'billing.subscription': typeof billingSubscriptionErrors\n    'billing.invoice': typeof billingInvoiceErrors\n  }\n}\n","Decentralised — one key per sub-domain",[557,3321,3322,3336,3344,3360,3375,3391,3395],{"__ignoreMap":885},[889,3323,3324,3326,3328,3330,3332,3334],{"class":891,"line":892},[889,3325,1393],{"class":936},[889,3327,1396],{"class":936},[889,3329,913],{"class":899},[889,3331,917],{"class":916},[889,3333,952],{"class":899},[889,3335,963],{"class":899},[889,3337,3338,3340,3342],{"class":891,"line":923},[889,3339,1409],{"class":936},[889,3341,1412],{"class":1084},[889,3343,963],{"class":899},[889,3345,3346,3349,3351,3353,3355,3357],{"class":891,"line":930},[889,3347,3348],{"class":899},"    '",[889,3350,677],{"class":916},[889,3352,952],{"class":899},[889,3354,973],{"class":899},[889,3356,1425],{"class":899},[889,3358,3359],{"class":903}," billingPaymentErrors\n",[889,3361,3362,3364,3366,3368,3370,3372],{"class":891,"line":966},[889,3363,3348],{"class":899},[889,3365,1489],{"class":916},[889,3367,952],{"class":899},[889,3369,973],{"class":899},[889,3371,1425],{"class":899},[889,3373,3374],{"class":903}," billingSubscriptionErrors\n",[889,3376,3377,3379,3382,3384,3386,3388],{"class":891,"line":1004},[889,3378,3348],{"class":899},[889,3380,3381],{"class":916},"billing.invoice",[889,3383,952],{"class":899},[889,3385,973],{"class":899},[889,3387,1425],{"class":899},[889,3389,3390],{"class":903}," billingInvoiceErrors\n",[889,3392,3393],{"class":891,"line":1036},[889,3394,1460],{"class":899},[889,3396,3397],{"class":891,"line":1046},[889,3398,1466],{"class":899},[553,3400,2273,3401,3404,3405,3407],{},[557,3402,3403],{},"_codes"," literal union is what produces the actual ",[557,3406,3188],{}," type — the keys themselves are arbitrary, choose what feels right for your structure.",[860,3409,3411],{"id":3410},"verifying-the-augmentation","Verifying the augmentation",[879,3413,3416],{"className":881,"code":3414,"filename":3415,"language":884,"meta":885,"style":885},"import type { ErrorCode, AuditAction } from 'evlog'\n\n\u002F\u002F Hover the type in your IDE — should show the union of all registered codes.\ntype AllErrorCodes = ErrorCode\ntype AllAuditActions = AuditAction\n\n\u002F\u002F Compile-time check:\nconst validCode: ErrorCode = 'billing.PAYMENT_DECLINED' \u002F\u002F OK\nconst invalidCode: ErrorCode = 'billing.NOPE' \u002F\u002F ← TS error if catalog is registered\n","Anywhere in the codebase",[557,3417,3418,3444,3448,3453,3466,3478,3482,3487,3509],{"__ignoreMap":885},[889,3419,3420,3422,3424,3426,3429,3431,3434,3436,3438,3440,3442],{"class":891,"line":892},[889,3421,896],{"class":895},[889,3423,1266],{"class":895},[889,3425,900],{"class":899},[889,3427,3428],{"class":903}," ErrorCode",[889,3430,960],{"class":899},[889,3432,3433],{"class":903}," AuditAction",[889,3435,907],{"class":899},[889,3437,910],{"class":895},[889,3439,913],{"class":899},[889,3441,917],{"class":916},[889,3443,920],{"class":899},[889,3445,3446],{"class":891,"line":923},[889,3447,927],{"emptyLinePlaceholder":926},[889,3449,3450],{"class":891,"line":930},[889,3451,3452],{"class":2213},"\u002F\u002F Hover the type in your IDE — should show the union of all registered codes.\n",[889,3454,3455,3457,3460,3463],{"class":891,"line":966},[889,3456,1788],{"class":936},[889,3458,3459],{"class":1084}," AllErrorCodes",[889,3461,3462],{"class":899}," =",[889,3464,3465],{"class":1084}," ErrorCode\n",[889,3467,3468,3470,3473,3475],{"class":891,"line":1004},[889,3469,1788],{"class":936},[889,3471,3472],{"class":1084}," AllAuditActions",[889,3474,3462],{"class":899},[889,3476,3477],{"class":1084}," AuditAction\n",[889,3479,3480],{"class":891,"line":1036},[889,3481,927],{"emptyLinePlaceholder":926},[889,3483,3484],{"class":891,"line":1046},[889,3485,3486],{"class":2213},"\u002F\u002F Compile-time check:\n",[889,3488,3489,3491,3494,3496,3498,3500,3502,3504,3506],{"class":891,"line":1060},[889,3490,2519],{"class":936},[889,3492,3493],{"class":903}," validCode",[889,3495,973],{"class":899},[889,3497,3428],{"class":1084},[889,3499,3462],{"class":899},[889,3501,913],{"class":899},[889,3503,616],{"class":916},[889,3505,952],{"class":899},[889,3507,3508],{"class":2213}," \u002F\u002F OK\n",[889,3510,3511,3513,3516,3518,3520,3522,3524,3527,3529],{"class":891,"line":1111},[889,3512,2519],{"class":936},[889,3514,3515],{"class":903}," invalidCode",[889,3517,973],{"class":899},[889,3519,3428],{"class":1084},[889,3521,3462],{"class":899},[889,3523,913],{"class":899},[889,3525,3526],{"class":916},"billing.NOPE",[889,3528,952],{"class":899},[889,3530,3531],{"class":2213}," \u002F\u002F ← TS error if catalog is registered\n",[553,3533,3534,3535,3538],{},"If autocomplete is empty, either no catalog is registered yet, or the augmentation file is not in the TypeScript program (check ",[557,3536,3537],{},"tsconfig.json"," includes).",[736,3540,3542],{"id":3541},"common-pitfalls","Common pitfalls",[3544,3545,3546,3552,3553,3555,3556,1703],"warning",{},[770,3547,3548,3549,3551],{},"Don't put ",[557,3550,711],{}," blocks in test files."," Augmentations from test files leak into the type-checker for the rest of the codebase if the test files are included in the main ",[557,3554,3537],{},". Keep augmentations next to the catalog source, never inside ",[557,3557,3558],{},"*.test.ts",[3544,3560,3561,3564,3565,3568,3569,3571],{},[770,3562,3563],{},"Avoid prefix collisions across packages."," If two packages augment the same ",[557,3566,3567],{},"RegisteredErrorCatalogs"," key (say both ship a ",[557,3570,2028],{}," catalog), TypeScript merges them silently and the runtime keeps the last-registered factory. Convention: one prefix per package, no overlap.",[3544,3573,3574,3580,3581,3584,3585,3587],{},[770,3575,3576,3577,3579],{},"Never override the ",[557,3578,557],{}," at the call site."," The catalog defines the code identity — overriding it would break dashboards, alerts, and consumer code branching on ",[557,3582,3583],{},"err.code",". The factory's call-site signature deliberately omits ",[557,3586,557],{}," from the overridable fields.",[723,3589,3590,3599],{},[553,3591,3592,3598],{},[770,3593,3594,3595,3597],{},"Prefer ",[557,3596,698],{}," over string comparisons in tests."," Both forms below are valid; the first survives renames (refactor-safe), the second doesn't.",[879,3600,3602],{"className":881,"code":3601,"language":884,"meta":885,"style":885},"expect(err.code).toBe(billingErrors.PAYMENT_DECLINED.code) \u002F\u002F ✓ refactor-safe\nexpect(err.code).toBe('billing.PAYMENT_DECLINED')          \u002F\u002F ✗ string literal\n",[557,3603,3604,3637],{"__ignoreMap":885},[889,3605,3606,3609,3612,3614,3617,3619,3622,3625,3627,3629,3631,3634],{"class":891,"line":892},[889,3607,3608],{"class":946},"expect",[889,3610,3611],{"class":903},"(err",[889,3613,1703],{"class":899},[889,3615,3616],{"class":903},"code)",[889,3618,1703],{"class":899},[889,3620,3621],{"class":946},"toBe",[889,3623,3624],{"class":903},"(billingErrors",[889,3626,1703],{"class":899},[889,3628,783],{"class":903},[889,3630,1703],{"class":899},[889,3632,3633],{"class":903},"code) ",[889,3635,3636],{"class":2213},"\u002F\u002F ✓ refactor-safe\n",[889,3638,3639,3641,3643,3645,3647,3649,3651,3653,3655,3657,3659,3662],{"class":891,"line":923},[889,3640,3608],{"class":946},[889,3642,3611],{"class":903},[889,3644,1703],{"class":899},[889,3646,3616],{"class":903},[889,3648,1703],{"class":899},[889,3650,3621],{"class":946},[889,3652,949],{"class":903},[889,3654,952],{"class":899},[889,3656,616],{"class":916},[889,3658,952],{"class":899},[889,3660,3661],{"class":903},")          ",[889,3663,3664],{"class":2213},"\u002F\u002F ✗ string literal\n",[736,3666,3668],{"id":3667},"api-reference","API reference",[744,3670,3671,3684],{},[747,3672,3673],{},[750,3674,3675,3678,3681],{},[753,3676,3677],{},"Symbol",[753,3679,3680],{},"Kind",[753,3682,3683],{},"Purpose",[762,3685,3686,3698,3709,3720,3731,3743,3755,3766],{},[750,3687,3688,3692,3695],{},[767,3689,3690],{},[557,3691,601],{},[767,3693,3694],{},"factory",[767,3696,3697],{},"Standalone single-error factory. No prefix derivation.",[750,3699,3700,3704,3706],{},[767,3701,3702],{},[557,3703,591],{},[767,3705,3694],{},[767,3707,3708],{},"Bundle of typed errors sharing a prefix.",[750,3710,3711,3715,3717],{},[767,3712,3713],{},[557,3714,605],{},[767,3716,3694],{},[767,3718,3719],{},"Standalone single-action audit factory.",[750,3721,3722,3726,3728],{},[767,3723,3724],{},[557,3725,595],{},[767,3727,3694],{},[767,3729,3730],{},"Bundle of typed audit actions sharing a prefix.",[750,3732,3733,3737,3740],{},[767,3734,3735],{},[557,3736,3567],{},[767,3738,3739],{},"interface",[767,3741,3742],{},"Augmentable registry of error catalogs.",[750,3744,3745,3750,3752],{},[767,3746,3747],{},[557,3748,3749],{},"RegisteredAuditCatalogs",[767,3751,3739],{},[767,3753,3754],{},"Augmentable registry of audit catalogs.",[750,3756,3757,3761,3763],{},[767,3758,3759],{},[557,3760,3188],{},[767,3762,1788],{},[767,3764,3765],{},"Union of all registered error codes.",[750,3767,3768,3772,3774],{},[767,3769,3770],{},[557,3771,3192],{},[767,3773,1788],{},[767,3775,3776],{},"Union of all registered audit actions.",[553,3778,3779,3780,3782],{},"Everything ships from the main ",[557,3781,917],{}," entrypoint.",[736,3784,3786],{"id":3785},"next-steps","Next Steps",[583,3788,3789,3802,3815],{},[586,3790,3791,3793,3794,3797,3798,3801],{},[717,3792,56],{"href":57},": The full ",[557,3795,3796],{},"createError"," API and ",[557,3799,3800],{},"parseError"," reference.",[586,3803,3804,3807,3808,560,3811,3814],{},[717,3805,3806],{"href":143},"Audit → Recording",": All audit-emission APIs (",[557,3809,3810],{},"log.audit",[557,3812,3813],{},"withAudit",", etc.).",[586,3816,3817,3819],{},[717,3818,202],{"href":207},": Auto-managed per-request loggers and HTTP error serialization.",[3821,3822,3823],"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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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 .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":885,"searchDepth":923,"depth":923,"links":3825},[3826,3827,3833,3838,3843,3848,3849,3850],{"id":738,"depth":923,"text":739},{"id":854,"depth":923,"text":855,"children":3828},[3829,3830,3831,3832],{"id":862,"depth":930,"text":863},{"id":1230,"depth":930,"text":1231},{"id":1480,"depth":930,"text":1481},{"id":1692,"depth":930,"text":1693},{"id":1712,"depth":923,"text":1713,"children":3834},[3835,3836,3837],{"id":1722,"depth":930,"text":1725},{"id":1979,"depth":930,"text":1980},{"id":2286,"depth":930,"text":2287},{"id":2588,"depth":923,"text":2589,"children":3839},[3840,3841,3842],{"id":2592,"depth":930,"text":2593},{"id":2834,"depth":930,"text":2835},{"id":3008,"depth":930,"text":3009},{"id":3173,"depth":923,"text":3174,"children":3844},[3845,3846,3847],{"id":3196,"depth":930,"text":3197},{"id":3265,"depth":930,"text":3266},{"id":3410,"depth":930,"text":3411},{"id":3541,"depth":923,"text":3542},{"id":3667,"depth":923,"text":3668},{"id":3785,"depth":923,"text":3786},"Scale typed error and audit catalogs from a single file to multi-package monorepos. Conventions, npm packaging recipe, composition patterns, and the type-augmentation deep dive.","md",[3854,3856],{"label":56,"icon":59,"to":57,"color":2569,"variant":3855},"subtle",{"label":128,"icon":129,"to":134,"color":2569,"variant":3855},{},{"icon":64},{"title":61,"description":3851},"_kHI8x64jCzfEy4CG1GKIHzBmswDcsJaZJzzqqxFIKM",[3862,3864],{"title":56,"path":57,"stem":58,"description":3863,"icon":59,"children":-1},"Create errors that explain why they occurred and how to fix them. Add actionable context with why, fix, and link fields for humans and AI agents.",{"title":66,"path":67,"stem":68,"description":3865,"icon":69,"children":-1},"Capture browser events with structured logging. Same API as the server, with automatic console styling, user identity context, and optional server transport.",1778338245794]