[{"data":1,"prerenderedAt":3006},["ShallowReactive",2],{"navigation_docs":3,"-docs-capabilities-health":493,"-docs-capabilities-health-surround":3001},[4,46,135,218,257,292,355,377,420],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":45},"Getting Started","i-lucide-rocket","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started",[10,15,20,25,30,35,40],{"title":11,"path":12,"stem":13,"icon":14},"What is Heximon?","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002F01.getting-started\u002F01.introduction","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","docs\u002F01.getting-started\u002F02.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Quick Start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","docs\u002F01.getting-started\u002F03.quick-start","i-lucide-zap",{"title":26,"path":27,"stem":28,"icon":29},"Core Concepts","\u002Fdocs\u002Fgetting-started\u002Fcore-concepts","docs\u002F01.getting-started\u002F04.core-concepts","i-lucide-shapes",{"title":31,"path":32,"stem":33,"icon":34},"Examples","\u002Fdocs\u002Fgetting-started\u002Fexamples","docs\u002F01.getting-started\u002F05.examples","i-lucide-library",{"title":36,"path":37,"stem":38,"icon":39},"Where Next?","\u002Fdocs\u002Fgetting-started\u002Fwhere-next","docs\u002F01.getting-started\u002F06.where-next","i-lucide-signpost",{"title":41,"path":42,"stem":43,"icon":44},"Troubleshooting","\u002Fdocs\u002Fgetting-started\u002Ftroubleshooting","docs\u002F01.getting-started\u002F07.troubleshooting","i-lucide-life-buoy",false,{"title":47,"icon":48,"path":49,"stem":50,"children":51,"page":45},"Essentials","i-lucide-boxes","\u002Fdocs\u002Fessentials","docs\u002F02.essentials",[52,56,61,66,71,76,81,86,91,96,101,105,110,115,120,125,130],{"title":53,"path":54,"stem":55,"icon":48},"Modules & DI","\u002Fdocs\u002Fessentials\u002Fmodules-and-di","docs\u002F02.essentials\u002F01.modules-and-di",{"title":57,"path":58,"stem":59,"icon":60},"Controllers","\u002Fdocs\u002Fessentials\u002Fcontrollers","docs\u002F02.essentials\u002F02.controllers","i-lucide-route",{"title":62,"path":63,"stem":64,"icon":65},"Validation & DTOs","\u002Fdocs\u002Fessentials\u002Fvalidation","docs\u002F02.essentials\u002F03.validation","i-lucide-shield-check",{"title":67,"path":68,"stem":69,"icon":70},"Contracts","\u002Fdocs\u002Fessentials\u002Fcontracts","docs\u002F02.essentials\u002F04.contracts","i-lucide-file-signature",{"title":72,"path":73,"stem":74,"icon":75},"REST Client","\u002Fdocs\u002Fessentials\u002Fclient","docs\u002F02.essentials\u002F05.client","i-lucide-plug",{"title":77,"path":78,"stem":79,"icon":80},"Database","\u002Fdocs\u002Fessentials\u002Fdatabase","docs\u002F02.essentials\u002F06.database","i-lucide-database",{"title":82,"path":83,"stem":84,"icon":85},"Drizzle ORM","\u002Fdocs\u002Fessentials\u002Fdrizzle","docs\u002F02.essentials\u002F07.drizzle","i-lucide-database-zap",{"title":87,"path":88,"stem":89,"icon":90},"Persistence & Transactions","\u002Fdocs\u002Fessentials\u002Fpersistence","docs\u002F02.essentials\u002F08.persistence","i-lucide-database-backup",{"title":92,"path":93,"stem":94,"icon":95},"Migrations","\u002Fdocs\u002Fessentials\u002Fmigrations","docs\u002F02.essentials\u002F09.migrations","i-lucide-git-branch",{"title":97,"path":98,"stem":99,"icon":100},"Authentication","\u002Fdocs\u002Fessentials\u002Fauthentication","docs\u002F02.essentials\u002F10.authentication","i-lucide-key-round",{"title":102,"path":103,"stem":104,"icon":65},"Permissions & scopes","\u002Fdocs\u002Fessentials\u002Fpermissions","docs\u002F02.essentials\u002F11.permissions",{"title":106,"path":107,"stem":108,"icon":109},"Error Handling","\u002Fdocs\u002Fessentials\u002Ferrors","docs\u002F02.essentials\u002F12.errors","i-lucide-triangle-alert",{"title":111,"path":112,"stem":113,"icon":114},"Testing a Heximon App","\u002Fdocs\u002Fessentials\u002Ftesting","docs\u002F02.essentials\u002F13.testing","i-lucide-flask-conical",{"title":116,"path":117,"stem":118,"icon":119},"Test app harness","\u002Fdocs\u002Fessentials\u002Fcreatetestapp","docs\u002F02.essentials\u002F14.createtestapp","i-lucide-test-tube",{"title":121,"path":122,"stem":123,"icon":124},"Logging & Observability","\u002Fdocs\u002Fessentials\u002Flogging","docs\u002F02.essentials\u002F17.logging","i-lucide-scroll-text",{"title":126,"path":127,"stem":128,"icon":129},"Context & Lifecycle","\u002Fdocs\u002Fessentials\u002Fcontext-and-lifecycle","docs\u002F02.essentials\u002F18.context-and-lifecycle","i-lucide-radio",{"title":131,"path":132,"stem":133,"icon":134},"Project Structure","\u002Fdocs\u002Fessentials\u002Fproject-structure","docs\u002F02.essentials\u002F19.project-structure","i-lucide-folder-tree",{"title":136,"icon":137,"path":138,"stem":139,"children":140,"page":45},"Capabilities","i-lucide-sparkles","\u002Fdocs\u002Fcapabilities","docs\u002F03.capabilities",[141,145,150,155,160,164,169,174,179,184,188,193,198,203,208,213],{"title":142,"path":143,"stem":144,"icon":137},"Overview","\u002Fdocs\u002Fcapabilities\u002Foverview","docs\u002F03.capabilities\u002F01.overview",{"title":146,"path":147,"stem":148,"icon":149},"Events","\u002Fdocs\u002Fcapabilities\u002Fevents","docs\u002F03.capabilities\u002F02.events","i-lucide-radio-tower",{"title":151,"path":152,"stem":153,"icon":154},"Queue","\u002Fdocs\u002Fcapabilities\u002Fbackground-jobs","docs\u002F03.capabilities\u002F03.background-jobs","i-lucide-list-ordered",{"title":156,"path":157,"stem":158,"icon":159},"Scheduled Work","\u002Fdocs\u002Fcapabilities\u002Fscheduled-jobs","docs\u002F03.capabilities\u002F04.scheduled-jobs","i-lucide-clock",{"title":161,"path":162,"stem":163,"icon":85},"Caching","\u002Fdocs\u002Fcapabilities\u002Fcaching","docs\u002F03.capabilities\u002F05.caching",{"title":165,"path":166,"stem":167,"icon":168},"Key\u002FValue Storage","\u002Fdocs\u002Fcapabilities\u002Fkey-value","docs\u002F03.capabilities\u002F06.key-value","i-lucide-hard-drive",{"title":170,"path":171,"stem":172,"icon":173},"Blob Storage","\u002Fdocs\u002Fcapabilities\u002Fblob","docs\u002F03.capabilities\u002F07.blob","i-lucide-folder-open",{"title":175,"path":176,"stem":177,"icon":178},"Health & Readiness","\u002Fdocs\u002Fcapabilities\u002Fhealth","docs\u002F03.capabilities\u002F08.health","i-lucide-heart-pulse",{"title":180,"path":181,"stem":182,"icon":183},"Notifications","\u002Fdocs\u002Fcapabilities\u002Fnotifications","docs\u002F03.capabilities\u002F09.notifications","i-lucide-mail",{"title":185,"path":186,"stem":187,"icon":65},"Idempotency","\u002Fdocs\u002Fcapabilities\u002Fidempotency","docs\u002F03.capabilities\u002F10.idempotency",{"title":189,"path":190,"stem":191,"icon":192},"Security Hardening","\u002Fdocs\u002Fcapabilities\u002Fsecurity","docs\u002F03.capabilities\u002F11.security","i-lucide-shield",{"title":194,"path":195,"stem":196,"icon":197},"Observability & Tracing","\u002Fdocs\u002Fcapabilities\u002Fobservability","docs\u002F03.capabilities\u002F12.observability","i-lucide-activity",{"title":199,"path":200,"stem":201,"icon":202},"OpenAPI","\u002Fdocs\u002Fcapabilities\u002Fopenapi","docs\u002F03.capabilities\u002F13.openapi","i-lucide-book-marked",{"title":204,"path":205,"stem":206,"icon":207},"MCP Server","\u002Fdocs\u002Fcapabilities\u002Fmcp","docs\u002F03.capabilities\u002F14.mcp","i-lucide-bot",{"title":209,"path":210,"stem":211,"icon":212},"Schema DTOs","\u002Fdocs\u002Fcapabilities\u002Fschema","docs\u002F03.capabilities\u002F15.schema","i-lucide-file-json",{"title":214,"path":215,"stem":216,"icon":217},"Branded IDs","\u002Fdocs\u002Fcapabilities\u002Fbranded-ids","docs\u002F03.capabilities\u002F16.branded-ids","i-lucide-tag",{"title":219,"icon":220,"path":221,"stem":222,"children":223,"page":45},"Architecture","i-lucide-building","\u002Fdocs\u002Farchitecture","docs\u002F04.architecture",[224,227,232,237,242,247,252],{"title":142,"path":225,"stem":226,"icon":220},"\u002Fdocs\u002Farchitecture\u002Foverview","docs\u002F04.architecture\u002F01.overview",{"title":228,"path":229,"stem":230,"icon":231},"Domain-Driven Design","\u002Fdocs\u002Farchitecture\u002Fddd","docs\u002F04.architecture\u002F02.ddd","i-lucide-hexagon",{"title":233,"path":234,"stem":235,"icon":236},"CQRS","\u002Fdocs\u002Farchitecture\u002Fcqrs","docs\u002F04.architecture\u002F03.cqrs","i-lucide-split",{"title":238,"path":239,"stem":240,"icon":241},"Repository Pattern","\u002Fdocs\u002Farchitecture\u002Frepository-pattern","docs\u002F04.architecture\u002F04.repository-pattern","i-lucide-archive",{"title":243,"path":244,"stem":245,"icon":246},"Integration Events","\u002Fdocs\u002Farchitecture\u002Fintegration-events","docs\u002F04.architecture\u002F05.integration-events","i-lucide-send-horizontal",{"title":248,"path":249,"stem":250,"icon":251},"Saga Orchestration","\u002Fdocs\u002Farchitecture\u002Fsagas","docs\u002F04.architecture\u002F06.sagas","i-lucide-hourglass",{"title":253,"path":254,"stem":255,"icon":256},"Durable Workflows","\u002Fdocs\u002Farchitecture\u002Fworkflows","docs\u002F04.architecture\u002F07.workflows","i-lucide-workflow",{"title":258,"icon":259,"path":260,"stem":261,"children":262,"page":45},"Realtime","i-lucide-cable","\u002Fdocs\u002Frealtime","docs\u002F05.realtime",[263,266,270,274,279,284,288],{"title":142,"path":264,"stem":265,"icon":259},"\u002Fdocs\u002Frealtime\u002Foverview","docs\u002F05.realtime\u002F01.overview",{"title":267,"path":268,"stem":269,"icon":129},"WebSockets","\u002Fdocs\u002Frealtime\u002Fwebsockets","docs\u002F05.realtime\u002F02.websockets",{"title":271,"path":272,"stem":273,"icon":70},"WebSocket Contracts","\u002Fdocs\u002Frealtime\u002Fwebsocket-contracts","docs\u002F05.realtime\u002F03.websocket-contracts",{"title":275,"path":276,"stem":277,"icon":278},"Server-Sent Events","\u002Fdocs\u002Frealtime\u002Fserver-sent-events","docs\u002F05.realtime\u002F04.server-sent-events","i-lucide-rss",{"title":280,"path":281,"stem":282,"icon":283},"Typed Clients","\u002Fdocs\u002Frealtime\u002Ftyped-clients","docs\u002F05.realtime\u002F05.typed-clients","i-lucide-plug-zap",{"title":285,"path":286,"stem":287,"icon":259},"AsyncAPI","\u002Fdocs\u002Frealtime\u002Fasyncapi","docs\u002F05.realtime\u002F06.asyncapi",{"title":289,"path":290,"stem":291,"icon":80},"Durable Objects","\u002Fdocs\u002Frealtime\u002Fdurable-objects","docs\u002F05.realtime\u002F07.durable-objects",{"title":293,"icon":294,"path":295,"stem":296,"children":297,"page":45},"Deploy","i-lucide-cloud-upload","\u002Fdocs\u002Fdeploy","docs\u002F06.deploy",[298,301,306,311,316,321,326,331,336,341,345,350],{"title":142,"path":299,"stem":300,"icon":6},"\u002Fdocs\u002Fdeploy\u002Foverview","docs\u002F06.deploy\u002F01.overview",{"title":302,"path":303,"stem":304,"icon":305},"Node","\u002Fdocs\u002Fdeploy\u002Fnode","docs\u002F06.deploy\u002F02.node","la:node-js",{"title":307,"path":308,"stem":309,"icon":310},"Cloudflare","\u002Fdocs\u002Fdeploy\u002Fcloudflare","docs\u002F06.deploy\u002F03.cloudflare","simple-icons:cloudflare",{"title":312,"path":313,"stem":314,"icon":315},"Vercel","\u002Fdocs\u002Fdeploy\u002Fvercel","docs\u002F06.deploy\u002F04.vercel","ri:vercel-fill",{"title":317,"path":318,"stem":319,"icon":320},"Netlify","\u002Fdocs\u002Fdeploy\u002Fnetlify","docs\u002F06.deploy\u002F05.netlify","i-simple-icons-netlify",{"title":322,"path":323,"stem":324,"icon":325},"AWS Lambda","\u002Fdocs\u002Fdeploy\u002Faws-lambda","docs\u002F06.deploy\u002F06.aws-lambda","hugeicons:aws-lambda",{"title":327,"path":328,"stem":329,"icon":330},"Deno Deploy","\u002Fdocs\u002Fdeploy\u002Fdeno-deploy","docs\u002F06.deploy\u002F07.deno-deploy","simple-icons:denodeploy",{"title":332,"path":333,"stem":334,"icon":335},"Nitro","\u002Fdocs\u002Fdeploy\u002Fnitro","docs\u002F06.deploy\u002F08.nitro","i-unjs-nitro",{"title":337,"path":338,"stem":339,"icon":340},"Nuxt","\u002Fdocs\u002Fdeploy\u002Fnuxt","docs\u002F06.deploy\u002F09.nuxt","i-devicon-nuxt",{"title":342,"path":343,"stem":344,"icon":236},"Mixed-runtime split","\u002Fdocs\u002Fdeploy\u002Fmixed-runtime-split","docs\u002F06.deploy\u002F10.mixed-runtime-split",{"title":346,"path":347,"stem":348,"icon":349},"Hosts","\u002Fdocs\u002Fdeploy\u002Fhosts","docs\u002F06.deploy\u002F11.hosts","i-lucide-map",{"title":351,"path":352,"stem":353,"icon":354},"Cross-service events","\u002Fdocs\u002Fdeploy\u002Fcross-service-events","docs\u002F06.deploy\u002F12.cross-service-events","i-lucide-network",{"title":356,"icon":357,"path":358,"stem":359,"children":360,"page":45},"CLI","i-lucide-terminal","\u002Fdocs\u002Fcli","docs\u002F07.cli",[361,365,369,373],{"title":362,"path":363,"stem":364,"icon":357},"The heximon CLI","\u002Fdocs\u002Fcli\u002Foverview","docs\u002F07.cli\u002F01.overview",{"title":366,"path":367,"stem":368,"icon":137},"Create a New App","\u002Fdocs\u002Fcli\u002Fcreate","docs\u002F07.cli\u002F02.create",{"title":370,"path":371,"stem":372,"icon":95},"Migrations from the CLI","\u002Fdocs\u002Fcli\u002Fmigrations","docs\u002F07.cli\u002F03.migrations",{"title":374,"path":375,"stem":376,"icon":6},"Deploying a Heximon app","\u002Fdocs\u002Fcli\u002Fdeploy","docs\u002F07.cli\u002F04.deploy",{"title":378,"icon":379,"path":380,"stem":381,"children":382,"page":45},"Under the Hood","i-lucide-wrench","\u002Fdocs\u002Funder-the-hood","docs\u002F08.under-the-hood",[383,388,393,397,402,407,411,415],{"title":384,"path":385,"stem":386,"icon":387},"How the Compiler Works","\u002Fdocs\u002Funder-the-hood\u002Fhow-the-compiler-works","docs\u002F08.under-the-hood\u002F01.how-the-compiler-works","i-lucide-cog",{"title":389,"path":390,"stem":391,"icon":392},"Compiler","\u002Fdocs\u002Funder-the-hood\u002Fextending-the-compiler","docs\u002F08.under-the-hood\u002F02.extending-the-compiler","i-lucide-cpu",{"title":394,"path":395,"stem":396,"icon":357},"Compiler Diagnostics","\u002Fdocs\u002Funder-the-hood\u002Fcompiler-diagnostics","docs\u002F08.under-the-hood\u002F03.compiler-diagnostics",{"title":398,"path":399,"stem":400,"icon":401},"Library Mode","\u002Fdocs\u002Funder-the-hood\u002Flibrary-mode","docs\u002F08.under-the-hood\u002F04.library-mode","i-lucide-package",{"title":403,"path":404,"stem":405,"icon":406},"Other bundlers","\u002Fdocs\u002Funder-the-hood\u002Falternate-bundlers","docs\u002F08.under-the-hood\u002F05.alternate-bundlers","i-lucide-blocks",{"title":408,"path":409,"stem":410,"icon":401},"Packages","\u002Fdocs\u002Funder-the-hood\u002Fpackages","docs\u002F08.under-the-hood\u002F06.packages",{"title":412,"path":413,"stem":414,"icon":207},"AI Skills","\u002Fdocs\u002Funder-the-hood\u002Fai-and-agents","docs\u002F08.under-the-hood\u002F07.ai-and-agents",{"title":416,"path":417,"stem":418,"icon":419},"Advanced DI","\u002Fdocs\u002Funder-the-hood\u002Fadvanced-di","docs\u002F08.under-the-hood\u002F08.advanced-di","i-lucide-git-fork",{"title":421,"icon":422,"path":423,"stem":424,"children":425,"page":45},"Recipes","i-lucide-book-open-check","\u002Fdocs\u002Frecipes","docs\u002F09.recipes",[426,431,436,440,444,448,452,456,460,465,469,474,479,484,488],{"title":427,"path":428,"stem":429,"icon":430},"Send an Email","\u002Fdocs\u002Frecipes\u002Fsend-an-email","docs\u002F09.recipes\u002F01.send-an-email","i-lucide-send",{"title":432,"path":433,"stem":434,"icon":435},"Upload a File","\u002Fdocs\u002Frecipes\u002Fupload-a-file","docs\u002F09.recipes\u002F02.upload-a-file","i-lucide-upload",{"title":437,"path":438,"stem":439,"icon":24},"Cache an Expensive Call","\u002Fdocs\u002Frecipes\u002Fcache-an-expensive-call","docs\u002F09.recipes\u002F03.cache-an-expensive-call",{"title":441,"path":442,"stem":443,"icon":154},"Paginate a List","\u002Fdocs\u002Frecipes\u002Fpaginate-a-list","docs\u002F09.recipes\u002F04.paginate-a-list",{"title":445,"path":446,"stem":447,"icon":65},"Protect Admin Routes","\u002Fdocs\u002Frecipes\u002Fprotect-admin-routes","docs\u002F09.recipes\u002F05.protect-admin-routes",{"title":449,"path":450,"stem":451,"icon":178},"Health Probes and a Nightly Job","\u002Fdocs\u002Frecipes\u002Fhealth-probes-and-a-nightly-job","docs\u002F09.recipes\u002F06.health-probes-and-a-nightly-job",{"title":453,"path":454,"stem":455,"icon":80},"Build a CRUD API","\u002Fdocs\u002Frecipes\u002Fcrud-api","docs\u002F09.recipes\u002F07.crud-api",{"title":457,"path":458,"stem":459,"icon":100},"Add Authentication","\u002Fdocs\u002Frecipes\u002Fadd-authentication","docs\u002F09.recipes\u002F08.add-authentication",{"title":461,"path":462,"stem":463,"icon":464},"Background Jobs","\u002Fdocs\u002Frecipes\u002Fbackground-jobs","docs\u002F09.recipes\u002F09.background-jobs","i-lucide-timer",{"title":466,"path":467,"stem":468,"icon":149},"Decouple Features with Events","\u002Fdocs\u002Frecipes\u002Fevent-driven-module","docs\u002F09.recipes\u002F10.event-driven-module",{"title":470,"path":471,"stem":472,"icon":473},"Build a DDD Aggregate","\u002Fdocs\u002Frecipes\u002Fddd-aggregate","docs\u002F09.recipes\u002F11.ddd-aggregate","i-lucide-box",{"title":475,"path":476,"stem":477,"icon":478},"Publish a Feature Package","\u002Fdocs\u002Frecipes\u002Ffeature-package","docs\u002F09.recipes\u002F12.feature-package","i-lucide-package-open",{"title":480,"path":481,"stem":482,"icon":483},"Reliable Integration Events","\u002Fdocs\u002Frecipes\u002Freliable-integration-events","docs\u002F09.recipes\u002F13.reliable-integration-events","i-lucide-inbox",{"title":485,"path":486,"stem":487,"icon":95},"Reactive Choreography","\u002Fdocs\u002Frecipes\u002Freactive-choreography","docs\u002F09.recipes\u002F14.reactive-choreography",{"title":489,"path":490,"stem":491,"icon":492},"Build a Production CRUD API","\u002Fdocs\u002Frecipes\u002Fproduction-crud-api","docs\u002F09.recipes\u002F15.production-crud-api","i-lucide-layers",{"id":494,"title":175,"body":495,"description":2994,"extension":2995,"links":2996,"meta":2997,"navigation":2998,"path":176,"seo":2999,"stem":177,"__hash__":3000},"docs\u002Fdocs\u002F03.capabilities\u002F08.health.md",{"type":496,"value":497,"toc":2977},"minimark",[498,518,523,594,605,714,844,848,860,863,1420,1423,1436,1440,1465,1533,1549,1556,1725,1729,1742,2059,2073,2080,2108,2122,2149,2154,2173,2449,2455,2462,2471,2576,2592,2596,2616,2683,2692,2696,2708,2714,2730,2755,2888,2914,2918,2973],[499,500,501,502,506,507,510,511,514,515,517],"p",{},"Container orchestrators need two different signals: is the process alive at all, and is it ready to handle\ntraffic? ",[503,504,505],"code",{},"@heximon\u002Fhealth"," discovers your ",[503,508,509],{},"HealthIndicator"," classes, aggregates them into an injectable\n",[503,512,513],{},"HealthRegistry",", and leaves the HTTP surface entirely to you. You expose the probes by injecting\n",[503,516,513],{}," into your own controller — giving you full control over paths, status codes, and response\nshapes with ordinary HTTP code.",[519,520,522],"h2",{"id":521},"install-and-register-the-plugin","Install and register the plugin",[524,525,526,551,566,580],"code-group",{},[527,528,534],"pre",{"className":529,"code":530,"filename":531,"language":532,"meta":533,"style":533},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @heximon\u002Fhealth\n","pnpm","bash","",[503,535,536],{"__ignoreMap":533},[537,538,541,544,548],"span",{"class":539,"line":540},"line",1,[537,542,531],{"class":543},"sBMFI",[537,545,547],{"class":546},"sfazB"," add",[537,549,550],{"class":546}," @heximon\u002Fhealth\n",[527,552,555],{"className":529,"code":553,"filename":554,"language":532,"meta":533,"style":533},"npm install @heximon\u002Fhealth\n","npm",[503,556,557],{"__ignoreMap":533},[537,558,559,561,564],{"class":539,"line":540},[537,560,554],{"class":543},[537,562,563],{"class":546}," install",[537,565,550],{"class":546},[527,567,570],{"className":529,"code":568,"filename":569,"language":532,"meta":533,"style":533},"yarn add @heximon\u002Fhealth\n","yarn",[503,571,572],{"__ignoreMap":533},[537,573,574,576,578],{"class":539,"line":540},[537,575,569],{"class":543},[537,577,547],{"class":546},[537,579,550],{"class":546},[527,581,584],{"className":529,"code":582,"filename":583,"language":532,"meta":533,"style":533},"bun add @heximon\u002Fhealth\n","bun",[503,585,586],{"__ignoreMap":533},[537,587,588,590,592],{"class":539,"line":540},[537,589,583],{"class":543},[537,591,547],{"class":546},[537,593,550],{"class":546},[499,595,596,597,600,601,604],{},"Add ",[503,598,599],{},"HealthPlugin"," alongside the HTTP plugin in your ",[503,602,603],{},"heximon.config.ts"," config file:",[527,606,611],{"className":607,"code":608,"filename":609,"language":610,"meta":533,"style":533},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import heximon from \"@heximon\u002Fbuild\u002Fvite\";\nimport { defineConfig } from \"vite-plus\";\n\nexport default defineConfig({ plugins: [heximon()] });\n","vite.config.ts","ts",[503,612,613,639,665,672],{"__ignoreMap":533},[537,614,615,619,623,626,630,633,636],{"class":539,"line":540},[537,616,618],{"class":617},"s7zQu","import",[537,620,622],{"class":621},"sTEyZ"," heximon ",[537,624,625],{"class":617},"from",[537,627,629],{"class":628},"sMK4o"," \"",[537,631,632],{"class":546},"@heximon\u002Fbuild\u002Fvite",[537,634,635],{"class":628},"\"",[537,637,638],{"class":628},";\n",[537,640,642,644,647,650,653,656,658,661,663],{"class":539,"line":641},2,[537,643,618],{"class":617},[537,645,646],{"class":628}," {",[537,648,649],{"class":621}," defineConfig",[537,651,652],{"class":628}," }",[537,654,655],{"class":617}," from",[537,657,629],{"class":628},[537,659,660],{"class":546},"vite-plus",[537,662,635],{"class":628},[537,664,638],{"class":628},[537,666,668],{"class":539,"line":667},3,[537,669,671],{"emptyLinePlaceholder":670},true,"\n",[537,673,675,678,681,684,687,690,694,697,700,703,706,709,712],{"class":539,"line":674},4,[537,676,677],{"class":617},"export",[537,679,680],{"class":617}," default",[537,682,649],{"class":683},"s2Zo4",[537,685,686],{"class":621},"(",[537,688,689],{"class":628},"{",[537,691,693],{"class":692},"swJcz"," plugins",[537,695,696],{"class":628},":",[537,698,699],{"class":621}," [",[537,701,702],{"class":683},"heximon",[537,704,705],{"class":621},"()] ",[537,707,708],{"class":628},"}",[537,710,711],{"class":621},")",[537,713,638],{"class":628},[527,715,717],{"className":607,"code":716,"filename":603,"language":610,"meta":533,"style":533},"import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { HttpPlugin } from \"@heximon\u002Fhttp\u002Fcompiler\";\nimport { HealthPlugin } from \"@heximon\u002Fhealth\u002Fcompiler\";\n\nexport default defineHeximonConfig({\n  plugins: [new HttpPlugin(), new HealthPlugin()],\n});\n",[503,718,719,741,763,785,789,803,835],{"__ignoreMap":533},[537,720,721,723,725,728,730,732,734,737,739],{"class":539,"line":540},[537,722,618],{"class":617},[537,724,646],{"class":628},[537,726,727],{"class":621}," defineHeximonConfig",[537,729,652],{"class":628},[537,731,655],{"class":617},[537,733,629],{"class":628},[537,735,736],{"class":546},"@heximon\u002Fbuild",[537,738,635],{"class":628},[537,740,638],{"class":628},[537,742,743,745,747,750,752,754,756,759,761],{"class":539,"line":641},[537,744,618],{"class":617},[537,746,646],{"class":628},[537,748,749],{"class":621}," HttpPlugin",[537,751,652],{"class":628},[537,753,655],{"class":617},[537,755,629],{"class":628},[537,757,758],{"class":546},"@heximon\u002Fhttp\u002Fcompiler",[537,760,635],{"class":628},[537,762,638],{"class":628},[537,764,765,767,769,772,774,776,778,781,783],{"class":539,"line":667},[537,766,618],{"class":617},[537,768,646],{"class":628},[537,770,771],{"class":621}," HealthPlugin",[537,773,652],{"class":628},[537,775,655],{"class":617},[537,777,629],{"class":628},[537,779,780],{"class":546},"@heximon\u002Fhealth\u002Fcompiler",[537,782,635],{"class":628},[537,784,638],{"class":628},[537,786,787],{"class":539,"line":674},[537,788,671],{"emptyLinePlaceholder":670},[537,790,792,794,796,798,800],{"class":539,"line":791},5,[537,793,677],{"class":617},[537,795,680],{"class":617},[537,797,727],{"class":683},[537,799,686],{"class":621},[537,801,802],{"class":628},"{\n",[537,804,806,809,811,813,816,818,821,824,827,829,832],{"class":539,"line":805},6,[537,807,808],{"class":692},"  plugins",[537,810,696],{"class":628},[537,812,699],{"class":621},[537,814,815],{"class":628},"new",[537,817,749],{"class":683},[537,819,820],{"class":621},"()",[537,822,823],{"class":628},",",[537,825,826],{"class":628}," new",[537,828,771],{"class":683},[537,830,831],{"class":621},"()]",[537,833,834],{"class":628},",\n",[537,836,838,840,842],{"class":539,"line":837},7,[537,839,708],{"class":628},[537,841,711],{"class":621},[537,843,638],{"class":628},[519,845,847],{"id":846},"the-app-owned-controller","The app-owned controller",[499,849,850,852,853,855,856,859],{},[503,851,505],{}," mounts no routes. It discovers your indicators and provides the injectable\n",[503,854,513],{}," as a core provider. You expose the probes by injecting the registry into a plain\ncontroller listed under ",[503,857,858],{},"http: { controllers }",".",[499,861,862],{},"The controller from the flagship example shows the full pattern:",[527,864,867],{"className":607,"code":865,"filename":866,"language":610,"meta":533,"style":533},"import { type AggregatedHealthResult, HealthRegistry } from \"@heximon\u002Fhealth\";\nimport type { Controller, Get } from \"@heximon\u002Fhttp\";\n\n\u002F**\n * The app-owned HTTP surface for the health probes. `@heximon\u002Fhealth` mounts nothing itself — it only\n * provides the injectable {@link HealthRegistry}. This controller injects the registry and exposes the\n * two conventional endpoints, owning their paths, status codes, and response shapes:\n *\n * - `GET \u002Fhealth` — liveness: responds `200 { status: \"up\" }` immediately. No indicator is run and no\n *   boot promise is awaited, so it is safe for a container liveness probe that fires before the app is\n *   ready.\n * - `GET \u002Fready` — readiness: runs every registered indicator via {@link HealthRegistry.checkAll}, then\n *   reports `200` when up or degraded and `503` when any indicator is down.\n *\u002F\nexport class HealthController implements Controller {\n  \u002F** @param health - The health registry, resolved by class identity (a core provider). *\u002F\n  public constructor(private readonly health: HealthRegistry) {}\n\n  \u002F**\n   * `GET \u002Fhealth` — liveness. Returns immediately without running any indicator.\n   *\n   * @returns A constant `{ status: \"up\" }` payload.\n   *\u002F\n  public live(_action: Get\u003C\"\u002Fhealth\">): { status: string } {\n    return { status: \"up\" };\n  }\n\n  \u002F**\n   * `GET \u002Fready` — readiness. Aggregates every indicator and maps the overall status to an HTTP code.\n   *\n   * @param action - The request action (used to set a `503` status when the aggregate is down).\n   * @returns The aggregated health result (overall status + per-indicator breakdown).\n   *\u002F\n  public async ready(action: Get\u003C\"\u002Fready\">): Promise\u003CAggregatedHealthResult> {\n    const result = await this.health.checkAll();\n\n    if (result.status === \"down\") {\n      action.response.status = 503;\n    }\n\n    return result;\n  }\n}\n","src\u002Fhealth\u002Fhealth.controller.ts",[503,868,869,898,927,931,937,942,962,967,973,979,985,991,1009,1015,1021,1041,1059,1087,1092,1098,1104,1110,1124,1130,1174,1196,1202,1207,1212,1218,1223,1238,1250,1255,1299,1329,1334,1366,1389,1395,1400,1409,1414],{"__ignoreMap":533},[537,870,871,873,875,878,881,883,886,888,890,892,894,896],{"class":539,"line":540},[537,872,618],{"class":617},[537,874,646],{"class":628},[537,876,877],{"class":617}," type",[537,879,880],{"class":621}," AggregatedHealthResult",[537,882,823],{"class":628},[537,884,885],{"class":621}," HealthRegistry",[537,887,652],{"class":628},[537,889,655],{"class":617},[537,891,629],{"class":628},[537,893,505],{"class":546},[537,895,635],{"class":628},[537,897,638],{"class":628},[537,899,900,902,904,906,909,911,914,916,918,920,923,925],{"class":539,"line":641},[537,901,618],{"class":617},[537,903,877],{"class":617},[537,905,646],{"class":628},[537,907,908],{"class":621}," Controller",[537,910,823],{"class":628},[537,912,913],{"class":621}," Get",[537,915,652],{"class":628},[537,917,655],{"class":617},[537,919,629],{"class":628},[537,921,922],{"class":546},"@heximon\u002Fhttp",[537,924,635],{"class":628},[537,926,638],{"class":628},[537,928,929],{"class":539,"line":667},[537,930,671],{"emptyLinePlaceholder":670},[537,932,933],{"class":539,"line":674},[537,934,936],{"class":935},"sHwdD","\u002F**\n",[537,938,939],{"class":539,"line":791},[537,940,941],{"class":935}," * The app-owned HTTP surface for the health probes. `@heximon\u002Fhealth` mounts nothing itself — it only\n",[537,943,944,947,950,954,957,959],{"class":539,"line":805},[537,945,946],{"class":935}," * provides the injectable ",[537,948,949],{"class":617},"{@",[537,951,953],{"class":952},"s6hCs","link",[537,955,885],{"class":956},"sHdIc",[537,958,708],{"class":617},[537,960,961],{"class":935},". This controller injects the registry and exposes the\n",[537,963,964],{"class":539,"line":837},[537,965,966],{"class":935}," * two conventional endpoints, owning their paths, status codes, and response shapes:\n",[537,968,970],{"class":539,"line":969},8,[537,971,972],{"class":935}," *\n",[537,974,976],{"class":539,"line":975},9,[537,977,978],{"class":935}," * - `GET \u002Fhealth` — liveness: responds `200 { status: \"up\" }` immediately. No indicator is run and no\n",[537,980,982],{"class":539,"line":981},10,[537,983,984],{"class":935}," *   boot promise is awaited, so it is safe for a container liveness probe that fires before the app is\n",[537,986,988],{"class":539,"line":987},11,[537,989,990],{"class":935}," *   ready.\n",[537,992,994,997,999,1001,1004,1006],{"class":539,"line":993},12,[537,995,996],{"class":935}," * - `GET \u002Fready` — readiness: runs every registered indicator via ",[537,998,949],{"class":617},[537,1000,953],{"class":952},[537,1002,1003],{"class":956}," HealthRegistry.checkAll",[537,1005,708],{"class":617},[537,1007,1008],{"class":935},", then\n",[537,1010,1012],{"class":539,"line":1011},13,[537,1013,1014],{"class":935}," *   reports `200` when up or degraded and `503` when any indicator is down.\n",[537,1016,1018],{"class":539,"line":1017},14,[537,1019,1020],{"class":935}," *\u002F\n",[537,1022,1024,1026,1030,1033,1036,1038],{"class":539,"line":1023},15,[537,1025,677],{"class":617},[537,1027,1029],{"class":1028},"spNyl"," class",[537,1031,1032],{"class":543}," HealthController",[537,1034,1035],{"class":1028}," implements",[537,1037,908],{"class":543},[537,1039,1040],{"class":628}," {\n",[537,1042,1044,1047,1050,1053,1056],{"class":539,"line":1043},16,[537,1045,1046],{"class":935},"  \u002F** ",[537,1048,1049],{"class":617},"@",[537,1051,1052],{"class":952},"param",[537,1054,1055],{"class":956}," health",[537,1057,1058],{"class":935}," - The health registry, resolved by class identity (a core provider). *\u002F\n",[537,1060,1062,1065,1068,1070,1073,1076,1078,1080,1082,1084],{"class":539,"line":1061},17,[537,1063,1064],{"class":1028},"  public",[537,1066,1067],{"class":1028}," constructor",[537,1069,686],{"class":628},[537,1071,1072],{"class":1028},"private",[537,1074,1075],{"class":1028}," readonly",[537,1077,1055],{"class":956},[537,1079,696],{"class":628},[537,1081,885],{"class":543},[537,1083,711],{"class":628},[537,1085,1086],{"class":628}," {}\n",[537,1088,1090],{"class":539,"line":1089},18,[537,1091,671],{"emptyLinePlaceholder":670},[537,1093,1095],{"class":539,"line":1094},19,[537,1096,1097],{"class":935},"  \u002F**\n",[537,1099,1101],{"class":539,"line":1100},20,[537,1102,1103],{"class":935},"   * `GET \u002Fhealth` — liveness. Returns immediately without running any indicator.\n",[537,1105,1107],{"class":539,"line":1106},21,[537,1108,1109],{"class":935},"   *\n",[537,1111,1113,1116,1118,1121],{"class":539,"line":1112},22,[537,1114,1115],{"class":935},"   * ",[537,1117,1049],{"class":617},[537,1119,1120],{"class":952},"returns",[537,1122,1123],{"class":935}," A constant `{ status: \"up\" }` payload.\n",[537,1125,1127],{"class":539,"line":1126},23,[537,1128,1129],{"class":935},"   *\u002F\n",[537,1131,1133,1135,1138,1140,1143,1145,1147,1150,1152,1155,1157,1160,1162,1165,1167,1170,1172],{"class":539,"line":1132},24,[537,1134,1064],{"class":1028},[537,1136,1137],{"class":692}," live",[537,1139,686],{"class":628},[537,1141,1142],{"class":956},"_action",[537,1144,696],{"class":628},[537,1146,913],{"class":543},[537,1148,1149],{"class":628},"\u003C",[537,1151,635],{"class":628},[537,1153,1154],{"class":546},"\u002Fhealth",[537,1156,635],{"class":628},[537,1158,1159],{"class":628},">):",[537,1161,646],{"class":628},[537,1163,1164],{"class":692}," status",[537,1166,696],{"class":628},[537,1168,1169],{"class":543}," string",[537,1171,652],{"class":628},[537,1173,1040],{"class":628},[537,1175,1177,1180,1182,1184,1186,1188,1191,1193],{"class":539,"line":1176},25,[537,1178,1179],{"class":617},"    return",[537,1181,646],{"class":628},[537,1183,1164],{"class":692},[537,1185,696],{"class":628},[537,1187,629],{"class":628},[537,1189,1190],{"class":546},"up",[537,1192,635],{"class":628},[537,1194,1195],{"class":628}," };\n",[537,1197,1199],{"class":539,"line":1198},26,[537,1200,1201],{"class":628},"  }\n",[537,1203,1205],{"class":539,"line":1204},27,[537,1206,671],{"emptyLinePlaceholder":670},[537,1208,1210],{"class":539,"line":1209},28,[537,1211,1097],{"class":935},[537,1213,1215],{"class":539,"line":1214},29,[537,1216,1217],{"class":935},"   * `GET \u002Fready` — readiness. Aggregates every indicator and maps the overall status to an HTTP code.\n",[537,1219,1221],{"class":539,"line":1220},30,[537,1222,1109],{"class":935},[537,1224,1226,1228,1230,1232,1235],{"class":539,"line":1225},31,[537,1227,1115],{"class":935},[537,1229,1049],{"class":617},[537,1231,1052],{"class":952},[537,1233,1234],{"class":956}," action",[537,1236,1237],{"class":935}," - The request action (used to set a `503` status when the aggregate is down).\n",[537,1239,1241,1243,1245,1247],{"class":539,"line":1240},32,[537,1242,1115],{"class":935},[537,1244,1049],{"class":617},[537,1246,1120],{"class":952},[537,1248,1249],{"class":935}," The aggregated health result (overall status + per-indicator breakdown).\n",[537,1251,1253],{"class":539,"line":1252},33,[537,1254,1129],{"class":935},[537,1256,1258,1260,1263,1266,1268,1271,1273,1275,1277,1279,1282,1284,1286,1289,1291,1294,1297],{"class":539,"line":1257},34,[537,1259,1064],{"class":1028},[537,1261,1262],{"class":1028}," async",[537,1264,1265],{"class":692}," ready",[537,1267,686],{"class":628},[537,1269,1270],{"class":956},"action",[537,1272,696],{"class":628},[537,1274,913],{"class":543},[537,1276,1149],{"class":628},[537,1278,635],{"class":628},[537,1280,1281],{"class":546},"\u002Fready",[537,1283,635],{"class":628},[537,1285,1159],{"class":628},[537,1287,1288],{"class":543}," Promise",[537,1290,1149],{"class":628},[537,1292,1293],{"class":543},"AggregatedHealthResult",[537,1295,1296],{"class":628},">",[537,1298,1040],{"class":628},[537,1300,1302,1305,1308,1311,1314,1317,1320,1322,1325,1327],{"class":539,"line":1301},35,[537,1303,1304],{"class":1028},"    const",[537,1306,1307],{"class":621}," result",[537,1309,1310],{"class":628}," =",[537,1312,1313],{"class":617}," await",[537,1315,1316],{"class":628}," this.",[537,1318,1319],{"class":621},"health",[537,1321,859],{"class":628},[537,1323,1324],{"class":683},"checkAll",[537,1326,820],{"class":692},[537,1328,638],{"class":628},[537,1330,1332],{"class":539,"line":1331},36,[537,1333,671],{"emptyLinePlaceholder":670},[537,1335,1337,1340,1343,1346,1348,1351,1354,1356,1359,1361,1364],{"class":539,"line":1336},37,[537,1338,1339],{"class":617},"    if",[537,1341,1342],{"class":692}," (",[537,1344,1345],{"class":621},"result",[537,1347,859],{"class":628},[537,1349,1350],{"class":621},"status",[537,1352,1353],{"class":628}," ===",[537,1355,629],{"class":628},[537,1357,1358],{"class":546},"down",[537,1360,635],{"class":628},[537,1362,1363],{"class":692},") ",[537,1365,802],{"class":628},[537,1367,1369,1372,1374,1377,1379,1381,1383,1387],{"class":539,"line":1368},38,[537,1370,1371],{"class":621},"      action",[537,1373,859],{"class":628},[537,1375,1376],{"class":621},"response",[537,1378,859],{"class":628},[537,1380,1350],{"class":621},[537,1382,1310],{"class":628},[537,1384,1386],{"class":1385},"sbssI"," 503",[537,1388,638],{"class":628},[537,1390,1392],{"class":539,"line":1391},39,[537,1393,1394],{"class":628},"    }\n",[537,1396,1398],{"class":539,"line":1397},40,[537,1399,671],{"emptyLinePlaceholder":670},[537,1401,1403,1405,1407],{"class":539,"line":1402},41,[537,1404,1179],{"class":617},[537,1406,1307],{"class":621},[537,1408,638],{"class":628},[537,1410,1412],{"class":539,"line":1411},42,[537,1413,1201],{"class":628},[537,1415,1417],{"class":539,"line":1416},43,[537,1418,1419],{"class":628},"}\n",[499,1421,1422],{},"The app owns the paths, verbs, status codes, and response shape — rename the endpoints, put readiness\nbehind auth, or fold the probes into an existing controller, all with plain HTTP code.",[1424,1425,1427,1431,1432,1435],"callout",{"type":1426},"info",[1428,1429,1430],"strong",{},"Liveness never awaits the boot promise."," ",[503,1433,1434],{},"GET \u002Fhealth"," returns immediately even if the app is still\nbooting — that is intentional. A liveness probe that fires during a slow boot must not trigger a pod\nrestart; the readiness probe is the correct gate for \"is the app done booting and healthy enough to\nreceive traffic.\" These two probes intentionally answer different questions.",[519,1437,1439],{"id":1438},"write-a-health-indicator","Write a health indicator",[499,1441,1442,1443,1445,1446,1449,1450,1453,1454,1456,1457,1460,1461,1464],{},"Implement ",[503,1444,509],{}," — declare both ",[503,1447,1448],{},"id"," and ",[503,1451,1452],{},"check()",". The ",[503,1455,1448],{}," is the key your indicator's\nresult appears under in the aggregated ",[503,1458,1459],{},"checks"," map — define it as an explicit source string so it\nstays meaningful in production (unlike a class name, it is not rewritten by a minifier). (",[503,1462,1463],{},"extends HealthIndicator"," binds identically — use it when you want your own base-class hierarchy on top of an\nindicator.)",[1466,1467,1468,1485],"table",{},[1469,1470,1471],"thead",{},[1472,1473,1474,1479,1482],"tr",{},[1475,1476,1478],"th",{"align":1477},"left","Value",[1475,1480,1481],{"align":1477},"HTTP status from your controller",[1475,1483,1484],{"align":1477},"Meaning",[1486,1487,1488,1504,1518],"tbody",{},[1472,1489,1490,1496,1501],{},[1491,1492,1493],"td",{"align":1477},[503,1494,1495],{},"HealthStatus.Up",[1491,1497,1498],{"align":1477},[503,1499,1500],{},"200",[1491,1502,1503],{"align":1477},"The subsystem is healthy.",[1472,1505,1506,1511,1515],{},[1491,1507,1508],{"align":1477},[503,1509,1510],{},"HealthStatus.Degraded",[1491,1512,1513],{"align":1477},[503,1514,1500],{},[1491,1516,1517],{"align":1477},"Partial degradation — still serving.",[1472,1519,1520,1525,1530],{},[1491,1521,1522],{"align":1477},[503,1523,1524],{},"HealthStatus.Down",[1491,1526,1527],{"align":1477},[503,1528,1529],{},"503",[1491,1531,1532],{"align":1477},"The subsystem is unavailable.",[499,1534,1535,1538,1539,1541,1542,1545,1546,1548],{},[503,1536,1537],{},"Degraded"," still returns ",[503,1540,1500],{}," because a degraded system is operational and should receive traffic. ",[503,1543,1544],{},"Down","\nreturns ",[503,1547,1529],{}," so an orchestrator's readiness gate stops routing to it.",[499,1550,1551,1552,1555],{},"Here's an illustrative custom indicator — one that always reports ",[503,1553,1554],{},"Up",", useful as the shape to copy when\nwrapping a subsystem that has no shipped indicator:",[527,1557,1560],{"className":607,"code":1558,"filename":1559,"language":610,"meta":533,"style":533},"import { HealthStatus, type HealthIndicator, type HealthStatusValue } from \"@heximon\u002Fhealth\";\n\n\u002F** A minimal custom indicator that always reports `Up` — the shape to copy for your own subsystem. *\u002F\nexport class AlwaysUpIndicator implements HealthIndicator {\n  \u002F** The key this indicator's result appears under in the aggregated `checks` map. *\u002F\n  public readonly id: string = \"always-up\";\n\n  \u002F**\n   * Always returns `Up` — this indicator represents a subsystem that is always healthy in this example.\n   *\n   * @returns A resolved `Up` status.\n   *\u002F\n  public async check(): Promise\u003CHealthStatusValue> {\n    return HealthStatus.Up;\n  }\n}\n","src\u002Fhealth\u002Falways-up-indicator.ts",[503,1561,1562,1597,1601,1606,1621,1626,1650,1654,1658,1663,1667,1678,1682,1705,1717,1721],{"__ignoreMap":533},[537,1563,1564,1566,1568,1571,1573,1575,1578,1580,1582,1585,1587,1589,1591,1593,1595],{"class":539,"line":540},[537,1565,618],{"class":617},[537,1567,646],{"class":628},[537,1569,1570],{"class":621}," HealthStatus",[537,1572,823],{"class":628},[537,1574,877],{"class":617},[537,1576,1577],{"class":621}," HealthIndicator",[537,1579,823],{"class":628},[537,1581,877],{"class":617},[537,1583,1584],{"class":621}," HealthStatusValue",[537,1586,652],{"class":628},[537,1588,655],{"class":617},[537,1590,629],{"class":628},[537,1592,505],{"class":546},[537,1594,635],{"class":628},[537,1596,638],{"class":628},[537,1598,1599],{"class":539,"line":641},[537,1600,671],{"emptyLinePlaceholder":670},[537,1602,1603],{"class":539,"line":667},[537,1604,1605],{"class":935},"\u002F** A minimal custom indicator that always reports `Up` — the shape to copy for your own subsystem. *\u002F\n",[537,1607,1608,1610,1612,1615,1617,1619],{"class":539,"line":674},[537,1609,677],{"class":617},[537,1611,1029],{"class":1028},[537,1613,1614],{"class":543}," AlwaysUpIndicator",[537,1616,1035],{"class":1028},[537,1618,1577],{"class":543},[537,1620,1040],{"class":628},[537,1622,1623],{"class":539,"line":791},[537,1624,1625],{"class":935},"  \u002F** The key this indicator's result appears under in the aggregated `checks` map. *\u002F\n",[537,1627,1628,1630,1632,1635,1637,1639,1641,1643,1646,1648],{"class":539,"line":805},[537,1629,1064],{"class":1028},[537,1631,1075],{"class":1028},[537,1633,1634],{"class":692}," id",[537,1636,696],{"class":628},[537,1638,1169],{"class":543},[537,1640,1310],{"class":628},[537,1642,629],{"class":628},[537,1644,1645],{"class":546},"always-up",[537,1647,635],{"class":628},[537,1649,638],{"class":628},[537,1651,1652],{"class":539,"line":837},[537,1653,671],{"emptyLinePlaceholder":670},[537,1655,1656],{"class":539,"line":969},[537,1657,1097],{"class":935},[537,1659,1660],{"class":539,"line":975},[537,1661,1662],{"class":935},"   * Always returns `Up` — this indicator represents a subsystem that is always healthy in this example.\n",[537,1664,1665],{"class":539,"line":981},[537,1666,1109],{"class":935},[537,1668,1669,1671,1673,1675],{"class":539,"line":987},[537,1670,1115],{"class":935},[537,1672,1049],{"class":617},[537,1674,1120],{"class":952},[537,1676,1677],{"class":935}," A resolved `Up` status.\n",[537,1679,1680],{"class":539,"line":993},[537,1681,1129],{"class":935},[537,1683,1684,1686,1688,1691,1694,1696,1698,1701,1703],{"class":539,"line":1011},[537,1685,1064],{"class":1028},[537,1687,1262],{"class":1028},[537,1689,1690],{"class":692}," check",[537,1692,1693],{"class":628},"():",[537,1695,1288],{"class":543},[537,1697,1149],{"class":628},[537,1699,1700],{"class":543},"HealthStatusValue",[537,1702,1296],{"class":628},[537,1704,1040],{"class":628},[537,1706,1707,1709,1711,1713,1715],{"class":539,"line":1017},[537,1708,1179],{"class":617},[537,1710,1570],{"class":621},[537,1712,859],{"class":628},[537,1714,1554],{"class":621},[537,1716,638],{"class":628},[537,1718,1719],{"class":539,"line":1023},[537,1720,1201],{"class":628},[537,1722,1723],{"class":539,"line":1043},[537,1724,1419],{"class":628},[519,1726,1728],{"id":1727},"register-indicators-and-the-controller","Register indicators and the controller",[499,1730,1731,1732,1735,1736,1738,1739,1741],{},"List indicator classes under ",[503,1733,1734],{},"health: { indicators }"," and the controller under ",[503,1737,858],{}," in\nthe same module. The compiler discovers all listed indicators and wires them into ",[503,1740,513],{},". This\nis the flagship app's actual health module, listing the two shipped indicators directly — no local\nwrapper:",[527,1743,1746],{"className":607,"code":1744,"filename":1745,"language":610,"meta":533,"style":533},"import { Module } from \"@heximon\u002Fruntime\";\nimport { DatabaseHealthIndicator } from \"@heximon\u002Fhealth\u002Fdatabase\";\nimport { StorageHealthIndicator } from \"@heximon\u002Fhealth\u002Fstorage\";\nimport { Storage } from \"@heximon\u002Fkv\";\nimport { Database } from \"@heximon\u002Fpersistence\";\nimport { HealthController } from \".\u002Fhealth.controller\";\n\n\u002F**\n * The health-and-readiness module — the app-owned `\u002Fhealth` (liveness) + `\u002Fready` (readiness) HTTP surface plus\n * the two probes it aggregates. `@heximon\u002Fhealth` mounts no routes itself; it only provides the injectable\n * `HealthRegistry`. This module lists the {@link HealthController} (which injects that registry and owns the\n * endpoint paths\u002Fstatus codes) and the two shipped indicators under `health: { indicators }`:\n *\n * - {@link DatabaseHealthIndicator} — pings the pool via an empty transaction (injects the abstract `Database`).\n * - {@link StorageHealthIndicator} — round-trips a sentinel key (injects the abstract `Storage`).\n *\n * Both indicators inject abstract platform-seam ports the consuming app supplies, so this module surfaces\n * `Database` and `Storage` as required dependencies the host routes.\n *\u002F\nexport class HealthModule extends Module({\n  requires: [Database, Storage],\n  http: { controllers: [HealthController] },\n  health: { indicators: [DatabaseHealthIndicator, StorageHealthIndicator] },\n}) {}\n","packages\u002Fapp\u002Fsrc\u002Fhealth\u002Fhealth.module.ts",[503,1747,1748,1770,1792,1814,1836,1858,1879,1883,1887,1892,1897,1913,1918,1922,1938,1953,1957,1962,1967,1971,1989,2006,2026,2050],{"__ignoreMap":533},[537,1749,1750,1752,1754,1757,1759,1761,1763,1766,1768],{"class":539,"line":540},[537,1751,618],{"class":617},[537,1753,646],{"class":628},[537,1755,1756],{"class":621}," Module",[537,1758,652],{"class":628},[537,1760,655],{"class":617},[537,1762,629],{"class":628},[537,1764,1765],{"class":546},"@heximon\u002Fruntime",[537,1767,635],{"class":628},[537,1769,638],{"class":628},[537,1771,1772,1774,1776,1779,1781,1783,1785,1788,1790],{"class":539,"line":641},[537,1773,618],{"class":617},[537,1775,646],{"class":628},[537,1777,1778],{"class":621}," DatabaseHealthIndicator",[537,1780,652],{"class":628},[537,1782,655],{"class":617},[537,1784,629],{"class":628},[537,1786,1787],{"class":546},"@heximon\u002Fhealth\u002Fdatabase",[537,1789,635],{"class":628},[537,1791,638],{"class":628},[537,1793,1794,1796,1798,1801,1803,1805,1807,1810,1812],{"class":539,"line":667},[537,1795,618],{"class":617},[537,1797,646],{"class":628},[537,1799,1800],{"class":621}," StorageHealthIndicator",[537,1802,652],{"class":628},[537,1804,655],{"class":617},[537,1806,629],{"class":628},[537,1808,1809],{"class":546},"@heximon\u002Fhealth\u002Fstorage",[537,1811,635],{"class":628},[537,1813,638],{"class":628},[537,1815,1816,1818,1820,1823,1825,1827,1829,1832,1834],{"class":539,"line":674},[537,1817,618],{"class":617},[537,1819,646],{"class":628},[537,1821,1822],{"class":621}," Storage",[537,1824,652],{"class":628},[537,1826,655],{"class":617},[537,1828,629],{"class":628},[537,1830,1831],{"class":546},"@heximon\u002Fkv",[537,1833,635],{"class":628},[537,1835,638],{"class":628},[537,1837,1838,1840,1842,1845,1847,1849,1851,1854,1856],{"class":539,"line":791},[537,1839,618],{"class":617},[537,1841,646],{"class":628},[537,1843,1844],{"class":621}," Database",[537,1846,652],{"class":628},[537,1848,655],{"class":617},[537,1850,629],{"class":628},[537,1852,1853],{"class":546},"@heximon\u002Fpersistence",[537,1855,635],{"class":628},[537,1857,638],{"class":628},[537,1859,1860,1862,1864,1866,1868,1870,1872,1875,1877],{"class":539,"line":805},[537,1861,618],{"class":617},[537,1863,646],{"class":628},[537,1865,1032],{"class":621},[537,1867,652],{"class":628},[537,1869,655],{"class":617},[537,1871,629],{"class":628},[537,1873,1874],{"class":546},".\u002Fhealth.controller",[537,1876,635],{"class":628},[537,1878,638],{"class":628},[537,1880,1881],{"class":539,"line":837},[537,1882,671],{"emptyLinePlaceholder":670},[537,1884,1885],{"class":539,"line":969},[537,1886,936],{"class":935},[537,1888,1889],{"class":539,"line":975},[537,1890,1891],{"class":935}," * The health-and-readiness module — the app-owned `\u002Fhealth` (liveness) + `\u002Fready` (readiness) HTTP surface plus\n",[537,1893,1894],{"class":539,"line":981},[537,1895,1896],{"class":935}," * the two probes it aggregates. `@heximon\u002Fhealth` mounts no routes itself; it only provides the injectable\n",[537,1898,1899,1902,1904,1906,1908,1910],{"class":539,"line":987},[537,1900,1901],{"class":935}," * `HealthRegistry`. This module lists the ",[537,1903,949],{"class":617},[537,1905,953],{"class":952},[537,1907,1032],{"class":956},[537,1909,708],{"class":617},[537,1911,1912],{"class":935}," (which injects that registry and owns the\n",[537,1914,1915],{"class":539,"line":993},[537,1916,1917],{"class":935}," * endpoint paths\u002Fstatus codes) and the two shipped indicators under `health: { indicators }`:\n",[537,1919,1920],{"class":539,"line":1011},[537,1921,972],{"class":935},[537,1923,1924,1927,1929,1931,1933,1935],{"class":539,"line":1017},[537,1925,1926],{"class":935}," * - ",[537,1928,949],{"class":617},[537,1930,953],{"class":952},[537,1932,1778],{"class":956},[537,1934,708],{"class":617},[537,1936,1937],{"class":935}," — pings the pool via an empty transaction (injects the abstract `Database`).\n",[537,1939,1940,1942,1944,1946,1948,1950],{"class":539,"line":1023},[537,1941,1926],{"class":935},[537,1943,949],{"class":617},[537,1945,953],{"class":952},[537,1947,1800],{"class":956},[537,1949,708],{"class":617},[537,1951,1952],{"class":935}," — round-trips a sentinel key (injects the abstract `Storage`).\n",[537,1954,1955],{"class":539,"line":1043},[537,1956,972],{"class":935},[537,1958,1959],{"class":539,"line":1061},[537,1960,1961],{"class":935}," * Both indicators inject abstract platform-seam ports the consuming app supplies, so this module surfaces\n",[537,1963,1964],{"class":539,"line":1089},[537,1965,1966],{"class":935}," * `Database` and `Storage` as required dependencies the host routes.\n",[537,1968,1969],{"class":539,"line":1094},[537,1970,1020],{"class":935},[537,1972,1973,1975,1977,1980,1983,1985,1987],{"class":539,"line":1100},[537,1974,677],{"class":617},[537,1976,1029],{"class":1028},[537,1978,1979],{"class":543}," HealthModule",[537,1981,1982],{"class":1028}," extends",[537,1984,1756],{"class":683},[537,1986,686],{"class":621},[537,1988,802],{"class":628},[537,1990,1991,1994,1996,1999,2001,2004],{"class":539,"line":1106},[537,1992,1993],{"class":692},"  requires",[537,1995,696],{"class":628},[537,1997,1998],{"class":621}," [Database",[537,2000,823],{"class":628},[537,2002,2003],{"class":621}," Storage]",[537,2005,834],{"class":628},[537,2007,2008,2011,2013,2015,2018,2020,2023],{"class":539,"line":1112},[537,2009,2010],{"class":692},"  http",[537,2012,696],{"class":628},[537,2014,646],{"class":628},[537,2016,2017],{"class":692}," controllers",[537,2019,696],{"class":628},[537,2021,2022],{"class":621}," [HealthController] ",[537,2024,2025],{"class":628},"},\n",[537,2027,2028,2031,2033,2035,2038,2040,2043,2045,2048],{"class":539,"line":1126},[537,2029,2030],{"class":692},"  health",[537,2032,696],{"class":628},[537,2034,646],{"class":628},[537,2036,2037],{"class":692}," indicators",[537,2039,696],{"class":628},[537,2041,2042],{"class":621}," [DatabaseHealthIndicator",[537,2044,823],{"class":628},[537,2046,2047],{"class":621}," StorageHealthIndicator] ",[537,2049,2025],{"class":628},[537,2051,2052,2054,2056],{"class":539,"line":1132},[537,2053,708],{"class":628},[537,2055,1363],{"class":621},[537,2057,2058],{"class":628},"{}\n",[499,2060,2061,2062,2065,2066,2069,2070,859],{},"A module mixing in your own indicator (like ",[503,2063,2064],{},"AlwaysUpIndicator"," above) alongside a shipped one just adds\nit to the same ",[503,2067,2068],{},"indicators"," array — ",[503,2071,2072],{},"health: { indicators: [AlwaysUpIndicator, DatabaseHealthIndicator] }",[519,2074,2076,2077],{"id":2075},"using-the-built-in-databasehealthindicator","Using the built-in ",[503,2078,2079],{},"DatabaseHealthIndicator",[499,2081,2082,2083,2085,2086,2088,2089,2092,2093,2097,2098,2100,2101,2103,2104,2107],{},"The built-in ",[503,2084,2079],{}," exercises the active ",[503,2087,77],{}," by running an empty transaction — a\ndialect-agnostic pool ping. It ships with ",[503,2090,2091],{},"id = \"database\"",". Import it from the ",[1428,2094,2095],{},[503,2096,1787],{},"\nsubpath (not the package root): it injects ",[503,2099,1853],{},"'s ",[503,2102,77],{},", so persistence is an\n",[1428,2105,2106],{},"optional peer dependency"," that only an app using this probe pulls in.",[499,2109,2110,2111,2114,2115,2117,2118,2121],{},"List it ",[1428,2112,2113],{},"directly"," under\n",[503,2116,1734],{}," — no local wrapper. The compiler reads the shipped indicator's type declarations,\nrecovers its ",[503,2119,2120],{},"(Database, Context)"," constructor, and wires both from your DI graph.",[499,2123,2124,2125,2127,2128,2130,2131,2134,2135,2137,2138,2141,2142,2145,2146,2148],{},"Your ",[503,2126,77],{}," typically reaches the abstract ",[503,2129,77],{}," token only through its dialect base classes\n(",[503,2132,2133],{},"class Database extends DrizzleLibSQLDatabase"," → … → ",[503,2136,1853],{},"). That's fine: the compiler\nfollows the cross-package ",[503,2139,2140],{},"extends","\u002F",[503,2143,2144],{},"implements"," chain to bind your ",[503,2147,77],{}," as the indicator's\ndependency — even when the provider lives in a different module you import.",[2150,2151,2153],"h3",{"id":2152},"customizing-a-shipped-indicator","Customizing a shipped indicator",[499,2155,2156,2157,2160,2161,2163,2164,2167,2168,2170,2171,696],{},"Direct listing is the default. To add behavior ",[1428,2158,2159],{},"around"," a shipped probe — extra logging, a degraded\nthreshold, combining two checks — write a thin local class that implements ",[503,2162,509],{}," and delegates\nto a constructed instance. The local class owns its own ",[503,2165,2166],{},"implements HealthIndicator"," declaration (its own\nDI identity), defines its own ",[503,2169,1448],{},", and customizes ",[503,2172,1452],{},[527,2174,2177],{"className":607,"code":2175,"filename":2176,"language":610,"meta":533,"style":533},"import { Context } from \"@heximon\u002Fruntime\";\nimport type { HealthIndicator, HealthStatusValue } from \"@heximon\u002Fhealth\";\nimport { DatabaseHealthIndicator } from \"@heximon\u002Fhealth\u002Fdatabase\";\nimport { Database } from \"..\u002Fdatabase\u002Fdatabase\";\n\nexport class AppDatabaseHealthIndicator implements HealthIndicator {\n  public readonly id: string = \"database\";\n\n  \u002F** The shipped indicator this class delegates the actual database ping to. *\u002F\n  private readonly delegate: DatabaseHealthIndicator;\n\n  public constructor(database: Database, context: Context) {\n    this.delegate = new DatabaseHealthIndicator(database, context);\n  }\n\n  public async check(): Promise\u003CHealthStatusValue> {\n    \u002F\u002F Add your own logic around the shipped probe here.\n    return this.delegate.check();\n  }\n}\n","src\u002Fhealth\u002Fdatabase-indicator.ts",[503,2178,2179,2200,2226,2246,2267,2271,2286,2309,2313,2318,2334,2338,2365,2391,2395,2399,2419,2424,2441,2445],{"__ignoreMap":533},[537,2180,2181,2183,2185,2188,2190,2192,2194,2196,2198],{"class":539,"line":540},[537,2182,618],{"class":617},[537,2184,646],{"class":628},[537,2186,2187],{"class":621}," Context",[537,2189,652],{"class":628},[537,2191,655],{"class":617},[537,2193,629],{"class":628},[537,2195,1765],{"class":546},[537,2197,635],{"class":628},[537,2199,638],{"class":628},[537,2201,2202,2204,2206,2208,2210,2212,2214,2216,2218,2220,2222,2224],{"class":539,"line":641},[537,2203,618],{"class":617},[537,2205,877],{"class":617},[537,2207,646],{"class":628},[537,2209,1577],{"class":621},[537,2211,823],{"class":628},[537,2213,1584],{"class":621},[537,2215,652],{"class":628},[537,2217,655],{"class":617},[537,2219,629],{"class":628},[537,2221,505],{"class":546},[537,2223,635],{"class":628},[537,2225,638],{"class":628},[537,2227,2228,2230,2232,2234,2236,2238,2240,2242,2244],{"class":539,"line":667},[537,2229,618],{"class":617},[537,2231,646],{"class":628},[537,2233,1778],{"class":621},[537,2235,652],{"class":628},[537,2237,655],{"class":617},[537,2239,629],{"class":628},[537,2241,1787],{"class":546},[537,2243,635],{"class":628},[537,2245,638],{"class":628},[537,2247,2248,2250,2252,2254,2256,2258,2260,2263,2265],{"class":539,"line":674},[537,2249,618],{"class":617},[537,2251,646],{"class":628},[537,2253,1844],{"class":621},[537,2255,652],{"class":628},[537,2257,655],{"class":617},[537,2259,629],{"class":628},[537,2261,2262],{"class":546},"..\u002Fdatabase\u002Fdatabase",[537,2264,635],{"class":628},[537,2266,638],{"class":628},[537,2268,2269],{"class":539,"line":791},[537,2270,671],{"emptyLinePlaceholder":670},[537,2272,2273,2275,2277,2280,2282,2284],{"class":539,"line":805},[537,2274,677],{"class":617},[537,2276,1029],{"class":1028},[537,2278,2279],{"class":543}," AppDatabaseHealthIndicator",[537,2281,1035],{"class":1028},[537,2283,1577],{"class":543},[537,2285,1040],{"class":628},[537,2287,2288,2290,2292,2294,2296,2298,2300,2302,2305,2307],{"class":539,"line":837},[537,2289,1064],{"class":1028},[537,2291,1075],{"class":1028},[537,2293,1634],{"class":692},[537,2295,696],{"class":628},[537,2297,1169],{"class":543},[537,2299,1310],{"class":628},[537,2301,629],{"class":628},[537,2303,2304],{"class":546},"database",[537,2306,635],{"class":628},[537,2308,638],{"class":628},[537,2310,2311],{"class":539,"line":969},[537,2312,671],{"emptyLinePlaceholder":670},[537,2314,2315],{"class":539,"line":975},[537,2316,2317],{"class":935},"  \u002F** The shipped indicator this class delegates the actual database ping to. *\u002F\n",[537,2319,2320,2323,2325,2328,2330,2332],{"class":539,"line":981},[537,2321,2322],{"class":1028},"  private",[537,2324,1075],{"class":1028},[537,2326,2327],{"class":692}," delegate",[537,2329,696],{"class":628},[537,2331,1778],{"class":543},[537,2333,638],{"class":628},[537,2335,2336],{"class":539,"line":987},[537,2337,671],{"emptyLinePlaceholder":670},[537,2339,2340,2342,2344,2346,2348,2350,2352,2354,2357,2359,2361,2363],{"class":539,"line":993},[537,2341,1064],{"class":1028},[537,2343,1067],{"class":1028},[537,2345,686],{"class":628},[537,2347,2304],{"class":956},[537,2349,696],{"class":628},[537,2351,1844],{"class":543},[537,2353,823],{"class":628},[537,2355,2356],{"class":956}," context",[537,2358,696],{"class":628},[537,2360,2187],{"class":543},[537,2362,711],{"class":628},[537,2364,1040],{"class":628},[537,2366,2367,2370,2373,2375,2377,2379,2381,2383,2385,2387,2389],{"class":539,"line":1011},[537,2368,2369],{"class":628},"    this.",[537,2371,2372],{"class":621},"delegate",[537,2374,1310],{"class":628},[537,2376,826],{"class":628},[537,2378,1778],{"class":683},[537,2380,686],{"class":692},[537,2382,2304],{"class":621},[537,2384,823],{"class":628},[537,2386,2356],{"class":621},[537,2388,711],{"class":692},[537,2390,638],{"class":628},[537,2392,2393],{"class":539,"line":1017},[537,2394,1201],{"class":628},[537,2396,2397],{"class":539,"line":1023},[537,2398,671],{"emptyLinePlaceholder":670},[537,2400,2401,2403,2405,2407,2409,2411,2413,2415,2417],{"class":539,"line":1043},[537,2402,1064],{"class":1028},[537,2404,1262],{"class":1028},[537,2406,1690],{"class":692},[537,2408,1693],{"class":628},[537,2410,1288],{"class":543},[537,2412,1149],{"class":628},[537,2414,1700],{"class":543},[537,2416,1296],{"class":628},[537,2418,1040],{"class":628},[537,2420,2421],{"class":539,"line":1061},[537,2422,2423],{"class":935},"    \u002F\u002F Add your own logic around the shipped probe here.\n",[537,2425,2426,2428,2430,2432,2434,2437,2439],{"class":539,"line":1089},[537,2427,1179],{"class":617},[537,2429,1316],{"class":628},[537,2431,2372],{"class":621},[537,2433,859],{"class":628},[537,2435,2436],{"class":683},"check",[537,2438,820],{"class":692},[537,2440,638],{"class":628},[537,2442,2443],{"class":539,"line":1094},[537,2444,1201],{"class":628},[537,2446,2447],{"class":539,"line":1100},[537,2448,1419],{"class":628},[499,2450,2451,2452,2454],{},"List the local class instead of (or alongside) the shipped one. Because its constructor reads from app\nsource, its ",[503,2453,77],{}," dependency is resolved the same way — by class identity.",[519,2456,2458,2459,2461],{"id":2457},"inject-healthregistry-directly","Inject ",[503,2460,513],{}," directly",[499,2463,2464,2466,2467,2470],{},[503,2465,513],{}," is always emitted as a core provider — even with zero indicators — so it is injectable\nwithout guarding. Call ",[503,2468,2469],{},"checkAll()"," to run all indicators programmatically, useful for admin dashboards or\npre-flight checks:",[527,2472,2474],{"className":607,"code":2473,"language":610,"meta":533,"style":533},"export class StatusService {\n  public constructor(private readonly healthRegistry: HealthRegistry) {}\n\n  public async getStatus() {\n    const result = await this.healthRegistry.checkAll();\n    \u002F\u002F result.status   — \"up\" | \"degraded\" | \"down\"\n    \u002F\u002F result.checks   — { [indicatorId]: { status, message? } }\n    return result;\n  }\n}\n",[503,2475,2476,2487,2510,2514,2527,2550,2555,2560,2568,2572],{"__ignoreMap":533},[537,2477,2478,2480,2482,2485],{"class":539,"line":540},[537,2479,677],{"class":617},[537,2481,1029],{"class":1028},[537,2483,2484],{"class":543}," StatusService",[537,2486,1040],{"class":628},[537,2488,2489,2491,2493,2495,2497,2499,2502,2504,2506,2508],{"class":539,"line":641},[537,2490,1064],{"class":1028},[537,2492,1067],{"class":1028},[537,2494,686],{"class":628},[537,2496,1072],{"class":1028},[537,2498,1075],{"class":1028},[537,2500,2501],{"class":956}," healthRegistry",[537,2503,696],{"class":628},[537,2505,885],{"class":543},[537,2507,711],{"class":628},[537,2509,1086],{"class":628},[537,2511,2512],{"class":539,"line":667},[537,2513,671],{"emptyLinePlaceholder":670},[537,2515,2516,2518,2520,2523,2525],{"class":539,"line":674},[537,2517,1064],{"class":1028},[537,2519,1262],{"class":1028},[537,2521,2522],{"class":692}," getStatus",[537,2524,820],{"class":628},[537,2526,1040],{"class":628},[537,2528,2529,2531,2533,2535,2537,2539,2542,2544,2546,2548],{"class":539,"line":791},[537,2530,1304],{"class":1028},[537,2532,1307],{"class":621},[537,2534,1310],{"class":628},[537,2536,1313],{"class":617},[537,2538,1316],{"class":628},[537,2540,2541],{"class":621},"healthRegistry",[537,2543,859],{"class":628},[537,2545,1324],{"class":683},[537,2547,820],{"class":692},[537,2549,638],{"class":628},[537,2551,2552],{"class":539,"line":805},[537,2553,2554],{"class":935},"    \u002F\u002F result.status   — \"up\" | \"degraded\" | \"down\"\n",[537,2556,2557],{"class":539,"line":837},[537,2558,2559],{"class":935},"    \u002F\u002F result.checks   — { [indicatorId]: { status, message? } }\n",[537,2561,2562,2564,2566],{"class":539,"line":969},[537,2563,1179],{"class":617},[537,2565,1307],{"class":621},[537,2567,638],{"class":628},[537,2569,2570],{"class":539,"line":975},[537,2571,1201],{"class":628},[537,2573,2574],{"class":539,"line":981},[537,2575,1419],{"class":628},[499,2577,2578,2580,2581,2584,2585,2588,2589,2591],{},[503,2579,2469],{}," accepts an optional ",[503,2582,2583],{},"timeout"," argument (a ",[503,2586,2587],{},"TimeSpan","; default: 5 seconds). A hanging or throwing indicator\nis treated as ",[503,2590,1544],{}," after the timeout — a permanently-hung check should not block traffic routing\nindefinitely.",[519,2593,2595],{"id":2594},"probe-responses","Probe responses",[499,2597,2598,2599,2601,2602,2604,2605,2608,2609,2611,2612,2615],{},"A ",[503,2600,1281],{}," response — with an ",[503,2603,2064],{}," (id ",[503,2606,2607],{},"\"always-up\"",") and a ",[503,2610,2079],{},"\n(id ",[503,2613,2614],{},"\"database\"",") registered — looks like:",[527,2617,2622],{"className":2618,"code":2619,"filename":2620,"language":2621,"meta":533,"style":533},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl http:\u002F\u002Flocalhost:3000\u002Fhealth\n# { \"status\": \"up\" }\n\ncurl http:\u002F\u002Flocalhost:3000\u002Fready\n# {\n#   \"status\": \"up\",\n#   \"checks\": {\n#     \"always-up\": { \"status\": \"up\" },\n#     \"database\": { \"status\": \"up\" }\n#   }\n# }\n","terminal","sh",[503,2623,2624,2632,2637,2641,2648,2653,2658,2663,2668,2673,2678],{"__ignoreMap":533},[537,2625,2626,2629],{"class":539,"line":540},[537,2627,2628],{"class":543},"curl",[537,2630,2631],{"class":546}," http:\u002F\u002Flocalhost:3000\u002Fhealth\n",[537,2633,2634],{"class":539,"line":641},[537,2635,2636],{"class":935},"# { \"status\": \"up\" }\n",[537,2638,2639],{"class":539,"line":667},[537,2640,671],{"emptyLinePlaceholder":670},[537,2642,2643,2645],{"class":539,"line":674},[537,2644,2628],{"class":543},[537,2646,2647],{"class":546}," http:\u002F\u002Flocalhost:3000\u002Fready\n",[537,2649,2650],{"class":539,"line":791},[537,2651,2652],{"class":935},"# {\n",[537,2654,2655],{"class":539,"line":805},[537,2656,2657],{"class":935},"#   \"status\": \"up\",\n",[537,2659,2660],{"class":539,"line":837},[537,2661,2662],{"class":935},"#   \"checks\": {\n",[537,2664,2665],{"class":539,"line":969},[537,2666,2667],{"class":935},"#     \"always-up\": { \"status\": \"up\" },\n",[537,2669,2670],{"class":539,"line":975},[537,2671,2672],{"class":935},"#     \"database\": { \"status\": \"up\" }\n",[537,2674,2675],{"class":539,"line":981},[537,2676,2677],{"class":935},"#   }\n",[537,2679,2680],{"class":539,"line":987},[537,2681,2682],{"class":935},"# }\n",[499,2684,2685,2686,2688,2689,2691],{},"The ",[503,2687,1459],{}," keys are each indicator's ",[503,2690,1448],{}," — an explicit source string that, unlike the class name,\nsurvives minification and stays meaningful in a production probe response.",[519,2693,2695],{"id":2694},"zero-indicator-behavior","Zero-indicator behavior",[499,2697,2698,2699,2701,2702,2704,2705,2707],{},"When no indicators are registered, ",[503,2700,513],{}," is still provided (always reports ",[503,2703,1554],{}," with an empty\n",[503,2706,1459],{}," map). No HTTP routes are contributed — the health module you import provides only the registry;\nyour controller decides whether to mount probe endpoints at all.",[519,2709,2076,2711],{"id":2710},"using-the-built-in-storagehealthindicator",[503,2712,2713],{},"StorageHealthIndicator",[499,2715,2082,2716,2718,2719,2722,2723,2726,2727,859],{},[503,2717,2713],{}," probes any ",[503,2720,2721],{},"Storage"," backend with a lightweight write + read\nround-trip. It writes a sentinel key (TTL 60 s, so it expires automatically) and reads it back via\n",[503,2724,2725],{},"has()"," — a backend-agnostic connectivity check that exercises the real read\u002Fwrite path and catches\nmisconfigured credentials, closed connections, and network failures. It ships with ",[503,2728,2729],{},"id = \"storage\"",[499,2731,2732,2733,2737,2738,2100,2740,2742,2743,2745,2746,2748,2749,2751,2752,2754],{},"Import it from the ",[1428,2734,2735],{},[503,2736,1809],{}," subpath, not the package root: it injects\n",[503,2739,1831],{},[503,2741,2721],{},", so ",[503,2744,1831],{}," is an ",[1428,2747,2106],{}," that only an app\nusing this probe pulls in. List it ",[1428,2750,2113],{}," under ",[503,2753,1734],{}," — no local wrapper:",[527,2756,2759],{"className":607,"code":2757,"filename":2758,"language":610,"meta":533,"style":533},"import { Module } from \"@heximon\u002Fruntime\";\nimport { StorageHealthIndicator } from \"@heximon\u002Fhealth\u002Fstorage\";\nimport { KvModule } from \"..\u002Fkv\u002Fkv.module\";\n\nexport class HealthModule extends Module({\n  imports: [KvModule],\n  health: {\n    indicators: [StorageHealthIndicator],\n  },\n}) {}\n","src\u002Fhealth\u002Fhealth.module.ts",[503,2760,2761,2781,2801,2823,2827,2843,2855,2863,2875,2880],{"__ignoreMap":533},[537,2762,2763,2765,2767,2769,2771,2773,2775,2777,2779],{"class":539,"line":540},[537,2764,618],{"class":617},[537,2766,646],{"class":628},[537,2768,1756],{"class":621},[537,2770,652],{"class":628},[537,2772,655],{"class":617},[537,2774,629],{"class":628},[537,2776,1765],{"class":546},[537,2778,635],{"class":628},[537,2780,638],{"class":628},[537,2782,2783,2785,2787,2789,2791,2793,2795,2797,2799],{"class":539,"line":641},[537,2784,618],{"class":617},[537,2786,646],{"class":628},[537,2788,1800],{"class":621},[537,2790,652],{"class":628},[537,2792,655],{"class":617},[537,2794,629],{"class":628},[537,2796,1809],{"class":546},[537,2798,635],{"class":628},[537,2800,638],{"class":628},[537,2802,2803,2805,2807,2810,2812,2814,2816,2819,2821],{"class":539,"line":667},[537,2804,618],{"class":617},[537,2806,646],{"class":628},[537,2808,2809],{"class":621}," KvModule",[537,2811,652],{"class":628},[537,2813,655],{"class":617},[537,2815,629],{"class":628},[537,2817,2818],{"class":546},"..\u002Fkv\u002Fkv.module",[537,2820,635],{"class":628},[537,2822,638],{"class":628},[537,2824,2825],{"class":539,"line":674},[537,2826,671],{"emptyLinePlaceholder":670},[537,2828,2829,2831,2833,2835,2837,2839,2841],{"class":539,"line":791},[537,2830,677],{"class":617},[537,2832,1029],{"class":1028},[537,2834,1979],{"class":543},[537,2836,1982],{"class":1028},[537,2838,1756],{"class":683},[537,2840,686],{"class":621},[537,2842,802],{"class":628},[537,2844,2845,2848,2850,2853],{"class":539,"line":805},[537,2846,2847],{"class":692},"  imports",[537,2849,696],{"class":628},[537,2851,2852],{"class":621}," [KvModule]",[537,2854,834],{"class":628},[537,2856,2857,2859,2861],{"class":539,"line":837},[537,2858,2030],{"class":692},[537,2860,696],{"class":628},[537,2862,1040],{"class":628},[537,2864,2865,2868,2870,2873],{"class":539,"line":969},[537,2866,2867],{"class":692},"    indicators",[537,2869,696],{"class":628},[537,2871,2872],{"class":621}," [StorageHealthIndicator]",[537,2874,834],{"class":628},[537,2876,2877],{"class":539,"line":975},[537,2878,2879],{"class":628},"  },\n",[537,2881,2882,2884,2886],{"class":539,"line":981},[537,2883,708],{"class":628},[537,2885,1363],{"class":621},[537,2887,2058],{"class":628},[499,2889,2890,2891,2893,2894,2896,2897,2900,2901,2900,2904,2900,2907,2910,2911,2913],{},"The indicator's ",[503,2892,2721],{}," dependency is satisfied by any concrete ",[503,2895,2721],{}," subclass your module\nprovides — ",[503,2898,2899],{},"MemoryStorage",", ",[503,2902,2903],{},"RedisStorage",[503,2905,2906],{},"UpstashStorage",[503,2908,2909],{},"CloudflareKvStorage",", or a custom\nadapter. The probe is backend-agnostic: the same indicator works across all ",[503,2912,2721],{}," backends\nwithout any per-backend configuration.",[519,2915,2917],{"id":2916},"see-also","See also",[2919,2920,2921,2944,2953,2964],"ul",{},[2922,2923,2924,2933,2934,2936,2937,2939,2940,2943],"li",{},[2925,2926,2930],"a",{"href":2927,"rel":2928},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fflagship",[2929],"nofollow",[1428,2931,2932],{},"Flagship Health \u002F Readiness","\n— the built-in ",[503,2935,2079],{}," + ",[503,2938,2713],{},", an app-owned ",[503,2941,2942],{},"HealthController",",\nand an in-process test that verifies both the liveness and readiness probes.",[2922,2945,2946,2949,2950,2952],{},[2925,2947,2948],{"href":409},"Packages overview"," — where ",[503,2951,505],{}," sits in the stack.",[2922,2954,2955,2957,2958,2960,2961,2963],{},[2925,2956,77],{"href":88}," — the ",[503,2959,77],{}," token that ",[503,2962,2079],{}," exercises.",[2922,2965,2966,2957,2969,2960,2971,2963],{},[2925,2967,2968],{"href":166},"Key-value storage",[503,2970,2721],{},[503,2972,2713],{},[2974,2975,2976],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .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 .s6hCs, html code.shiki .s6hCs{--shiki-light:#9C3EDA;--shiki-light-font-style:italic;--shiki-default:#C792EA;--shiki-default-font-style:italic;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":533,"searchDepth":641,"depth":641,"links":2978},[2979,2980,2981,2982,2983,2987,2989,2990,2991,2993],{"id":521,"depth":641,"text":522},{"id":846,"depth":641,"text":847},{"id":1438,"depth":641,"text":1439},{"id":1727,"depth":641,"text":1728},{"id":2075,"depth":641,"text":2984,"children":2985},"Using the built-in DatabaseHealthIndicator",[2986],{"id":2152,"depth":667,"text":2153},{"id":2457,"depth":641,"text":2988},"Inject HealthRegistry directly",{"id":2594,"depth":641,"text":2595},{"id":2694,"depth":641,"text":2695},{"id":2710,"depth":641,"text":2992},"Using the built-in StorageHealthIndicator",{"id":2916,"depth":641,"text":2917},"Liveness and readiness probes with HealthIndicator, HealthRegistry, and an app-owned controller — DatabaseHealthIndicator, per-indicator timeout, id-keyed results.","md",null,{},{"icon":178},{"title":175,"description":2994},"DAu1GSpDmFo8CZgEmauk1qZAwq1a2kodVzmpCNyAVdk",[3002,3004],{"title":170,"path":171,"stem":172,"description":3003,"icon":173,"children":-1},"The abstract BlobStore DI token for streamed bodies and byte ranges, the memory\u002Ffilesystem\u002FR2\u002FS3 drivers, and the SignedUrlBlobStore capability for direct-to-storage signed upload\u002Fdownload URLs.",{"title":180,"path":181,"stem":182,"description":3005,"icon":183,"children":-1},"Multi-channel notifications behind one Message \u002F MessageTransport contract — email (Resend, unemail), SMS (Twilio), push (OneSignal, FCM, Web Push), TemplateRenderer, SuppressionService, and the NotificationDispatcher.",1783300761903]