[{"data":1,"prerenderedAt":3152},["ShallowReactive",2],{"navigation_docs":3,"-modules-platform-module-kit-database":587,"-modules-platform-module-kit-database-surround":3147},[4,50,155,441,504],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":49},"Get Started","i-lucide-rocket","\u002Fget-started","1.get-started",[10,15,20,25,30,35,40,45],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fget-started\u002Fintroduction","1.get-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fget-started\u002Finstallation","1.get-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Project structure","\u002Fget-started\u002Fproject-structure","1.get-started\u002F3.project-structure","i-lucide-folder-tree",{"title":26,"path":27,"stem":28,"icon":29},"Configuration","\u002Fget-started\u002Fconfiguration","1.get-started\u002F4.configuration","i-lucide-settings",{"title":31,"path":32,"stem":33,"icon":34},"Authentication","\u002Fget-started\u002Fauthentication","1.get-started\u002F5.authentication","i-lucide-lock",{"title":36,"path":37,"stem":38,"icon":39},"Adding modules","\u002Fget-started\u002Fadding-modules","1.get-started\u002F6.adding-modules","i-lucide-puzzle",{"title":41,"path":42,"stem":43,"icon":44},"Database","\u002Fget-started\u002Fdatabase","1.get-started\u002F7.database","i-lucide-database",{"title":46,"path":47,"stem":48,"icon":6},"Deployment","\u002Fget-started\u002Fdeployment","1.get-started\u002F8.deployment",false,{"title":51,"icon":52,"path":53,"stem":54,"children":55,"page":49},"Guide","i-lucide-book-open","\u002Fguide","2.guide",[56,90,115,125],{"title":57,"icon":49,"path":58,"stem":59,"children":60,"page":49},"Concepts","\u002Fguide\u002Fconcepts","2.guide\u002F1.concepts",[61,66,71,76,80,85],{"title":62,"path":63,"stem":64,"icon":65},"Architecture","\u002Fguide\u002Fconcepts\u002Farchitecture","2.guide\u002F1.concepts\u002F1.architecture","i-lucide-blocks",{"title":67,"path":68,"stem":69,"icon":70},"Access control","\u002Fguide\u002Fconcepts\u002Fauth-and-scopes","2.guide\u002F1.concepts\u002F2.auth-and-scopes","i-lucide-shield-check",{"title":72,"path":73,"stem":74,"icon":75},"Extension points","\u002Fguide\u002Fconcepts\u002Fextension-points","2.guide\u002F1.concepts\u002F3.extension-points","i-lucide-plug",{"title":77,"path":78,"stem":79,"icon":44},"Database extensions","\u002Fguide\u002Fconcepts\u002Fdatabase-extensions","2.guide\u002F1.concepts\u002F4.database-extensions",{"title":81,"path":82,"stem":83,"icon":84},"Identity","\u002Fguide\u002Fconcepts\u002Fidentity","2.guide\u002F1.concepts\u002F5.identity","i-lucide-fingerprint",{"title":86,"path":87,"stem":88,"icon":89},"Glossary","\u002Fguide\u002Fconcepts\u002Fglossary","2.guide\u002F1.concepts\u002F6.glossary","i-lucide-book-a",{"title":91,"icon":49,"path":92,"stem":93,"children":94,"page":49},"UX patterns","\u002Fguide\u002Fux-patterns","2.guide\u002F2.ux-patterns",[95,100,105,110],{"title":96,"path":97,"stem":98,"icon":99},"Layouts and navigation","\u002Fguide\u002Fux-patterns\u002Flayouts-and-navigation","2.guide\u002F2.ux-patterns\u002F1.layouts-and-navigation","i-lucide-layout-template",{"title":101,"path":102,"stem":103,"icon":104},"Pages","\u002Fguide\u002Fux-patterns\u002Fpages","2.guide\u002F2.ux-patterns\u002F2.pages","i-lucide-table",{"title":106,"path":107,"stem":108,"icon":109},"Forms and actions","\u002Fguide\u002Fux-patterns\u002Fforms-and-actions","2.guide\u002F2.ux-patterns\u002F3.forms-and-actions","i-lucide-square-pen",{"title":111,"path":112,"stem":113,"icon":114},"Text and formatting","\u002Fguide\u002Fux-patterns\u002Ftext-and-formatting","2.guide\u002F2.ux-patterns\u002F4.text-and-formatting","i-lucide-type",{"title":116,"icon":49,"path":117,"stem":118,"children":119,"page":49},"Best practices","\u002Fguide\u002Fbest-practices","2.guide\u002F3.best-practices",[120],{"title":121,"path":122,"stem":123,"icon":124},"HTTP routes","\u002Fguide\u002Fbest-practices\u002Fhttp-routes","2.guide\u002F3.best-practices\u002F1.http-routes","i-lucide-route",{"title":126,"icon":49,"path":127,"stem":128,"children":129,"page":49},"Going further","\u002Fguide\u002Fgoing-further","2.guide\u002F4.going-further",[130,135,140,145,150],{"title":131,"path":132,"stem":133,"icon":134},"Use your own OAuth server","\u002Fguide\u002Fgoing-further\u002Fown-oauth-server","2.guide\u002F4.going-further\u002F1.own-oauth-server","i-lucide-key-round",{"title":136,"path":137,"stem":138,"icon":139},"Create an OAuth application","\u002Fguide\u002Fgoing-further\u002Foauth-application","2.guide\u002F4.going-further\u002F2.oauth-application","i-lucide-app-window",{"title":141,"path":142,"stem":143,"icon":144},"Signing keys","\u002Fguide\u002Fgoing-further\u002Fsigning-keys","2.guide\u002F4.going-further\u002F3.signing-keys","i-lucide-key-square",{"title":146,"path":147,"stem":148,"icon":149},"Stripe setup","\u002Fguide\u002Fgoing-further\u002Fstripe-setup","2.guide\u002F4.going-further\u002F4.stripe-setup","i-lucide-credit-card",{"title":151,"path":152,"stem":153,"icon":154},"Migrate to the permission model","\u002Fguide\u002Fgoing-further\u002Fmigrate-access-control","2.guide\u002F4.going-further\u002F5.migrate-access-control","i-lucide-arrow-right-left",{"title":156,"icon":157,"path":158,"stem":159,"children":160},"Modules","i-lucide-boxes","\u002Fmodules","3.modules",[161,163,244,273,320,375],{"title":156,"path":158,"stem":162},"3.modules\u002Findex",{"title":81,"icon":49,"path":164,"stem":165,"children":166,"page":49},"\u002Fmodules\u002Fidentity","3.modules\u002F1.identity",[167,190,194,198,220,224,240],{"title":168,"path":169,"stem":170,"children":171},"Auth","\u002Fmodules\u002Fidentity\u002Fauth","3.modules\u002F1.identity\u002F1.auth\u002Findex",[172,174,178,182,186],{"title":173,"path":169,"stem":170},"Overview",{"title":175,"path":176,"stem":177},"Server API","\u002Fmodules\u002Fidentity\u002Fauth\u002Fserver","3.modules\u002F1.identity\u002F1.auth\u002F2.server",{"title":179,"path":180,"stem":181},"Reference","\u002Fmodules\u002Fidentity\u002Fauth\u002Freference","3.modules\u002F1.identity\u002F1.auth\u002F3.reference",{"title":183,"path":184,"stem":185},"Client mode","\u002Fmodules\u002Fidentity\u002Fauth\u002Fclient-mode","3.modules\u002F1.identity\u002F1.auth\u002F4.client-mode",{"title":187,"path":188,"stem":189},"OAuth providers","\u002Fmodules\u002Fidentity\u002Fauth\u002Foauth-providers","3.modules\u002F1.identity\u002F1.auth\u002F5.oauth-providers",{"title":191,"path":192,"stem":193},"Users","\u002Fmodules\u002Fidentity\u002Fusers","3.modules\u002F1.identity\u002F2.users",{"title":195,"path":196,"stem":197},"Account","\u002Fmodules\u002Fidentity\u002Faccount","3.modules\u002F1.identity\u002F3.account",{"title":199,"path":200,"stem":201,"children":202},"Authorization","\u002Fmodules\u002Fidentity\u002Fauthorization","3.modules\u002F1.identity\u002F4.authorization\u002Findex",[203,204,208,212,216],{"title":173,"path":200,"stem":201},{"title":205,"path":206,"stem":207},"Roles and requirements","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Froles-and-requirements","3.modules\u002F1.identity\u002F4.authorization\u002F2.roles-and-requirements",{"title":209,"path":210,"stem":211},"Policies","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fpolicies","3.modules\u002F1.identity\u002F4.authorization\u002F3.policies",{"title":213,"path":214,"stem":215},"Client","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fclient","3.modules\u002F1.identity\u002F4.authorization\u002F4.client",{"title":217,"path":218,"stem":219},"Admin","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fadmin","3.modules\u002F1.identity\u002F4.authorization\u002F5.admin",{"title":221,"path":222,"stem":223},"Preferences","\u002Fmodules\u002Fidentity\u002Fpreferences","3.modules\u002F1.identity\u002F5.preferences",{"title":225,"path":226,"stem":227,"children":228},"OAuth Server","\u002Fmodules\u002Fidentity\u002Foauth-server","3.modules\u002F1.identity\u002F6.oauth-server\u002Findex",[229,230,233,237],{"title":173,"path":226,"stem":227},{"title":175,"path":231,"stem":232},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fserver","3.modules\u002F1.identity\u002F6.oauth-server\u002F2.server",{"title":234,"path":235,"stem":236},"Hooks","\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fhooks","3.modules\u002F1.identity\u002F6.oauth-server\u002F3.hooks",{"title":179,"path":238,"stem":239},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients","3.modules\u002F1.identity\u002F6.oauth-server\u002F4.routes-and-clients",{"title":241,"path":242,"stem":243},"OAuth Resource","\u002Fmodules\u002Fidentity\u002Foauth-resource","3.modules\u002F1.identity\u002F8.oauth-resource",{"title":245,"icon":49,"path":246,"stem":247,"children":248,"page":49},"Commerce","\u002Fmodules\u002Fcommerce","3.modules\u002F2.commerce",[249,253,257],{"title":250,"path":251,"stem":252},"Stripe","\u002Fmodules\u002Fcommerce\u002Fstripe","3.modules\u002F2.commerce\u002F1.stripe",{"title":254,"path":255,"stem":256},"Payments","\u002Fmodules\u002Fcommerce\u002Fpayments","3.modules\u002F2.commerce\u002F2.payments",{"title":258,"path":259,"stem":260,"children":261},"Subscriptions","\u002Fmodules\u002Fcommerce\u002Fsubscriptions","3.modules\u002F2.commerce\u002F3.subscriptions\u002Findex",[262,263,266,270],{"title":173,"path":259,"stem":260},{"title":175,"path":264,"stem":265},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fserver","3.modules\u002F2.commerce\u002F3.subscriptions\u002F2.server",{"title":267,"path":268,"stem":269},"App","\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fapp","3.modules\u002F2.commerce\u002F3.subscriptions\u002F3.app",{"title":179,"path":271,"stem":272},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Freference","3.modules\u002F2.commerce\u002F3.subscriptions\u002F4.reference",{"title":274,"icon":49,"path":275,"stem":276,"children":277,"page":49},"Features","\u002Fmodules\u002Ffeatures","3.modules\u002F3.features",[278,293,312,316],{"title":279,"path":280,"stem":281,"children":282},"Events","\u002Fmodules\u002Ffeatures\u002Fevents","3.modules\u002F3.features\u002F1.events\u002Findex",[283,284,287,290],{"title":173,"path":280,"stem":281},{"title":175,"path":285,"stem":286},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fserver","3.modules\u002F3.features\u002F1.events\u002F2.server",{"title":267,"path":288,"stem":289},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fapp","3.modules\u002F3.features\u002F1.events\u002F3.app",{"title":179,"path":291,"stem":292},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Freference","3.modules\u002F3.features\u002F1.events\u002F4.reference",{"title":294,"path":295,"stem":296,"children":297},"Forms","\u002Fmodules\u002Ffeatures\u002Fforms","3.modules\u002F3.features\u002F2.forms\u002Findex",[298,299,303,306,309],{"title":173,"path":295,"stem":296},{"title":300,"path":301,"stem":302},"Definition","\u002Fmodules\u002Ffeatures\u002Fforms\u002Fdefinition","3.modules\u002F3.features\u002F2.forms\u002F2.definition",{"title":175,"path":304,"stem":305},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fserver","3.modules\u002F3.features\u002F2.forms\u002F3.server",{"title":267,"path":307,"stem":308},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fapp","3.modules\u002F3.features\u002F2.forms\u002F4.app",{"title":179,"path":310,"stem":311},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Freference","3.modules\u002F3.features\u002F2.forms\u002F5.reference",{"title":313,"path":314,"stem":315},"Cookie Consent","\u002Fmodules\u002Ffeatures\u002Fcookie-consent","3.modules\u002F3.features\u002F3.cookie-consent",{"title":317,"path":318,"stem":319},"MCP","\u002Fmodules\u002Ffeatures\u002Fmcp","3.modules\u002F3.features\u002F4.mcp",{"title":321,"icon":49,"path":322,"stem":323,"children":324,"page":49},"Interface","\u002Fmodules\u002Finterface","3.modules\u002F4.interface",[325,350,353,357,361],{"title":326,"path":327,"stem":328,"children":329},"UI","\u002Fmodules\u002Finterface\u002Fui","3.modules\u002F4.interface\u002F1.ui\u002Findex",[330,331,335,339,343,347],{"title":173,"path":327,"stem":328},{"title":332,"path":333,"stem":334},"Page components","\u002Fmodules\u002Finterface\u002Fui\u002Fpage-components","3.modules\u002F4.interface\u002F1.ui\u002F2.page-components",{"title":336,"path":337,"stem":338},"App shell","\u002Fmodules\u002Finterface\u002Fui\u002Fapp-shell","3.modules\u002F4.interface\u002F1.ui\u002F3.app-shell",{"title":340,"path":341,"stem":342},"Form inputs","\u002Fmodules\u002Finterface\u002Fui\u002Fform-inputs","3.modules\u002F4.interface\u002F1.ui\u002F4.form-inputs",{"title":344,"path":345,"stem":346},"Composables and helpers","\u002Fmodules\u002Finterface\u002Fui\u002Fcomposables","3.modules\u002F4.interface\u002F1.ui\u002F5.composables",{"title":179,"path":348,"stem":349},"\u002Fmodules\u002Finterface\u002Fui\u002Freference","3.modules\u002F4.interface\u002F1.ui\u002F6.reference",{"title":217,"path":351,"stem":352},"\u002Fmodules\u002Finterface\u002Fadmin","3.modules\u002F4.interface\u002F2.admin",{"title":354,"path":355,"stem":356},"Menu","\u002Fmodules\u002Finterface\u002Fmenu","3.modules\u002F4.interface\u002F3.menu",{"title":358,"path":359,"stem":360},"Widget","\u002Fmodules\u002Finterface\u002Fwidget","3.modules\u002F4.interface\u002F4.widget",{"title":362,"path":363,"stem":364,"children":365},"Mobile","\u002Fmodules\u002Finterface\u002Fmobile","3.modules\u002F4.interface\u002F5.mobile\u002Findex",[366,367,371],{"title":173,"path":363,"stem":364},{"title":368,"path":369,"stem":370},"CLI and devices","\u002Fmodules\u002Finterface\u002Fmobile\u002Fcli-and-devices","3.modules\u002F4.interface\u002F5.mobile\u002F2.cli-and-devices",{"title":372,"path":373,"stem":374},"Splash screen","\u002Fmodules\u002Finterface\u002Fmobile\u002Fsplash-screen","3.modules\u002F4.interface\u002F5.mobile\u002F3.splash-screen",{"title":376,"icon":49,"path":377,"stem":378,"children":379,"page":49},"Platform","\u002Fmodules\u002Fplatform","3.modules\u002F5.platform",[380,402,406,423],{"title":381,"path":382,"stem":383,"children":384},"Module Kit","\u002Fmodules\u002Fplatform\u002Fmodule-kit","3.modules\u002F5.platform\u002F1.module-kit\u002Findex",[385,386,390,394,398],{"title":173,"path":382,"stem":383},{"title":387,"path":388,"stem":389},"Server toolkit","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fserver-toolkit","3.modules\u002F5.platform\u002F1.module-kit\u002F2.server-toolkit",{"title":391,"path":392,"stem":393},"Registries and menus","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fregistries-and-menus","3.modules\u002F5.platform\u002F1.module-kit\u002F3.registries-and-menus",{"title":395,"path":396,"stem":397},"Translations","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fi18n","3.modules\u002F5.platform\u002F1.module-kit\u002F4.i18n",{"title":399,"path":400,"stem":401},"Database helpers","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fdatabase","3.modules\u002F5.platform\u002F1.module-kit\u002F5.database",{"title":403,"path":404,"stem":405},"Notify","\u002Fmodules\u002Fplatform\u002Fnotify","3.modules\u002F5.platform\u002F2.notify",{"title":407,"path":408,"stem":409,"children":410},"Email Templates","\u002Fmodules\u002Fplatform\u002Femail-templates","3.modules\u002F5.platform\u002F3.email-templates\u002Findex",[411,412,416,419],{"title":173,"path":408,"stem":409},{"title":413,"path":414,"stem":415},"Email components","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fcomponents","3.modules\u002F5.platform\u002F3.email-templates\u002F2.components",{"title":175,"path":417,"stem":418},"\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fserver","3.modules\u002F5.platform\u002F3.email-templates\u002F3.server",{"title":420,"path":421,"stem":422},"Module emails","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fmodule-emails","3.modules\u002F5.platform\u002F3.email-templates\u002F4.module-emails",{"title":424,"path":425,"stem":426,"children":427},"Base Layer","\u002Fmodules\u002Fplatform\u002Fbase-layer","3.modules\u002F5.platform\u002F4.base-layer\u002Findex",[428,429,433,437],{"title":173,"path":425,"stem":426},{"title":430,"path":431,"stem":432},"Content collections","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcontent-collections","3.modules\u002F5.platform\u002F4.base-layer\u002F2.content-collections",{"title":434,"path":435,"stem":436},"Layouts and routing","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Flayouts-and-routing","3.modules\u002F5.platform\u002F4.base-layer\u002F3.layouts-and-routing",{"title":438,"path":439,"stem":440},"Composables and utils","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcomposables-and-utils","3.modules\u002F5.platform\u002F4.base-layer\u002F4.composables-and-utils",{"title":442,"icon":443,"path":444,"stem":445,"children":446,"page":49},"Examples","i-lucide-code-xml","\u002Fexamples","4.examples",[447,466,476],{"title":448,"icon":49,"path":449,"stem":450,"children":451,"page":49},"Starters","\u002Fexamples\u002Fstarters","4.examples\u002F1.starters",[452,456,461],{"title":453,"path":454,"stem":455,"icon":6},"Workspace starter","\u002Fexamples\u002Fstarters\u002Fworkspace","4.examples\u002F1.starters\u002F1.workspace",{"title":457,"path":458,"stem":459,"icon":460},"Mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile","4.examples\u002F1.starters\u002F2.mobile","i-lucide-smartphone",{"title":462,"path":463,"stem":464,"icon":465},"Standalone mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile-standalone","4.examples\u002F1.starters\u002F3.mobile-standalone","i-lucide-tablet-smartphone",{"title":467,"icon":49,"path":468,"stem":469,"children":470,"page":49},"Apps","\u002Fexamples\u002Fapps","4.examples\u002F2.apps",[471],{"title":472,"path":473,"stem":474,"icon":475},"Frigear website app","\u002Fexamples\u002Fapps\u002Ffrigear-nu-website","4.examples\u002F2.apps\u002F1.frigear-nu-website","i-lucide-layout-dashboard",{"title":477,"icon":49,"path":478,"stem":479,"children":480,"page":49},"Tasks","\u002Fexamples\u002Ftasks","4.examples\u002F3.tasks",[481,485,489,494,499],{"title":482,"path":483,"stem":484,"icon":70},"Protect a route","\u002Fexamples\u002Ftasks\u002Fprotect-a-route","4.examples\u002F3.tasks\u002F1.protect-a-route",{"title":486,"path":487,"stem":488,"icon":475},"Add an admin page","\u002Fexamples\u002Ftasks\u002Fadd-an-admin-page","4.examples\u002F3.tasks\u002F2.add-an-admin-page",{"title":490,"path":491,"stem":492,"icon":493},"Sell event tickets","\u002Fexamples\u002Ftasks\u002Fsell-event-tickets","4.examples\u002F3.tasks\u002F3.sell-event-tickets","i-lucide-ticket",{"title":495,"path":496,"stem":497,"icon":498},"Build a form","\u002Fexamples\u002Ftasks\u002Fbuild-a-form","4.examples\u002F3.tasks\u002F4.build-a-form","i-lucide-clipboard-list",{"title":500,"path":501,"stem":502,"icon":503},"Send an email","\u002Fexamples\u002Ftasks\u002Fsend-an-email","4.examples\u002F3.tasks\u002F5.send-an-email","i-lucide-mail",{"title":505,"icon":506,"path":507,"stem":508,"children":509,"page":49},"Contribute","i-lucide-git-pull-request","\u002Fcontribute","5.contribute",[510,513,518,544,549,552,556,571],{"title":173,"path":511,"stem":512,"icon":506},"\u002Fcontribute\u002Foverview","5.contribute\u002F1.overview",{"title":514,"path":515,"stem":516,"icon":517},"Local development","\u002Fcontribute\u002Flocal-development","5.contribute\u002F2.local-development","i-lucide-terminal",{"title":519,"icon":49,"path":520,"stem":521,"children":522,"page":49},"Writing a module","\u002Fcontribute\u002Fwriting-a-module","5.contribute\u002F3.writing-a-module",[523,527,532,536,541],{"title":524,"path":525,"stem":526,"icon":39},"Scaffold a module","\u002Fcontribute\u002Fwriting-a-module\u002Fscaffold","5.contribute\u002F3.writing-a-module\u002F1.scaffold",{"title":528,"path":529,"stem":530,"icon":531},"Setup checklist","\u002Fcontribute\u002Fwriting-a-module\u002Fsetup-checklist","5.contribute\u002F3.writing-a-module\u002F2.setup-checklist","i-lucide-list-checks",{"title":533,"path":534,"stem":535,"icon":44},"Database tables","\u002Fcontribute\u002Fwriting-a-module\u002Fdatabase-tables","5.contribute\u002F3.writing-a-module\u002F3.database-tables",{"title":537,"path":538,"stem":539,"icon":540},"Testing","\u002Fcontribute\u002Fwriting-a-module\u002Ftesting","5.contribute\u002F3.writing-a-module\u002F4.testing","i-lucide-flask-conical",{"title":67,"path":542,"stem":543,"icon":70},"\u002Fcontribute\u002Fwriting-a-module\u002Faccess-control","5.contribute\u002F3.writing-a-module\u002F5.access-control",{"title":545,"path":546,"stem":547,"icon":548},"Publishing","\u002Fcontribute\u002Fpublishing","5.contribute\u002F4.publishing","i-lucide-package-check",{"title":448,"path":550,"stem":551,"icon":6},"\u002Fcontribute\u002Fstarters","5.contribute\u002F5.starters",{"title":553,"path":554,"stem":555,"icon":52},"Documentation","\u002Fcontribute\u002Fdocumentation","5.contribute\u002F6.documentation",{"title":557,"icon":49,"path":558,"stem":559,"children":560,"page":49},"Tooling","\u002Fcontribute\u002Ftooling","5.contribute\u002F7.tooling",[561,566],{"title":562,"path":563,"stem":564,"icon":565},"CLI","\u002Fcontribute\u002Ftooling\u002Fcli","5.contribute\u002F7.tooling\u002F1.cli","i-lucide-square-terminal",{"title":567,"path":568,"stem":569,"icon":570},"ESLint config","\u002Fcontribute\u002Ftooling\u002Feslint-config","5.contribute\u002F7.tooling\u002F2.eslint-config","i-lucide-spell-check",{"title":572,"icon":49,"path":573,"stem":574,"children":575},"Decisions","\u002Fcontribute\u002Fdecisions","5.contribute\u002F8.decisions\u002Findex",[576,578,583],{"title":572,"path":573,"stem":574,"icon":577},"i-lucide-scale",{"title":579,"path":580,"stem":581,"icon":582},"Session lifetimes per OAuth client","\u002Fcontribute\u002Fdecisions\u002Foauth-token-lifetimes","5.contribute\u002F8.decisions\u002F1.oauth-token-lifetimes","i-lucide-timer",{"title":584,"path":585,"stem":586,"icon":70},"One permission model","\u002Fcontribute\u002Fdecisions\u002Fpermission-model","5.contribute\u002F8.decisions\u002F2.permission-model",{"id":588,"title":589,"body":590,"description":3140,"extension":3141,"links":3142,"meta":3143,"navigation":3144,"path":400,"seo":3145,"stem":401,"__hash__":3146},"docs\u002F3.modules\u002F5.platform\u002F1.module-kit\u002F5.database.md","Module Kit database helpers",{"type":591,"value":592,"toc":3121},"minimark",[593,601,610,615,622,725,751,755,762,1066,1205,1215,1222,1356,1364,1527,1536,1540,1566,1575,1794,1797,1904,1935,2071,2096,2100,2109,2164,2255,2343,2346,2412,2416,2419,2524,2537,2541,2548,2594,2597,2603,2659,2663,2674,2689,2693,2706,2709,2713,2716,3026,3041,3045,3095,3099,3117],[594,595,596,597,600],"p",{},"Your module needs a table of its own, or one more column on a table another module owns. It must run on SQLite and\nPostgreSQL, and its test fixtures need committed migrations. This page is the full reference for module authors.\nSet up the module first: ",[598,599,173],"a",{"href":382},".",[594,602,603,604,606,607,609],{},"App developers start at ",[598,605,41],{"href":42},". ",[598,608,77],{"href":78},"\nexplains why tables are extended this way.",[611,612,614],"h2",{"id":613},"helpers","Helpers",[594,616,617,618,621],{},"These helpers work on the schema that ",[598,619,620],{"href":87},"NuxtHub"," generates, not on the database.",[623,624,625,641],"table",{},[626,627,628],"thead",{},[629,630,631,635,638],"tr",{},[632,633,634],"th",{},"Helper",[632,636,637],{},"Signature",[632,639,640],{},"Purpose",[642,643,644,661,676,691,710],"tbody",{},[629,645,646,653,658],{},[647,648,649],"td",{},[650,651,652],"code",{},"registerDatabaseTable",[647,654,655],{},[650,656,657],{},"(nuxt: Nuxt, options: DatabaseTableOptions) => void",[647,659,660],{},"The owning module registers its schema file.",[629,662,663,668,673],{},[647,664,665],{},[650,666,667],{},"extendDatabaseTable",[647,669,670],{},[650,671,672],{},"(nuxt: Nuxt, options: TableExtensionOptions) => void",[647,674,675],{},"Another module adds a column file to the tables it extends.",[629,677,678,683,688],{},[647,679,680],{},[650,681,682],{},"defineTableColumns",[647,684,685],{},[650,686,687],{},"\u003CT extends Record\u003Cstring, ColumnBuilderBase>>(columns: T) => T",[647,689,690],{},"Types a columns object in an extension file.",[629,692,693,698,703],{},[647,694,695],{},[650,696,697],{},"onDatabaseSchemaExtend",[647,699,700],{},[650,701,702],{},"(nuxt: Nuxt, extender: DbExtenderFn) => void",[647,704,705,706,709],{},"Hooks ",[650,707,708],{},"hub:db:schema:extend"," to add schema files by hand.",[629,711,712,717,722],{},[647,713,714],{},[650,715,716],{},"defineExtendableTable",[647,718,719],{},[650,720,721],{},"\u003CT>(table: ({ name, columns }) => T) => ({ name, columns }) => T",[647,723,724],{},"Deprecated; export plain tables.",[594,726,727,728,731,732,735,736,739,740,743,744,747,748,600],{},"The calls only register hooks. NuxtHub does the work when it builds the schema, so there is nothing to ",[650,729,730],{},"await",". The\noption and callback types are exported from ",[650,733,734],{},"@frigear-nu\u002Fmodule-kit\u002Futils",": ",[650,737,738],{},"DatabaseTableOptions",",\n",[650,741,742],{},"TableExtensionOptions",", ",[650,745,746],{},"DbExtenderFn"," and ",[650,749,750],{},"TableExtenderFn",[611,752,754],{"id":753},"registering-a-table","Registering a table",[594,756,757,758,761],{},"The owning module ships a plain ",[598,759,760],{"href":87},"Drizzle"," schema file and registers it:",[763,764,770],"pre",{"className":765,"code":766,"filename":767,"language":768,"meta":769,"style":769},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { sqliteTable, text, integer } from 'drizzle-orm\u002Fsqlite-core'\n\nexport const users = sqliteTable('users', {\n  id: integer().primaryKey({ autoIncrement: true }),\n  email: text().notNull().unique(),\n})\n\nexport const userPasskeys = sqliteTable('user_passkeys', {\n  id: integer().primaryKey({ autoIncrement: true }),\n  userId: integer().notNull().references(() => users.id, { onDelete: 'cascade' }),\n})\n","src\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.sqlite.ts","ts","",[650,771,772,816,823,858,899,927,936,941,968,999,1059],{"__ignoreMap":769},[773,774,777,781,785,789,792,795,797,800,803,806,809,813],"span",{"class":775,"line":776},"line",1,[773,778,780],{"class":779},"s7zQu","import",[773,782,784],{"class":783},"sMK4o"," {",[773,786,788],{"class":787},"sTEyZ"," sqliteTable",[773,790,791],{"class":783},",",[773,793,794],{"class":787}," text",[773,796,791],{"class":783},[773,798,799],{"class":787}," integer",[773,801,802],{"class":783}," }",[773,804,805],{"class":779}," from",[773,807,808],{"class":783}," '",[773,810,812],{"class":811},"sfazB","drizzle-orm\u002Fsqlite-core",[773,814,815],{"class":783},"'\n",[773,817,819],{"class":775,"line":818},2,[773,820,822],{"emptyLinePlaceholder":821},true,"\n",[773,824,826,829,833,836,839,842,845,848,851,853,855],{"class":775,"line":825},3,[773,827,828],{"class":779},"export",[773,830,832],{"class":831},"spNyl"," const",[773,834,835],{"class":787}," users ",[773,837,838],{"class":783},"=",[773,840,788],{"class":841},"s2Zo4",[773,843,844],{"class":787},"(",[773,846,847],{"class":783},"'",[773,849,850],{"class":811},"users",[773,852,847],{"class":783},[773,854,791],{"class":783},[773,856,857],{"class":783}," {\n",[773,859,861,865,868,870,873,875,878,880,883,886,888,892,894,897],{"class":775,"line":860},4,[773,862,864],{"class":863},"swJcz","  id",[773,866,867],{"class":783},":",[773,869,799],{"class":841},[773,871,872],{"class":787},"()",[773,874,600],{"class":783},[773,876,877],{"class":841},"primaryKey",[773,879,844],{"class":787},[773,881,882],{"class":783},"{",[773,884,885],{"class":863}," autoIncrement",[773,887,867],{"class":783},[773,889,891],{"class":890},"sfNiH"," true",[773,893,802],{"class":783},[773,895,896],{"class":787},")",[773,898,739],{"class":783},[773,900,902,905,907,909,911,913,916,918,920,923,925],{"class":775,"line":901},5,[773,903,904],{"class":863},"  email",[773,906,867],{"class":783},[773,908,794],{"class":841},[773,910,872],{"class":787},[773,912,600],{"class":783},[773,914,915],{"class":841},"notNull",[773,917,872],{"class":787},[773,919,600],{"class":783},[773,921,922],{"class":841},"unique",[773,924,872],{"class":787},[773,926,739],{"class":783},[773,928,930,933],{"class":775,"line":929},6,[773,931,932],{"class":783},"}",[773,934,935],{"class":787},")\n",[773,937,939],{"class":775,"line":938},7,[773,940,822],{"emptyLinePlaceholder":821},[773,942,944,946,948,951,953,955,957,959,962,964,966],{"class":775,"line":943},8,[773,945,828],{"class":779},[773,947,832],{"class":831},[773,949,950],{"class":787}," userPasskeys ",[773,952,838],{"class":783},[773,954,788],{"class":841},[773,956,844],{"class":787},[773,958,847],{"class":783},[773,960,961],{"class":811},"user_passkeys",[773,963,847],{"class":783},[773,965,791],{"class":783},[773,967,857],{"class":783},[773,969,971,973,975,977,979,981,983,985,987,989,991,993,995,997],{"class":775,"line":970},9,[773,972,864],{"class":863},[773,974,867],{"class":783},[773,976,799],{"class":841},[773,978,872],{"class":787},[773,980,600],{"class":783},[773,982,877],{"class":841},[773,984,844],{"class":787},[773,986,882],{"class":783},[773,988,885],{"class":863},[773,990,867],{"class":783},[773,992,891],{"class":890},[773,994,802],{"class":783},[773,996,896],{"class":787},[773,998,739],{"class":783},[773,1000,1002,1005,1007,1009,1011,1013,1015,1017,1019,1022,1024,1026,1029,1032,1034,1037,1039,1041,1044,1046,1048,1051,1053,1055,1057],{"class":775,"line":1001},10,[773,1003,1004],{"class":863},"  userId",[773,1006,867],{"class":783},[773,1008,799],{"class":841},[773,1010,872],{"class":787},[773,1012,600],{"class":783},[773,1014,915],{"class":841},[773,1016,872],{"class":787},[773,1018,600],{"class":783},[773,1020,1021],{"class":841},"references",[773,1023,844],{"class":787},[773,1025,872],{"class":783},[773,1027,1028],{"class":831}," =>",[773,1030,1031],{"class":787}," users",[773,1033,600],{"class":783},[773,1035,1036],{"class":787},"id",[773,1038,791],{"class":783},[773,1040,784],{"class":783},[773,1042,1043],{"class":863}," onDelete",[773,1045,867],{"class":783},[773,1047,808],{"class":783},[773,1049,1050],{"class":811},"cascade",[773,1052,847],{"class":783},[773,1054,802],{"class":783},[773,1056,896],{"class":787},[773,1058,739],{"class":783},[773,1060,1062,1064],{"class":775,"line":1061},11,[773,1063,932],{"class":783},[773,1065,935],{"class":787},[763,1067,1070],{"className":765,"code":1068,"filename":1069,"language":768,"meta":769,"style":769},"import { createResolver } from '@nuxt\u002Fkit'\nimport { registerDatabaseTable } from '@frigear-nu\u002Fmodule-kit\u002Futils'\n\n\u002F\u002F in setup()\nconst resolver = createResolver(import.meta.url)\n\nregisterDatabaseTable(nuxt, {\n  resolver,\n  schema: dialect => `.\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.${dialect}`,\n})\n","src\u002Fmodule.ts",[650,1071,1072,1092,1111,1115,1121,1147,1151,1162,1169,1199],{"__ignoreMap":769},[773,1073,1074,1076,1078,1081,1083,1085,1087,1090],{"class":775,"line":776},[773,1075,780],{"class":779},[773,1077,784],{"class":783},[773,1079,1080],{"class":787}," createResolver",[773,1082,802],{"class":783},[773,1084,805],{"class":779},[773,1086,808],{"class":783},[773,1088,1089],{"class":811},"@nuxt\u002Fkit",[773,1091,815],{"class":783},[773,1093,1094,1096,1098,1101,1103,1105,1107,1109],{"class":775,"line":818},[773,1095,780],{"class":779},[773,1097,784],{"class":783},[773,1099,1100],{"class":787}," registerDatabaseTable",[773,1102,802],{"class":783},[773,1104,805],{"class":779},[773,1106,808],{"class":783},[773,1108,734],{"class":811},[773,1110,815],{"class":783},[773,1112,1113],{"class":775,"line":825},[773,1114,822],{"emptyLinePlaceholder":821},[773,1116,1117],{"class":775,"line":860},[773,1118,1120],{"class":1119},"sHwdD","\u002F\u002F in setup()\n",[773,1122,1123,1126,1129,1131,1133,1135,1137,1139,1142,1144],{"class":775,"line":901},[773,1124,1125],{"class":831},"const",[773,1127,1128],{"class":787}," resolver ",[773,1130,838],{"class":783},[773,1132,1080],{"class":841},[773,1134,844],{"class":787},[773,1136,780],{"class":779},[773,1138,600],{"class":783},[773,1140,1141],{"class":787},"meta",[773,1143,600],{"class":783},[773,1145,1146],{"class":787},"url)\n",[773,1148,1149],{"class":775,"line":929},[773,1150,822],{"emptyLinePlaceholder":821},[773,1152,1153,1155,1158,1160],{"class":775,"line":938},[773,1154,652],{"class":841},[773,1156,1157],{"class":787},"(nuxt",[773,1159,791],{"class":783},[773,1161,857],{"class":783},[773,1163,1164,1167],{"class":775,"line":943},[773,1165,1166],{"class":787},"  resolver",[773,1168,739],{"class":783},[773,1170,1171,1174,1176,1180,1182,1185,1188,1191,1194,1197],{"class":775,"line":970},[773,1172,1173],{"class":841},"  schema",[773,1175,867],{"class":783},[773,1177,1179],{"class":1178},"sHdIc"," dialect",[773,1181,1028],{"class":831},[773,1183,1184],{"class":783}," `",[773,1186,1187],{"class":811},".\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.",[773,1189,1190],{"class":783},"${",[773,1192,1193],{"class":787},"dialect",[773,1195,1196],{"class":783},"}`",[773,1198,739],{"class":783},[773,1200,1201,1203],{"class":775,"line":1001},[773,1202,932],{"class":783},[773,1204,935],{"class":787},[594,1206,1207,1208,743,1211,1214],{},"Every export initialised by a table call (",[650,1209,1210],{},"sqliteTable(...)",[650,1212,1213],{},"pgTable(...)",") is registered. Other exports are\nignored. All tables of the file are generated into one file, so they can reference each other, as the foreign key\nabove does. The base file decides the table function and the SQL table name of the merged result.",[1216,1217,1219,1221],"h3",{"id":1218},"registerdatabasetable-options",[650,1220,652],{}," options",[623,1223,1224,1239],{},[626,1225,1226],{},[629,1227,1228,1231,1234,1237],{},[632,1229,1230],{},"Option",[632,1232,1233],{},"Type",[632,1235,1236],{},"Default",[632,1238,640],{},[642,1240,1241,1263,1282,1300,1322,1341],{},[629,1242,1243,1248,1253,1256],{},[647,1244,1245],{},[650,1246,1247],{},"resolver",[647,1249,1250],{},[650,1251,1252],{},"ReturnType\u003Ctypeof createResolver>",[647,1254,1255],{},"required",[647,1257,1258,1259,1262],{},"Resolves the ",[650,1260,1261],{},"schema"," path.",[629,1264,1265,1269,1274,1276],{},[647,1266,1267],{},[650,1268,1261],{},[647,1270,1271],{},[650,1272,1273],{},"(dialect: string) => string",[647,1275,1255],{},[647,1277,1278,1279,600],{},"The schema file for a dialect, such as ",[650,1280,1281],{},"dialect => `.\u002Fruntime\u002Fdb\u002Fschema.${dialect}`",[629,1283,1284,1289,1294,1297],{},[647,1285,1286],{},[650,1287,1288],{},"name",[647,1290,1291],{},[650,1292,1293],{},"string | string[]",[647,1295,1296],{},"every table export",[647,1298,1299],{},"Restricts which table exports are registered.",[629,1301,1302,1307,1312,1315],{},[647,1303,1304],{},[650,1305,1306],{},"override",[647,1308,1309],{},[650,1310,1311],{},"string",[647,1313,1314],{},"none",[647,1316,1317,1318,1321],{},"A path from the app's root that replaces the generated table. ",[650,1319,1320],{},"'default'"," keeps the generated one.",[629,1323,1324,1329,1333,1338],{},[647,1325,1326],{},[650,1327,1328],{},"extensionFile",[647,1330,1331],{},[650,1332,1273],{},[647,1334,1335],{},[650,1336,1337],{},"server\u002Fdb\u002Fextend.\u003Cdialect>.ts",[647,1339,1340],{},"Moves the extension file each layer can have. Also turns off the legacy lookup.",[629,1342,1343,1348,1352,1354],{},[647,1344,1345],{},[650,1346,1347],{},"factory",[647,1349,1350],{},[650,1351,1311],{},[647,1353,1314],{},[647,1355,724],{},[594,1357,1358,1363],{},[1359,1360,1361],"strong",{},[650,1362,1288],{}," is for restricting only. Auth passes it because which of its tables exist depends on the enabled features:",[763,1365,1368],{"className":765,"code":1366,"filename":1367,"language":768,"meta":769,"style":769},"const tables = ['authUserTokens']\nif (withWebAuthn) tables.push('userCredentials')\nif (withPasswordReset) tables.push('passwordResets')\nif (withMagicLink || withVerifyEmail) tables.push('magicLinks')\n\nregisterDatabaseTable(nuxt, {\n  name: tables,\n  resolver,\n  schema: dialect => `.\u002Fruntime\u002Fdb\u002Fschema.${dialect}`,\n})\n","packages\u002Fauth\u002Fsrc\u002Fmodule.ts",[650,1369,1370,1392,1416,1438,1466,1470,1480,1492,1498,1521],{"__ignoreMap":769},[773,1371,1372,1374,1377,1379,1382,1384,1387,1389],{"class":775,"line":776},[773,1373,1125],{"class":831},[773,1375,1376],{"class":787}," tables ",[773,1378,838],{"class":783},[773,1380,1381],{"class":787}," [",[773,1383,847],{"class":783},[773,1385,1386],{"class":811},"authUserTokens",[773,1388,847],{"class":783},[773,1390,1391],{"class":787},"]\n",[773,1393,1394,1397,1400,1402,1405,1407,1409,1412,1414],{"class":775,"line":818},[773,1395,1396],{"class":779},"if",[773,1398,1399],{"class":787}," (withWebAuthn) tables",[773,1401,600],{"class":783},[773,1403,1404],{"class":841},"push",[773,1406,844],{"class":787},[773,1408,847],{"class":783},[773,1410,1411],{"class":811},"userCredentials",[773,1413,847],{"class":783},[773,1415,935],{"class":787},[773,1417,1418,1420,1423,1425,1427,1429,1431,1434,1436],{"class":775,"line":825},[773,1419,1396],{"class":779},[773,1421,1422],{"class":787}," (withPasswordReset) tables",[773,1424,600],{"class":783},[773,1426,1404],{"class":841},[773,1428,844],{"class":787},[773,1430,847],{"class":783},[773,1432,1433],{"class":811},"passwordResets",[773,1435,847],{"class":783},[773,1437,935],{"class":787},[773,1439,1440,1442,1445,1448,1451,1453,1455,1457,1459,1462,1464],{"class":775,"line":860},[773,1441,1396],{"class":779},[773,1443,1444],{"class":787}," (withMagicLink ",[773,1446,1447],{"class":783},"||",[773,1449,1450],{"class":787}," withVerifyEmail) tables",[773,1452,600],{"class":783},[773,1454,1404],{"class":841},[773,1456,844],{"class":787},[773,1458,847],{"class":783},[773,1460,1461],{"class":811},"magicLinks",[773,1463,847],{"class":783},[773,1465,935],{"class":787},[773,1467,1468],{"class":775,"line":901},[773,1469,822],{"emptyLinePlaceholder":821},[773,1471,1472,1474,1476,1478],{"class":775,"line":929},[773,1473,652],{"class":841},[773,1475,1157],{"class":787},[773,1477,791],{"class":783},[773,1479,857],{"class":783},[773,1481,1482,1485,1487,1490],{"class":775,"line":938},[773,1483,1484],{"class":863},"  name",[773,1486,867],{"class":783},[773,1488,1489],{"class":787}," tables",[773,1491,739],{"class":783},[773,1493,1494,1496],{"class":775,"line":943},[773,1495,1166],{"class":787},[773,1497,739],{"class":783},[773,1499,1500,1502,1504,1506,1508,1510,1513,1515,1517,1519],{"class":775,"line":970},[773,1501,1173],{"class":841},[773,1503,867],{"class":783},[773,1505,1179],{"class":1178},[773,1507,1028],{"class":831},[773,1509,1184],{"class":783},[773,1511,1512],{"class":811},".\u002Fruntime\u002Fdb\u002Fschema.",[773,1514,1190],{"class":783},[773,1516,1193],{"class":787},[773,1518,1196],{"class":783},[773,1520,739],{"class":783},[773,1522,1523,1525],{"class":775,"line":1001},[773,1524,932],{"class":783},[773,1526,935],{"class":787},[594,1528,1529,1530,1532,1533,1535],{},"A ",[650,1531,1288],{}," that the file does not export throws. So does a ",[650,1534,1288],{}," whose export is not a table call.",[611,1537,1539],{"id":1538},"one-schema-file-per-dialect","One schema file per dialect",[594,1541,1542,1543,747,1545,1548,1549,743,1551,1554,1555,1558,1559,747,1562,1565],{},"NuxtHub resolves ",[650,1544,1261],{},[650,1546,1547],{},"file"," for the host app's ",[598,1550,1193],{"href":87},[650,1552,1553],{},"sqlite"," or\n",[650,1556,1557],{},"postgresql",". So every schema and extension file ships twice, as ",[650,1560,1561],{},".sqlite.ts",[650,1563,1564],{},".postgresql.ts",". Both export the\nsame tables, with the same table, column and index names.",[1567,1568,1569,1571,1572,1574],"warning",{},[650,1570,652],{}," throws at build time when the file for the active dialect is missing. The error names the\ndialect, the expected file and the ",[650,1573,1306],{}," option.",[763,1576,1579],{"className":765,"code":1577,"filename":1578,"language":768,"meta":769,"style":769},"import { pgTable, text, serial, integer } from 'drizzle-orm\u002Fpg-core'\n\nexport const users = pgTable('users', {\n  id: serial().primaryKey(),\n  email: text().notNull().unique(),\n})\n\nexport const userPasskeys = pgTable('user_passkeys', {\n  id: serial().primaryKey(),\n  userId: integer().notNull().references(() => users.id, { onDelete: 'cascade' }),\n})\n","src\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.postgresql.ts",[650,1580,1581,1614,1618,1642,1660,1684,1690,1694,1718,1736,1788],{"__ignoreMap":769},[773,1582,1583,1585,1587,1590,1592,1594,1596,1599,1601,1603,1605,1607,1609,1612],{"class":775,"line":776},[773,1584,780],{"class":779},[773,1586,784],{"class":783},[773,1588,1589],{"class":787}," pgTable",[773,1591,791],{"class":783},[773,1593,794],{"class":787},[773,1595,791],{"class":783},[773,1597,1598],{"class":787}," serial",[773,1600,791],{"class":783},[773,1602,799],{"class":787},[773,1604,802],{"class":783},[773,1606,805],{"class":779},[773,1608,808],{"class":783},[773,1610,1611],{"class":811},"drizzle-orm\u002Fpg-core",[773,1613,815],{"class":783},[773,1615,1616],{"class":775,"line":818},[773,1617,822],{"emptyLinePlaceholder":821},[773,1619,1620,1622,1624,1626,1628,1630,1632,1634,1636,1638,1640],{"class":775,"line":825},[773,1621,828],{"class":779},[773,1623,832],{"class":831},[773,1625,835],{"class":787},[773,1627,838],{"class":783},[773,1629,1589],{"class":841},[773,1631,844],{"class":787},[773,1633,847],{"class":783},[773,1635,850],{"class":811},[773,1637,847],{"class":783},[773,1639,791],{"class":783},[773,1641,857],{"class":783},[773,1643,1644,1646,1648,1650,1652,1654,1656,1658],{"class":775,"line":860},[773,1645,864],{"class":863},[773,1647,867],{"class":783},[773,1649,1598],{"class":841},[773,1651,872],{"class":787},[773,1653,600],{"class":783},[773,1655,877],{"class":841},[773,1657,872],{"class":787},[773,1659,739],{"class":783},[773,1661,1662,1664,1666,1668,1670,1672,1674,1676,1678,1680,1682],{"class":775,"line":901},[773,1663,904],{"class":863},[773,1665,867],{"class":783},[773,1667,794],{"class":841},[773,1669,872],{"class":787},[773,1671,600],{"class":783},[773,1673,915],{"class":841},[773,1675,872],{"class":787},[773,1677,600],{"class":783},[773,1679,922],{"class":841},[773,1681,872],{"class":787},[773,1683,739],{"class":783},[773,1685,1686,1688],{"class":775,"line":929},[773,1687,932],{"class":783},[773,1689,935],{"class":787},[773,1691,1692],{"class":775,"line":938},[773,1693,822],{"emptyLinePlaceholder":821},[773,1695,1696,1698,1700,1702,1704,1706,1708,1710,1712,1714,1716],{"class":775,"line":943},[773,1697,828],{"class":779},[773,1699,832],{"class":831},[773,1701,950],{"class":787},[773,1703,838],{"class":783},[773,1705,1589],{"class":841},[773,1707,844],{"class":787},[773,1709,847],{"class":783},[773,1711,961],{"class":811},[773,1713,847],{"class":783},[773,1715,791],{"class":783},[773,1717,857],{"class":783},[773,1719,1720,1722,1724,1726,1728,1730,1732,1734],{"class":775,"line":970},[773,1721,864],{"class":863},[773,1723,867],{"class":783},[773,1725,1598],{"class":841},[773,1727,872],{"class":787},[773,1729,600],{"class":783},[773,1731,877],{"class":841},[773,1733,872],{"class":787},[773,1735,739],{"class":783},[773,1737,1738,1740,1742,1744,1746,1748,1750,1752,1754,1756,1758,1760,1762,1764,1766,1768,1770,1772,1774,1776,1778,1780,1782,1784,1786],{"class":775,"line":1001},[773,1739,1004],{"class":863},[773,1741,867],{"class":783},[773,1743,799],{"class":841},[773,1745,872],{"class":787},[773,1747,600],{"class":783},[773,1749,915],{"class":841},[773,1751,872],{"class":787},[773,1753,600],{"class":783},[773,1755,1021],{"class":841},[773,1757,844],{"class":787},[773,1759,872],{"class":783},[773,1761,1028],{"class":831},[773,1763,1031],{"class":787},[773,1765,600],{"class":783},[773,1767,1036],{"class":787},[773,1769,791],{"class":783},[773,1771,784],{"class":783},[773,1773,1043],{"class":863},[773,1775,867],{"class":783},[773,1777,808],{"class":783},[773,1779,1050],{"class":811},[773,1781,847],{"class":783},[773,1783,802],{"class":783},[773,1785,896],{"class":787},[773,1787,739],{"class":783},[773,1789,1790,1792],{"class":775,"line":1061},[773,1791,932],{"class":783},[773,1793,935],{"class":787},[594,1795,1796],{},"Map the types like this, so the Drizzle data types match:",[623,1798,1799,1807],{},[626,1800,1801],{},[629,1802,1803,1805],{},[632,1804,1553],{},[632,1806,1557],{},[642,1808,1809,1826,1838,1850,1862,1874,1887],{},[629,1810,1811,1819],{},[647,1812,1813,1816,1817,896],{},[650,1814,1815],{},"sqliteTable"," (",[650,1818,812],{},[647,1820,1821,1816,1824,896],{},[650,1822,1823],{},"pgTable",[650,1825,1611],{},[629,1827,1828,1833],{},[647,1829,1830],{},[650,1831,1832],{},"integer().primaryKey({ autoIncrement: true })",[647,1834,1835],{},[650,1836,1837],{},"serial().primaryKey()",[629,1839,1840,1845],{},[647,1841,1842],{},[650,1843,1844],{},"integer({ mode: 'timestamp' })",[647,1846,1847],{},[650,1848,1849],{},"timestamp({ withTimezone: true })",[629,1851,1852,1857],{},[647,1853,1854],{},[650,1855,1856],{},"integer({ mode: 'boolean' })",[647,1858,1859],{},[650,1860,1861],{},"boolean()",[629,1863,1864,1869],{},[647,1865,1866],{},[650,1867,1868],{},"text({ mode: 'json' })",[647,1870,1871],{},[650,1872,1873],{},"jsonb()",[629,1875,1876,1882],{},[647,1877,1878,1881],{},[650,1879,1880],{},"integer()"," holding epoch milliseconds",[647,1883,1884],{},[650,1885,1886],{},"bigint({ mode: 'number' })",[629,1888,1889,1894],{},[647,1890,1891],{},[650,1892,1893],{},"customType({ dataType: () => 'text' })",[647,1895,1896,1897,1900,1901],{},"the same ",[650,1898,1899],{},"customType"," from ",[650,1902,1903],{},"pg-core",[594,1905,1906,1907,1909,1910,1912,1913,606,1916,1919,1920,1923,1924,743,1927,1930,1931,1934],{},"A Module Kit test fails when a ",[650,1908,1561],{}," schema has no ",[650,1911,1564],{}," twin. Keep the two files in step with a\ntest in ",[650,1914,1915],{},"test\u002Fschema-parity.test.ts",[650,1917,1918],{},"expectSchemaParity"," from\n",[650,1921,1922],{},"@frigear-nu\u002Fmodule-kit\u002Ftesting"," throws and lists every difference. It compares tables, columns (Drizzle data type,\nnot null, primary key, unique, defaults, ",[650,1925,1926],{},"$defaultFn",[650,1928,1929],{},"$onUpdateFn","), indexes and foreign keys.\n",[650,1932,1933],{},"compareSchemaDialects"," returns the same list instead of throwing.",[763,1936,1938],{"className":765,"code":1937,"filename":1915,"language":768,"meta":769,"style":769},"import { it } from 'vitest'\nimport { expectSchemaParity } from '@frigear-nu\u002Fmodule-kit\u002Ftesting'\nimport * as sqlite from '..\u002Fsrc\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.sqlite'\nimport * as postgresql from '..\u002Fsrc\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.postgresql'\n\nit('schema.postgresql matches schema.sqlite', () => {\n  expectSchemaParity(sqlite, postgresql)\n})\n",[650,1939,1940,1960,1979,2002,2022,2026,2049,2065],{"__ignoreMap":769},[773,1941,1942,1944,1946,1949,1951,1953,1955,1958],{"class":775,"line":776},[773,1943,780],{"class":779},[773,1945,784],{"class":783},[773,1947,1948],{"class":787}," it",[773,1950,802],{"class":783},[773,1952,805],{"class":779},[773,1954,808],{"class":783},[773,1956,1957],{"class":811},"vitest",[773,1959,815],{"class":783},[773,1961,1962,1964,1966,1969,1971,1973,1975,1977],{"class":775,"line":818},[773,1963,780],{"class":779},[773,1965,784],{"class":783},[773,1967,1968],{"class":787}," expectSchemaParity",[773,1970,802],{"class":783},[773,1972,805],{"class":779},[773,1974,808],{"class":783},[773,1976,1922],{"class":811},[773,1978,815],{"class":783},[773,1980,1981,1983,1986,1989,1992,1995,1997,2000],{"class":775,"line":825},[773,1982,780],{"class":779},[773,1984,1985],{"class":783}," *",[773,1987,1988],{"class":779}," as",[773,1990,1991],{"class":787}," sqlite ",[773,1993,1994],{"class":779},"from",[773,1996,808],{"class":783},[773,1998,1999],{"class":811},"..\u002Fsrc\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.sqlite",[773,2001,815],{"class":783},[773,2003,2004,2006,2008,2010,2013,2015,2017,2020],{"class":775,"line":860},[773,2005,780],{"class":779},[773,2007,1985],{"class":783},[773,2009,1988],{"class":779},[773,2011,2012],{"class":787}," postgresql ",[773,2014,1994],{"class":779},[773,2016,808],{"class":783},[773,2018,2019],{"class":811},"..\u002Fsrc\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.postgresql",[773,2021,815],{"class":783},[773,2023,2024],{"class":775,"line":901},[773,2025,822],{"emptyLinePlaceholder":821},[773,2027,2028,2031,2033,2035,2038,2040,2042,2045,2047],{"class":775,"line":929},[773,2029,2030],{"class":841},"it",[773,2032,844],{"class":787},[773,2034,847],{"class":783},[773,2036,2037],{"class":811},"schema.postgresql matches schema.sqlite",[773,2039,847],{"class":783},[773,2041,791],{"class":783},[773,2043,2044],{"class":783}," ()",[773,2046,1028],{"class":831},[773,2048,857],{"class":783},[773,2050,2051,2054,2056,2058,2060,2063],{"class":775,"line":938},[773,2052,2053],{"class":841},"  expectSchemaParity",[773,2055,844],{"class":863},[773,2057,1553],{"class":787},[773,2059,791],{"class":783},[773,2061,2062],{"class":787}," postgresql",[773,2064,935],{"class":863},[773,2066,2067,2069],{"class":775,"line":943},[773,2068,932],{"class":783},[773,2070,935],{"class":787},[2072,2073,2074,2075,743,2078,743,2081,743,2084,2087,2088,2091,2092,2095],"note",{},"Runtime code must work on both dialects too. Avoid ",[650,2076,2077],{},"db.run",[650,2079,2080],{},"db.batch",[650,2082,2083],{},"PRAGMA",[650,2085,2086],{},"rowid"," and other SQL that only\nSQLite understands, unless you add a PostgreSQL branch. ",[650,2089,2090],{},"changeId"," in ",[650,2093,2094],{},"packages\u002Fusers\u002Fsrc\u002Fruntime\u002Fserver\u002Fuser-store.ts","\nshows one.",[611,2097,2099],{"id":2098},"extending-a-table","Extending a table",[594,2101,2102,2103,2105,2106,2108],{},"Another module adds columns to a table it does not own with ",[650,2104,667],{},". The column file exports, under the\ntable's name, a table call, a plain columns object or a ",[650,2107,682],{}," call:",[763,2110,2112],{"className":765,"code":2111,"filename":1069,"language":768,"meta":769,"style":769},"\u002F\u002F in setup()\nextendDatabaseTable(nuxt, {\n  resolver,\n  file: dialect => `.\u002Fruntime\u002Fdb\u002Fusers.${dialect}`,\n})\n",[650,2113,2114,2118,2128,2134,2158],{"__ignoreMap":769},[773,2115,2116],{"class":775,"line":776},[773,2117,1120],{"class":1119},[773,2119,2120,2122,2124,2126],{"class":775,"line":818},[773,2121,667],{"class":841},[773,2123,1157],{"class":787},[773,2125,791],{"class":783},[773,2127,857],{"class":783},[773,2129,2130,2132],{"class":775,"line":825},[773,2131,1166],{"class":787},[773,2133,739],{"class":783},[773,2135,2136,2139,2141,2143,2145,2147,2150,2152,2154,2156],{"class":775,"line":860},[773,2137,2138],{"class":841},"  file",[773,2140,867],{"class":783},[773,2142,1179],{"class":1178},[773,2144,1028],{"class":831},[773,2146,1184],{"class":783},[773,2148,2149],{"class":811},".\u002Fruntime\u002Fdb\u002Fusers.",[773,2151,1190],{"class":783},[773,2153,1193],{"class":787},[773,2155,1196],{"class":783},[773,2157,739],{"class":783},[773,2159,2160,2162],{"class":775,"line":901},[773,2161,932],{"class":783},[773,2163,935],{"class":787},[763,2165,2168],{"className":765,"code":2166,"filename":2167,"language":768,"meta":769,"style":769},"import { sqliteTable, text } from 'drizzle-orm\u002Fsqlite-core'\n\nexport const users = sqliteTable('users', {\n  locale: text().default('da'),\n})\n","src\u002Fruntime\u002Fdb\u002Fusers.sqlite.ts",[650,2169,2170,2192,2196,2220,2249],{"__ignoreMap":769},[773,2171,2172,2174,2176,2178,2180,2182,2184,2186,2188,2190],{"class":775,"line":776},[773,2173,780],{"class":779},[773,2175,784],{"class":783},[773,2177,788],{"class":787},[773,2179,791],{"class":783},[773,2181,794],{"class":787},[773,2183,802],{"class":783},[773,2185,805],{"class":779},[773,2187,808],{"class":783},[773,2189,812],{"class":811},[773,2191,815],{"class":783},[773,2193,2194],{"class":775,"line":818},[773,2195,822],{"emptyLinePlaceholder":821},[773,2197,2198,2200,2202,2204,2206,2208,2210,2212,2214,2216,2218],{"class":775,"line":825},[773,2199,828],{"class":779},[773,2201,832],{"class":831},[773,2203,835],{"class":787},[773,2205,838],{"class":783},[773,2207,788],{"class":841},[773,2209,844],{"class":787},[773,2211,847],{"class":783},[773,2213,850],{"class":811},[773,2215,847],{"class":783},[773,2217,791],{"class":783},[773,2219,857],{"class":783},[773,2221,2222,2225,2227,2229,2231,2233,2236,2238,2240,2243,2245,2247],{"class":775,"line":860},[773,2223,2224],{"class":863},"  locale",[773,2226,867],{"class":783},[773,2228,794],{"class":841},[773,2230,872],{"class":787},[773,2232,600],{"class":783},[773,2234,2235],{"class":841},"default",[773,2237,844],{"class":787},[773,2239,847],{"class":783},[773,2241,2242],{"class":811},"da",[773,2244,847],{"class":783},[773,2246,896],{"class":787},[773,2248,739],{"class":783},[773,2250,2251,2253],{"class":775,"line":901},[773,2252,932],{"class":783},[773,2254,935],{"class":787},[763,2256,2259],{"className":765,"code":2257,"filename":2258,"language":768,"meta":769,"style":769},"import { pgTable, text } from 'drizzle-orm\u002Fpg-core'\n\nexport const users = pgTable('users', {\n  locale: text().default('da'),\n})\n","src\u002Fruntime\u002Fdb\u002Fusers.postgresql.ts",[650,2260,2261,2283,2287,2311,2337],{"__ignoreMap":769},[773,2262,2263,2265,2267,2269,2271,2273,2275,2277,2279,2281],{"class":775,"line":776},[773,2264,780],{"class":779},[773,2266,784],{"class":783},[773,2268,1589],{"class":787},[773,2270,791],{"class":783},[773,2272,794],{"class":787},[773,2274,802],{"class":783},[773,2276,805],{"class":779},[773,2278,808],{"class":783},[773,2280,1611],{"class":811},[773,2282,815],{"class":783},[773,2284,2285],{"class":775,"line":818},[773,2286,822],{"emptyLinePlaceholder":821},[773,2288,2289,2291,2293,2295,2297,2299,2301,2303,2305,2307,2309],{"class":775,"line":825},[773,2290,828],{"class":779},[773,2292,832],{"class":831},[773,2294,835],{"class":787},[773,2296,838],{"class":783},[773,2298,1589],{"class":841},[773,2300,844],{"class":787},[773,2302,847],{"class":783},[773,2304,850],{"class":811},[773,2306,847],{"class":783},[773,2308,791],{"class":783},[773,2310,857],{"class":783},[773,2312,2313,2315,2317,2319,2321,2323,2325,2327,2329,2331,2333,2335],{"class":775,"line":860},[773,2314,2224],{"class":863},[773,2316,867],{"class":783},[773,2318,794],{"class":841},[773,2320,872],{"class":787},[773,2322,600],{"class":783},[773,2324,2235],{"class":841},[773,2326,844],{"class":787},[773,2328,847],{"class":783},[773,2330,2242],{"class":811},[773,2332,847],{"class":783},[773,2334,896],{"class":787},[773,2336,739],{"class":783},[773,2338,2339,2341],{"class":775,"line":901},[773,2340,932],{"class":783},[773,2342,935],{"class":787},[594,2344,2345],{},"The file is merged only into registered tables it has a matching export for. Other tables are untouched, and so are\nother exports of the file. So you never need to name the table. When the owning module is not installed, nothing\nmatches and the call does nothing.",[623,2347,2348,2360],{},[626,2349,2350],{},[629,2351,2352,2354,2356,2358],{},[632,2353,1230],{},[632,2355,1233],{},[632,2357,1236],{},[632,2359,640],{},[642,2361,2362,2378,2396],{},[629,2363,2364,2368,2372,2374],{},[647,2365,2366],{},[650,2367,1247],{},[647,2369,2370],{},[650,2371,1252],{},[647,2373,1255],{},[647,2375,1258,2376,1262],{},[650,2377,1547],{},[629,2379,2380,2384,2388,2390],{},[647,2381,2382],{},[650,2383,1547],{},[647,2385,2386],{},[650,2387,1273],{},[647,2389,1255],{},[647,2391,2392,2393,2395],{},"The column file for a dialect. A missing file is skipped, with a warning when the ",[650,2394,1553],{}," file exists.",[629,2397,2398,2402,2406,2409],{},[647,2399,2400],{},[650,2401,1288],{},[647,2403,2404],{},[650,2405,1293],{},[647,2407,2408],{},"every table",[647,2410,2411],{},"Offers the file only to these tables. Matching exports already decide, so it is rarely needed.",[1216,2413,2415],{"id":2414},"merge-order","Merge order",[594,2417,2418],{},"Columns are merged in this order. A column that appears again replaces the earlier one and moves to the end of the\ntable.",[2420,2421,2422,2426,2432],"ol",{},[2423,2424,2425],"li",{},"The base schema file of the owning module.",[2423,2427,2428,2429,2431],{},"Files registered with ",[650,2430,667],{},", in registration order.",[2423,2433,2434,2435,2438,2439,2441,2442],{},"For each Nuxt layer, from the base layers towards the host app: the legacy ",[650,2436,2437],{},"server\u002Fdb\u002F\u003Cname>.extend.\u003Cdialect>","\nfile, then the shared ",[650,2440,1337],{},". One shared file can extend several tables:",[763,2443,2446],{"className":765,"code":2444,"filename":2445,"language":768,"meta":769,"style":769},"export const users = defineTableColumns({ locale: text().default('da') })\nexport const posts = defineTableColumns({ summary: text() })\n","server\u002Fdb\u002Fextend.sqlite.ts",[650,2447,2448,2493],{"__ignoreMap":769},[773,2449,2450,2452,2454,2456,2458,2461,2463,2465,2468,2470,2472,2474,2476,2478,2480,2482,2484,2486,2489,2491],{"class":775,"line":776},[773,2451,828],{"class":779},[773,2453,832],{"class":831},[773,2455,835],{"class":787},[773,2457,838],{"class":783},[773,2459,2460],{"class":841}," defineTableColumns",[773,2462,844],{"class":787},[773,2464,882],{"class":783},[773,2466,2467],{"class":863}," locale",[773,2469,867],{"class":783},[773,2471,794],{"class":841},[773,2473,872],{"class":787},[773,2475,600],{"class":783},[773,2477,2235],{"class":841},[773,2479,844],{"class":787},[773,2481,847],{"class":783},[773,2483,2242],{"class":811},[773,2485,847],{"class":783},[773,2487,2488],{"class":787},") ",[773,2490,932],{"class":783},[773,2492,935],{"class":787},[773,2494,2495,2497,2499,2502,2504,2506,2508,2510,2513,2515,2517,2520,2522],{"class":775,"line":818},[773,2496,828],{"class":779},[773,2498,832],{"class":831},[773,2500,2501],{"class":787}," posts ",[773,2503,838],{"class":783},[773,2505,2460],{"class":841},[773,2507,844],{"class":787},[773,2509,882],{"class":783},[773,2511,2512],{"class":863}," summary",[773,2514,867],{"class":783},[773,2516,794],{"class":841},[773,2518,2519],{"class":787},"() ",[773,2521,932],{"class":783},[773,2523,935],{"class":787},[594,2525,2526,2527,2530,2531,2533,2534,2536],{},"Legacy ",[650,2528,2529],{},"\u003Cname>.extend.\u003Cdialect>"," files with a ",[650,2532,2235],{}," export still work. Passing ",[650,2535,1328],{}," replaces the shared\nfile location and turns off the legacy lookup.",[1216,2538,2540],{"id":2539},"constraints-of-schema-files","Constraints of schema files",[1567,2542,2543,2544,2547],{},"Schema and extension files are ",[1359,2545,2546],{},"parsed as text, not executed",". The generated file is built from what the parser\nfinds, so code it does not understand is lost.",[2549,2550,2551,2558,2569,2583],"ul",{},[2423,2552,2553,2554,2557],{},"Only top-level exports initialised by a table call are registered. In an extension file, a plain columns object or a\nsingle-argument wrapper such as ",[650,2555,2556],{},"defineTableColumns({ ... })"," works too.",[2423,2559,2560,2561,2564,2565,2568],{},"Named imports are carried over and de-duplicated, and a value import wins over ",[650,2562,2563],{},"type X",". Relative paths such as\n",[650,2566,2567],{},"'..\u002Ftypes'"," become absolute. Default and namespace imports are not carried over.",[2423,2570,2571,2572,2575,2576,2579,2580,2582],{},"Top-level helpers, constants and type aliases are ",[1359,2573,2574],{},"not"," carried over. Declare what a column needs inline, or\nimport it by name. ",[650,2577,2578],{},"packages\u002Fevents\u002Fsrc\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.sqlite.ts"," writes a ",[650,2581,1899],{}," inline this way.",[2423,2584,2585,2586,2589,2590,2593],{},"Indexes and constraints (the third argument of the table call) of the ",[1359,2587,2588],{},"base"," file are kept. In an ",[1359,2591,2592],{},"extension","\nfile they are dropped with a warning, and so is a SQL table name that differs from the base. Put indexes on\nextension columns in the base file or in a migration.",[1216,2595,234],{"id":2596},"hooks",[594,2598,2599,2600,2602],{},"Module Kit uses two build-time ",[598,2601,2596],{"href":87},". Hook them yourself only to add files by hand.",[623,2604,2605,2617],{},[626,2606,2607],{},[629,2608,2609,2612,2615],{},[632,2610,2611],{},"Hook",[632,2613,2614],{},"Payload",[632,2616,640],{},[642,2618,2619,2639],{},[629,2620,2621,2625,2630],{},[647,2622,2623],{},[650,2624,708],{},[647,2626,2627],{},[650,2628,2629],{},"{ dialect: string, paths: string[] }",[647,2631,2632,2633,2635,2636,600],{},"NuxtHub's hook. ",[650,2634,652],{}," pushes each generated file to ",[650,2637,2638],{},"paths",[629,2640,2641,2646,2651],{},[647,2642,2643],{},[650,2644,2645],{},"module-kit:db:table:extend",[647,2647,2648],{},[650,2649,2650],{},"{ name: string, dialect: string, paths: string[] }",[647,2652,2653,2654,2656,2657,600],{},"Called once per registered table. ",[650,2655,667],{}," pushes its file to ",[650,2658,2638],{},[1216,2660,2662],{"id":2661},"generated-files","Generated files",[594,2664,2665,2666,2669,2670,2673],{},"Merged tables are written to ",[650,2667,2668],{},".nuxt\u002Fmodule-kit\u002Fdb\u002F\u003Ckebab-case table names>.\u003Cdialect>.ts",", such as\n",[650,2671,2672],{},".nuxt\u002Fmodule-kit\u002Fdb\u002Fusers-user-passkeys.sqlite.ts",". A name over 80 characters is shortened and gets a hash suffix.\nNuxtHub builds the schema from exactly these files, so open them when a migration looks wrong.",[594,2675,2676,2677,2680,2681,2684,2685,2688],{},"NuxtHub bundles them into ",[650,2678,2679],{},".nuxt\u002Fhub\u002Fdb\u002Fschema.mjs"," on every boot and every ",[650,2682,2683],{},"nuxt prepare",". It caches the generated\ntypes in ",[650,2686,2687],{},".nuxt\u002Fcache\u002Fnuxthub\u002Fdb\u002F"," and reuses them while the inputs are unchanged, so the bundle takes milliseconds\nafter the first boot. Delete that folder to force a full rebuild.",[611,2690,2692],{"id":2691},"migrations-and-database-backed-module-tests","Migrations and database-backed module tests",[594,2694,1529,2695,2698,2699,2702,2703,600],{},[598,2696,2697],{"href":87},"migration"," is what changes the database. Every app that installs your module needs one,\nincluding each ",[598,2700,2701],{"href":87},"test fixture"," with committed migrations. Fixtures that have them are listed\nby ",[650,2704,2705],{},"ls packages\u002F*\u002Ftest\u002Ffixtures\u002F*\u002Fserver\u002Fdb\u002Fmigrations",[1567,2707,2708],{},"Generate migrations from the app's complete module configuration, including every module that extends a table. A\nmigration generated from the owning module's tables alone misses every extension column.",[1216,2710,2712],{"id":2711},"checking-and-updating-a-fixtures-migrations","Checking and updating a fixture's migrations",[594,2714,2715],{},"Run these steps from the repository root after changing a schema or an extension, for every fixture with committed\nmigrations.",[2717,2718,2720,2725,2735,2793,2797,2807,2811,2814,2818,2829,2975,2998,3002],"steps",{"level":2719},"4",[2721,2722,2724],"h4",{"id":2723},"check-the-fixture","Check the fixture",[594,2726,2727,2730,2731,2734],{},[650,2728,2729],{},"nuxt db generate"," prepares the fixture, so its schema includes every extension, and compares it with the committed\nmigrations. Pass ",[650,2732,2733],{},"--cwd"," as an absolute path: a relative one is resolved twice and fails.",[763,2736,2740],{"className":2737,"code":2738,"language":2739,"meta":769,"style":769},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm --filter @frigear-nu\u002F\u003Cpackage> exec nuxt db generate --cwd \"$PWD\u002Fpackages\u002F\u003Cpackage>\u002Ftest\u002Ffixtures\u002F\u003Cfixture>\"\n","bash",[650,2741,2742],{"__ignoreMap":769},[773,2743,2744,2748,2751,2754,2757,2760,2763,2766,2769,2772,2775,2778,2781,2784,2787,2790],{"class":775,"line":776},[773,2745,2747],{"class":2746},"sBMFI","pnpm",[773,2749,2750],{"class":811}," --filter",[773,2752,2753],{"class":811}," @frigear-nu\u002F",[773,2755,2756],{"class":783},"\u003C",[773,2758,2759],{"class":811},"packag",[773,2761,2762],{"class":787},"e",[773,2764,2765],{"class":783},">",[773,2767,2768],{"class":811}," exec",[773,2770,2771],{"class":811}," nuxt",[773,2773,2774],{"class":811}," db",[773,2776,2777],{"class":811}," generate",[773,2779,2780],{"class":811}," --cwd",[773,2782,2783],{"class":783}," \"",[773,2785,2786],{"class":787},"$PWD",[773,2788,2789],{"class":811},"\u002Fpackages\u002F\u003Cpackage>\u002Ftest\u002Ffixtures\u002F\u003Cfixture>",[773,2791,2792],{"class":783},"\"\n",[2721,2794,2796],{"id":2795},"read-the-result","Read the result",[594,2798,2799,2802,2803,2806],{},[650,2800,2801],{},"No schema changes, nothing to migrate"," and a clean ",[650,2804,2805],{},"git status"," mean the fixture is in sync, and you are done. Any\nother output means the fixture needs a new migration, and the command has already written one.",[2721,2808,2810],{"id":2809},"keep-or-rename-the-migration-it-wrote","Keep or rename the migration it wrote",[594,2812,2813],{},"The fixture needs that migration. Keep it and go to the last step, or delete it and generate it again with a name in\nthe next step. Delete a stray migration without replacing it only when the schema change itself was unintended.",[2721,2815,2817],{"id":2816},"generate-a-named-migration-optional","Generate a named migration (optional)",[2072,2819,2820,2821,2824,2825,2828],{},"With NuxtHub ",[650,2822,2823],{},"0.10.8"," the command does not pass ",[650,2826,2827],{},"--name"," on correctly. To pick the migration's name, use this manual\nflow, which gives the same result.",[763,2830,2832],{"className":2737,"code":2831,"language":2739,"meta":769,"style":769},"pnpm --filter @frigear-nu\u002F\u003Cpackage> exec nuxt prepare \"$PWD\u002Fpackages\u002F\u003Cpackage>\u002Ftest\u002Ffixtures\u002F\u003Cfixture>\"\npnpm --filter @frigear-nu\u002F\u003Cpackage> exec drizzle-kit generate \\\n  --dialect sqlite \\\n  --schema \"$PWD\u002Fpackages\u002F\u003Cpackage>\u002Ftest\u002Ffixtures\u002F\u003Cfixture>\u002F.nuxt\u002Fhub\u002Fdb\u002Fschema.mjs\" \\\n  --out test\u002Ffixtures\u002F\u003Cfixture>\u002Fserver\u002Fdb\u002Fmigrations\u002Fsqlite \\\n  --name \u003Cmigration-name>\npnpm --filter @frigear-nu\u002F\u003Cpackage> test\n",[650,2833,2834,2865,2891,2901,2918,2940,2956],{"__ignoreMap":769},[773,2835,2836,2838,2840,2842,2844,2846,2848,2850,2852,2854,2857,2859,2861,2863],{"class":775,"line":776},[773,2837,2747],{"class":2746},[773,2839,2750],{"class":811},[773,2841,2753],{"class":811},[773,2843,2756],{"class":783},[773,2845,2759],{"class":811},[773,2847,2762],{"class":787},[773,2849,2765],{"class":783},[773,2851,2768],{"class":811},[773,2853,2771],{"class":811},[773,2855,2856],{"class":811}," prepare",[773,2858,2783],{"class":783},[773,2860,2786],{"class":787},[773,2862,2789],{"class":811},[773,2864,2792],{"class":783},[773,2866,2867,2869,2871,2873,2875,2877,2879,2881,2883,2886,2888],{"class":775,"line":818},[773,2868,2747],{"class":2746},[773,2870,2750],{"class":811},[773,2872,2753],{"class":811},[773,2874,2756],{"class":783},[773,2876,2759],{"class":811},[773,2878,2762],{"class":787},[773,2880,2765],{"class":783},[773,2882,2768],{"class":811},[773,2884,2885],{"class":811}," drizzle-kit",[773,2887,2777],{"class":811},[773,2889,2890],{"class":787}," \\\n",[773,2892,2893,2896,2899],{"class":775,"line":825},[773,2894,2895],{"class":811},"  --dialect",[773,2897,2898],{"class":811}," sqlite",[773,2900,2890],{"class":787},[773,2902,2903,2906,2908,2910,2913,2916],{"class":775,"line":860},[773,2904,2905],{"class":811},"  --schema",[773,2907,2783],{"class":783},[773,2909,2786],{"class":787},[773,2911,2912],{"class":811},"\u002Fpackages\u002F\u003Cpackage>\u002Ftest\u002Ffixtures\u002F\u003Cfixture>\u002F.nuxt\u002Fhub\u002Fdb\u002Fschema.mjs",[773,2914,2915],{"class":783},"\"",[773,2917,2890],{"class":787},[773,2919,2920,2923,2926,2928,2931,2933,2935,2938],{"class":775,"line":901},[773,2921,2922],{"class":811},"  --out",[773,2924,2925],{"class":811}," test\u002Ffixtures\u002F",[773,2927,2756],{"class":783},[773,2929,2930],{"class":811},"fixtur",[773,2932,2762],{"class":787},[773,2934,2765],{"class":783},[773,2936,2937],{"class":811},"\u002Fserver\u002Fdb\u002Fmigrations\u002Fsqlite",[773,2939,2890],{"class":787},[773,2941,2942,2945,2948,2951,2953],{"class":775,"line":929},[773,2943,2944],{"class":811},"  --name",[773,2946,2947],{"class":783}," \u003C",[773,2949,2950],{"class":811},"migration-nam",[773,2952,2762],{"class":787},[773,2954,2955],{"class":783},">\n",[773,2957,2958,2960,2962,2964,2966,2968,2970,2972],{"class":775,"line":938},[773,2959,2747],{"class":2746},[773,2961,2750],{"class":811},[773,2963,2753],{"class":811},[773,2965,2756],{"class":783},[773,2967,2759],{"class":811},[773,2969,2762],{"class":787},[773,2971,2765],{"class":783},[773,2973,2974],{"class":811}," test\n",[594,2976,2977,2978,2981,2982,2985,2986,2989,2990,2993,2994,2997],{},"The filtered ",[650,2979,2980],{},"exec"," runs in the package folder, so ",[650,2983,2984],{},"--out"," is relative to the package and ",[650,2987,2988],{},"--schema"," is absolute. Use\n",[650,2991,2992],{},"generate",", not ",[650,2995,2996],{},"drizzle-kit check",": it creates a migration only when something changed.",[2721,2999,3001],{"id":3000},"commit-the-migration","Commit the migration",[3003,3004,3005,3006,747,3009,3012,3013,743,3016,743,3019,3022,3023,600],"caution",{},"Commit the SQL with ",[650,3007,3008],{},"meta\u002F*_snapshot.json",[650,3010,3011],{},"meta\u002F_journal.json",". They are versioned schema history, so never edit\nor delete a committed migration. Never commit ",[650,3014,3015],{},".nuxt",[650,3017,3018],{},".data",[650,3020,3021],{},"node_modules"," or ",[650,3024,3025],{},"dist",[3027,3028,3031,3034,3035,3037,3038,3040],"callout",{"color":3029,"icon":3030},"success","i-lucide-check",[1359,3032,3033],{},"What you should see:"," the first step prints ",[650,3036,2801],{},", and ",[650,3039,2805],{}," shows only\nthe migration you mean to commit.",[1216,3042,3044],{"id":3043},"database-backed-fixture-requirements","Database-backed fixture requirements",[2549,3046,3047,3050,3067,3078,3084,3087],{},[2423,3048,3049],{},"Configure a test-only session password and a local SQLite or libsql database.",[2423,3051,3052,3053,3022,3056,3059,3060,3063,3064,3066],{},"A fixture that includes a module using ",[650,3054,3055],{},"requireAuth",[650,3057,3058],{},"requireUser"," needs the ",[650,3061,3062],{},"auth_user_tokens"," migration. The\n",[598,3065,168],{"href":169}," fixtures show it.",[2423,3068,3069,3070,3073,3074,3077],{},"Use ",[650,3071,3072],{},"dev: true"," in the ",[650,3075,3076],{},"@nuxt\u002Ftest-utils\u002Fe2e"," setup, so NuxtHub applies the fixture's committed migrations at\nstartup. Turning off build-time migrations does not turn these off.",[2423,3079,3080,3081,3083],{},"Remove only the fixture's own ",[650,3082,3018],{}," folder before the suite, and clean it up afterwards.",[2423,3085,3086],{},"Assert a request's HTTP status, with the response body as the message, before its side effects, such as a session\ncookie. The underlying HTTP or database error then shows.",[2423,3088,3089,3090,747,3092,3094],{},"Run the suite twice, to check that migrations apply and that runs do not share data.\n",[598,3091,191],{"href":192},[598,3093,279],{"href":280}," have working fixture lifecycles.",[611,3096,3098],{"id":3097},"next-steps","Next steps",[2549,3100,3101,3106,3111],{},[2423,3102,3103,3105],{},[598,3104,533],{"href":534}," – add a table to your module step by step.",[2423,3107,3108,3110],{},[598,3109,537],{"href":538}," – boot the database-backed test fixture.",[2423,3112,3113,3116],{},[598,3114,3115],{"href":388},"Module Kit server toolkit"," – serve the table from your routes.",[3118,3119,3120],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":769,"searchDepth":818,"depth":818,"links":3122},[3123,3124,3128,3129,3135,3139],{"id":613,"depth":818,"text":614},{"id":753,"depth":818,"text":754,"children":3125},[3126],{"id":1218,"depth":825,"text":3127},"registerDatabaseTable options",{"id":1538,"depth":818,"text":1539},{"id":2098,"depth":818,"text":2099,"children":3130},[3131,3132,3133,3134],{"id":2414,"depth":825,"text":2415},{"id":2539,"depth":825,"text":2540},{"id":2596,"depth":825,"text":234},{"id":2661,"depth":825,"text":2662},{"id":2691,"depth":818,"text":2692,"children":3136},[3137,3138],{"id":2711,"depth":825,"text":2712},{"id":3043,"depth":825,"text":3044},{"id":3097,"depth":818,"text":3098},"Give your module tables, add columns to another module's table, ship both dialects and commit migrations.","md",null,{},{"title":399},{"title":589,"description":3140},"qdtus_THQvIvbjyfMJxY5HrRkQVBrgcknbnuwE0ceUE",[3148,3150],{"title":395,"path":396,"stem":397,"description":3149,"children":-1},"Ship a module's strings as locale files, and override any module string from your app.",{"title":403,"path":404,"stem":405,"description":3151,"children":-1},"Send email, SMS and simple notifications from any module, with the delivery service chosen once by your app.",1794503152548]