[{"data":1,"prerenderedAt":2149},["ShallowReactive",2],{"navigation_docs":3,"-get-started-configuration":587,"-get-started-configuration-surround":2144},[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":26,"body":589,"description":2137,"extension":2138,"links":2139,"meta":2140,"navigation":2141,"path":27,"seo":2142,"stem":28,"__hash__":2143},"docs\u002F1.get-started\u002F4.configuration.md",{"type":590,"value":591,"toc":2131},"minimark",[592,599,609,626,631,638,642,662,679,685,1689,1692,1889,1896,1914,1924,1934,1942,1946,1969,1975,2039,2053,2063,2066,2087,2093,2111,2115,2127],[593,594,595],"p",{},[596,597,598],"strong",{},"What you'll have afterwards:",[600,601,602,606],"ul",{},[603,604,605],"li",{},"You can change what a module does by editing its options.",[603,607,608],{},"You can set a secret or a per-environment value without putting it in code.",[593,610,611,612,616,617,621,622,625],{},"A Frigear app is configured in two places. ",[613,614,615],"code",{},"apps\u002Fweb\u002Fnuxt.config.ts"," holds the modules and their\n",[618,619,620],"a",{"href":87},"options",". ",[613,623,624],{},"apps\u002Fweb\u002F.env"," holds secrets and values that differ per environment.",[627,628,630],"h2",{"id":629},"prerequisites","Prerequisites",[593,632,633,634,637],{},"A project created in ",[618,635,16],{"href":636},"\u002Fget-started\u002Finstallation#_1-create-the-project",".",[627,639,641],{"id":640},"_1-set-module-options-in-nuxtconfigts","1. Set module options in nuxt.config.ts",[593,643,644,645,648,649,648,652,648,655,658,659,637],{},"Each module has its own config key, such as ",[613,646,647],{},"account",", ",[613,650,651],{},"admin",[613,653,654],{},"users",[613,656,657],{},"notify"," or ",[613,660,661],{},"authentication",[663,664,665,666,668,669,671,672,675,676,678],"warning",{},"The key of ",[618,667,168],{"href":169}," is ",[613,670,661],{},", not ",[613,673,674],{},"auth",". The ",[613,677,674],{}," key belongs to nuxt-auth-utils.",[593,680,681,682,684],{},"Every module's options are listed on its page under ",[618,683,156],{"href":158},". This is the starter's config:",[686,687,692],"pre",{"className":688,"code":689,"filename":615,"language":690,"meta":691,"style":691},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F A Nuxt 4 app on the @frigear-nu modules: register\u002Flogin, \u002Faccount and \u002Fadmin with user management.\n\u002F\u002F Every module option is documented in https:\u002F\u002Fdocs.frigear.dev\u002Fmodules\nexport default defineNuxtConfig({\n  \u002F\u002F Order matters only for readability: each module installs the ones it depends on (auth, notify, ui, ...).\n  modules: [\n    '@nuxt\u002Feslint',\n    '@nuxthub\u002Fcore',\n    '@nuxt\u002Fui',\n    '@frigear-nu\u002Fmenu',\n    '@frigear-nu\u002Fwidget',\n    '@frigear-nu\u002Fusers',\n    '@frigear-nu\u002Fauthorization',\n    '@frigear-nu\u002Faccount',\n    '@frigear-nu\u002Fadmin',\n  ],\n\n  devtools: { enabled: true },\n  css: ['~\u002Fassets\u002Fcss\u002Fmain.css'],\n\n  runtimeConfig: {\n    \u002F\u002F NUXT_ACL_ADMINS: comma separated emails that are always admins (see server\u002Fplugins\u002Fauthorization-roles.ts).\n    aclAdmins: '',\n    public: {\n      \u002F\u002F NUXT_PUBLIC_SITE_URL: the public URL of the site. Emailed links (password reset, sign-in, verification) point\n      \u002F\u002F here; in production they fail until it is set.\n      siteUrl: '',\n    },\n  },\n\n  compatibilityDate: '2026-06-30',\n\n  \u002F\u002F Local sqlite in .data\u002F; NuxtHub applies server\u002Fdb\u002Fmigrations on `nuxt dev` and `nuxt build`.\n  \u002F\u002F For production, point `connection` at your database (Turso, D1, Postgres): https:\u002F\u002Fhub.nuxt.com\u002Fdocs\u002Fdatabase\n  hub: {\n    db: {\n      dialect: 'sqlite',\n      driver: 'libsql',\n      connection: { url: 'file:.\u002F.data\u002Fdb\u002Fsqlite.db' },\n    },\n  },\n\n  \u002F\u002F @frigear-nu\u002Faccount: the \u002Faccount pages.\n  account: {\n    settings: {\n      pages: { index: true, profile: true, security: true, apiTokens: true },\n    },\n  },\n\n  \u002F\u002F @frigear-nu\u002Fauth: sign-in with email\u002Fpassword (on by default) and passkeys, which users add on\n  \u002F\u002F \u002Faccount\u002Fsecurity. Passkeys are bound to the domain the site runs on: choose the production domain before launch.\n  \u002F\u002F `verifyEmail`: a new account signs in through the emailed link, which proves the address (NUXT_ACL_ADMINS counts\n  \u002F\u002F only for verified addresses).\n  authentication: {\n    settings: {\n      webAuthn: true,\n      verifyEmail: true,\n      afterLogin: '\u002Faccount',\n      pages: { login: true, register: true },\n    },\n  },\n\n  \u002F\u002F @frigear-nu\u002Fauthorization: guests on a guarded page (\u002Faccount\u002F**, \u002Fadmin\u002F**) go to the login page. A role is a\n  \u002F\u002F bundle of permissions; `server\u002Fplugins\u002Fauthorization-roles.ts` makes verified NUXT_ACL_ADMINS addresses admins.\n  authorization: {\n    redirectTo: '\u002Flogin',\n    defaultRoles: ['user'],\n    roles: {\n      admin: { label: 'Admin', grant: ['*'] },\n      user: { label: 'User' },\n    },\n  },\n\n  eslint: {\n    config: {\n      stylistic: true,\n    },\n  },\n\n  \u002F\u002F @frigear-nu\u002Fnotify: emails (password reset, ...) are printed to the terminal until you configure a driver.\n  notify: {\n    email: { driver: 'log' },\n  },\n\n  \u002F\u002F @frigear-nu\u002Fusers: \u002Fadmin\u002Fusers; who may do what is decided by the roles' permissions (`authorization.roles`).\n  users: {\n    settings: {\n      admin: true,\n      profilePath: '\u002Faccount\u002Fprofile',\n      \u002F\u002F A new email address takes effect once its owner confirms it from the emailed link.\n      verifyEmailChange: true,\n    },\n  },\n})\n","ts","",[613,693,694,703,709,731,737,750,766,778,790,802,814,826,838,850,862,870,877,900,923,928,939,945,958,968,974,980,992,998,1004,1009,1027,1032,1038,1044,1054,1064,1081,1098,1122,1127,1132,1137,1143,1153,1163,1210,1215,1220,1225,1231,1237,1243,1249,1259,1268,1280,1292,1309,1336,1341,1346,1351,1357,1363,1373,1390,1411,1421,1464,1487,1492,1497,1502,1512,1522,1534,1539,1544,1549,1555,1565,1589,1594,1599,1605,1615,1624,1635,1652,1658,1670,1675,1680],{"__ignoreMap":691},[695,696,699],"span",{"class":697,"line":698},"line",1,[695,700,702],{"class":701},"sHwdD","\u002F\u002F A Nuxt 4 app on the @frigear-nu modules: register\u002Flogin, \u002Faccount and \u002Fadmin with user management.\n",[695,704,706],{"class":697,"line":705},2,[695,707,708],{"class":701},"\u002F\u002F Every module option is documented in https:\u002F\u002Fdocs.frigear.dev\u002Fmodules\n",[695,710,712,716,719,723,727],{"class":697,"line":711},3,[695,713,715],{"class":714},"s7zQu","export",[695,717,718],{"class":714}," default",[695,720,722],{"class":721},"s2Zo4"," defineNuxtConfig",[695,724,726],{"class":725},"sTEyZ","(",[695,728,730],{"class":729},"sMK4o","{\n",[695,732,734],{"class":697,"line":733},4,[695,735,736],{"class":701},"  \u002F\u002F Order matters only for readability: each module installs the ones it depends on (auth, notify, ui, ...).\n",[695,738,740,744,747],{"class":697,"line":739},5,[695,741,743],{"class":742},"swJcz","  modules",[695,745,746],{"class":729},":",[695,748,749],{"class":725}," [\n",[695,751,753,756,760,763],{"class":697,"line":752},6,[695,754,755],{"class":729},"    '",[695,757,759],{"class":758},"sfazB","@nuxt\u002Feslint",[695,761,762],{"class":729},"'",[695,764,765],{"class":729},",\n",[695,767,769,771,774,776],{"class":697,"line":768},7,[695,770,755],{"class":729},[695,772,773],{"class":758},"@nuxthub\u002Fcore",[695,775,762],{"class":729},[695,777,765],{"class":729},[695,779,781,783,786,788],{"class":697,"line":780},8,[695,782,755],{"class":729},[695,784,785],{"class":758},"@nuxt\u002Fui",[695,787,762],{"class":729},[695,789,765],{"class":729},[695,791,793,795,798,800],{"class":697,"line":792},9,[695,794,755],{"class":729},[695,796,797],{"class":758},"@frigear-nu\u002Fmenu",[695,799,762],{"class":729},[695,801,765],{"class":729},[695,803,805,807,810,812],{"class":697,"line":804},10,[695,806,755],{"class":729},[695,808,809],{"class":758},"@frigear-nu\u002Fwidget",[695,811,762],{"class":729},[695,813,765],{"class":729},[695,815,817,819,822,824],{"class":697,"line":816},11,[695,818,755],{"class":729},[695,820,821],{"class":758},"@frigear-nu\u002Fusers",[695,823,762],{"class":729},[695,825,765],{"class":729},[695,827,829,831,834,836],{"class":697,"line":828},12,[695,830,755],{"class":729},[695,832,833],{"class":758},"@frigear-nu\u002Fauthorization",[695,835,762],{"class":729},[695,837,765],{"class":729},[695,839,841,843,846,848],{"class":697,"line":840},13,[695,842,755],{"class":729},[695,844,845],{"class":758},"@frigear-nu\u002Faccount",[695,847,762],{"class":729},[695,849,765],{"class":729},[695,851,853,855,858,860],{"class":697,"line":852},14,[695,854,755],{"class":729},[695,856,857],{"class":758},"@frigear-nu\u002Fadmin",[695,859,762],{"class":729},[695,861,765],{"class":729},[695,863,865,868],{"class":697,"line":864},15,[695,866,867],{"class":725},"  ]",[695,869,765],{"class":729},[695,871,873],{"class":697,"line":872},16,[695,874,876],{"emptyLinePlaceholder":875},true,"\n",[695,878,880,883,885,888,891,893,897],{"class":697,"line":879},17,[695,881,882],{"class":742},"  devtools",[695,884,746],{"class":729},[695,886,887],{"class":729}," {",[695,889,890],{"class":742}," enabled",[695,892,746],{"class":729},[695,894,896],{"class":895},"sfNiH"," true",[695,898,899],{"class":729}," },\n",[695,901,903,906,908,911,913,916,918,921],{"class":697,"line":902},18,[695,904,905],{"class":742},"  css",[695,907,746],{"class":729},[695,909,910],{"class":725}," [",[695,912,762],{"class":729},[695,914,915],{"class":758},"~\u002Fassets\u002Fcss\u002Fmain.css",[695,917,762],{"class":729},[695,919,920],{"class":725},"]",[695,922,765],{"class":729},[695,924,926],{"class":697,"line":925},19,[695,927,876],{"emptyLinePlaceholder":875},[695,929,931,934,936],{"class":697,"line":930},20,[695,932,933],{"class":742},"  runtimeConfig",[695,935,746],{"class":729},[695,937,938],{"class":729}," {\n",[695,940,942],{"class":697,"line":941},21,[695,943,944],{"class":701},"    \u002F\u002F NUXT_ACL_ADMINS: comma separated emails that are always admins (see server\u002Fplugins\u002Fauthorization-roles.ts).\n",[695,946,948,951,953,956],{"class":697,"line":947},22,[695,949,950],{"class":742},"    aclAdmins",[695,952,746],{"class":729},[695,954,955],{"class":729}," ''",[695,957,765],{"class":729},[695,959,961,964,966],{"class":697,"line":960},23,[695,962,963],{"class":742},"    public",[695,965,746],{"class":729},[695,967,938],{"class":729},[695,969,971],{"class":697,"line":970},24,[695,972,973],{"class":701},"      \u002F\u002F NUXT_PUBLIC_SITE_URL: the public URL of the site. Emailed links (password reset, sign-in, verification) point\n",[695,975,977],{"class":697,"line":976},25,[695,978,979],{"class":701},"      \u002F\u002F here; in production they fail until it is set.\n",[695,981,983,986,988,990],{"class":697,"line":982},26,[695,984,985],{"class":742},"      siteUrl",[695,987,746],{"class":729},[695,989,955],{"class":729},[695,991,765],{"class":729},[695,993,995],{"class":697,"line":994},27,[695,996,997],{"class":729},"    },\n",[695,999,1001],{"class":697,"line":1000},28,[695,1002,1003],{"class":729},"  },\n",[695,1005,1007],{"class":697,"line":1006},29,[695,1008,876],{"emptyLinePlaceholder":875},[695,1010,1012,1015,1017,1020,1023,1025],{"class":697,"line":1011},30,[695,1013,1014],{"class":742},"  compatibilityDate",[695,1016,746],{"class":729},[695,1018,1019],{"class":729}," '",[695,1021,1022],{"class":758},"2026-06-30",[695,1024,762],{"class":729},[695,1026,765],{"class":729},[695,1028,1030],{"class":697,"line":1029},31,[695,1031,876],{"emptyLinePlaceholder":875},[695,1033,1035],{"class":697,"line":1034},32,[695,1036,1037],{"class":701},"  \u002F\u002F Local sqlite in .data\u002F; NuxtHub applies server\u002Fdb\u002Fmigrations on `nuxt dev` and `nuxt build`.\n",[695,1039,1041],{"class":697,"line":1040},33,[695,1042,1043],{"class":701},"  \u002F\u002F For production, point `connection` at your database (Turso, D1, Postgres): https:\u002F\u002Fhub.nuxt.com\u002Fdocs\u002Fdatabase\n",[695,1045,1047,1050,1052],{"class":697,"line":1046},34,[695,1048,1049],{"class":742},"  hub",[695,1051,746],{"class":729},[695,1053,938],{"class":729},[695,1055,1057,1060,1062],{"class":697,"line":1056},35,[695,1058,1059],{"class":742},"    db",[695,1061,746],{"class":729},[695,1063,938],{"class":729},[695,1065,1067,1070,1072,1074,1077,1079],{"class":697,"line":1066},36,[695,1068,1069],{"class":742},"      dialect",[695,1071,746],{"class":729},[695,1073,1019],{"class":729},[695,1075,1076],{"class":758},"sqlite",[695,1078,762],{"class":729},[695,1080,765],{"class":729},[695,1082,1084,1087,1089,1091,1094,1096],{"class":697,"line":1083},37,[695,1085,1086],{"class":742},"      driver",[695,1088,746],{"class":729},[695,1090,1019],{"class":729},[695,1092,1093],{"class":758},"libsql",[695,1095,762],{"class":729},[695,1097,765],{"class":729},[695,1099,1101,1104,1106,1108,1111,1113,1115,1118,1120],{"class":697,"line":1100},38,[695,1102,1103],{"class":742},"      connection",[695,1105,746],{"class":729},[695,1107,887],{"class":729},[695,1109,1110],{"class":742}," url",[695,1112,746],{"class":729},[695,1114,1019],{"class":729},[695,1116,1117],{"class":758},"file:.\u002F.data\u002Fdb\u002Fsqlite.db",[695,1119,762],{"class":729},[695,1121,899],{"class":729},[695,1123,1125],{"class":697,"line":1124},39,[695,1126,997],{"class":729},[695,1128,1130],{"class":697,"line":1129},40,[695,1131,1003],{"class":729},[695,1133,1135],{"class":697,"line":1134},41,[695,1136,876],{"emptyLinePlaceholder":875},[695,1138,1140],{"class":697,"line":1139},42,[695,1141,1142],{"class":701},"  \u002F\u002F @frigear-nu\u002Faccount: the \u002Faccount pages.\n",[695,1144,1146,1149,1151],{"class":697,"line":1145},43,[695,1147,1148],{"class":742},"  account",[695,1150,746],{"class":729},[695,1152,938],{"class":729},[695,1154,1156,1159,1161],{"class":697,"line":1155},44,[695,1157,1158],{"class":742},"    settings",[695,1160,746],{"class":729},[695,1162,938],{"class":729},[695,1164,1166,1169,1171,1173,1176,1178,1180,1183,1186,1188,1190,1192,1195,1197,1199,1201,1204,1206,1208],{"class":697,"line":1165},45,[695,1167,1168],{"class":742},"      pages",[695,1170,746],{"class":729},[695,1172,887],{"class":729},[695,1174,1175],{"class":742}," index",[695,1177,746],{"class":729},[695,1179,896],{"class":895},[695,1181,1182],{"class":729},",",[695,1184,1185],{"class":742}," profile",[695,1187,746],{"class":729},[695,1189,896],{"class":895},[695,1191,1182],{"class":729},[695,1193,1194],{"class":742}," security",[695,1196,746],{"class":729},[695,1198,896],{"class":895},[695,1200,1182],{"class":729},[695,1202,1203],{"class":742}," apiTokens",[695,1205,746],{"class":729},[695,1207,896],{"class":895},[695,1209,899],{"class":729},[695,1211,1213],{"class":697,"line":1212},46,[695,1214,997],{"class":729},[695,1216,1218],{"class":697,"line":1217},47,[695,1219,1003],{"class":729},[695,1221,1223],{"class":697,"line":1222},48,[695,1224,876],{"emptyLinePlaceholder":875},[695,1226,1228],{"class":697,"line":1227},49,[695,1229,1230],{"class":701},"  \u002F\u002F @frigear-nu\u002Fauth: sign-in with email\u002Fpassword (on by default) and passkeys, which users add on\n",[695,1232,1234],{"class":697,"line":1233},50,[695,1235,1236],{"class":701},"  \u002F\u002F \u002Faccount\u002Fsecurity. Passkeys are bound to the domain the site runs on: choose the production domain before launch.\n",[695,1238,1240],{"class":697,"line":1239},51,[695,1241,1242],{"class":701},"  \u002F\u002F `verifyEmail`: a new account signs in through the emailed link, which proves the address (NUXT_ACL_ADMINS counts\n",[695,1244,1246],{"class":697,"line":1245},52,[695,1247,1248],{"class":701},"  \u002F\u002F only for verified addresses).\n",[695,1250,1252,1255,1257],{"class":697,"line":1251},53,[695,1253,1254],{"class":742},"  authentication",[695,1256,746],{"class":729},[695,1258,938],{"class":729},[695,1260,1262,1264,1266],{"class":697,"line":1261},54,[695,1263,1158],{"class":742},[695,1265,746],{"class":729},[695,1267,938],{"class":729},[695,1269,1271,1274,1276,1278],{"class":697,"line":1270},55,[695,1272,1273],{"class":742},"      webAuthn",[695,1275,746],{"class":729},[695,1277,896],{"class":895},[695,1279,765],{"class":729},[695,1281,1283,1286,1288,1290],{"class":697,"line":1282},56,[695,1284,1285],{"class":742},"      verifyEmail",[695,1287,746],{"class":729},[695,1289,896],{"class":895},[695,1291,765],{"class":729},[695,1293,1295,1298,1300,1302,1305,1307],{"class":697,"line":1294},57,[695,1296,1297],{"class":742},"      afterLogin",[695,1299,746],{"class":729},[695,1301,1019],{"class":729},[695,1303,1304],{"class":758},"\u002Faccount",[695,1306,762],{"class":729},[695,1308,765],{"class":729},[695,1310,1312,1314,1316,1318,1321,1323,1325,1327,1330,1332,1334],{"class":697,"line":1311},58,[695,1313,1168],{"class":742},[695,1315,746],{"class":729},[695,1317,887],{"class":729},[695,1319,1320],{"class":742}," login",[695,1322,746],{"class":729},[695,1324,896],{"class":895},[695,1326,1182],{"class":729},[695,1328,1329],{"class":742}," register",[695,1331,746],{"class":729},[695,1333,896],{"class":895},[695,1335,899],{"class":729},[695,1337,1339],{"class":697,"line":1338},59,[695,1340,997],{"class":729},[695,1342,1344],{"class":697,"line":1343},60,[695,1345,1003],{"class":729},[695,1347,1349],{"class":697,"line":1348},61,[695,1350,876],{"emptyLinePlaceholder":875},[695,1352,1354],{"class":697,"line":1353},62,[695,1355,1356],{"class":701},"  \u002F\u002F @frigear-nu\u002Fauthorization: guests on a guarded page (\u002Faccount\u002F**, \u002Fadmin\u002F**) go to the login page. A role is a\n",[695,1358,1360],{"class":697,"line":1359},63,[695,1361,1362],{"class":701},"  \u002F\u002F bundle of permissions; `server\u002Fplugins\u002Fauthorization-roles.ts` makes verified NUXT_ACL_ADMINS addresses admins.\n",[695,1364,1366,1369,1371],{"class":697,"line":1365},64,[695,1367,1368],{"class":742},"  authorization",[695,1370,746],{"class":729},[695,1372,938],{"class":729},[695,1374,1376,1379,1381,1383,1386,1388],{"class":697,"line":1375},65,[695,1377,1378],{"class":742},"    redirectTo",[695,1380,746],{"class":729},[695,1382,1019],{"class":729},[695,1384,1385],{"class":758},"\u002Flogin",[695,1387,762],{"class":729},[695,1389,765],{"class":729},[695,1391,1393,1396,1398,1400,1402,1405,1407,1409],{"class":697,"line":1392},66,[695,1394,1395],{"class":742},"    defaultRoles",[695,1397,746],{"class":729},[695,1399,910],{"class":725},[695,1401,762],{"class":729},[695,1403,1404],{"class":758},"user",[695,1406,762],{"class":729},[695,1408,920],{"class":725},[695,1410,765],{"class":729},[695,1412,1414,1417,1419],{"class":697,"line":1413},67,[695,1415,1416],{"class":742},"    roles",[695,1418,746],{"class":729},[695,1420,938],{"class":729},[695,1422,1424,1427,1429,1431,1434,1436,1438,1440,1442,1444,1447,1449,1451,1453,1456,1458,1461],{"class":697,"line":1423},68,[695,1425,1426],{"class":742},"      admin",[695,1428,746],{"class":729},[695,1430,887],{"class":729},[695,1432,1433],{"class":742}," label",[695,1435,746],{"class":729},[695,1437,1019],{"class":729},[695,1439,217],{"class":758},[695,1441,762],{"class":729},[695,1443,1182],{"class":729},[695,1445,1446],{"class":742}," grant",[695,1448,746],{"class":729},[695,1450,910],{"class":725},[695,1452,762],{"class":729},[695,1454,1455],{"class":758},"*",[695,1457,762],{"class":729},[695,1459,1460],{"class":725},"] ",[695,1462,1463],{"class":729},"},\n",[695,1465,1467,1470,1472,1474,1476,1478,1480,1483,1485],{"class":697,"line":1466},69,[695,1468,1469],{"class":742},"      user",[695,1471,746],{"class":729},[695,1473,887],{"class":729},[695,1475,1433],{"class":742},[695,1477,746],{"class":729},[695,1479,1019],{"class":729},[695,1481,1482],{"class":758},"User",[695,1484,762],{"class":729},[695,1486,899],{"class":729},[695,1488,1490],{"class":697,"line":1489},70,[695,1491,997],{"class":729},[695,1493,1495],{"class":697,"line":1494},71,[695,1496,1003],{"class":729},[695,1498,1500],{"class":697,"line":1499},72,[695,1501,876],{"emptyLinePlaceholder":875},[695,1503,1505,1508,1510],{"class":697,"line":1504},73,[695,1506,1507],{"class":742},"  eslint",[695,1509,746],{"class":729},[695,1511,938],{"class":729},[695,1513,1515,1518,1520],{"class":697,"line":1514},74,[695,1516,1517],{"class":742},"    config",[695,1519,746],{"class":729},[695,1521,938],{"class":729},[695,1523,1525,1528,1530,1532],{"class":697,"line":1524},75,[695,1526,1527],{"class":742},"      stylistic",[695,1529,746],{"class":729},[695,1531,896],{"class":895},[695,1533,765],{"class":729},[695,1535,1537],{"class":697,"line":1536},76,[695,1538,997],{"class":729},[695,1540,1542],{"class":697,"line":1541},77,[695,1543,1003],{"class":729},[695,1545,1547],{"class":697,"line":1546},78,[695,1548,876],{"emptyLinePlaceholder":875},[695,1550,1552],{"class":697,"line":1551},79,[695,1553,1554],{"class":701},"  \u002F\u002F @frigear-nu\u002Fnotify: emails (password reset, ...) are printed to the terminal until you configure a driver.\n",[695,1556,1558,1561,1563],{"class":697,"line":1557},80,[695,1559,1560],{"class":742},"  notify",[695,1562,746],{"class":729},[695,1564,938],{"class":729},[695,1566,1568,1571,1573,1575,1578,1580,1582,1585,1587],{"class":697,"line":1567},81,[695,1569,1570],{"class":742},"    email",[695,1572,746],{"class":729},[695,1574,887],{"class":729},[695,1576,1577],{"class":742}," driver",[695,1579,746],{"class":729},[695,1581,1019],{"class":729},[695,1583,1584],{"class":758},"log",[695,1586,762],{"class":729},[695,1588,899],{"class":729},[695,1590,1592],{"class":697,"line":1591},82,[695,1593,1003],{"class":729},[695,1595,1597],{"class":697,"line":1596},83,[695,1598,876],{"emptyLinePlaceholder":875},[695,1600,1602],{"class":697,"line":1601},84,[695,1603,1604],{"class":701},"  \u002F\u002F @frigear-nu\u002Fusers: \u002Fadmin\u002Fusers; who may do what is decided by the roles' permissions (`authorization.roles`).\n",[695,1606,1608,1611,1613],{"class":697,"line":1607},85,[695,1609,1610],{"class":742},"  users",[695,1612,746],{"class":729},[695,1614,938],{"class":729},[695,1616,1618,1620,1622],{"class":697,"line":1617},86,[695,1619,1158],{"class":742},[695,1621,746],{"class":729},[695,1623,938],{"class":729},[695,1625,1627,1629,1631,1633],{"class":697,"line":1626},87,[695,1628,1426],{"class":742},[695,1630,746],{"class":729},[695,1632,896],{"class":895},[695,1634,765],{"class":729},[695,1636,1638,1641,1643,1645,1648,1650],{"class":697,"line":1637},88,[695,1639,1640],{"class":742},"      profilePath",[695,1642,746],{"class":729},[695,1644,1019],{"class":729},[695,1646,1647],{"class":758},"\u002Faccount\u002Fprofile",[695,1649,762],{"class":729},[695,1651,765],{"class":729},[695,1653,1655],{"class":697,"line":1654},89,[695,1656,1657],{"class":701},"      \u002F\u002F A new email address takes effect once its owner confirms it from the emailed link.\n",[695,1659,1661,1664,1666,1668],{"class":697,"line":1660},90,[695,1662,1663],{"class":742},"      verifyEmailChange",[695,1665,746],{"class":729},[695,1667,896],{"class":895},[695,1669,765],{"class":729},[695,1671,1673],{"class":697,"line":1672},91,[695,1674,997],{"class":729},[695,1676,1678],{"class":697,"line":1677},92,[695,1679,1003],{"class":729},[695,1681,1683,1686],{"class":697,"line":1682},93,[695,1684,1685],{"class":729},"}",[695,1687,1688],{"class":725},")\n",[593,1690,1691],{},"What the options do:",[1693,1694,1695,1708],"table",{},[1696,1697,1698],"thead",{},[1699,1700,1701,1705],"tr",{},[1702,1703,1704],"th",{},"Key",[1702,1706,1707],{},"Purpose",[1709,1710,1711,1722,1749,1765,1778,1799,1809,1822,1839,1852,1865],"tbody",{},[1699,1712,1713,1719],{},[1714,1715,1716],"td",{},[613,1717,1718],{},"modules",[1714,1720,1721],{},"The modules the app uses. Order matters only for readability.",[1699,1723,1724,1729],{},[1714,1725,1726],{},[613,1727,1728],{},"runtimeConfig",[1714,1730,1731,1734,1735,1738,1739,1734,1742,1745,1746,637],{},[613,1732,1733],{},"aclAdmins"," (",[613,1736,1737],{},"NUXT_ACL_ADMINS",") and ",[613,1740,1741],{},"public.siteUrl",[613,1743,1744],{},"NUXT_PUBLIC_SITE_URL","), set from ",[613,1747,1748],{},".env",[1699,1750,1751,1756],{},[1714,1752,1753],{},[613,1754,1755],{},"hub.db",[1714,1757,1758,1759,1762,1763,637],{},"The database: local SQLite in ",[613,1760,1761],{},".data\u002F",". See ",[618,1764,41],{"href":42},[1699,1766,1767,1772],{},[1714,1768,1769],{},[613,1770,1771],{},"account.settings.pages",[1714,1773,1774,1775,1777],{},"Which ",[613,1776,1304],{}," pages exist.",[1699,1779,1780,1785],{},[1714,1781,1782],{},[613,1783,1784],{},"admin.settings.permission",[1714,1786,1787,1788,1791,1792,1795,1796,1798],{},"Optional. The permission that opens the admin area at ",[613,1789,1790],{},"\u002Fadmin"," (default ",[613,1793,1794],{},"admin:access",", granted to ",[613,1797,651],{},").",[1699,1800,1801,1806],{},[1714,1802,1803],{},[613,1804,1805],{},"authentication.settings",[1714,1807,1808],{},"Sign-in: passkeys, email verification, the pages and where users land after signing in.",[1699,1810,1811,1819],{},[1714,1812,1813,648,1816],{},[613,1814,1815],{},"authorization.roles",[613,1817,1818],{},"defaultRoles",[1714,1820,1821],{},"The roles, what each grants and inherits, and the roles every user holds.",[1699,1823,1824,1829],{},[1714,1825,1826],{},[613,1827,1828],{},"authorization.redirectTo",[1714,1830,1831,1832,648,1835,1838],{},"Where a visitor on a guarded page (",[613,1833,1834],{},"\u002Faccount\u002F**",[613,1836,1837],{},"\u002Fadmin\u002F**",") is sent.",[1699,1840,1841,1846],{},[1714,1842,1843],{},[613,1844,1845],{},"eslint",[1714,1847,1848,1849,1851],{},"The lint config of ",[613,1850,759],{},", with stylistic rules.",[1699,1853,1854,1859],{},[1714,1855,1856],{},[613,1857,1858],{},"notify.email",[1714,1860,1861,1862,1864],{},"Email delivery. The ",[613,1863,1584],{}," driver prints emails in the terminal.",[1699,1866,1867,1872],{},[1714,1868,1869],{},[613,1870,1871],{},"users.settings",[1714,1873,1874,1877,1878,621,1881,1884,1885,1888],{},[613,1875,1876],{},"admin: true"," turns on ",[613,1879,1880],{},"\u002Fadmin\u002Fusers",[613,1882,1883],{},"profilePath"," is where the profile page lives. ",[613,1886,1887],{},"verifyEmailChange"," applies a new email once it is confirmed.",[593,1890,1891,1895],{},[596,1892,1893,637],{},[613,1894,1718],{}," Each module installs the ones it depends on, such as Auth, Notify and UI. You list only the ones you use\ndirectly.",[593,1897,1898,1902,1903,1906,1907,1910,1911,637],{},[596,1899,1900,637],{},[613,1901,1755],{}," NuxtHub applies ",[613,1904,1905],{},"server\u002Fdb\u002Fmigrations"," on ",[613,1908,1909],{},"nuxt dev"," and ",[613,1912,1913],{},"nuxt build",[593,1915,1916,1920,1921,1923],{},[596,1917,1918,637],{},[613,1919,1805],{}," ",[618,1922,31],{"href":32}," explains each option.",[593,1925,1926,1930,1931,1933],{},[596,1927,1928,637],{},[613,1929,1858],{}," The ",[613,1932,1584],{}," driver stays in place until you configure a real driver.",[1935,1936,1937,1938,1941],"note",{},"Restart ",[613,1939,1940],{},"pnpm dev"," after you change module options, so Nuxt regenerates its types.",[627,1943,1945],{"id":1944},"_2-set-environment-variables","2. Set environment variables",[593,1947,1948,1949,1952,1953,1955,1956,1958,1959,1962,1963,671,1966,637],{},"Nuxt maps environment variables that start with ",[613,1950,1951],{},"NUXT_"," onto ",[613,1954,1728],{},". For example, ",[613,1957,1737],{}," sets\n",[613,1960,1961],{},"runtimeConfig.aclAdmins",". Read values with ",[613,1964,1965],{},"useRuntimeConfig()",[613,1967,1968],{},"process.env",[593,1970,1971,1974],{},[613,1972,1973],{},"apps\u002Fweb\u002F.env.example"," documents the starter's three variables:",[686,1976,1980],{"className":1977,"code":1978,"language":1979,"meta":691,"style":691},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Seals the session cookie (Nuxt's appSecret); 32+ characters in production. `pnpm prepare:env` fills in a random one.\nNUXT_APP_SECRET=\n\n# The public URL of the site: emailed links (password reset, sign-in, verification) point here. Set it to your\n# domain in production, where those emails fail without it.\nNUXT_PUBLIC_SITE_URL=http:\u002F\u002Flocalhost:3000\n\n# Comma separated emails that are always admins, once verified. Register with one of them and open the\n# verification link printed in the terminal.\nNUXT_ACL_ADMINS=\n","bash",[613,1981,1982,1987,1995,1999,2004,2009,2019,2023,2028,2033],{"__ignoreMap":691},[695,1983,1984],{"class":697,"line":698},[695,1985,1986],{"class":701},"# Seals the session cookie (Nuxt's appSecret); 32+ characters in production. `pnpm prepare:env` fills in a random one.\n",[695,1988,1989,1992],{"class":697,"line":705},[695,1990,1991],{"class":725},"NUXT_APP_SECRET",[695,1993,1994],{"class":729},"=\n",[695,1996,1997],{"class":697,"line":711},[695,1998,876],{"emptyLinePlaceholder":875},[695,2000,2001],{"class":697,"line":733},[695,2002,2003],{"class":701},"# The public URL of the site: emailed links (password reset, sign-in, verification) point here. Set it to your\n",[695,2005,2006],{"class":697,"line":739},[695,2007,2008],{"class":701},"# domain in production, where those emails fail without it.\n",[695,2010,2011,2013,2016],{"class":697,"line":752},[695,2012,1744],{"class":725},[695,2014,2015],{"class":729},"=",[695,2017,2018],{"class":758},"http:\u002F\u002Flocalhost:3000\n",[695,2020,2021],{"class":697,"line":768},[695,2022,876],{"emptyLinePlaceholder":875},[695,2024,2025],{"class":697,"line":780},[695,2026,2027],{"class":701},"# Comma separated emails that are always admins, once verified. Register with one of them and open the\n",[695,2029,2030],{"class":697,"line":792},[695,2031,2032],{"class":701},"# verification link printed in the terminal.\n",[695,2034,2035,2037],{"class":697,"line":804},[695,2036,1737],{"class":725},[695,2038,1994],{"class":729},[593,2040,2041,2042,2045,2046,2049,2050,2052],{},"Run ",[613,2043,2044],{},"pnpm prepare:env"," to copy every ",[613,2047,2048],{},"apps\u002F*\u002F.env.example"," to ",[613,2051,1748],{},". It generates empty secrets. It never overwrites a\nvalue, so it is safe to run again.",[2054,2055,2056,2057,2059,2060,2062],"caution",{},"Never commit ",[613,2058,1748],{},". It holds ",[613,2061,1991],{},", which seals every session cookie. Nuxt generates one in development\nwhen it is empty. In production set 32+ characters: with a shorter value every session request fails with a 500.",[593,2064,2065],{},"Each module documents its own variables on its page:",[600,2067,2068,2073,2079],{},[603,2069,2070,2071,637],{},"Stripe keys on ",[618,2072,250],{"href":251},[603,2074,2075,2076,637],{},"Email drivers on ",[618,2077,403],{"href":2078},"\u002Fmodules\u002Fplatform\u002Fnotify#environment-variables",[603,2080,2081,2084,2085,637],{},[618,2082,2083],{"href":87},"OAuth provider"," credentials on ",[618,2086,187],{"href":188},[593,2088,2089,2090,2092],{},"The ",[618,2091,472],{"href":473}," lists the full set it uses.",[2094,2095,2098,2101,2102,2104,2105,2107,2108,2110],"callout",{"color":2096,"icon":2097},"success","i-lucide-check",[596,2099,2100],{},"What you should see:"," after a restart of ",[613,2103,1940],{},", the app picks up the new option or variable. For example, a new\nverified email in ",[613,2106,1737],{}," holds the ",[613,2109,651],{}," role on its next request.",[627,2112,2114],{"id":2113},"next-steps","Next steps",[600,2116,2117,2122],{},[603,2118,2119,2121],{},[618,2120,31],{"href":32}," – turn on sign-in methods and protect your own routes and pages.",[603,2123,2124,2126],{},[618,2125,41],{"href":42}," – learn when to generate a migration.",[2128,2129,2130],"style",{},"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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .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 .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}",{"title":691,"searchDepth":705,"depth":705,"links":2132},[2133,2134,2135,2136],{"id":629,"depth":705,"text":630},{"id":640,"depth":705,"text":641},{"id":1944,"depth":705,"text":1945},{"id":2113,"depth":705,"text":2114},"Configure the modules in nuxt.config.ts, and set secrets and runtime config through environment variables.","md",null,{},{"icon":29},{"title":26,"description":2137},"J7YxBKqgnyeQVGseaaysKdL3XWk95OwBm03jzg4TPAs",[2145,2147],{"title":21,"path":22,"stem":23,"description":2146,"icon":24,"children":-1},"The folders and files of the workspace starter, and what each one does.",{"title":31,"path":32,"stem":33,"description":2148,"icon":34,"children":-1},"Let people sign in, and protect your own server routes and pages.",1794503144944]