[{"data":1,"prerenderedAt":1281},["ShallowReactive",2],{"navigation_docs":3,"-docs-capabilities-scheduled-jobs":493,"-docs-capabilities-scheduled-jobs-surround":1276},[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":156,"body":495,"description":1269,"extension":1270,"links":1271,"meta":1272,"navigation":1273,"path":157,"seo":1274,"stem":158,"__hash__":1275},"docs\u002Fdocs\u002F03.capabilities\u002F04.scheduled-jobs.md",{"type":496,"value":497,"toc":1262},"minimark",[498,507,515,520,535,546,793,843,847,862,1055,1066,1076,1080,1091,1197,1201,1228,1232,1258],[499,500,501,502,506],"p",{},"Run work on a wall-clock schedule — a nightly cleanup, an hourly rollup, a per-tenant reconciliation — without\nstanding up an external cron service or hand-rolling ",[503,504,505],"code",{},"setInterval"," glue.",[499,508,509,510,514],{},"You declare a job as a class, list it in your module, and it fires on its cron: a process-local timer on Node,\nthe platform's cron trigger on Cloudflare. The cron expression is checked ",[511,512,513],"strong",{},"at build time",", so a typo fails\nthe compile rather than silently never running.",[516,517,519],"h2",{"id":518},"declare-a-scheduled-job","Declare a scheduled job",[499,521,522,523,526,527,530,531,534],{},"A job is ",[503,524,525],{},"class X implements ScheduledHandler\u003Ccron, options>",". The ",[511,528,529],{},"cron expression is the first type\nargument"," — a string literal the compiler reads as the dispatch key. Optional ",[503,532,533],{},"{ timezone?, name? }"," ride the\nsecond.",[499,536,537,538,541,542,545],{},"It declares ",[503,539,540],{},"handle(scheduledAt)",", and its constructor is its dependency declaration — injected like\nany other Heximon provider, no decorators. (",[503,543,544],{},"extends ScheduledHandler\u003C...>"," binds identically — use it when\nyou want your own base-class hierarchy on top of a job.)",[547,548,554],"pre",{"className":549,"code":550,"filename":551,"language":552,"meta":553,"style":553},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import type { ScheduledHandler } from \"@heximon\u002Fschedule\";\nimport { ReportsRepository } from \".\u002Freports.repository\";\n\nexport class NightlyReport implements ScheduledHandler\u003C\"0 3 * * *\", { timezone: \"UTC\"; name: \"nightly-report\" }> {\n  public constructor(private readonly reports: ReportsRepository) {}\n\n  public handle(scheduledAt: Date): void {\n    this.reports.record(scheduledAt);\n  }\n}\n","nightly-report.ts","ts","",[503,555,556,595,618,625,694,726,731,757,781,787],{"__ignoreMap":553},[557,558,561,565,568,572,576,579,582,585,589,592],"span",{"class":559,"line":560},"line",1,[557,562,564],{"class":563},"s7zQu","import",[557,566,567],{"class":563}," type",[557,569,571],{"class":570},"sMK4o"," {",[557,573,575],{"class":574},"sTEyZ"," ScheduledHandler",[557,577,578],{"class":570}," }",[557,580,581],{"class":563}," from",[557,583,584],{"class":570}," \"",[557,586,588],{"class":587},"sfazB","@heximon\u002Fschedule",[557,590,591],{"class":570},"\"",[557,593,594],{"class":570},";\n",[557,596,598,600,602,605,607,609,611,614,616],{"class":559,"line":597},2,[557,599,564],{"class":563},[557,601,571],{"class":570},[557,603,604],{"class":574}," ReportsRepository",[557,606,578],{"class":570},[557,608,581],{"class":563},[557,610,584],{"class":570},[557,612,613],{"class":587},".\u002Freports.repository",[557,615,591],{"class":570},[557,617,594],{"class":570},[557,619,621],{"class":559,"line":620},3,[557,622,624],{"emptyLinePlaceholder":623},true,"\n",[557,626,628,631,635,639,642,644,647,649,652,654,657,659,663,666,668,671,673,676,679,681,683,686,688,691],{"class":559,"line":627},4,[557,629,630],{"class":563},"export",[557,632,634],{"class":633},"spNyl"," class",[557,636,638],{"class":637},"sBMFI"," NightlyReport",[557,640,641],{"class":633}," implements",[557,643,575],{"class":637},[557,645,646],{"class":570},"\u003C",[557,648,591],{"class":570},[557,650,651],{"class":587},"0 3 * * *",[557,653,591],{"class":570},[557,655,656],{"class":570},",",[557,658,571],{"class":570},[557,660,662],{"class":661},"swJcz"," timezone",[557,664,665],{"class":570},":",[557,667,584],{"class":570},[557,669,670],{"class":587},"UTC",[557,672,591],{"class":570},[557,674,675],{"class":570},";",[557,677,678],{"class":661}," name",[557,680,665],{"class":570},[557,682,584],{"class":570},[557,684,685],{"class":587},"nightly-report",[557,687,591],{"class":570},[557,689,690],{"class":570}," }>",[557,692,693],{"class":570}," {\n",[557,695,697,700,703,706,709,712,716,718,720,723],{"class":559,"line":696},5,[557,698,699],{"class":633},"  public",[557,701,702],{"class":633}," constructor",[557,704,705],{"class":570},"(",[557,707,708],{"class":633},"private",[557,710,711],{"class":633}," readonly",[557,713,715],{"class":714},"sHdIc"," reports",[557,717,665],{"class":570},[557,719,604],{"class":637},[557,721,722],{"class":570},")",[557,724,725],{"class":570}," {}\n",[557,727,729],{"class":559,"line":728},6,[557,730,624],{"emptyLinePlaceholder":623},[557,732,734,736,739,741,744,746,749,752,755],{"class":559,"line":733},7,[557,735,699],{"class":633},[557,737,738],{"class":661}," handle",[557,740,705],{"class":570},[557,742,743],{"class":714},"scheduledAt",[557,745,665],{"class":570},[557,747,748],{"class":637}," Date",[557,750,751],{"class":570},"):",[557,753,754],{"class":637}," void",[557,756,693],{"class":570},[557,758,760,763,766,769,773,775,777,779],{"class":559,"line":759},8,[557,761,762],{"class":570},"    this.",[557,764,765],{"class":574},"reports",[557,767,768],{"class":570},".",[557,770,772],{"class":771},"s2Zo4","record",[557,774,705],{"class":661},[557,776,743],{"class":574},[557,778,722],{"class":661},[557,780,594],{"class":570},[557,782,784],{"class":559,"line":783},9,[557,785,786],{"class":570},"  }\n",[557,788,790],{"class":559,"line":789},10,[557,791,792],{"class":570},"}\n",[794,795,796,807,819,827],"ul",{},[797,798,799,802,803,806],"li",{},[511,800,801],{},"The cron must be a string literal"," — the compiler turns it into the dispatch key (and the cron-trigger\nconfig it emits for Cloudflare) at build time, so a value computed at runtime couldn't be wired statically. A\nmalformed expression is a build error (",[503,804,805],{},"schedule.invalid-cron","), caught by the same parser the runtime uses —\nso a build-green expression is guaranteed to run.",[797,808,809,814,815,818],{},[511,810,811],{},[503,812,813],{},"timezone"," (IANA, e.g. ",[503,816,817],{},"\"Europe\u002FBudapest\"",") is honored by the Node timer, DST-correct; it defaults to UTC.\nCloudflare evaluates all crons in UTC, so a non-UTC zone targeting a Cloudflare build raises a build warning.",[797,820,821,826],{},[511,822,823],{},[503,824,825],{},"name"," is a stable label for logs and traces; it defaults to the cron string.",[797,828,829,833,834,838,839,842],{},[511,830,831],{},[503,832,540],{}," always receives the ",[835,836,837],"em",{},"platform's"," scheduled time, never ",[503,840,841],{},"Date.now()"," — so a late or\nreplayed run computes against the intended wall-clock instant.",[516,844,846],{"id":845},"register-under-the-schedule-namespace","Register under the schedule namespace",[499,848,849,850,853,854,857,858,861],{},"List the handler under the module's ",[503,851,852],{},"schedule"," namespace, in its ",[503,855,856],{},"handlers"," list — never in ",[503,859,860],{},"providers",". That\nis how the compiler knows to route it to its cron rather than treat it as a plain injectable. Anything it\ndepends on stays an ordinary provider.",[547,863,866],{"className":549,"code":864,"filename":865,"language":552,"meta":553,"style":553},"import { Module } from \"@heximon\u002Fruntime\";\nimport { NightlyReport } from \".\u002Fnightly-report\";\nimport { ReportsController } from \".\u002Freports.controller\";\nimport { ReportsRepository } from \".\u002Freports.repository\";\n\nexport class ReportsModule extends Module({\n  providers: [ReportsRepository],\n  http: {\n    controllers: [ReportsController],\n  },\n  schedule: {\n    handlers: [NightlyReport],\n  },\n}) {}\n","reports.module.ts",[503,867,868,890,911,933,953,957,976,989,998,1010,1015,1025,1038,1043],{"__ignoreMap":553},[557,869,870,872,874,877,879,881,883,886,888],{"class":559,"line":560},[557,871,564],{"class":563},[557,873,571],{"class":570},[557,875,876],{"class":574}," Module",[557,878,578],{"class":570},[557,880,581],{"class":563},[557,882,584],{"class":570},[557,884,885],{"class":587},"@heximon\u002Fruntime",[557,887,591],{"class":570},[557,889,594],{"class":570},[557,891,892,894,896,898,900,902,904,907,909],{"class":559,"line":597},[557,893,564],{"class":563},[557,895,571],{"class":570},[557,897,638],{"class":574},[557,899,578],{"class":570},[557,901,581],{"class":563},[557,903,584],{"class":570},[557,905,906],{"class":587},".\u002Fnightly-report",[557,908,591],{"class":570},[557,910,594],{"class":570},[557,912,913,915,917,920,922,924,926,929,931],{"class":559,"line":620},[557,914,564],{"class":563},[557,916,571],{"class":570},[557,918,919],{"class":574}," ReportsController",[557,921,578],{"class":570},[557,923,581],{"class":563},[557,925,584],{"class":570},[557,927,928],{"class":587},".\u002Freports.controller",[557,930,591],{"class":570},[557,932,594],{"class":570},[557,934,935,937,939,941,943,945,947,949,951],{"class":559,"line":627},[557,936,564],{"class":563},[557,938,571],{"class":570},[557,940,604],{"class":574},[557,942,578],{"class":570},[557,944,581],{"class":563},[557,946,584],{"class":570},[557,948,613],{"class":587},[557,950,591],{"class":570},[557,952,594],{"class":570},[557,954,955],{"class":559,"line":696},[557,956,624],{"emptyLinePlaceholder":623},[557,958,959,961,963,966,969,971,973],{"class":559,"line":728},[557,960,630],{"class":563},[557,962,634],{"class":633},[557,964,965],{"class":637}," ReportsModule",[557,967,968],{"class":633}," extends",[557,970,876],{"class":771},[557,972,705],{"class":574},[557,974,975],{"class":570},"{\n",[557,977,978,981,983,986],{"class":559,"line":733},[557,979,980],{"class":661},"  providers",[557,982,665],{"class":570},[557,984,985],{"class":574}," [ReportsRepository]",[557,987,988],{"class":570},",\n",[557,990,991,994,996],{"class":559,"line":759},[557,992,993],{"class":661},"  http",[557,995,665],{"class":570},[557,997,693],{"class":570},[557,999,1000,1003,1005,1008],{"class":559,"line":783},[557,1001,1002],{"class":661},"    controllers",[557,1004,665],{"class":570},[557,1006,1007],{"class":574}," [ReportsController]",[557,1009,988],{"class":570},[557,1011,1012],{"class":559,"line":789},[557,1013,1014],{"class":570},"  },\n",[557,1016,1018,1021,1023],{"class":559,"line":1017},11,[557,1019,1020],{"class":661},"  schedule",[557,1022,665],{"class":570},[557,1024,693],{"class":570},[557,1026,1028,1031,1033,1036],{"class":559,"line":1027},12,[557,1029,1030],{"class":661},"    handlers",[557,1032,665],{"class":570},[557,1034,1035],{"class":574}," [NightlyReport]",[557,1037,988],{"class":570},[557,1039,1041],{"class":559,"line":1040},13,[557,1042,1014],{"class":570},[557,1044,1046,1049,1052],{"class":559,"line":1045},14,[557,1047,1048],{"class":570},"}",[557,1050,1051],{"class":574},") ",[557,1053,1054],{"class":570},"{}\n",[499,1056,1057,1058,1061,1062,1065],{},"That is the entire app surface. List a class under ",[503,1059,1060],{},"schedule: { handlers }"," that names no ",[503,1063,1064],{},"ScheduledHandler","\nin its heritage and nothing routes to it — it is constructed but never fires.",[499,1067,1068,1071,1072,1075],{},[511,1069,1070],{},"One job per cron expression."," Two handlers binding the same expression is a build error\n(",[503,1073,1074],{},"schedule.duplicate-cron","): which one runs would be order-dependent. An app that wants several jobs at the same\nminute gives each its own expression, or writes one handler that fans out to its collaborators.",[516,1077,1079],{"id":1078},"how-it-fires-per-host","How it fires per host",[499,1081,1082,1083,1086,1087,1090],{},"The job dispatches through the same ",[503,1084,1085],{},"Context.run"," substrate as every other Heximon tier — a fresh frame per\nfire (so an ORM handler opens a clean top-level transaction), with the platform ",[503,1088,1089],{},"waitUntil"," threaded through.\nThe driver owns dispatch, not the clock; where the clock lives differs per host:",[794,1092,1093,1114],{},[797,1094,1095,1097,1098,1101,1102,1105,1106,1109,1110,1113],{},[511,1096,302],{}," — ",[503,1099,1100],{},"NodeScheduleDriver"," (",[503,1103,1104],{},"@heximon\u002Fschedule\u002Fnode",") owns the clock: it starts one process-local timer\nper schedule at boot (self-starting — no host wiring) and stops them on shutdown. This is the tier that runs\nunder ",[503,1107,1108],{},"pnpm dev",", a Node server, or any long-lived process. Overlap is ",[511,1111,1112],{},"skip-if-running",": a fire that\narrives while the previous one is still running is skipped, so a slow nightly job never stacks.",[797,1115,1116,1119,1120,1123,1124,1127,1128,1131,1132,1135,1136,1139,1140,1143,1144,1147,1148,1150,1151,1154,1155,1158,1159,1162,1163,1165,1166,1169,1170,1172,1173,1101,1179,1181,1182,1184,1185,1188,1189,1192,1193,1196],{},[511,1117,1118],{},"Cloudflare Workers"," — the platform's cron trigger is the clock. Selecting this tier means deploying to\nCloudflare: set ",[503,1121,1122],{},"platform: new CloudflareWorkersStrategy()"," in ",[503,1125,1126],{},"heximon.config.ts"," (an edge-class strategy that\nalso declares the Cloudflare vendor). A Nitro ",[503,1129,1130],{},"cloudflare-*"," preset selects it for you.",[1133,1134],"br",{},"(The ",[503,1137,1138],{},"edge"," runtime class alone is not the vendor — a bare edge build, e.g. a non-Cloudflare ",[503,1141,1142],{},"*-edge"," preset,\nwith a scheduled handler but no recognized Cloudflare platform fails with a clear diagnostic instead of\nemitting the ",[503,1145,1146],{},"CloudflareScheduleDriver",".)",[1133,1149],{},"The cron list is emitted into ",[503,1152,1153],{},"wrangler.json","'s ",[503,1156,1157],{},"triggers.crons"," (so the platform\nschedules it), and the platform's ",[503,1160,1161],{},"scheduled"," invocation is dispatched to your handler.",[1133,1164],{},"Both deploy paths wire this for you with no app code: on the ",[511,1167,1168],{},"Nitro Cloudflare deploy path"," Nitro merges the\ncrons into its wrangler config and forwards the fired cron to the handler.",[1133,1171],{},"On the host-independent ",[511,1174,1175,1178],{},[503,1176,1177],{},"@heximon\u002Fbuild"," path",[503,1180,1122],{},") the Cloudflare\nWorker host bakes the ",[503,1183,1161],{}," handler straight into the emitted worker entry, so ",[503,1186,1187],{},"vp build"," produces a\nself-contained ",[503,1190,1191],{},"dist\u002Fworker.js"," exporting ",[503,1194,1195],{},"default { fetch, scheduled }"," — no hand-written Worker entry.",[516,1198,1200],{"id":1199},"semantics","Semantics",[794,1202,1203,1209,1222],{},[797,1204,1205,1208],{},[511,1206,1207],{},"At-least-once \u002F missed runs"," are delegated to the platform trigger, not reconstructed. Cloudflare\nguarantees at-least-once delivery and may fire late; the Node timer fires only while the process is alive (a\nprocess down across the scheduled minute misses that run — the Node tier is best-effort).",[797,1210,1211,1214,1215,1218,1219,1221],{},[511,1212,1213],{},"Idempotency."," Because a run can fire twice (a platform replay, a late fire), and scheduled dispatch flows\nthrough the same substrate as every other tier, write ",[503,1216,1217],{},"handle"," to be idempotent — key off ",[503,1220,743],{}," (the\nintended instant), which is stable across replays of the same tick.",[797,1223,1224,1227],{},[511,1225,1226],{},"Node multi-replica."," N Node replicas each run their own timer, so a cron fires N times across the fleet.\nUse an idempotency key, designate a single replica, or use the Cloudflare-cron tier. Distributed leader\nelection is out of scope.",[516,1229,1231],{"id":1230},"see-also","See also",[794,1233,1234,1243,1249],{},[797,1235,1236,1239,1240,1242],{},[1237,1238,151],"a",{"href":152}," — the sibling tier for moving work off the request path; scheduled\nwork and queue handlers share the same ",[503,1241,1085],{}," dispatch substrate.",[797,1244,1245,1248],{},[1237,1246,1247],{"href":347},"Deploy targets"," — where each host (Nitro, a Cloudflare Workers entry) boots\nthe schedule driver and wires the cron trigger.",[797,1250,1251,1257],{},[1237,1252,1256],{"href":1253,"rel":1254},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fedge-platforms\u002Fnetlify",[1255],"nofollow","Scheduled work on Netlify"," — a nightly\nreport job firing on its cron, observable over an HTTP route, with an e2e that drives the dispatch directly.",[1259,1260,1261],"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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":553,"searchDepth":597,"depth":597,"links":1263},[1264,1265,1266,1267,1268],{"id":518,"depth":597,"text":519},{"id":845,"depth":597,"text":846},{"id":1078,"depth":597,"text":1079},{"id":1199,"depth":597,"text":1200},{"id":1230,"depth":597,"text":1231},"Run work on a wall-clock cron schedule with ScheduledHandler — a process-local timer on Node, the platform cron trigger on Cloudflare, validated at build time.","md",null,{},{"icon":159},{"title":156,"description":1269},"kvxxDTJ_sYQI3JHb0Pwnd3XMppD2Osj1A6sHK_DkiPU",[1277,1279],{"title":151,"path":152,"stem":153,"description":1278,"icon":154,"children":-1},"Move slow work off the request path onto durable channels — the Queue producer port, QueueEventHandler consumers under queue { handlers }, per-handler retry and payload validation, MemoryQueue in dev, and a durable transport per platform.",{"title":161,"path":162,"stem":163,"description":1280,"icon":85,"children":-1},"Multi-tier caching — TieredCache over the Storage port, the Cache facade with single-flight and tag invalidation, QueryCacheInterceptor for CQRS query results, CacheMiddleware for HTTP responses, CacheEnvelope TTL, CdnPurgeAdapter.",1783300761903]