[{"data":1,"prerenderedAt":4340},["ShallowReactive",2],{"navigation_docs":3,"-docs-essentials-persistence":493,"-docs-essentials-persistence-surround":4335},[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":87,"body":495,"description":4328,"extension":4329,"links":4330,"meta":4331,"navigation":4332,"path":88,"seo":4333,"stem":89,"__hash__":4334},"docs\u002Fdocs\u002F02.essentials\u002F08.persistence.md",{"type":496,"value":497,"toc":4316},"minimark",[498,515,530,535,542,599,609,653,657,675,900,919,923,934,1114,1140,1147,1457,1464,1532,1536,1556,1729,1739,2016,2048,2052,2066,2318,2365,2372,2415,2425,2429,2450,2453,2637,2938,2950,2954,2976,3142,3161,3444,3453,3457,3491,3708,3734,3767,3796,3800,3810,4219,4253,4257,4312],[499,500,501,502,505,506,509,510,514],"p",{},"You want a persistence boundary you can swap dialects under: write your repositories against one\nabstract ",[503,504,77],"code",{},", and decide later whether it's backed by SQLite, Postgres, or MySQL.\n",[503,507,508],{},"@heximon\u002Fpersistence"," gives you abstract classes and structural interfaces with ",[511,512,513],"strong",{},"no SQL or ORM\ntypes in them",". A dialect package binds a concrete implementation; your code never sees the difference.",[499,516,517,518,521,522,525,526,529],{},"This page covers both halves: the ",[511,519,520],{},"contracts"," every dialect implements, and the ",[511,523,524],{},"wiring"," that plugs\na concrete dialect in. The Drizzle-specific schema and repository APIs live on the\n",[527,528,82],"a",{"href":83}," page.",[531,532,534],"h2",{"id":533},"install-the-contracts","Install the contracts",[499,536,537,538,541],{},"The contracts hold no driver types, so there's nothing extra to install — the driver itself (e.g.\n",[503,539,540],{},"@libsql\u002Fclient",") comes in with whichever dialect package implements these contracts.",[543,544,545,570,585],"code-group",{},[546,547,553],"pre",{"className":548,"code":549,"filename":550,"language":551,"meta":552,"style":552},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @heximon\u002Fpersistence\n","pnpm","bash","",[503,554,555],{"__ignoreMap":552},[556,557,560,563,567],"span",{"class":558,"line":559},"line",1,[556,561,550],{"class":562},"sBMFI",[556,564,566],{"class":565},"sfazB"," add",[556,568,569],{"class":565}," @heximon\u002Fpersistence\n",[546,571,574],{"className":548,"code":572,"filename":573,"language":551,"meta":552,"style":552},"npm install @heximon\u002Fpersistence\n","npm",[503,575,576],{"__ignoreMap":552},[556,577,578,580,583],{"class":558,"line":559},[556,579,573],{"class":562},[556,581,582],{"class":565}," install",[556,584,569],{"class":565},[546,586,589],{"className":548,"code":587,"filename":588,"language":551,"meta":552,"style":552},"yarn add @heximon\u002Fpersistence\n","yarn",[503,590,591],{"__ignoreMap":552},[556,592,593,595,597],{"class":558,"line":559},[556,594,588],{"class":562},[556,596,566],{"class":565},[556,598,569],{"class":565},[499,600,601,602,605,606,608],{},"The bare specifier and its ",[503,603,604],{},".\u002Fcore"," subpath export the same symbols; reach for ",[503,607,604],{}," only when you're\nauthoring a dialect, to match the import path dialect packages use.",[546,610,614],{"className":611,"code":612,"language":613,"meta":552,"style":552},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Database, MigrationRunner } from \"@heximon\u002Fpersistence\";\n","ts",[503,615,616],{"__ignoreMap":552},[556,617,618,622,626,630,633,636,639,642,645,647,650],{"class":558,"line":559},[556,619,621],{"class":620},"s7zQu","import",[556,623,625],{"class":624},"sMK4o"," {",[556,627,629],{"class":628},"sTEyZ"," Database",[556,631,632],{"class":624},",",[556,634,635],{"class":628}," MigrationRunner",[556,637,638],{"class":624}," }",[556,640,641],{"class":620}," from",[556,643,644],{"class":624}," \"",[556,646,508],{"class":565},[556,648,649],{"class":624},"\"",[556,651,652],{"class":624},";\n",[531,654,656],{"id":655},"bind-a-concrete-database","Bind a concrete database",[499,658,659,660,663,664,666,667,670,671,674],{},"A database in Heximon is an ",[511,661,662],{},"ordinary DI provider"," — no Drizzle compiler plugin, no runtime container.\nYou bind a dialect's ",[503,665,77],{}," class to the DI token with a ",[503,668,669],{},"useFactory",", and the compiler constructs it\ndirectly. A ",[503,672,673],{},"DatabaseModule"," owns that single instance and exports it so feature modules can inject it.",[546,676,679],{"className":611,"code":677,"filename":678,"language":613,"meta":552,"style":552},"import { type Context, Module } from \"@heximon\u002Fruntime\";\nimport { DrizzleLibSQLDatabase } from \"@heximon\u002Fdrizzle\u002Flibsql\";\nimport { databaseConfig } from \".\u002Fdatabase.config\";\n\nexport class DatabaseModule extends Module({\n  providers: [\n    {\n      provide: DrizzleLibSQLDatabase,\n      useFactory: (context: Context) => new DrizzleLibSQLDatabase(databaseConfig, context),\n    },\n  ],\n  exports: [DrizzleLibSQLDatabase],\n}) {}\n","src\u002Fdatabase\u002Fdatabase.module.ts",[503,680,681,711,734,757,764,789,802,808,821,861,867,875,888],{"__ignoreMap":552},[556,682,683,685,687,690,693,695,698,700,702,704,707,709],{"class":558,"line":559},[556,684,621],{"class":620},[556,686,625],{"class":624},[556,688,689],{"class":620}," type",[556,691,692],{"class":628}," Context",[556,694,632],{"class":624},[556,696,697],{"class":628}," Module",[556,699,638],{"class":624},[556,701,641],{"class":620},[556,703,644],{"class":624},[556,705,706],{"class":565},"@heximon\u002Fruntime",[556,708,649],{"class":624},[556,710,652],{"class":624},[556,712,714,716,718,721,723,725,727,730,732],{"class":558,"line":713},2,[556,715,621],{"class":620},[556,717,625],{"class":624},[556,719,720],{"class":628}," DrizzleLibSQLDatabase",[556,722,638],{"class":624},[556,724,641],{"class":620},[556,726,644],{"class":624},[556,728,729],{"class":565},"@heximon\u002Fdrizzle\u002Flibsql",[556,731,649],{"class":624},[556,733,652],{"class":624},[556,735,737,739,741,744,746,748,750,753,755],{"class":558,"line":736},3,[556,738,621],{"class":620},[556,740,625],{"class":624},[556,742,743],{"class":628}," databaseConfig",[556,745,638],{"class":624},[556,747,641],{"class":620},[556,749,644],{"class":624},[556,751,752],{"class":565},".\u002Fdatabase.config",[556,754,649],{"class":624},[556,756,652],{"class":624},[556,758,760],{"class":558,"line":759},4,[556,761,763],{"emptyLinePlaceholder":762},true,"\n",[556,765,767,770,774,777,780,783,786],{"class":558,"line":766},5,[556,768,769],{"class":620},"export",[556,771,773],{"class":772},"spNyl"," class",[556,775,776],{"class":562}," DatabaseModule",[556,778,779],{"class":772}," extends",[556,781,697],{"class":782},"s2Zo4",[556,784,785],{"class":628},"(",[556,787,788],{"class":624},"{\n",[556,790,792,796,799],{"class":558,"line":791},6,[556,793,795],{"class":794},"swJcz","  providers",[556,797,798],{"class":624},":",[556,800,801],{"class":628}," [\n",[556,803,805],{"class":558,"line":804},7,[556,806,807],{"class":624},"    {\n",[556,809,811,814,816,818],{"class":558,"line":810},8,[556,812,813],{"class":794},"      provide",[556,815,798],{"class":624},[556,817,720],{"class":628},[556,819,820],{"class":624},",\n",[556,822,824,827,829,832,836,838,840,843,846,849,851,854,856,859],{"class":558,"line":823},9,[556,825,826],{"class":782},"      useFactory",[556,828,798],{"class":624},[556,830,831],{"class":624}," (",[556,833,835],{"class":834},"sHdIc","context",[556,837,798],{"class":624},[556,839,692],{"class":562},[556,841,842],{"class":624},")",[556,844,845],{"class":772}," =>",[556,847,848],{"class":624}," new",[556,850,720],{"class":782},[556,852,853],{"class":628},"(databaseConfig",[556,855,632],{"class":624},[556,857,858],{"class":628}," context)",[556,860,820],{"class":624},[556,862,864],{"class":558,"line":863},10,[556,865,866],{"class":624},"    },\n",[556,868,870,873],{"class":558,"line":869},11,[556,871,872],{"class":628},"  ]",[556,874,820],{"class":624},[556,876,878,881,883,886],{"class":558,"line":877},12,[556,879,880],{"class":794},"  exports",[556,882,798],{"class":624},[556,884,885],{"class":628}," [DrizzleLibSQLDatabase]",[556,887,820],{"class":624},[556,889,891,894,897],{"class":558,"line":890},13,[556,892,893],{"class":624},"}",[556,895,896],{"class":628},") ",[556,898,899],{"class":624},"{}\n",[499,901,902,903,906,907,910,911,914,915,918],{},"The factory's ",[511,904,905],{},"parameter type is its dependency declaration"," — there's no ",[503,908,909],{},"inject"," array and no token\nlist. The compiler reads ",[503,912,913],{},"(context: Context)",", resolves the built-in ",[503,916,917],{},"Context"," by class identity, and\nthreads it in.",[531,920,922],{"id":921},"author-the-unified-config","Author the unified config",[499,924,925,926,929,930,933],{},"The config object is authored ",[511,927,928],{},"once"," and consumed by both the runtime factory and the stock\n",[503,931,932],{},"drizzle-kit"," CLI, so the migration tooling and the running app can never read different definitions.",[546,935,938],{"className":611,"code":936,"filename":937,"language":613,"meta":552,"style":552},"import { DrizzleLibSQLConfig } from \"@heximon\u002Fdrizzle\u002Flibsql\u002Fconfig\";\nimport { relations, schema } from \".\u002Fschema\";\n\nexport const databaseConfig = new DrizzleLibSQLConfig(schema, relations, {\n  dialect: \"sqlite\",\n  schema: \".\u002Fsrc\u002Fdatabase\u002Fschema.ts\",\n  out: \".\u002Fmigrations\",\n  url: \":memory:\",\n});\n\nexport default databaseConfig; \u002F\u002F `drizzle-kit --config` loads the default export\n","src\u002Fdatabase\u002Fdatabase.config.ts",[503,939,940,962,989,993,1022,1038,1054,1070,1086,1094,1098],{"__ignoreMap":552},[556,941,942,944,946,949,951,953,955,958,960],{"class":558,"line":559},[556,943,621],{"class":620},[556,945,625],{"class":624},[556,947,948],{"class":628}," DrizzleLibSQLConfig",[556,950,638],{"class":624},[556,952,641],{"class":620},[556,954,644],{"class":624},[556,956,957],{"class":565},"@heximon\u002Fdrizzle\u002Flibsql\u002Fconfig",[556,959,649],{"class":624},[556,961,652],{"class":624},[556,963,964,966,968,971,973,976,978,980,982,985,987],{"class":558,"line":713},[556,965,621],{"class":620},[556,967,625],{"class":624},[556,969,970],{"class":628}," relations",[556,972,632],{"class":624},[556,974,975],{"class":628}," schema",[556,977,638],{"class":624},[556,979,641],{"class":620},[556,981,644],{"class":624},[556,983,984],{"class":565},".\u002Fschema",[556,986,649],{"class":624},[556,988,652],{"class":624},[556,990,991],{"class":558,"line":736},[556,992,763],{"emptyLinePlaceholder":762},[556,994,995,997,1000,1003,1006,1008,1010,1013,1015,1017,1019],{"class":558,"line":759},[556,996,769],{"class":620},[556,998,999],{"class":772}," const",[556,1001,1002],{"class":628}," databaseConfig ",[556,1004,1005],{"class":624},"=",[556,1007,848],{"class":624},[556,1009,948],{"class":782},[556,1011,1012],{"class":628},"(schema",[556,1014,632],{"class":624},[556,1016,970],{"class":628},[556,1018,632],{"class":624},[556,1020,1021],{"class":624}," {\n",[556,1023,1024,1027,1029,1031,1034,1036],{"class":558,"line":766},[556,1025,1026],{"class":794},"  dialect",[556,1028,798],{"class":624},[556,1030,644],{"class":624},[556,1032,1033],{"class":565},"sqlite",[556,1035,649],{"class":624},[556,1037,820],{"class":624},[556,1039,1040,1043,1045,1047,1050,1052],{"class":558,"line":791},[556,1041,1042],{"class":794},"  schema",[556,1044,798],{"class":624},[556,1046,644],{"class":624},[556,1048,1049],{"class":565},".\u002Fsrc\u002Fdatabase\u002Fschema.ts",[556,1051,649],{"class":624},[556,1053,820],{"class":624},[556,1055,1056,1059,1061,1063,1066,1068],{"class":558,"line":804},[556,1057,1058],{"class":794},"  out",[556,1060,798],{"class":624},[556,1062,644],{"class":624},[556,1064,1065],{"class":565},".\u002Fmigrations",[556,1067,649],{"class":624},[556,1069,820],{"class":624},[556,1071,1072,1075,1077,1079,1082,1084],{"class":558,"line":810},[556,1073,1074],{"class":794},"  url",[556,1076,798],{"class":624},[556,1078,644],{"class":624},[556,1080,1081],{"class":565},":memory:",[556,1083,649],{"class":624},[556,1085,820],{"class":624},[556,1087,1088,1090,1092],{"class":558,"line":823},[556,1089,893],{"class":624},[556,1091,842],{"class":628},[556,1093,652],{"class":624},[556,1095,1096],{"class":558,"line":863},[556,1097,763],{"emptyLinePlaceholder":762},[556,1099,1100,1102,1105,1107,1110],{"class":558,"line":869},[556,1101,769],{"class":620},[556,1103,1104],{"class":620}," default",[556,1106,743],{"class":628},[556,1108,1109],{"class":624},";",[556,1111,1113],{"class":1112},"sHwdD"," \u002F\u002F `drizzle-kit --config` loads the default export\n",[499,1115,1116,1117,1120,1121,1124,1125,1128,1129,1132,1133,1136,1137,1139],{},"The ",[503,1118,1119],{},"dialect",", ",[503,1122,1123],{},"schema"," path, ",[503,1126,1127],{},"out",", and derived ",[503,1130,1131],{},"dbCredentials"," let ",[503,1134,1135],{},"drizzle-kit --config"," consume the\ninstance directly — no wrapper CLI — while its schema, relations, and connection fields are what a\n",[503,1138,77],{}," is built from at runtime.",[499,1141,1142,1143,1146],{},"For edge runtimes, where ",[503,1144,1145],{},"process.env"," isn't populated at import time, make the connection a getter so\ncredentials resolve the moment the config is read:",[546,1148,1150],{"className":611,"code":1149,"filename":937,"language":613,"meta":552,"style":552},"import { Platform } from \"@heximon\u002Fruntime\";\nimport { DrizzleMySQL2Config } from \"@heximon\u002Fdrizzle\u002Fmysql2\";\nimport { relations } from \".\u002Frelations\";\nimport * as schema from \".\u002Fschema\";\n\nexport default new DrizzleMySQL2Config(schema, relations, {\n  dialect: \"mysql\",\n  schema: \".\u002Fsrc\u002Fdatabase\u002Fschema.ts\",\n  out: \".\u002Fdatabase\u002Fmigrations\",\n  get connection() {\n    return {\n      database: Platform.get(\"DB_NAME\"),\n      host: Platform.get(\"DB_HOST\"),\n      user: Platform.get(\"DB_USER\"),\n      password: Platform.get(\"DB_PASSWORD\"),\n    };\n  },\n});\n",[503,1151,1152,1173,1195,1216,1240,1244,1264,1279,1293,1308,1321,1328,1356,1382,1409,1436,1442,1448],{"__ignoreMap":552},[556,1153,1154,1156,1158,1161,1163,1165,1167,1169,1171],{"class":558,"line":559},[556,1155,621],{"class":620},[556,1157,625],{"class":624},[556,1159,1160],{"class":628}," Platform",[556,1162,638],{"class":624},[556,1164,641],{"class":620},[556,1166,644],{"class":624},[556,1168,706],{"class":565},[556,1170,649],{"class":624},[556,1172,652],{"class":624},[556,1174,1175,1177,1179,1182,1184,1186,1188,1191,1193],{"class":558,"line":713},[556,1176,621],{"class":620},[556,1178,625],{"class":624},[556,1180,1181],{"class":628}," DrizzleMySQL2Config",[556,1183,638],{"class":624},[556,1185,641],{"class":620},[556,1187,644],{"class":624},[556,1189,1190],{"class":565},"@heximon\u002Fdrizzle\u002Fmysql2",[556,1192,649],{"class":624},[556,1194,652],{"class":624},[556,1196,1197,1199,1201,1203,1205,1207,1209,1212,1214],{"class":558,"line":736},[556,1198,621],{"class":620},[556,1200,625],{"class":624},[556,1202,970],{"class":628},[556,1204,638],{"class":624},[556,1206,641],{"class":620},[556,1208,644],{"class":624},[556,1210,1211],{"class":565},".\u002Frelations",[556,1213,649],{"class":624},[556,1215,652],{"class":624},[556,1217,1218,1220,1223,1226,1229,1232,1234,1236,1238],{"class":558,"line":759},[556,1219,621],{"class":620},[556,1221,1222],{"class":624}," *",[556,1224,1225],{"class":620}," as",[556,1227,1228],{"class":628}," schema ",[556,1230,1231],{"class":620},"from",[556,1233,644],{"class":624},[556,1235,984],{"class":565},[556,1237,649],{"class":624},[556,1239,652],{"class":624},[556,1241,1242],{"class":558,"line":766},[556,1243,763],{"emptyLinePlaceholder":762},[556,1245,1246,1248,1250,1252,1254,1256,1258,1260,1262],{"class":558,"line":791},[556,1247,769],{"class":620},[556,1249,1104],{"class":620},[556,1251,848],{"class":624},[556,1253,1181],{"class":782},[556,1255,1012],{"class":628},[556,1257,632],{"class":624},[556,1259,970],{"class":628},[556,1261,632],{"class":624},[556,1263,1021],{"class":624},[556,1265,1266,1268,1270,1272,1275,1277],{"class":558,"line":804},[556,1267,1026],{"class":794},[556,1269,798],{"class":624},[556,1271,644],{"class":624},[556,1273,1274],{"class":565},"mysql",[556,1276,649],{"class":624},[556,1278,820],{"class":624},[556,1280,1281,1283,1285,1287,1289,1291],{"class":558,"line":810},[556,1282,1042],{"class":794},[556,1284,798],{"class":624},[556,1286,644],{"class":624},[556,1288,1049],{"class":565},[556,1290,649],{"class":624},[556,1292,820],{"class":624},[556,1294,1295,1297,1299,1301,1304,1306],{"class":558,"line":823},[556,1296,1058],{"class":794},[556,1298,798],{"class":624},[556,1300,644],{"class":624},[556,1302,1303],{"class":565},".\u002Fdatabase\u002Fmigrations",[556,1305,649],{"class":624},[556,1307,820],{"class":624},[556,1309,1310,1313,1316,1319],{"class":558,"line":863},[556,1311,1312],{"class":772},"  get",[556,1314,1315],{"class":794}," connection",[556,1317,1318],{"class":624},"()",[556,1320,1021],{"class":624},[556,1322,1323,1326],{"class":558,"line":869},[556,1324,1325],{"class":620},"    return",[556,1327,1021],{"class":624},[556,1329,1330,1333,1335,1337,1340,1343,1345,1347,1350,1352,1354],{"class":558,"line":877},[556,1331,1332],{"class":794},"      database",[556,1334,798],{"class":624},[556,1336,1160],{"class":628},[556,1338,1339],{"class":624},".",[556,1341,1342],{"class":782},"get",[556,1344,785],{"class":794},[556,1346,649],{"class":624},[556,1348,1349],{"class":565},"DB_NAME",[556,1351,649],{"class":624},[556,1353,842],{"class":794},[556,1355,820],{"class":624},[556,1357,1358,1361,1363,1365,1367,1369,1371,1373,1376,1378,1380],{"class":558,"line":890},[556,1359,1360],{"class":794},"      host",[556,1362,798],{"class":624},[556,1364,1160],{"class":628},[556,1366,1339],{"class":624},[556,1368,1342],{"class":782},[556,1370,785],{"class":794},[556,1372,649],{"class":624},[556,1374,1375],{"class":565},"DB_HOST",[556,1377,649],{"class":624},[556,1379,842],{"class":794},[556,1381,820],{"class":624},[556,1383,1385,1388,1390,1392,1394,1396,1398,1400,1403,1405,1407],{"class":558,"line":1384},14,[556,1386,1387],{"class":794},"      user",[556,1389,798],{"class":624},[556,1391,1160],{"class":628},[556,1393,1339],{"class":624},[556,1395,1342],{"class":782},[556,1397,785],{"class":794},[556,1399,649],{"class":624},[556,1401,1402],{"class":565},"DB_USER",[556,1404,649],{"class":624},[556,1406,842],{"class":794},[556,1408,820],{"class":624},[556,1410,1412,1415,1417,1419,1421,1423,1425,1427,1430,1432,1434],{"class":558,"line":1411},15,[556,1413,1414],{"class":794},"      password",[556,1416,798],{"class":624},[556,1418,1160],{"class":628},[556,1420,1339],{"class":624},[556,1422,1342],{"class":782},[556,1424,785],{"class":794},[556,1426,649],{"class":624},[556,1428,1429],{"class":565},"DB_PASSWORD",[556,1431,649],{"class":624},[556,1433,842],{"class":794},[556,1435,820],{"class":624},[556,1437,1439],{"class":558,"line":1438},16,[556,1440,1441],{"class":624},"    };\n",[556,1443,1445],{"class":558,"line":1444},17,[556,1446,1447],{"class":624},"  },\n",[556,1449,1451,1453,1455],{"class":558,"line":1450},18,[556,1452,893],{"class":624},[556,1454,842],{"class":628},[556,1456,652],{"class":624},[499,1458,1459,1460,1463],{},"The three dialect config classes differ only in how the connection is expressed — flat for libsql, a\nnested ",[503,1461,1462],{},"connection"," (the driver's pool options) for mysql2 and pg:",[1465,1466,1467,1484],"table",{},[1468,1469,1470],"thead",{},[1471,1472,1473,1478,1481],"tr",{},[1474,1475,1477],"th",{"align":1476},"left","Dialect",[1474,1479,1480],{"align":1476},"Config class",[1474,1482,1483],{"align":1476},"Subpath",[1485,1486,1487,1502,1517],"tbody",{},[1471,1488,1489,1493,1498],{},[1490,1491,1492],"td",{"align":1476},"LibSQL \u002F Turso",[1490,1494,1495],{"align":1476},[503,1496,1497],{},"DrizzleLibSQLConfig",[1490,1499,1500],{"align":1476},[503,1501,957],{},[1471,1503,1504,1507,1512],{},[1490,1505,1506],{"align":1476},"MySQL2",[1490,1508,1509],{"align":1476},[503,1510,1511],{},"DrizzleMySQL2Config",[1490,1513,1514],{"align":1476},[503,1515,1516],{},"@heximon\u002Fdrizzle\u002Fmysql2\u002Fconfig",[1471,1518,1519,1522,1527],{},[1490,1520,1521],{"align":1476},"PostgreSQL",[1490,1523,1524],{"align":1476},[503,1525,1526],{},"DrizzlePgConfig",[1490,1528,1529],{"align":1476},[503,1530,1531],{},"@heximon\u002Fdrizzle\u002Fpg\u002Fconfig",[531,1533,1535],{"id":1534},"inject-the-one-shared-instance","Inject the one shared instance",[499,1537,1538,1539,1545,1546,1548,1549,1552,1553,1555],{},"There is exactly ",[511,1540,1541,1542,1544],{},"one ",[503,1543,77],{}," instance per app",", by design: transaction routing lives on the\n",[503,1547,77],{},", not on each repository, so every repository must share one connection pool and one\ntransaction slot the engine can nest savepoints in across a single request. Because every feature imports\nthe ",[511,1550,1551],{},"same"," ",[503,1554,673],{},", every repository injects that one singleton.",[546,1557,1560],{"className":611,"code":1558,"filename":1559,"language":613,"meta":552,"style":552},"import { Module } from \"@heximon\u002Fruntime\";\nimport { DatabaseModule } from \"..\u002Fdatabase\u002Fdatabase.module\";\nimport { UserController } from \".\u002Fuser.controller\";\nimport { UserRepository } from \".\u002Fuser.repository\";\n\nexport class UserModule extends Module({\n  imports: [DatabaseModule],\n  providers: [UserRepository],\n  http: { controllers: [UserController] },\n  exports: [UserRepository],\n}) {}\n","src\u002Fusers\u002Fuser.module.ts",[503,1561,1562,1582,1603,1625,1647,1651,1668,1680,1691,1711,1721],{"__ignoreMap":552},[556,1563,1564,1566,1568,1570,1572,1574,1576,1578,1580],{"class":558,"line":559},[556,1565,621],{"class":620},[556,1567,625],{"class":624},[556,1569,697],{"class":628},[556,1571,638],{"class":624},[556,1573,641],{"class":620},[556,1575,644],{"class":624},[556,1577,706],{"class":565},[556,1579,649],{"class":624},[556,1581,652],{"class":624},[556,1583,1584,1586,1588,1590,1592,1594,1596,1599,1601],{"class":558,"line":713},[556,1585,621],{"class":620},[556,1587,625],{"class":624},[556,1589,776],{"class":628},[556,1591,638],{"class":624},[556,1593,641],{"class":620},[556,1595,644],{"class":624},[556,1597,1598],{"class":565},"..\u002Fdatabase\u002Fdatabase.module",[556,1600,649],{"class":624},[556,1602,652],{"class":624},[556,1604,1605,1607,1609,1612,1614,1616,1618,1621,1623],{"class":558,"line":736},[556,1606,621],{"class":620},[556,1608,625],{"class":624},[556,1610,1611],{"class":628}," UserController",[556,1613,638],{"class":624},[556,1615,641],{"class":620},[556,1617,644],{"class":624},[556,1619,1620],{"class":565},".\u002Fuser.controller",[556,1622,649],{"class":624},[556,1624,652],{"class":624},[556,1626,1627,1629,1631,1634,1636,1638,1640,1643,1645],{"class":558,"line":759},[556,1628,621],{"class":620},[556,1630,625],{"class":624},[556,1632,1633],{"class":628}," UserRepository",[556,1635,638],{"class":624},[556,1637,641],{"class":620},[556,1639,644],{"class":624},[556,1641,1642],{"class":565},".\u002Fuser.repository",[556,1644,649],{"class":624},[556,1646,652],{"class":624},[556,1648,1649],{"class":558,"line":766},[556,1650,763],{"emptyLinePlaceholder":762},[556,1652,1653,1655,1657,1660,1662,1664,1666],{"class":558,"line":791},[556,1654,769],{"class":620},[556,1656,773],{"class":772},[556,1658,1659],{"class":562}," UserModule",[556,1661,779],{"class":772},[556,1663,697],{"class":782},[556,1665,785],{"class":628},[556,1667,788],{"class":624},[556,1669,1670,1673,1675,1678],{"class":558,"line":804},[556,1671,1672],{"class":794},"  imports",[556,1674,798],{"class":624},[556,1676,1677],{"class":628}," [DatabaseModule]",[556,1679,820],{"class":624},[556,1681,1682,1684,1686,1689],{"class":558,"line":810},[556,1683,795],{"class":794},[556,1685,798],{"class":624},[556,1687,1688],{"class":628}," [UserRepository]",[556,1690,820],{"class":624},[556,1692,1693,1696,1698,1700,1703,1705,1708],{"class":558,"line":823},[556,1694,1695],{"class":794},"  http",[556,1697,798],{"class":624},[556,1699,625],{"class":624},[556,1701,1702],{"class":794}," controllers",[556,1704,798],{"class":624},[556,1706,1707],{"class":628}," [UserController] ",[556,1709,1710],{"class":624},"},\n",[556,1712,1713,1715,1717,1719],{"class":558,"line":863},[556,1714,880],{"class":794},[556,1716,798],{"class":624},[556,1718,1688],{"class":628},[556,1720,820],{"class":624},[556,1722,1723,1725,1727],{"class":558,"line":869},[556,1724,893],{"class":624},[556,1726,896],{"class":628},[556,1728,899],{"class":624},[499,1730,1731,1732,1552,1735,1738],{},"A repository takes the database through its constructor and runs queries through the dialect's ORM. The\nparameter is annotated with the ",[503,1733,1734],{},"DrizzleLibSQLDatabase",[511,1736,1737],{},"class name"," — that name is the DI token, so the\nshared instance arrives by class identity:",[546,1740,1743],{"className":611,"code":1741,"filename":1742,"language":613,"meta":552,"style":552},"import { DrizzleLibSQLDatabase } from \"@heximon\u002Fdrizzle\u002Flibsql\";\nimport { eq } from \"drizzle-orm\";\nimport { tasks } from \"..\u002Fdatabase\u002Fschema\";\n\nexport class TasksRepository {\n  public constructor(private readonly database: DrizzleLibSQLDatabase) {}\n\n  public async findById(id: number): Promise\u003Ctypeof tasks.$inferSelect | undefined> {\n    const rows = await this.database.getOrm().select().from(tasks).where(eq(tasks.id, id)).limit(1);\n    return rows[0];\n  }\n}\n","src\u002Fusers\u002Fuser.repository.ts",[503,1744,1745,1765,1787,1809,1813,1824,1852,1856,1903,1989,2006,2011],{"__ignoreMap":552},[556,1746,1747,1749,1751,1753,1755,1757,1759,1761,1763],{"class":558,"line":559},[556,1748,621],{"class":620},[556,1750,625],{"class":624},[556,1752,720],{"class":628},[556,1754,638],{"class":624},[556,1756,641],{"class":620},[556,1758,644],{"class":624},[556,1760,729],{"class":565},[556,1762,649],{"class":624},[556,1764,652],{"class":624},[556,1766,1767,1769,1771,1774,1776,1778,1780,1783,1785],{"class":558,"line":713},[556,1768,621],{"class":620},[556,1770,625],{"class":624},[556,1772,1773],{"class":628}," eq",[556,1775,638],{"class":624},[556,1777,641],{"class":620},[556,1779,644],{"class":624},[556,1781,1782],{"class":565},"drizzle-orm",[556,1784,649],{"class":624},[556,1786,652],{"class":624},[556,1788,1789,1791,1793,1796,1798,1800,1802,1805,1807],{"class":558,"line":736},[556,1790,621],{"class":620},[556,1792,625],{"class":624},[556,1794,1795],{"class":628}," tasks",[556,1797,638],{"class":624},[556,1799,641],{"class":620},[556,1801,644],{"class":624},[556,1803,1804],{"class":565},"..\u002Fdatabase\u002Fschema",[556,1806,649],{"class":624},[556,1808,652],{"class":624},[556,1810,1811],{"class":558,"line":759},[556,1812,763],{"emptyLinePlaceholder":762},[556,1814,1815,1817,1819,1822],{"class":558,"line":766},[556,1816,769],{"class":620},[556,1818,773],{"class":772},[556,1820,1821],{"class":562}," TasksRepository",[556,1823,1021],{"class":624},[556,1825,1826,1829,1832,1834,1837,1840,1843,1845,1847,1849],{"class":558,"line":791},[556,1827,1828],{"class":772},"  public",[556,1830,1831],{"class":772}," constructor",[556,1833,785],{"class":624},[556,1835,1836],{"class":772},"private",[556,1838,1839],{"class":772}," readonly",[556,1841,1842],{"class":834}," database",[556,1844,798],{"class":624},[556,1846,720],{"class":562},[556,1848,842],{"class":624},[556,1850,1851],{"class":624}," {}\n",[556,1853,1854],{"class":558,"line":804},[556,1855,763],{"emptyLinePlaceholder":762},[556,1857,1858,1860,1863,1866,1868,1871,1873,1876,1879,1882,1885,1887,1889,1892,1895,1898,1901],{"class":558,"line":810},[556,1859,1828],{"class":772},[556,1861,1862],{"class":772}," async",[556,1864,1865],{"class":794}," findById",[556,1867,785],{"class":624},[556,1869,1870],{"class":834},"id",[556,1872,798],{"class":624},[556,1874,1875],{"class":562}," number",[556,1877,1878],{"class":624},"):",[556,1880,1881],{"class":562}," Promise",[556,1883,1884],{"class":624},"\u003Ctypeof",[556,1886,1795],{"class":628},[556,1888,1339],{"class":624},[556,1890,1891],{"class":628},"$inferSelect ",[556,1893,1894],{"class":624},"|",[556,1896,1897],{"class":562}," undefined",[556,1899,1900],{"class":624},">",[556,1902,1021],{"class":624},[556,1904,1905,1908,1911,1914,1917,1920,1923,1925,1928,1930,1932,1935,1937,1939,1941,1943,1946,1948,1950,1953,1955,1958,1960,1962,1964,1966,1968,1971,1974,1976,1979,1981,1985,1987],{"class":558,"line":823},[556,1906,1907],{"class":772},"    const",[556,1909,1910],{"class":628}," rows",[556,1912,1913],{"class":624}," =",[556,1915,1916],{"class":620}," await",[556,1918,1919],{"class":624}," this.",[556,1921,1922],{"class":628},"database",[556,1924,1339],{"class":624},[556,1926,1927],{"class":782},"getOrm",[556,1929,1318],{"class":794},[556,1931,1339],{"class":624},[556,1933,1934],{"class":782},"select",[556,1936,1318],{"class":794},[556,1938,1339],{"class":624},[556,1940,1231],{"class":782},[556,1942,785],{"class":794},[556,1944,1945],{"class":628},"tasks",[556,1947,842],{"class":794},[556,1949,1339],{"class":624},[556,1951,1952],{"class":782},"where",[556,1954,785],{"class":794},[556,1956,1957],{"class":782},"eq",[556,1959,785],{"class":794},[556,1961,1945],{"class":628},[556,1963,1339],{"class":624},[556,1965,1870],{"class":628},[556,1967,632],{"class":624},[556,1969,1970],{"class":628}," id",[556,1972,1973],{"class":794},"))",[556,1975,1339],{"class":624},[556,1977,1978],{"class":782},"limit",[556,1980,785],{"class":794},[556,1982,1984],{"class":1983},"sbssI","1",[556,1986,842],{"class":794},[556,1988,652],{"class":624},[556,1990,1991,1993,1995,1998,2001,2004],{"class":558,"line":863},[556,1992,1325],{"class":620},[556,1994,1910],{"class":628},[556,1996,1997],{"class":794},"[",[556,1999,2000],{"class":1983},"0",[556,2002,2003],{"class":794},"]",[556,2005,652],{"class":624},[556,2007,2008],{"class":558,"line":869},[556,2009,2010],{"class":624},"  }\n",[556,2012,2013],{"class":558,"line":877},[556,2014,2015],{"class":624},"}\n",[2017,2018,2020,2021,2024,2025,2028,2029,2032,2033,2036,2037,2040,2041,2047],"callout",{"type":2019},"tip","For a handle narrowed to your app's schema, give the database a ",[511,2022,2023],{},"named subclass"," and use it as the DI\ntoken: ",[503,2026,2027],{},"export class AppDatabase extends DrizzleLibSQLDatabase\u003Ctypeof schema, typeof relations> {}",".\nRepositories then inject ",[503,2030,2031],{},"AppDatabase"," (not the schema-erased base), so the entity repository's\n",[503,2034,2035],{},"TableNames\u003CAppDatabase>"," narrows to the real schema keys and ",[503,2038,2039],{},"super(database, \"Users\", User)"," is checked\nagainst them at compile time. See ",[527,2042,2046],{"href":2043,"rel":2044},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fladder\u002FL06-ddd",[2045],"nofollow","the ladder's L06 — DDD","\nfor the named-subclass token wired end-to-end.",[531,2049,2051],{"id":2050},"the-database-surface","The Database surface",[499,2053,2054,2057,2058,2061,2062,2065],{},[503,2055,2056],{},"Database\u003CTTransaction>"," is ",[511,2059,2060],{},"both"," the dialect-agnostic connection surface ",[511,2063,2064],{},"and"," the class-identity DI\ntoken a dialect binds its implementation to. Your repositories depend on the abstract base; a concrete\nsubclass is what's actually wired.",[546,2067,2069],{"className":611,"code":2068,"language":613,"meta":552,"style":552},"abstract class Database\u003CTTransaction extends TransactionHandle = TransactionHandle> {\n  abstract executeStatement(statement: DatabaseStatement): Promise\u003CAffectedRows>;\n  abstract isWriteStatement(statement: DatabaseStatement): boolean;\n  abstract runInTransaction\u003CResult>(\n    work: (transaction: TTransaction) => Promise\u003CResult>,\n  ): Promise\u003CResult>;\n  abstract onRollback(hook: () => void | Promise\u003Cvoid>): void;\n  abstract onCommit(hook: () => void | Promise\u003Cvoid>): void;\n  abstract onBeforeCommit(hook: () => void | Promise\u003Cvoid>): void;\n}\n",[503,2070,2071,2099,2129,2151,2166,2196,2209,2248,2281,2314],{"__ignoreMap":552},[556,2072,2073,2076,2078,2080,2083,2086,2088,2091,2093,2095,2097],{"class":558,"line":559},[556,2074,2075],{"class":772},"abstract",[556,2077,773],{"class":772},[556,2079,629],{"class":562},[556,2081,2082],{"class":624},"\u003C",[556,2084,2085],{"class":562},"TTransaction",[556,2087,779],{"class":772},[556,2089,2090],{"class":562}," TransactionHandle",[556,2092,1913],{"class":624},[556,2094,2090],{"class":562},[556,2096,1900],{"class":624},[556,2098,1021],{"class":624},[556,2100,2101,2104,2107,2109,2112,2114,2117,2119,2121,2123,2126],{"class":558,"line":713},[556,2102,2103],{"class":772},"  abstract",[556,2105,2106],{"class":794}," executeStatement",[556,2108,785],{"class":624},[556,2110,2111],{"class":834},"statement",[556,2113,798],{"class":624},[556,2115,2116],{"class":562}," DatabaseStatement",[556,2118,1878],{"class":624},[556,2120,1881],{"class":562},[556,2122,2082],{"class":624},[556,2124,2125],{"class":562},"AffectedRows",[556,2127,2128],{"class":624},">;\n",[556,2130,2131,2133,2136,2138,2140,2142,2144,2146,2149],{"class":558,"line":736},[556,2132,2103],{"class":772},[556,2134,2135],{"class":794}," isWriteStatement",[556,2137,785],{"class":624},[556,2139,2111],{"class":834},[556,2141,798],{"class":624},[556,2143,2116],{"class":562},[556,2145,1878],{"class":624},[556,2147,2148],{"class":562}," boolean",[556,2150,652],{"class":624},[556,2152,2153,2155,2158,2160,2163],{"class":558,"line":759},[556,2154,2103],{"class":772},[556,2156,2157],{"class":794}," runInTransaction",[556,2159,2082],{"class":624},[556,2161,2162],{"class":562},"Result",[556,2164,2165],{"class":624},">(\n",[556,2167,2168,2171,2173,2175,2178,2180,2183,2185,2187,2189,2191,2193],{"class":558,"line":766},[556,2169,2170],{"class":782},"    work",[556,2172,798],{"class":624},[556,2174,831],{"class":624},[556,2176,2177],{"class":834},"transaction",[556,2179,798],{"class":624},[556,2181,2182],{"class":562}," TTransaction",[556,2184,842],{"class":624},[556,2186,845],{"class":772},[556,2188,1881],{"class":562},[556,2190,2082],{"class":624},[556,2192,2162],{"class":562},[556,2194,2195],{"class":624},">,\n",[556,2197,2198,2201,2203,2205,2207],{"class":558,"line":791},[556,2199,2200],{"class":624},"  ):",[556,2202,1881],{"class":562},[556,2204,2082],{"class":624},[556,2206,2162],{"class":562},[556,2208,2128],{"class":624},[556,2210,2211,2213,2216,2218,2221,2223,2226,2228,2231,2234,2236,2238,2241,2244,2246],{"class":558,"line":804},[556,2212,2103],{"class":772},[556,2214,2215],{"class":794}," onRollback",[556,2217,785],{"class":624},[556,2219,2220],{"class":782},"hook",[556,2222,798],{"class":624},[556,2224,2225],{"class":624}," ()",[556,2227,845],{"class":772},[556,2229,2230],{"class":562}," void",[556,2232,2233],{"class":624}," |",[556,2235,1881],{"class":562},[556,2237,2082],{"class":624},[556,2239,2240],{"class":562},"void",[556,2242,2243],{"class":624},">):",[556,2245,2230],{"class":562},[556,2247,652],{"class":624},[556,2249,2250,2252,2255,2257,2259,2261,2263,2265,2267,2269,2271,2273,2275,2277,2279],{"class":558,"line":810},[556,2251,2103],{"class":772},[556,2253,2254],{"class":794}," onCommit",[556,2256,785],{"class":624},[556,2258,2220],{"class":782},[556,2260,798],{"class":624},[556,2262,2225],{"class":624},[556,2264,845],{"class":772},[556,2266,2230],{"class":562},[556,2268,2233],{"class":624},[556,2270,1881],{"class":562},[556,2272,2082],{"class":624},[556,2274,2240],{"class":562},[556,2276,2243],{"class":624},[556,2278,2230],{"class":562},[556,2280,652],{"class":624},[556,2282,2283,2285,2288,2290,2292,2294,2296,2298,2300,2302,2304,2306,2308,2310,2312],{"class":558,"line":823},[556,2284,2103],{"class":772},[556,2286,2287],{"class":794}," onBeforeCommit",[556,2289,785],{"class":624},[556,2291,2220],{"class":782},[556,2293,798],{"class":624},[556,2295,2225],{"class":624},[556,2297,845],{"class":772},[556,2299,2230],{"class":562},[556,2301,2233],{"class":624},[556,2303,1881],{"class":562},[556,2305,2082],{"class":624},[556,2307,2240],{"class":562},[556,2309,2243],{"class":624},[556,2311,2230],{"class":562},[556,2313,652],{"class":624},[556,2315,2316],{"class":558,"line":863},[556,2317,2015],{"class":624},[2319,2320,2321,2328,2334,2340,2346,2356],"ul",{},[2322,2323,2324,2327],"li",{},[503,2325,2326],{},"executeStatement"," routes a statement through the active transaction (or the bare connection) and reports\nrows affected.",[2322,2329,2330,2333],{},[503,2331,2332],{},"isWriteStatement"," classifies a statement as a write.",[2322,2335,2336,2339],{},[503,2337,2338],{},"runInTransaction"," opens (or nests) a transaction and commits-or-rolls-back.",[2322,2341,2342,2345],{},[503,2343,2344],{},"onRollback"," registers a callback that runs when the active transaction rolls back (in-memory savepoint\nrestore). A no-op when no transaction is active.",[2322,2347,2348,2351,2352,2355],{},[503,2349,2350],{},"onCommit"," registers a callback that runs ",[511,2353,2354],{},"after"," the outermost transaction durably commits (outbox\ndispatch, cache invalidation). Fires only at the outermost commit boundary — a nested savepoint hands\nits hooks up to the parent. A throwing hook is absorbed (the commit is already permanent). A no-op when\nno transaction is active.",[2322,2357,2358,2351,2361,2364],{},[503,2359,2360],{},"onBeforeCommit",[511,2362,2363],{},"inside"," the transaction just before the outermost\ncommit is issued (a last write\u002Fflush within the same atomic scope). A throw aborts the commit and rolls\nthe whole transaction back. A no-op when no transaction is active.",[499,2366,2367,2368,2371],{},"It carries ",[511,2369,2370],{},"no SQL or Drizzle types",", which keeps it swappable — a statement is opaque, so nothing from\none ORM leaks into the contract:",[546,2373,2375],{"className":611,"code":2374,"language":613,"meta":552,"style":552},"type DatabaseStatement = unknown; \u002F\u002F a Drizzle QueryPromise, a raw SQL string + bindings, …\ntype AffectedRows = number;       \u002F\u002F a conditional UPDATE … WHERE version = ? that affects\n                                  \u002F\u002F zero rows signals a stale-version conflict\n",[503,2376,2377,2394,2410],{"__ignoreMap":552},[556,2378,2379,2382,2384,2386,2389,2391],{"class":558,"line":559},[556,2380,2381],{"class":772},"type",[556,2383,2116],{"class":562},[556,2385,1913],{"class":624},[556,2387,2388],{"class":562}," unknown",[556,2390,1109],{"class":624},[556,2392,2393],{"class":1112}," \u002F\u002F a Drizzle QueryPromise, a raw SQL string + bindings, …\n",[556,2395,2396,2398,2401,2403,2405,2407],{"class":558,"line":713},[556,2397,2381],{"class":772},[556,2399,2400],{"class":562}," AffectedRows",[556,2402,1913],{"class":624},[556,2404,1875],{"class":562},[556,2406,1109],{"class":624},[556,2408,2409],{"class":1112},"       \u002F\u002F a conditional UPDATE … WHERE version = ? that affects\n",[556,2411,2412],{"class":558,"line":736},[556,2413,2414],{"class":1112},"                                  \u002F\u002F zero rows signals a stale-version conflict\n",[499,2416,2417,2418,2420,2421,2424],{},"The class is ",[503,2419,2075],{},", so a direct ",[503,2422,2423],{},"new Database(...)"," is a build error — only a concrete dialect subclass\nis ever bound to the token.",[531,2426,2428],{"id":2427},"runintransaction-transactions-and-savepoint-nesting","runInTransaction — transactions and savepoint nesting",[499,2430,2431,1552,2434,2437,2438,2441,2442,2445,2446,2449],{},[503,2432,2433],{},"Database.runInTransaction(work)",[511,2435,2436],{},"is"," the transaction abstraction — there is no separate unit-of-work\nobject. A dialect implements it directly: open a transaction — or a savepoint when one is already active for\nthe request — run ",[503,2439,2440],{},"work",", then ",[511,2443,2444],{},"commit on success"," or ",[511,2447,2448],{},"roll back on throw"," (re-raising the original\nerror).",[499,2451,2452],{},"Nesting is automatic and savepoint-style: an inner rollback unwinds only the inner savepoint and\nleaves the outer transaction intact.",[546,2454,2456],{"className":611,"code":2455,"language":613,"meta":552,"style":552},"abstract class Database\u003CTTransaction extends TransactionHandle = TransactionHandle> {\n  abstract runInTransaction\u003CResult>(\n    work: (transaction: TTransaction) => Promise\u003CResult>,\n  ): Promise\u003CResult>;\n  abstract onRollback(hook: () => void | Promise\u003Cvoid>): void;\n  abstract onCommit(hook: () => void | Promise\u003Cvoid>): void;\n  abstract onBeforeCommit(hook: () => void | Promise\u003Cvoid>): void;\n  \u002F\u002F … executeStatement \u002F isWriteStatement\n}\n",[503,2457,2458,2482,2494,2520,2532,2564,2596,2628,2633],{"__ignoreMap":552},[556,2459,2460,2462,2464,2466,2468,2470,2472,2474,2476,2478,2480],{"class":558,"line":559},[556,2461,2075],{"class":772},[556,2463,773],{"class":772},[556,2465,629],{"class":562},[556,2467,2082],{"class":624},[556,2469,2085],{"class":562},[556,2471,779],{"class":772},[556,2473,2090],{"class":562},[556,2475,1913],{"class":624},[556,2477,2090],{"class":562},[556,2479,1900],{"class":624},[556,2481,1021],{"class":624},[556,2483,2484,2486,2488,2490,2492],{"class":558,"line":713},[556,2485,2103],{"class":772},[556,2487,2157],{"class":794},[556,2489,2082],{"class":624},[556,2491,2162],{"class":562},[556,2493,2165],{"class":624},[556,2495,2496,2498,2500,2502,2504,2506,2508,2510,2512,2514,2516,2518],{"class":558,"line":736},[556,2497,2170],{"class":782},[556,2499,798],{"class":624},[556,2501,831],{"class":624},[556,2503,2177],{"class":834},[556,2505,798],{"class":624},[556,2507,2182],{"class":562},[556,2509,842],{"class":624},[556,2511,845],{"class":772},[556,2513,1881],{"class":562},[556,2515,2082],{"class":624},[556,2517,2162],{"class":562},[556,2519,2195],{"class":624},[556,2521,2522,2524,2526,2528,2530],{"class":558,"line":759},[556,2523,2200],{"class":624},[556,2525,1881],{"class":562},[556,2527,2082],{"class":624},[556,2529,2162],{"class":562},[556,2531,2128],{"class":624},[556,2533,2534,2536,2538,2540,2542,2544,2546,2548,2550,2552,2554,2556,2558,2560,2562],{"class":558,"line":766},[556,2535,2103],{"class":772},[556,2537,2215],{"class":794},[556,2539,785],{"class":624},[556,2541,2220],{"class":782},[556,2543,798],{"class":624},[556,2545,2225],{"class":624},[556,2547,845],{"class":772},[556,2549,2230],{"class":562},[556,2551,2233],{"class":624},[556,2553,1881],{"class":562},[556,2555,2082],{"class":624},[556,2557,2240],{"class":562},[556,2559,2243],{"class":624},[556,2561,2230],{"class":562},[556,2563,652],{"class":624},[556,2565,2566,2568,2570,2572,2574,2576,2578,2580,2582,2584,2586,2588,2590,2592,2594],{"class":558,"line":791},[556,2567,2103],{"class":772},[556,2569,2254],{"class":794},[556,2571,785],{"class":624},[556,2573,2220],{"class":782},[556,2575,798],{"class":624},[556,2577,2225],{"class":624},[556,2579,845],{"class":772},[556,2581,2230],{"class":562},[556,2583,2233],{"class":624},[556,2585,1881],{"class":562},[556,2587,2082],{"class":624},[556,2589,2240],{"class":562},[556,2591,2243],{"class":624},[556,2593,2230],{"class":562},[556,2595,652],{"class":624},[556,2597,2598,2600,2602,2604,2606,2608,2610,2612,2614,2616,2618,2620,2622,2624,2626],{"class":558,"line":804},[556,2599,2103],{"class":772},[556,2601,2287],{"class":794},[556,2603,785],{"class":624},[556,2605,2220],{"class":782},[556,2607,798],{"class":624},[556,2609,2225],{"class":624},[556,2611,845],{"class":772},[556,2613,2230],{"class":562},[556,2615,2233],{"class":624},[556,2617,1881],{"class":562},[556,2619,2082],{"class":624},[556,2621,2240],{"class":562},[556,2623,2243],{"class":624},[556,2625,2230],{"class":562},[556,2627,652],{"class":624},[556,2629,2630],{"class":558,"line":810},[556,2631,2632],{"class":1112},"  \u002F\u002F … executeStatement \u002F isWriteStatement\n",[556,2634,2635],{"class":558,"line":823},[556,2636,2015],{"class":624},[546,2638,2640],{"className":611,"code":2639,"language":613,"meta":552,"style":552},"await context.run(async () => {\n  await database.runInTransaction(async (outer) => {\n    await database.executeStatement({ write: true, sql: \"OUTER\" });\n\n    \u002F\u002F Inner scope throws → only the inner savepoint rolls back; the outer stays alive.\n    await expect(\n      database.runInTransaction(async () => {\n        await database.executeStatement({ write: true, sql: \"INNER\" });\n        throw new Error(\"inner failed\");\n      }),\n    ).rejects.toThrow(\"inner failed\");\n\n    await database.executeStatement({ write: true, sql: \"OUTER-AFTER\" });\n  });\n});\n\u002F\u002F committed writes === [\"OUTER\", \"OUTER-AFTER\"]  (INNER dropped)\n",[503,2641,2642,2666,2692,2737,2741,2746,2756,2774,2814,2837,2846,2873,2877,2916,2925,2933],{"__ignoreMap":552},[556,2643,2644,2647,2650,2652,2655,2657,2660,2662,2664],{"class":558,"line":559},[556,2645,2646],{"class":620},"await",[556,2648,2649],{"class":628}," context",[556,2651,1339],{"class":624},[556,2653,2654],{"class":782},"run",[556,2656,785],{"class":628},[556,2658,2659],{"class":772},"async",[556,2661,2225],{"class":624},[556,2663,845],{"class":772},[556,2665,1021],{"class":624},[556,2667,2668,2671,2673,2675,2677,2679,2681,2683,2686,2688,2690],{"class":558,"line":713},[556,2669,2670],{"class":620},"  await",[556,2672,1842],{"class":628},[556,2674,1339],{"class":624},[556,2676,2338],{"class":782},[556,2678,785],{"class":794},[556,2680,2659],{"class":772},[556,2682,831],{"class":624},[556,2684,2685],{"class":834},"outer",[556,2687,842],{"class":624},[556,2689,845],{"class":772},[556,2691,1021],{"class":624},[556,2693,2694,2697,2699,2701,2703,2705,2708,2711,2713,2717,2719,2722,2724,2726,2729,2731,2733,2735],{"class":558,"line":736},[556,2695,2696],{"class":620},"    await",[556,2698,1842],{"class":628},[556,2700,1339],{"class":624},[556,2702,2326],{"class":782},[556,2704,785],{"class":794},[556,2706,2707],{"class":624},"{",[556,2709,2710],{"class":794}," write",[556,2712,798],{"class":624},[556,2714,2716],{"class":2715},"sfNiH"," true",[556,2718,632],{"class":624},[556,2720,2721],{"class":794}," sql",[556,2723,798],{"class":624},[556,2725,644],{"class":624},[556,2727,2728],{"class":565},"OUTER",[556,2730,649],{"class":624},[556,2732,638],{"class":624},[556,2734,842],{"class":794},[556,2736,652],{"class":624},[556,2738,2739],{"class":558,"line":759},[556,2740,763],{"emptyLinePlaceholder":762},[556,2742,2743],{"class":558,"line":766},[556,2744,2745],{"class":1112},"    \u002F\u002F Inner scope throws → only the inner savepoint rolls back; the outer stays alive.\n",[556,2747,2748,2750,2753],{"class":558,"line":791},[556,2749,2696],{"class":620},[556,2751,2752],{"class":782}," expect",[556,2754,2755],{"class":794},"(\n",[556,2757,2758,2760,2762,2764,2766,2768,2770,2772],{"class":558,"line":804},[556,2759,1332],{"class":628},[556,2761,1339],{"class":624},[556,2763,2338],{"class":782},[556,2765,785],{"class":794},[556,2767,2659],{"class":772},[556,2769,2225],{"class":624},[556,2771,845],{"class":772},[556,2773,1021],{"class":624},[556,2775,2776,2779,2781,2783,2785,2787,2789,2791,2793,2795,2797,2799,2801,2803,2806,2808,2810,2812],{"class":558,"line":810},[556,2777,2778],{"class":620},"        await",[556,2780,1842],{"class":628},[556,2782,1339],{"class":624},[556,2784,2326],{"class":782},[556,2786,785],{"class":794},[556,2788,2707],{"class":624},[556,2790,2710],{"class":794},[556,2792,798],{"class":624},[556,2794,2716],{"class":2715},[556,2796,632],{"class":624},[556,2798,2721],{"class":794},[556,2800,798],{"class":624},[556,2802,644],{"class":624},[556,2804,2805],{"class":565},"INNER",[556,2807,649],{"class":624},[556,2809,638],{"class":624},[556,2811,842],{"class":794},[556,2813,652],{"class":624},[556,2815,2816,2819,2821,2824,2826,2828,2831,2833,2835],{"class":558,"line":823},[556,2817,2818],{"class":620},"        throw",[556,2820,848],{"class":624},[556,2822,2823],{"class":782}," Error",[556,2825,785],{"class":794},[556,2827,649],{"class":624},[556,2829,2830],{"class":565},"inner failed",[556,2832,649],{"class":624},[556,2834,842],{"class":794},[556,2836,652],{"class":624},[556,2838,2839,2842,2844],{"class":558,"line":863},[556,2840,2841],{"class":624},"      }",[556,2843,842],{"class":794},[556,2845,820],{"class":624},[556,2847,2848,2851,2853,2856,2858,2861,2863,2865,2867,2869,2871],{"class":558,"line":869},[556,2849,2850],{"class":794},"    )",[556,2852,1339],{"class":624},[556,2854,2855],{"class":628},"rejects",[556,2857,1339],{"class":624},[556,2859,2860],{"class":782},"toThrow",[556,2862,785],{"class":794},[556,2864,649],{"class":624},[556,2866,2830],{"class":565},[556,2868,649],{"class":624},[556,2870,842],{"class":794},[556,2872,652],{"class":624},[556,2874,2875],{"class":558,"line":877},[556,2876,763],{"emptyLinePlaceholder":762},[556,2878,2879,2881,2883,2885,2887,2889,2891,2893,2895,2897,2899,2901,2903,2905,2908,2910,2912,2914],{"class":558,"line":890},[556,2880,2696],{"class":620},[556,2882,1842],{"class":628},[556,2884,1339],{"class":624},[556,2886,2326],{"class":782},[556,2888,785],{"class":794},[556,2890,2707],{"class":624},[556,2892,2710],{"class":794},[556,2894,798],{"class":624},[556,2896,2716],{"class":2715},[556,2898,632],{"class":624},[556,2900,2721],{"class":794},[556,2902,798],{"class":624},[556,2904,644],{"class":624},[556,2906,2907],{"class":565},"OUTER-AFTER",[556,2909,649],{"class":624},[556,2911,638],{"class":624},[556,2913,842],{"class":794},[556,2915,652],{"class":624},[556,2917,2918,2921,2923],{"class":558,"line":1384},[556,2919,2920],{"class":624},"  }",[556,2922,842],{"class":794},[556,2924,652],{"class":624},[556,2926,2927,2929,2931],{"class":558,"line":1411},[556,2928,893],{"class":624},[556,2930,842],{"class":628},[556,2932,652],{"class":624},[556,2934,2935],{"class":558,"line":1438},[556,2936,2937],{"class":1112},"\u002F\u002F committed writes === [\"OUTER\", \"OUTER-AFTER\"]  (INNER dropped)\n",[499,2939,2940,2941,2943,2944,2946,2947,1339],{},"All transaction state lives in a request-scoped slot on the request ",[503,2942,917],{},", so concurrent requests stay\nisolated. A transaction therefore only nests inside an active request: the framework opens that ",[503,2945,917],{}," per\nrequest, and tests open it explicitly with ",[503,2948,2949],{},"Context.run(...)",[531,2951,2953],{"id":2952},"optimistic-concurrency","Optimistic concurrency",[499,2955,2956,2959,2960,2963,2964,2967,2968,2971,2972,2975],{},[503,2957,2958],{},"Versioned"," is a ",[511,2961,2962],{},"structural interface"," — not a class, so any persisted shape satisfies it — carrying a\nmonotonically increasing ",[503,2965,2966],{},"version",". A dialect persists it in an integer column, reads the in-memory version\non ",[503,2969,2970],{},"save",", issues a conditional ",[503,2973,2974],{},"UPDATE … WHERE version = \u003Cexpected>",", and treats \"zero rows updated\" as a\nconflict. No row locks held across the request, just a version check at write time.",[546,2977,2979],{"className":611,"code":2978,"language":613,"meta":552,"style":552},"interface Versioned {\n  readonly version: number;\n}\n\ninterface ConcurrencyConflictDetails {\n  readonly resource: string;\n  readonly expectedVersion: number;\n  readonly actualVersion?: number;\n}\n\nclass ConcurrencyConflictError extends ConcurrencyError {\n  static override readonly errorName: string; \u002F\u002F \"ConcurrencyConflictError\"\n  readonly details: ConcurrencyConflictDetails;\n  constructor(details: ConcurrencyConflictDetails);\n}\n",[503,2980,2981,2991,3005,3009,3013,3022,3036,3049,3063,3067,3071,3086,3108,3121,3138],{"__ignoreMap":552},[556,2982,2983,2986,2989],{"class":558,"line":559},[556,2984,2985],{"class":772},"interface",[556,2987,2988],{"class":562}," Versioned",[556,2990,1021],{"class":624},[556,2992,2993,2996,2999,3001,3003],{"class":558,"line":713},[556,2994,2995],{"class":772},"  readonly",[556,2997,2998],{"class":794}," version",[556,3000,798],{"class":624},[556,3002,1875],{"class":562},[556,3004,652],{"class":624},[556,3006,3007],{"class":558,"line":736},[556,3008,2015],{"class":624},[556,3010,3011],{"class":558,"line":759},[556,3012,763],{"emptyLinePlaceholder":762},[556,3014,3015,3017,3020],{"class":558,"line":766},[556,3016,2985],{"class":772},[556,3018,3019],{"class":562}," ConcurrencyConflictDetails",[556,3021,1021],{"class":624},[556,3023,3024,3026,3029,3031,3034],{"class":558,"line":791},[556,3025,2995],{"class":772},[556,3027,3028],{"class":794}," resource",[556,3030,798],{"class":624},[556,3032,3033],{"class":562}," string",[556,3035,652],{"class":624},[556,3037,3038,3040,3043,3045,3047],{"class":558,"line":804},[556,3039,2995],{"class":772},[556,3041,3042],{"class":794}," expectedVersion",[556,3044,798],{"class":624},[556,3046,1875],{"class":562},[556,3048,652],{"class":624},[556,3050,3051,3053,3056,3059,3061],{"class":558,"line":810},[556,3052,2995],{"class":772},[556,3054,3055],{"class":794}," actualVersion",[556,3057,3058],{"class":624},"?:",[556,3060,1875],{"class":562},[556,3062,652],{"class":624},[556,3064,3065],{"class":558,"line":823},[556,3066,2015],{"class":624},[556,3068,3069],{"class":558,"line":863},[556,3070,763],{"emptyLinePlaceholder":762},[556,3072,3073,3076,3079,3081,3084],{"class":558,"line":869},[556,3074,3075],{"class":772},"class",[556,3077,3078],{"class":562}," ConcurrencyConflictError",[556,3080,779],{"class":772},[556,3082,3083],{"class":562}," ConcurrencyError",[556,3085,1021],{"class":624},[556,3087,3088,3091,3094,3096,3099,3101,3103,3105],{"class":558,"line":877},[556,3089,3090],{"class":772},"  static",[556,3092,3093],{"class":772}," override",[556,3095,1839],{"class":772},[556,3097,3098],{"class":794}," errorName",[556,3100,798],{"class":624},[556,3102,3033],{"class":562},[556,3104,1109],{"class":624},[556,3106,3107],{"class":1112}," \u002F\u002F \"ConcurrencyConflictError\"\n",[556,3109,3110,3112,3115,3117,3119],{"class":558,"line":890},[556,3111,2995],{"class":772},[556,3113,3114],{"class":794}," details",[556,3116,798],{"class":624},[556,3118,3019],{"class":562},[556,3120,652],{"class":624},[556,3122,3123,3126,3128,3131,3133,3135],{"class":558,"line":1384},[556,3124,3125],{"class":772},"  constructor",[556,3127,785],{"class":624},[556,3129,3130],{"class":834},"details",[556,3132,798],{"class":624},[556,3134,3019],{"class":562},[556,3136,3137],{"class":624},");\n",[556,3139,3140],{"class":558,"line":1411},[556,3141,2015],{"class":624},[499,3143,3144,1552,3147,3153,3154,3157,3158,3160],{},[503,3145,3146],{},"ConcurrencyConflictError",[511,3148,3149,3150],{},"extends the core ",[503,3151,3152],{},"ConcurrencyError"," (from ",[503,3155,3156],{},"@heximon\u002Fruntime\u002Ferrors","), so\nexisting catch sites that key on ",[503,3159,3152],{}," — including the CQRS command retry — still match, while\nthe subclass carries the expected and actual versions for diagnostics. Catch the base to handle any\nconflict; catch the subclass when you want the version detail.",[546,3162,3164],{"className":611,"code":3163,"language":613,"meta":552,"style":552},"import { ConcurrencyError } from \"@heximon\u002Fruntime\u002Ferrors\";\nimport { ConcurrencyConflictError } from \"@heximon\u002Fpersistence\";\n\ndatabase.save({ id: \"athlete-1\", version: 1 }); \u002F\u002F stored version is now 2\n\ntry {\n  database.save({ id: \"athlete-1\", version: 1 }); \u002F\u002F writer still holds the stale version 1\n} catch (error) {\n  expect(error).toBeInstanceOf(ConcurrencyConflictError);\n  expect(error).toBeInstanceOf(ConcurrencyError); \u002F\u002F extends the core hierarchy\n  expect((error as ConcurrencyConflictError).details).toEqual({\n    resource: \"athlete-1\",\n    expectedVersion: 1,\n    actualVersion: 2,\n  });\n}\n",[503,3165,3166,3186,3206,3210,3251,3255,3262,3302,3314,3339,3364,3394,3409,3420,3432,3440],{"__ignoreMap":552},[556,3167,3168,3170,3172,3174,3176,3178,3180,3182,3184],{"class":558,"line":559},[556,3169,621],{"class":620},[556,3171,625],{"class":624},[556,3173,3083],{"class":628},[556,3175,638],{"class":624},[556,3177,641],{"class":620},[556,3179,644],{"class":624},[556,3181,3156],{"class":565},[556,3183,649],{"class":624},[556,3185,652],{"class":624},[556,3187,3188,3190,3192,3194,3196,3198,3200,3202,3204],{"class":558,"line":713},[556,3189,621],{"class":620},[556,3191,625],{"class":624},[556,3193,3078],{"class":628},[556,3195,638],{"class":624},[556,3197,641],{"class":620},[556,3199,644],{"class":624},[556,3201,508],{"class":565},[556,3203,649],{"class":624},[556,3205,652],{"class":624},[556,3207,3208],{"class":558,"line":736},[556,3209,763],{"emptyLinePlaceholder":762},[556,3211,3212,3214,3216,3218,3220,3222,3224,3226,3228,3231,3233,3235,3237,3239,3242,3244,3246,3248],{"class":558,"line":759},[556,3213,1922],{"class":628},[556,3215,1339],{"class":624},[556,3217,2970],{"class":782},[556,3219,785],{"class":628},[556,3221,2707],{"class":624},[556,3223,1970],{"class":794},[556,3225,798],{"class":624},[556,3227,644],{"class":624},[556,3229,3230],{"class":565},"athlete-1",[556,3232,649],{"class":624},[556,3234,632],{"class":624},[556,3236,2998],{"class":794},[556,3238,798],{"class":624},[556,3240,3241],{"class":1983}," 1",[556,3243,638],{"class":624},[556,3245,842],{"class":628},[556,3247,1109],{"class":624},[556,3249,3250],{"class":1112}," \u002F\u002F stored version is now 2\n",[556,3252,3253],{"class":558,"line":766},[556,3254,763],{"emptyLinePlaceholder":762},[556,3256,3257,3260],{"class":558,"line":791},[556,3258,3259],{"class":620},"try",[556,3261,1021],{"class":624},[556,3263,3264,3267,3269,3271,3273,3275,3277,3279,3281,3283,3285,3287,3289,3291,3293,3295,3297,3299],{"class":558,"line":804},[556,3265,3266],{"class":628},"  database",[556,3268,1339],{"class":624},[556,3270,2970],{"class":782},[556,3272,785],{"class":794},[556,3274,2707],{"class":624},[556,3276,1970],{"class":794},[556,3278,798],{"class":624},[556,3280,644],{"class":624},[556,3282,3230],{"class":565},[556,3284,649],{"class":624},[556,3286,632],{"class":624},[556,3288,2998],{"class":794},[556,3290,798],{"class":624},[556,3292,3241],{"class":1983},[556,3294,638],{"class":624},[556,3296,842],{"class":794},[556,3298,1109],{"class":624},[556,3300,3301],{"class":1112}," \u002F\u002F writer still holds the stale version 1\n",[556,3303,3304,3306,3309,3312],{"class":558,"line":810},[556,3305,893],{"class":624},[556,3307,3308],{"class":620}," catch",[556,3310,3311],{"class":628}," (error) ",[556,3313,788],{"class":624},[556,3315,3316,3319,3321,3324,3326,3328,3331,3333,3335,3337],{"class":558,"line":823},[556,3317,3318],{"class":782},"  expect",[556,3320,785],{"class":794},[556,3322,3323],{"class":628},"error",[556,3325,842],{"class":794},[556,3327,1339],{"class":624},[556,3329,3330],{"class":782},"toBeInstanceOf",[556,3332,785],{"class":794},[556,3334,3146],{"class":628},[556,3336,842],{"class":794},[556,3338,652],{"class":624},[556,3340,3341,3343,3345,3347,3349,3351,3353,3355,3357,3359,3361],{"class":558,"line":863},[556,3342,3318],{"class":782},[556,3344,785],{"class":794},[556,3346,3323],{"class":628},[556,3348,842],{"class":794},[556,3350,1339],{"class":624},[556,3352,3330],{"class":782},[556,3354,785],{"class":794},[556,3356,3152],{"class":628},[556,3358,842],{"class":794},[556,3360,1109],{"class":624},[556,3362,3363],{"class":1112}," \u002F\u002F extends the core hierarchy\n",[556,3365,3366,3368,3371,3373,3375,3377,3379,3381,3383,3385,3387,3390,3392],{"class":558,"line":869},[556,3367,3318],{"class":782},[556,3369,3370],{"class":794},"((",[556,3372,3323],{"class":628},[556,3374,1225],{"class":620},[556,3376,3078],{"class":562},[556,3378,842],{"class":794},[556,3380,1339],{"class":624},[556,3382,3130],{"class":628},[556,3384,842],{"class":794},[556,3386,1339],{"class":624},[556,3388,3389],{"class":782},"toEqual",[556,3391,785],{"class":794},[556,3393,788],{"class":624},[556,3395,3396,3399,3401,3403,3405,3407],{"class":558,"line":877},[556,3397,3398],{"class":794},"    resource",[556,3400,798],{"class":624},[556,3402,644],{"class":624},[556,3404,3230],{"class":565},[556,3406,649],{"class":624},[556,3408,820],{"class":624},[556,3410,3411,3414,3416,3418],{"class":558,"line":890},[556,3412,3413],{"class":794},"    expectedVersion",[556,3415,798],{"class":624},[556,3417,3241],{"class":1983},[556,3419,820],{"class":624},[556,3421,3422,3425,3427,3430],{"class":558,"line":1384},[556,3423,3424],{"class":794},"    actualVersion",[556,3426,798],{"class":624},[556,3428,3429],{"class":1983}," 2",[556,3431,820],{"class":624},[556,3433,3434,3436,3438],{"class":558,"line":1411},[556,3435,2920],{"class":624},[556,3437,842],{"class":794},[556,3439,652],{"class":624},[556,3441,3442],{"class":558,"line":1438},[556,3443,2015],{"class":624},[499,3445,3446,3447,3449,3450,3452],{},"That shared hierarchy is what makes the ",[527,3448,233],{"href":234}," command retry work without any coupling:\nthe repository throws, and the command bus — which already retries on ",[503,3451,3152],{}," — re-runs the\ncommand with fresh state.",[531,3454,3456],{"id":3455},"migration-contracts","Migration contracts",[499,3458,3459,3460,3463,3464,3467,3468,3471,3472,3475,3476,3479,3480,3483,3484,3486,3487,3490],{},"The package defines the migration ",[3461,3462,520],"em",{},"; a dialect supplies the ",[3461,3465,3466],{},"runner",". ",[511,3469,3470],{},"File generation"," is the\nstock ",[503,3473,3474],{},"drizzle-kit generate"," CLI's job — these contracts only ",[511,3477,3478],{},"apply \u002F report"," an already-generated folder,\nwhich keeps schema authoring in one well-known tool. Migrations are forward-only: ",[503,3481,3482],{},"rollback()"," rejects because\n",[503,3485,3474],{}," writes no ",[503,3488,3489],{},"down"," SQL.",[546,3492,3494],{"className":611,"code":3493,"language":613,"meta":552,"style":552},"interface MigrationStatusEntry {\n  readonly id: string;\n  readonly applied: boolean;\n}\n\nabstract class MigrationConfig {\n  abstract readonly migrationsFolder: string;                  \u002F\u002F the one required field\n  readonly migrationsTable: string | undefined = undefined;    \u002F\u002F dialect default when omitted\n  readonly migrationsSchema: string | undefined = undefined;   \u002F\u002F dialect default when omitted\n}\n\nabstract class MigrationRunner {\n  abstract apply(): Promise\u003Creadonly string[]>;       \u002F\u002F pending migrations, in id order; idempotent\n  abstract rollback(): Promise\u003Cstring | undefined>;   \u002F\u002F forward-only — always rejects\n  abstract status(): Promise\u003Creadonly MigrationStatusEntry[]>;\n}\n",[503,3495,3496,3505,3517,3530,3534,3538,3549,3567,3590,3612,3616,3620,3630,3658,3683,3704],{"__ignoreMap":552},[556,3497,3498,3500,3503],{"class":558,"line":559},[556,3499,2985],{"class":772},[556,3501,3502],{"class":562}," MigrationStatusEntry",[556,3504,1021],{"class":624},[556,3506,3507,3509,3511,3513,3515],{"class":558,"line":713},[556,3508,2995],{"class":772},[556,3510,1970],{"class":794},[556,3512,798],{"class":624},[556,3514,3033],{"class":562},[556,3516,652],{"class":624},[556,3518,3519,3521,3524,3526,3528],{"class":558,"line":736},[556,3520,2995],{"class":772},[556,3522,3523],{"class":794}," applied",[556,3525,798],{"class":624},[556,3527,2148],{"class":562},[556,3529,652],{"class":624},[556,3531,3532],{"class":558,"line":759},[556,3533,2015],{"class":624},[556,3535,3536],{"class":558,"line":766},[556,3537,763],{"emptyLinePlaceholder":762},[556,3539,3540,3542,3544,3547],{"class":558,"line":791},[556,3541,2075],{"class":772},[556,3543,773],{"class":772},[556,3545,3546],{"class":562}," MigrationConfig",[556,3548,1021],{"class":624},[556,3550,3551,3553,3555,3558,3560,3562,3564],{"class":558,"line":804},[556,3552,2103],{"class":772},[556,3554,1839],{"class":772},[556,3556,3557],{"class":794}," migrationsFolder",[556,3559,798],{"class":624},[556,3561,3033],{"class":562},[556,3563,1109],{"class":624},[556,3565,3566],{"class":1112},"                  \u002F\u002F the one required field\n",[556,3568,3569,3571,3574,3576,3578,3580,3582,3584,3587],{"class":558,"line":810},[556,3570,2995],{"class":772},[556,3572,3573],{"class":794}," migrationsTable",[556,3575,798],{"class":624},[556,3577,3033],{"class":562},[556,3579,2233],{"class":624},[556,3581,1897],{"class":562},[556,3583,1913],{"class":624},[556,3585,3586],{"class":624}," undefined;",[556,3588,3589],{"class":1112},"    \u002F\u002F dialect default when omitted\n",[556,3591,3592,3594,3597,3599,3601,3603,3605,3607,3609],{"class":558,"line":823},[556,3593,2995],{"class":772},[556,3595,3596],{"class":794}," migrationsSchema",[556,3598,798],{"class":624},[556,3600,3033],{"class":562},[556,3602,2233],{"class":624},[556,3604,1897],{"class":562},[556,3606,1913],{"class":624},[556,3608,3586],{"class":624},[556,3610,3611],{"class":1112},"   \u002F\u002F dialect default when omitted\n",[556,3613,3614],{"class":558,"line":863},[556,3615,2015],{"class":624},[556,3617,3618],{"class":558,"line":869},[556,3619,763],{"emptyLinePlaceholder":762},[556,3621,3622,3624,3626,3628],{"class":558,"line":877},[556,3623,2075],{"class":772},[556,3625,773],{"class":772},[556,3627,635],{"class":562},[556,3629,1021],{"class":624},[556,3631,3632,3634,3637,3640,3642,3644,3647,3649,3652,3655],{"class":558,"line":890},[556,3633,2103],{"class":772},[556,3635,3636],{"class":794}," apply",[556,3638,3639],{"class":624},"():",[556,3641,1881],{"class":562},[556,3643,2082],{"class":624},[556,3645,3646],{"class":772},"readonly",[556,3648,3033],{"class":562},[556,3650,3651],{"class":628},"[]",[556,3653,3654],{"class":624},">;",[556,3656,3657],{"class":1112},"       \u002F\u002F pending migrations, in id order; idempotent\n",[556,3659,3660,3662,3665,3667,3669,3671,3674,3676,3678,3680],{"class":558,"line":1384},[556,3661,2103],{"class":772},[556,3663,3664],{"class":794}," rollback",[556,3666,3639],{"class":624},[556,3668,1881],{"class":562},[556,3670,2082],{"class":624},[556,3672,3673],{"class":562},"string",[556,3675,2233],{"class":624},[556,3677,1897],{"class":562},[556,3679,3654],{"class":624},[556,3681,3682],{"class":1112},"   \u002F\u002F forward-only — always rejects\n",[556,3684,3685,3687,3690,3692,3694,3696,3698,3700,3702],{"class":558,"line":1411},[556,3686,2103],{"class":772},[556,3688,3689],{"class":794}," status",[556,3691,3639],{"class":624},[556,3693,1881],{"class":562},[556,3695,2082],{"class":624},[556,3697,3646],{"class":772},[556,3699,3502],{"class":562},[556,3701,3651],{"class":628},[556,3703,2128],{"class":624},[556,3705,3706],{"class":558,"line":1438},[556,3707,2015],{"class":624},[499,3709,3710,3713,3714,3717,3718,3717,3721,3724,3725,3727,3728,3730,3731,1339],{},[503,3711,3712],{},"MigrationConfig"," is the config a runner reads to locate and record migrations (modeled on Drizzle's\n",[503,3715,3716],{},"migrationsFolder"," \u002F ",[503,3719,3720],{},"migrationsTable",[503,3722,3723],{},"migrationsSchema","). Only ",[503,3726,3716],{}," is abstract — a runner\nmust know ",[511,3729,1952],{}," the migrations live; the bookkeeping table\u002Fschema overrides default to ",[503,3732,3733],{},"undefined",[499,3735,3736,3737,1552,3740,3745,3746,3748,3749,3751,3752,3756,3757,3759,3760,3763,3764,3766],{},"You rarely write a standalone config: the Drizzle ",[503,3738,3739],{},"Drizzle\u003CDialect>Config",[511,3741,3742,3743],{},"implements ",[503,3744,3712],{},"\n(deriving ",[503,3747,3716],{}," from drizzle-kit's ",[503,3750,1127],{},"), so a single ",[527,3753,3755],{"href":3754},"#author-the-unified-config","unified config","\nbinds to both the ",[503,3758,77],{}," factory and the ",[503,3761,3762],{},"MigrationRunner",". See ",[527,3765,92],{"href":93}," for the\none-config wiring.",[499,3768,3769,3771,3772,3775,3776,1120,3779,3782,3783,3467,3786,3789,3790,3792,3793,3795],{},[503,3770,3762],{}," is the apply\u002Fstatus surface the app and tests drive; the concrete runner is the dialect's\njob. ",[503,3773,3774],{},"@heximon\u002Fdrizzle"," supplies ",[503,3777,3778],{},"DrizzleLibSQLMigrationRunner",[503,3780,3781],{},"DrizzleMySQL2MigrationRunner",", and\n",[503,3784,3785],{},"DrizzlePgMigrationRunner",[503,3787,3788],{},"apply()"," is idempotent — a second call applies nothing and returns ",[503,3791,3651],{},". See\n",[527,3794,92],{"href":93}," for the generate-then-apply workflow.",[531,3797,3799],{"id":3798},"how-a-dialect-implements-the-contract","How a dialect implements the contract",[499,3801,3802,3803,3805,3806,3809],{},"If you're plugging in a new dialect, a concrete ",[503,3804,77],{}," implements the connection surface and drives its\nown begin·commit·rollback mechanics through the ",[503,3807,3808],{},"TransactionContext"," fork — reading the active handle back to\ndecide whether to open a top-level transaction or nest a savepoint:",[546,3811,3813],{"className":611,"code":3812,"language":613,"meta":552,"style":552},"import {\n  type AffectedRows,\n  Database,\n  type DatabaseStatement,\n} from \"@heximon\u002Fpersistence\u002Fcore\";\n\nexport class InMemoryDatabase extends Database\u003CInMemoryTransaction> {\n  private readonly transactionContext: TransactionContext;\n  \u002F\u002F …\n\n  public override async runInTransaction\u003CResult>(\n    work: (transaction: InMemoryTransaction) => Promise\u003CResult>,\n  ): Promise\u003CResult> {\n    const parent = this.transactionContext.getActive\u003CInMemoryTransaction>();\n    const handle = parent === undefined ? await this.begin() : await this.beginSavepoint(parent);\n\n    return this.transactionContext.runInTransaction(handle, async () => {\n      try {\n        const result = await work(handle);\n\n        await this.commit(handle);\n\n        return result;\n      } catch (error) {\n        await this.rollback(handle);\n\n        throw error;\n      }\n    });\n  }\n}\n",[503,3814,3815,3821,3830,3837,3845,3860,3864,3886,3903,3908,3912,3928,3955,3969,3998,4045,4049,4076,4083,4107,4112,4130,4135,4145,4160,4178,4183,4193,4199,4209,4214],{"__ignoreMap":552},[556,3816,3817,3819],{"class":558,"line":559},[556,3818,621],{"class":620},[556,3820,1021],{"class":624},[556,3822,3823,3826,3828],{"class":558,"line":713},[556,3824,3825],{"class":620},"  type",[556,3827,2400],{"class":628},[556,3829,820],{"class":624},[556,3831,3832,3835],{"class":558,"line":736},[556,3833,3834],{"class":628},"  Database",[556,3836,820],{"class":624},[556,3838,3839,3841,3843],{"class":558,"line":759},[556,3840,3825],{"class":620},[556,3842,2116],{"class":628},[556,3844,820],{"class":624},[556,3846,3847,3849,3851,3853,3856,3858],{"class":558,"line":766},[556,3848,893],{"class":624},[556,3850,641],{"class":620},[556,3852,644],{"class":624},[556,3854,3855],{"class":565},"@heximon\u002Fpersistence\u002Fcore",[556,3857,649],{"class":624},[556,3859,652],{"class":624},[556,3861,3862],{"class":558,"line":791},[556,3863,763],{"emptyLinePlaceholder":762},[556,3865,3866,3868,3870,3873,3875,3877,3879,3882,3884],{"class":558,"line":804},[556,3867,769],{"class":620},[556,3869,773],{"class":772},[556,3871,3872],{"class":562}," InMemoryDatabase",[556,3874,779],{"class":772},[556,3876,629],{"class":562},[556,3878,2082],{"class":624},[556,3880,3881],{"class":562},"InMemoryTransaction",[556,3883,1900],{"class":624},[556,3885,1021],{"class":624},[556,3887,3888,3891,3893,3896,3898,3901],{"class":558,"line":810},[556,3889,3890],{"class":772},"  private",[556,3892,1839],{"class":772},[556,3894,3895],{"class":794}," transactionContext",[556,3897,798],{"class":624},[556,3899,3900],{"class":562}," TransactionContext",[556,3902,652],{"class":624},[556,3904,3905],{"class":558,"line":823},[556,3906,3907],{"class":1112},"  \u002F\u002F …\n",[556,3909,3910],{"class":558,"line":863},[556,3911,763],{"emptyLinePlaceholder":762},[556,3913,3914,3916,3918,3920,3922,3924,3926],{"class":558,"line":869},[556,3915,1828],{"class":772},[556,3917,3093],{"class":772},[556,3919,1862],{"class":772},[556,3921,2157],{"class":794},[556,3923,2082],{"class":624},[556,3925,2162],{"class":562},[556,3927,2165],{"class":624},[556,3929,3930,3932,3934,3936,3938,3940,3943,3945,3947,3949,3951,3953],{"class":558,"line":877},[556,3931,2170],{"class":782},[556,3933,798],{"class":624},[556,3935,831],{"class":624},[556,3937,2177],{"class":834},[556,3939,798],{"class":624},[556,3941,3942],{"class":562}," InMemoryTransaction",[556,3944,842],{"class":624},[556,3946,845],{"class":772},[556,3948,1881],{"class":562},[556,3950,2082],{"class":624},[556,3952,2162],{"class":562},[556,3954,2195],{"class":624},[556,3956,3957,3959,3961,3963,3965,3967],{"class":558,"line":890},[556,3958,2200],{"class":624},[556,3960,1881],{"class":562},[556,3962,2082],{"class":624},[556,3964,2162],{"class":562},[556,3966,1900],{"class":624},[556,3968,1021],{"class":624},[556,3970,3971,3973,3976,3978,3980,3983,3985,3988,3990,3992,3994,3996],{"class":558,"line":1384},[556,3972,1907],{"class":772},[556,3974,3975],{"class":628}," parent",[556,3977,1913],{"class":624},[556,3979,1919],{"class":624},[556,3981,3982],{"class":628},"transactionContext",[556,3984,1339],{"class":624},[556,3986,3987],{"class":782},"getActive",[556,3989,2082],{"class":624},[556,3991,3881],{"class":562},[556,3993,1900],{"class":624},[556,3995,1318],{"class":794},[556,3997,652],{"class":624},[556,3999,4000,4002,4005,4007,4009,4012,4014,4017,4019,4021,4024,4027,4029,4031,4033,4036,4038,4041,4043],{"class":558,"line":1411},[556,4001,1907],{"class":772},[556,4003,4004],{"class":628}," handle",[556,4006,1913],{"class":624},[556,4008,3975],{"class":628},[556,4010,4011],{"class":624}," ===",[556,4013,1897],{"class":624},[556,4015,4016],{"class":624}," ?",[556,4018,1916],{"class":620},[556,4020,1919],{"class":624},[556,4022,4023],{"class":782},"begin",[556,4025,4026],{"class":794},"() ",[556,4028,798],{"class":624},[556,4030,1916],{"class":620},[556,4032,1919],{"class":624},[556,4034,4035],{"class":782},"beginSavepoint",[556,4037,785],{"class":794},[556,4039,4040],{"class":628},"parent",[556,4042,842],{"class":794},[556,4044,652],{"class":624},[556,4046,4047],{"class":558,"line":1438},[556,4048,763],{"emptyLinePlaceholder":762},[556,4050,4051,4053,4055,4057,4059,4061,4063,4066,4068,4070,4072,4074],{"class":558,"line":1444},[556,4052,1325],{"class":620},[556,4054,1919],{"class":624},[556,4056,3982],{"class":628},[556,4058,1339],{"class":624},[556,4060,2338],{"class":782},[556,4062,785],{"class":794},[556,4064,4065],{"class":628},"handle",[556,4067,632],{"class":624},[556,4069,1862],{"class":772},[556,4071,2225],{"class":624},[556,4073,845],{"class":772},[556,4075,1021],{"class":624},[556,4077,4078,4081],{"class":558,"line":1450},[556,4079,4080],{"class":620},"      try",[556,4082,1021],{"class":624},[556,4084,4086,4089,4092,4094,4096,4099,4101,4103,4105],{"class":558,"line":4085},19,[556,4087,4088],{"class":772},"        const",[556,4090,4091],{"class":628}," result",[556,4093,1913],{"class":624},[556,4095,1916],{"class":620},[556,4097,4098],{"class":782}," work",[556,4100,785],{"class":794},[556,4102,4065],{"class":628},[556,4104,842],{"class":794},[556,4106,652],{"class":624},[556,4108,4110],{"class":558,"line":4109},20,[556,4111,763],{"emptyLinePlaceholder":762},[556,4113,4115,4117,4119,4122,4124,4126,4128],{"class":558,"line":4114},21,[556,4116,2778],{"class":620},[556,4118,1919],{"class":624},[556,4120,4121],{"class":782},"commit",[556,4123,785],{"class":794},[556,4125,4065],{"class":628},[556,4127,842],{"class":794},[556,4129,652],{"class":624},[556,4131,4133],{"class":558,"line":4132},22,[556,4134,763],{"emptyLinePlaceholder":762},[556,4136,4138,4141,4143],{"class":558,"line":4137},23,[556,4139,4140],{"class":620},"        return",[556,4142,4091],{"class":628},[556,4144,652],{"class":624},[556,4146,4148,4150,4152,4154,4156,4158],{"class":558,"line":4147},24,[556,4149,2841],{"class":624},[556,4151,3308],{"class":620},[556,4153,831],{"class":794},[556,4155,3323],{"class":628},[556,4157,896],{"class":794},[556,4159,788],{"class":624},[556,4161,4163,4165,4167,4170,4172,4174,4176],{"class":558,"line":4162},25,[556,4164,2778],{"class":620},[556,4166,1919],{"class":624},[556,4168,4169],{"class":782},"rollback",[556,4171,785],{"class":794},[556,4173,4065],{"class":628},[556,4175,842],{"class":794},[556,4177,652],{"class":624},[556,4179,4181],{"class":558,"line":4180},26,[556,4182,763],{"emptyLinePlaceholder":762},[556,4184,4186,4188,4191],{"class":558,"line":4185},27,[556,4187,2818],{"class":620},[556,4189,4190],{"class":628}," error",[556,4192,652],{"class":624},[556,4194,4196],{"class":558,"line":4195},28,[556,4197,4198],{"class":624},"      }\n",[556,4200,4202,4205,4207],{"class":558,"line":4201},29,[556,4203,4204],{"class":624},"    }",[556,4206,842],{"class":794},[556,4208,652],{"class":624},[556,4210,4212],{"class":558,"line":4211},30,[556,4213,2010],{"class":624},[556,4215,4217],{"class":558,"line":4216},31,[556,4218,2015],{"class":624},[2017,4220,4222,4233,4234,4236,4237,4240,4241,4244,4245,4248,4249,4252],{"type":4221},"warning",[511,4223,4224,4225,4228,4229,4232],{},"An in-memory libsql ",[503,4226,4227],{},"url"," needs ",[503,4230,4231],{},"cache=shared",", or your tables vanish between connections."," A bare\n",[503,4235,1081],{}," libsql URL creates a ",[3461,4238,4239],{},"separate"," private database per connection — a table created on one\nconnection is invisible to another, and the moment a raw client and the ORM (or two providers) both run\nqueries you get ",[503,4242,4243],{},"SqliteError: no such table",". Point every connection at the same in-memory database with\n",[503,4246,4247],{},"url: \"file::memory:?cache=shared\"",", or use a real file path or remote ",[503,4250,4251],{},"libsql:\u002F\u002F"," URL in production.",[531,4254,4256],{"id":4255},"see-also","See also",[2319,4258,4259,4264,4269,4277,4285,4299],{},[2322,4260,4261,4263],{},[527,4262,82],{"href":83}," — the concrete dialect: schemas, value-object columns, entity repositories,\nrelations, and transactions across SQLite, Postgres, and MySQL.",[2322,4265,4266,4268],{},[527,4267,92],{"href":93}," — generate with drizzle-kit and apply on boot with the migration runner.",[2322,4270,4271,4273,4274,4276],{},[527,4272,228],{"href":229}," — entities and aggregates whose repositories sit on this\n",[503,4275,77],{}," boundary.",[2322,4278,4279,4281,4282,4284],{},[527,4280,233],{"href":234}," — the command retry that consumes ",[503,4283,3152],{}," from an optimistic write.",[2322,4286,4287,4292,4293,4295,4296,4298],{},[527,4288,4291],{"href":4289,"rel":4290},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fladder\u002FL04-database",[2045],"the ladder's L04 — Database","\n— a repository over a single shared ",[503,4294,1734],{},", wired by a ",[503,4297,669],{}," and re-exported by\nclass identity.",[2322,4300,4301,4304,4305,4308,4309,4311],{},[527,4302,2046],{"href":2043,"rel":4303},[2045],"\n— entity repositories, value-object columns, and the version-guarded ",[503,4306,4307],{},"UPDATE"," that proves the\n",[503,4310,3152],{}," path.",[4313,4314,4315],"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 .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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":552,"searchDepth":713,"depth":713,"links":4317},[4318,4319,4320,4321,4322,4323,4324,4325,4326,4327],{"id":533,"depth":713,"text":534},{"id":655,"depth":713,"text":656},{"id":921,"depth":713,"text":922},{"id":1534,"depth":713,"text":1535},{"id":2050,"depth":713,"text":2051},{"id":2427,"depth":713,"text":2428},{"id":2952,"depth":713,"text":2953},{"id":3455,"depth":713,"text":3456},{"id":3798,"depth":713,"text":3799},{"id":4255,"depth":713,"text":4256},"A dialect-agnostic persistence boundary — the abstract Database surface, runInTransaction transactions, optimistic concurrency with ConcurrencyConflictError, MigrationRunner contracts, and how a concrete dialect plugs in via a useFactory provider.","md",null,{},{"icon":90},{"title":87,"description":4328},"aLrptiVcFRn7kjCnDbqUK-Bf3z1gQ_TWO-gHmSpuX_A",[4336,4338],{"title":82,"path":83,"stem":84,"description":4337,"icon":85,"children":-1},"Map domain entities to Drizzle tables — value-object columns, DDD repositories, optimistic concurrency, relations, nested transactions, and seven dialects (libsql, better-sqlite3, Cloudflare D1, Durable Object SQLite, Postgres, MySQL, Cloudflare Hyperdrive MySQL).",{"title":92,"path":93,"stem":94,"description":4339,"icon":95,"children":-1},"Generate Drizzle migrations with stock drizzle-kit, then apply them with the injectable MigrationRunner, MigrationConfig, and a Task — one unified config drives both the CLI and the runtime.",1783300761903]