[{"data":1,"prerenderedAt":1933},["ShallowReactive",2],{"navigation_docs":3,"-modules-identity-preferences":587,"-modules-identity-preferences-surround":1928},[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":221,"body":589,"description":1922,"extension":1923,"links":1924,"meta":1925,"navigation":952,"path":222,"seo":1926,"stem":223,"__hash__":1927},"docs\u002F3.modules\u002F1.identity\u002F5.preferences.md",{"type":590,"value":591,"toc":1904},"minimark",[592,601,608,613,663,667,711,715,1157,1181,1185,1191,1240,1250,1254,1263,1311,1314,1324,1396,1399,1499,1502,1520,1542,1545,1548,1654,1663,1666,1669,1706,1713,1717,1731,1780,1795,1846,1849,1856,1873,1881,1885,1900],[593,594,595,596,600],"p",{},"Preferences stores small per-user settings, such as colour mode, table density or a notification digest. Each setting\nfollows the user across devices. With OAuth Server, other apps that sign in through yours can receive it too, when you\nallow it. Install it when users\nshould be able to choose how your app behaves for them. For settings that belong to the whole app, use module options\nor ",[597,598,599],"code",{},"app.config.ts"," instead.",[593,602,603,604,607],{},"The package is ",[597,605,606],{},"@frigear-nu\u002Fpreferences",". Your app and any module declare each preference once, with a zod schema.\nThat schema validates the API and generates the TypeScript types.",[609,610,612],"h2",{"id":611},"what-you-get","What you get",[614,615,616,631,640,649],"ul",{},[617,618,619,622,623,626,627,630],"li",{},[620,621,344],"strong",{}," (on by default): ",[597,624,625],{},"useUserPreferences()"," reads and sets preferences in the app, and\n",[597,628,629],{},"getUserPreference"," reads one on the server.",[617,632,633,622,636,639],{},[620,634,635],{},"Server routes",[597,637,638],{},"PATCH \u002Fapi\u002Fpreferences"," for the signed-in user.",[617,641,642,622,645,648],{},[620,643,644],{},"Types",[597,646,647],{},"UserPreferences"," is generated from the registered files, so a misspelled key or a wrong\nvalue does not compile.",[617,650,651,654,655,658,659,662],{},[620,652,653],{},"OAuth claims"," (opt-in per preference): with ",[656,657,225],"a",{"href":226},", a preference can be\npassed to ",[656,660,661],{"href":87},"OAuth applications"," as a claim. A preference is private unless its definition\nsays so.",[664,665],"module-runtime",{":client":666,":server":666},"true",[668,669,670,692,700],"note",{},[593,671,672,675,676,679,680,685,686,691],{},[620,673,674],{},"Installed for you:"," ",[597,677,678],{},"@frigear-nu\u002Fmodule-kit",", ",[656,681,682],{"href":169},[597,683,684],{},"@frigear-nu\u002Fauth"," and\n",[656,687,688],{"href":192},[597,689,690],{},"@frigear-nu\u002Fusers",".",[593,693,694,675,697,691],{},[620,695,696],{},"You add:",[597,698,699],{},"@nuxthub\u002Fcore",[593,701,702,675,705,710],{},[620,703,704],{},"Optional:",[656,706,707],{"href":226},[597,708,709],{},"@frigear-nu\u002Foauth-server",", to pass preferences on as claims.",[609,712,714],{"id":713},"quick-setup","Quick setup",[716,717,718,723,751,755,837,841,857,866,878,887,891,898],"steps",{},[719,720,722],"h3",{"id":721},"install-preferences","Install Preferences",[724,725,730],"pre",{"className":726,"code":727,"language":728,"meta":729,"style":729},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @frigear-nu\u002Fpreferences @nuxthub\u002Fcore\n","bash","",[597,731,732],{"__ignoreMap":729},[733,734,737,741,745,748],"span",{"class":735,"line":736},"line",1,[733,738,740],{"class":739},"sBMFI","pnpm",[733,742,744],{"class":743},"sfazB"," add",[733,746,747],{"class":743}," @frigear-nu\u002Fpreferences",[733,749,750],{"class":743}," @nuxthub\u002Fcore\n",[719,752,754],{"id":753},"add-it-to-nuxtconfigts","Add it to nuxt.config.ts",[724,756,761],{"className":757,"code":758,"filename":759,"language":760,"meta":729,"style":729},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineNuxtConfig({\n  modules: ['@nuxthub\u002Fcore', '@frigear-nu\u002Fusers', '@frigear-nu\u002Fpreferences'],\n})\n","nuxt.config.ts","ts",[597,762,763,784,828],{"__ignoreMap":729},[733,764,765,769,772,776,780],{"class":735,"line":736},[733,766,768],{"class":767},"s7zQu","export",[733,770,771],{"class":767}," default",[733,773,775],{"class":774},"s2Zo4"," defineNuxtConfig",[733,777,779],{"class":778},"sTEyZ","(",[733,781,783],{"class":782},"sMK4o","{\n",[733,785,787,791,794,797,800,802,804,807,810,812,814,816,818,820,822,825],{"class":735,"line":786},2,[733,788,790],{"class":789},"swJcz","  modules",[733,792,793],{"class":782},":",[733,795,796],{"class":778}," [",[733,798,799],{"class":782},"'",[733,801,699],{"class":743},[733,803,799],{"class":782},[733,805,806],{"class":782},",",[733,808,809],{"class":782}," '",[733,811,690],{"class":743},[733,813,799],{"class":782},[733,815,806],{"class":782},[733,817,809],{"class":782},[733,819,606],{"class":743},[733,821,799],{"class":782},[733,823,824],{"class":778},"]",[733,826,827],{"class":782},",\n",[733,829,831,834],{"class":735,"line":830},3,[733,832,833],{"class":782},"}",[733,835,836],{"class":778},")\n",[719,838,840],{"id":839},"generate-the-migration","Generate the migration",[842,843,844,845,848,849,852,853,856],"warning",{},"Without a ",[656,846,847],{"href":87},"migration",", every write to the ",[597,850,851],{},"users"," table fails: the database lacks the\n",[597,854,855],{},"preferences"," column.",[593,858,859,860,862,863,865],{},"The module adds a ",[597,861,855],{}," column to ",[597,864,851],{},". Generate a migration and commit it:",[724,867,869],{"className":726,"code":868,"language":728,"meta":729,"style":729},"pnpm db:generate\n",[597,870,871],{"__ignoreMap":729},[733,872,873,875],{"class":735,"line":736},[733,874,740],{"class":739},[733,876,877],{"class":743}," db:generate\n",[593,879,880,881,884,885,691],{},"Module authors do the same in every ",[656,882,883],{"href":87},"test fixture"," that installs it. See\n",[656,886,77],{"href":78},[719,888,890],{"id":889},"declare-your-preferences","Declare your preferences",[593,892,893,894,897],{},"Declare them in ",[597,895,896],{},"shared\u002Fpreferences.ts",", which the module picks up automatically:",[724,899,901],{"className":757,"code":900,"filename":896,"language":760,"meta":729,"style":729},"import { z } from 'zod'\nimport { definePreferences } from '@frigear-nu\u002Fpreferences\u002Fdefine'\n\nexport default definePreferences({\n  \u002F\u002F Plain schema: stored and readable by this app only.\n  compactTables: z.boolean(),\n\n  \u002F\u002F Also forwarded to OAuth applications as the `color_mode` claim.\n  colorMode: { schema: z.enum(['light', 'dark', 'system']), claim: 'color_mode' },\n\n  \u002F\u002F Defaults come from the schema.\n  pageSize: z.number().int().min(10).max(100).default(25),\n})\n",[597,902,903,928,948,954,967,974,994,999,1005,1075,1080,1086,1150],{"__ignoreMap":729},[733,904,905,908,911,914,917,920,922,925],{"class":735,"line":736},[733,906,907],{"class":767},"import",[733,909,910],{"class":782}," {",[733,912,913],{"class":778}," z",[733,915,916],{"class":782}," }",[733,918,919],{"class":767}," from",[733,921,809],{"class":782},[733,923,924],{"class":743},"zod",[733,926,927],{"class":782},"'\n",[733,929,930,932,934,937,939,941,943,946],{"class":735,"line":786},[733,931,907],{"class":767},[733,933,910],{"class":782},[733,935,936],{"class":778}," definePreferences",[733,938,916],{"class":782},[733,940,919],{"class":767},[733,942,809],{"class":782},[733,944,945],{"class":743},"@frigear-nu\u002Fpreferences\u002Fdefine",[733,947,927],{"class":782},[733,949,950],{"class":735,"line":830},[733,951,953],{"emptyLinePlaceholder":952},true,"\n",[733,955,957,959,961,963,965],{"class":735,"line":956},4,[733,958,768],{"class":767},[733,960,771],{"class":767},[733,962,936],{"class":774},[733,964,779],{"class":778},[733,966,783],{"class":782},[733,968,970],{"class":735,"line":969},5,[733,971,973],{"class":972},"sHwdD","  \u002F\u002F Plain schema: stored and readable by this app only.\n",[733,975,977,980,982,984,986,989,992],{"class":735,"line":976},6,[733,978,979],{"class":789},"  compactTables",[733,981,793],{"class":782},[733,983,913],{"class":778},[733,985,691],{"class":782},[733,987,988],{"class":774},"boolean",[733,990,991],{"class":778},"()",[733,993,827],{"class":782},[733,995,997],{"class":735,"line":996},7,[733,998,953],{"emptyLinePlaceholder":952},[733,1000,1002],{"class":735,"line":1001},8,[733,1003,1004],{"class":972},"  \u002F\u002F Also forwarded to OAuth applications as the `color_mode` claim.\n",[733,1006,1008,1011,1013,1015,1018,1020,1022,1024,1027,1030,1032,1035,1037,1039,1041,1044,1046,1048,1050,1053,1055,1058,1060,1063,1065,1067,1070,1072],{"class":735,"line":1007},9,[733,1009,1010],{"class":789},"  colorMode",[733,1012,793],{"class":782},[733,1014,910],{"class":782},[733,1016,1017],{"class":789}," schema",[733,1019,793],{"class":782},[733,1021,913],{"class":778},[733,1023,691],{"class":782},[733,1025,1026],{"class":774},"enum",[733,1028,1029],{"class":778},"([",[733,1031,799],{"class":782},[733,1033,1034],{"class":743},"light",[733,1036,799],{"class":782},[733,1038,806],{"class":782},[733,1040,809],{"class":782},[733,1042,1043],{"class":743},"dark",[733,1045,799],{"class":782},[733,1047,806],{"class":782},[733,1049,809],{"class":782},[733,1051,1052],{"class":743},"system",[733,1054,799],{"class":782},[733,1056,1057],{"class":778},"])",[733,1059,806],{"class":782},[733,1061,1062],{"class":789}," claim",[733,1064,793],{"class":782},[733,1066,809],{"class":782},[733,1068,1069],{"class":743},"color_mode",[733,1071,799],{"class":782},[733,1073,1074],{"class":782}," },\n",[733,1076,1078],{"class":735,"line":1077},10,[733,1079,953],{"emptyLinePlaceholder":952},[733,1081,1083],{"class":735,"line":1082},11,[733,1084,1085],{"class":972},"  \u002F\u002F Defaults come from the schema.\n",[733,1087,1089,1092,1094,1096,1098,1101,1103,1105,1108,1110,1112,1115,1117,1121,1124,1126,1129,1131,1134,1136,1138,1141,1143,1146,1148],{"class":735,"line":1088},12,[733,1090,1091],{"class":789},"  pageSize",[733,1093,793],{"class":782},[733,1095,913],{"class":778},[733,1097,691],{"class":782},[733,1099,1100],{"class":774},"number",[733,1102,991],{"class":778},[733,1104,691],{"class":782},[733,1106,1107],{"class":774},"int",[733,1109,991],{"class":778},[733,1111,691],{"class":782},[733,1113,1114],{"class":774},"min",[733,1116,779],{"class":778},[733,1118,1120],{"class":1119},"sbssI","10",[733,1122,1123],{"class":778},")",[733,1125,691],{"class":782},[733,1127,1128],{"class":774},"max",[733,1130,779],{"class":778},[733,1132,1133],{"class":1119},"100",[733,1135,1123],{"class":778},[733,1137,691],{"class":782},[733,1139,1140],{"class":774},"default",[733,1142,779],{"class":778},[733,1144,1145],{"class":1119},"25",[733,1147,1123],{"class":778},[733,1149,827],{"class":782},[733,1151,1153,1155],{"class":735,"line":1152},13,[733,1154,833],{"class":782},[733,1156,836],{"class":778},[1158,1159,1162,1165,1166,1169,1170,1173,1174,1177,1178,691],"callout",{"color":1160,"icon":1161},"success","i-lucide-check",[620,1163,1164],{},"What you should see:"," signed in, ",[597,1167,1168],{},"await useUserPreferences().set('colorMode', 'dark')"," succeeds, and\n",[597,1171,1172],{},"get('colorMode')"," returns ",[597,1175,1176],{},"'dark'",". A value outside the schema is rejected with ",[597,1179,1180],{},"400",[609,1182,1184],{"id":1183},"options","Options",[593,1186,1187,1188,1190],{},"Options go under the ",[597,1189,855],{}," key.",[1192,1193,1194,1213],"table",{},[1195,1196,1197],"thead",{},[1198,1199,1200,1204,1207,1210],"tr",{},[1201,1202,1203],"th",{},"Option",[1201,1205,1206],{},"Type",[1201,1208,1209],{},"Default",[1201,1211,1212],{},"Purpose",[1214,1215,1216],"tbody",{},[1198,1217,1218,1224,1229,1234],{},[1219,1220,1221],"td",{},[597,1222,1223],{},"definitions",[1219,1225,1226],{},[597,1227,1228],{},"string | string[]",[1219,1230,1231,1233],{},[597,1232,896],{}," when it exists",[1219,1235,1236,1237,691],{},"Files that default-export ",[597,1238,1239],{},"definePreferences({...})",[593,1241,1242,1246,1247,1249],{},[620,1243,1244,691],{},[597,1245,1223],{}," Paths resolve from the project root. Listing files turns off the ",[597,1248,896],{}," default.",[609,1251,1253],{"id":1252},"server","Server",[593,1255,1256,1258,1259,1262],{},[597,1257,629],{}," and ",[597,1260,1261],{},"getPreferenceRegistry()"," are auto-imported.",[724,1264,1266],{"className":757,"code":1265,"language":760,"meta":729,"style":729},"const user = await requireUser(event)\ngetUserPreference(user, 'colorMode') \u002F\u002F typed; undefined when unset or no longer valid\n",[597,1267,1268,1289],{"__ignoreMap":729},[733,1269,1270,1274,1277,1280,1283,1286],{"class":735,"line":736},[733,1271,1273],{"class":1272},"spNyl","const",[733,1275,1276],{"class":778}," user ",[733,1278,1279],{"class":782},"=",[733,1281,1282],{"class":767}," await",[733,1284,1285],{"class":774}," requireUser",[733,1287,1288],{"class":778},"(event)\n",[733,1290,1291,1293,1296,1298,1300,1303,1305,1308],{"class":735,"line":786},[733,1292,629],{"class":774},[733,1294,1295],{"class":778},"(user",[733,1297,806],{"class":782},[733,1299,809],{"class":782},[733,1301,1302],{"class":743},"colorMode",[733,1304,799],{"class":782},[733,1306,1307],{"class":778},") ",[733,1309,1310],{"class":972},"\u002F\u002F typed; undefined when unset or no longer valid\n",[593,1312,1313],{},"Preferences are registered, not free-form. Unknown keys and invalid values are rejected. A stored value that no longer\nsatisfies its schema reads as unset.",[593,1315,1316,1317,1320,1321,1323],{},"A module registers its own definition file from ",[597,1318,1319],{},"setup()",", and its keys join ",[597,1322,647],{}," the same way. The same\nkey in two files fails at startup.",[724,1325,1327],{"className":757,"code":1326,"language":760,"meta":729,"style":729},"import { addUserPreferences } from '@frigear-nu\u002Fpreferences\u002Futils'\n\naddUserPreferences(nuxt, { path: resolver.resolve('.\u002Fruntime\u002Fpreferences') }) \u002F\u002F absolute path\n",[597,1328,1329,1349,1353],{"__ignoreMap":729},[733,1330,1331,1333,1335,1338,1340,1342,1344,1347],{"class":735,"line":736},[733,1332,907],{"class":767},[733,1334,910],{"class":782},[733,1336,1337],{"class":778}," addUserPreferences",[733,1339,916],{"class":782},[733,1341,919],{"class":767},[733,1343,809],{"class":782},[733,1345,1346],{"class":743},"@frigear-nu\u002Fpreferences\u002Futils",[733,1348,927],{"class":782},[733,1350,1351],{"class":735,"line":786},[733,1352,953],{"emptyLinePlaceholder":952},[733,1354,1355,1358,1361,1363,1365,1368,1370,1373,1375,1378,1380,1382,1385,1387,1389,1391,1393],{"class":735,"line":830},[733,1356,1357],{"class":774},"addUserPreferences",[733,1359,1360],{"class":778},"(nuxt",[733,1362,806],{"class":782},[733,1364,910],{"class":782},[733,1366,1367],{"class":789}," path",[733,1369,793],{"class":782},[733,1371,1372],{"class":778}," resolver",[733,1374,691],{"class":782},[733,1376,1377],{"class":774},"resolve",[733,1379,779],{"class":778},[733,1381,799],{"class":782},[733,1383,1384],{"class":743},".\u002Fruntime\u002Fpreferences",[733,1386,799],{"class":782},[733,1388,1307],{"class":778},[733,1390,833],{"class":782},[733,1392,1307],{"class":778},[733,1394,1395],{"class":972},"\u002F\u002F absolute path\n",[593,1397,1398],{},"A definition is a zod schema, or an object with a schema and how it is exposed:",[724,1400,1402],{"className":757,"code":1401,"language":760,"meta":729,"style":729},"type PreferenceDefinition\u003CS extends z.ZodType = z.ZodType>\n  = S | {\n    schema: S\n    \u002F** Forward the value to OAuth applications under this claim name (ID token and `userinfo`). *\u002F\n    claim?: string\n    \u002F** Scope an application must have been granted to receive the claim. Defaults to `profile`. *\u002F\n    scope?: string\n  }\n",[597,1403,1404,1440,1454,1464,1469,1480,1485,1494],{"__ignoreMap":729},[733,1405,1406,1409,1412,1415,1418,1421,1423,1425,1428,1431,1433,1435,1437],{"class":735,"line":736},[733,1407,1408],{"class":1272},"type",[733,1410,1411],{"class":739}," PreferenceDefinition",[733,1413,1414],{"class":782},"\u003C",[733,1416,1417],{"class":739},"S",[733,1419,1420],{"class":1272}," extends",[733,1422,913],{"class":739},[733,1424,691],{"class":782},[733,1426,1427],{"class":739},"ZodType",[733,1429,1430],{"class":782}," =",[733,1432,913],{"class":739},[733,1434,691],{"class":782},[733,1436,1427],{"class":739},[733,1438,1439],{"class":782},">\n",[733,1441,1442,1445,1448,1451],{"class":735,"line":786},[733,1443,1444],{"class":782},"  =",[733,1446,1447],{"class":739}," S",[733,1449,1450],{"class":782}," |",[733,1452,1453],{"class":782}," {\n",[733,1455,1456,1459,1461],{"class":735,"line":830},[733,1457,1458],{"class":789},"    schema",[733,1460,793],{"class":782},[733,1462,1463],{"class":739}," S\n",[733,1465,1466],{"class":735,"line":956},[733,1467,1468],{"class":972},"    \u002F** Forward the value to OAuth applications under this claim name (ID token and `userinfo`). *\u002F\n",[733,1470,1471,1474,1477],{"class":735,"line":969},[733,1472,1473],{"class":789},"    claim",[733,1475,1476],{"class":782},"?:",[733,1478,1479],{"class":739}," string\n",[733,1481,1482],{"class":735,"line":976},[733,1483,1484],{"class":972},"    \u002F** Scope an application must have been granted to receive the claim. Defaults to `profile`. *\u002F\n",[733,1486,1487,1490,1492],{"class":735,"line":996},[733,1488,1489],{"class":789},"    scope",[733,1491,1476],{"class":782},[733,1493,1479],{"class":739},[733,1495,1496],{"class":735,"line":1001},[733,1497,1498],{"class":782},"  }\n",[719,1500,653],{"id":1501},"oauth-claims",[593,1503,1504,1505,1507,1508,1511,1512,1515,1516,1519],{},"With ",[656,1506,225],{"href":226},", a preference that declares a ",[597,1509,1510],{},"claim"," is added to the ID token and\nto ",[597,1513,1514],{},"userinfo",". Only applications granted the definition's ",[597,1517,1518],{},"scope"," receive it.",[614,1521,1522,1525,1528,1535],{},[617,1523,1524],{},"Access tokens stay bare.",[617,1526,1527],{},"A preference that is not set adds no claim.",[617,1529,1530,1531,1534],{},"An existing claim such as ",[597,1532,1533],{},"name"," is never replaced.",[617,1536,1537,1538,1541],{},"OAuth Server knows nothing about preferences. This module registers an ",[597,1539,1540],{},"oauth:claims"," listener.",[609,1543,267],{"id":1544},"app",[593,1546,1547],{},"Read and set the signed-in user's preferences:",[724,1549,1551],{"className":757,"code":1550,"language":760,"meta":729,"style":729},"const { preferences, get, set, pending } = useUserPreferences()\n\npreferences.value.colorMode \u002F\u002F 'light' | 'dark' | 'system' | undefined\nget('colorMode') \u002F\u002F the same, for one key\nawait set('colorMode', 'dark') \u002F\u002F validated by the server; `null` clears it, then the session is refreshed\n",[597,1552,1553,1587,1591,1608,1626],{"__ignoreMap":729},[733,1554,1555,1557,1559,1562,1564,1567,1569,1572,1574,1577,1579,1581,1584],{"class":735,"line":736},[733,1556,1273],{"class":1272},[733,1558,910],{"class":782},[733,1560,1561],{"class":778}," preferences",[733,1563,806],{"class":782},[733,1565,1566],{"class":778}," get",[733,1568,806],{"class":782},[733,1570,1571],{"class":778}," set",[733,1573,806],{"class":782},[733,1575,1576],{"class":778}," pending ",[733,1578,833],{"class":782},[733,1580,1430],{"class":782},[733,1582,1583],{"class":774}," useUserPreferences",[733,1585,1586],{"class":778},"()\n",[733,1588,1589],{"class":735,"line":786},[733,1590,953],{"emptyLinePlaceholder":952},[733,1592,1593,1595,1597,1600,1602,1605],{"class":735,"line":830},[733,1594,855],{"class":778},[733,1596,691],{"class":782},[733,1598,1599],{"class":778},"value",[733,1601,691],{"class":782},[733,1603,1604],{"class":778},"colorMode ",[733,1606,1607],{"class":972},"\u002F\u002F 'light' | 'dark' | 'system' | undefined\n",[733,1609,1610,1613,1615,1617,1619,1621,1623],{"class":735,"line":956},[733,1611,1612],{"class":774},"get",[733,1614,779],{"class":778},[733,1616,799],{"class":782},[733,1618,1302],{"class":743},[733,1620,799],{"class":782},[733,1622,1307],{"class":778},[733,1624,1625],{"class":972},"\u002F\u002F the same, for one key\n",[733,1627,1628,1631,1633,1635,1637,1639,1641,1643,1645,1647,1649,1651],{"class":735,"line":969},[733,1629,1630],{"class":767},"await",[733,1632,1571],{"class":774},[733,1634,779],{"class":778},[733,1636,799],{"class":782},[733,1638,1302],{"class":743},[733,1640,799],{"class":782},[733,1642,806],{"class":782},[733,1644,809],{"class":782},[733,1646,1043],{"class":743},[733,1648,799],{"class":782},[733,1650,1307],{"class":778},[733,1652,1653],{"class":972},"\u002F\u002F validated by the server; `null` clears it, then the session is refreshed\n",[593,1655,1656,1659,1660,691],{},[597,1657,1658],{},"useUserPreferences"," is auto-imported. It is also exported from ",[597,1661,1662],{},"@frigear-nu\u002Fpreferences\u002Fcomposables",[609,1664,234],{"id":1665},"hooks",[593,1667,1668],{},"The module has one build-time hook for module authors, and listens to one hook of OAuth Server.",[1192,1670,1671,1684],{},[1195,1672,1673],{},[1198,1674,1675,1678,1681],{},[1201,1676,1677],{},"Hook",[1201,1679,1680],{},"When",[1201,1682,1683],{},"Payload",[1214,1685,1686],{},[1198,1687,1688,1694,1697],{},[1219,1689,1690,1693],{},[597,1691,1692],{},"preferences:definitions"," (Nuxt)",[1219,1695,1696],{},"Build time, when the definition files are collected",[1219,1698,1699,1702,1703,1705],{},[597,1700,1701],{},"{ path: string }[]",". Push to register; ",[597,1704,1357],{}," does this.",[593,1707,1708,1709,691],{},"When OAuth Server is installed, the module listens to its Nitro hook\n",[656,1710,1711],{"href":235},[597,1712,1540],{},[609,1714,1716],{"id":1715},"routes","Routes",[593,1718,1719,1720,1723,1724,1727,1728,1730],{},"Routes the module registers, and who may call them. The path is ",[597,1721,1722],{},"preferencesApi.root"," from\n",[597,1725,1726],{},"@frigear-nu\u002Fpreferences\u002Fapi",". ",[597,1729,1346],{}," exports it too.",[1192,1732,1733,1750],{},[1195,1734,1735],{},[1198,1736,1737,1740,1743,1745,1748],{},[1201,1738,1739],{},"Method",[1201,1741,1742],{},"Path",[1201,1744,168],{},[1201,1746,1747],{},"Status",[1201,1749,1212],{},[1214,1751,1752],{},[1198,1753,1754,1759,1764,1767,1770],{},[1219,1755,1756],{},[597,1757,1758],{},"PATCH",[1219,1760,1761],{},[597,1762,1763],{},"\u002Fapi\u002Fpreferences",[1219,1765,1766],{},"session only",[1219,1768,1769],{},"200",[1219,1771,1772,1773,1727,1776,1779],{},"A partial update, for example ",[597,1774,1775],{},"{ \"colorMode\": \"dark\" }",[597,1777,1778],{},"null"," clears a key.",[614,1781,1782,1785,1792],{},[617,1783,1784],{},"The body is validated against a zod schema built from the registered definitions.",[617,1786,1787,1788,1791],{},"The answer is the stored preferences (",[597,1789,1790],{},"PreferencesDto","), not the user row.",[617,1793,1794],{},"The route refreshes the session.",[1192,1796,1797,1805],{},[1195,1798,1799],{},[1198,1800,1801,1803],{},[1201,1802,1747],{},[1201,1804,1680],{},[1214,1806,1807,1816,1826,1836],{},[1198,1808,1809,1813],{},[1219,1810,1811],{},[597,1812,1180],{},[1219,1814,1815],{},"The body is not an object, or has an unknown key or an invalid value. Nothing is stored.",[1198,1817,1818,1823],{},[1219,1819,1820],{},[597,1821,1822],{},"401",[1219,1824,1825],{},"No session.",[1198,1827,1828,1833],{},[1219,1829,1830],{},[597,1831,1832],{},"403",[1219,1834,1835],{},"An API token or an access token.",[1198,1837,1838,1843],{},[1219,1839,1840],{},[597,1841,1842],{},"404 not_found",[1219,1844,1845],{},"The user no longer exists.",[609,1847,41],{"id":1848},"database",[593,1850,1851,1852,1855],{},"Tables the module adds. Generate and commit a ",[656,1853,847],{"href":1854},"\u002Fget-started\u002Fdatabase#migrations"," after installing.",[593,1857,1858,1859,1861,1862,1865,1866,1868,1869,1872],{},"The module adds one nullable JSON column to ",[597,1860,851],{},", through a\n",[656,1863,1864],{"href":78},"database extension",": ",[597,1867,855],{}," (",[597,1870,1871],{},"Record\u003Cstring, unknown>",").",[614,1874,1875,1878],{},[617,1876,1877],{},"Every preference lives in this one column, so adding a preference never needs a migration. Only installing the module\ndoes.",[617,1879,1880],{},"SQLite and PostgreSQL can filter and index JSON keys when a preference must be queried.",[609,1882,1884],{"id":1883},"next-steps","Next steps",[614,1886,1887,1892],{},[617,1888,1889,1891],{},[656,1890,191],{"href":192}," – the user record your preferences are stored on.",[617,1893,1894,1897,1898,691],{},[656,1895,1896],{"href":235},"OAuth Server hooks"," – add more claims to the ID token in ",[597,1899,1540],{},[1901,1902,1903],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":729,"searchDepth":786,"depth":786,"links":1905},[1906,1907,1913,1914,1917,1918,1919,1920,1921],{"id":611,"depth":786,"text":612},{"id":713,"depth":786,"text":714,"children":1908},[1909,1910,1911,1912],{"id":721,"depth":830,"text":722},{"id":753,"depth":830,"text":754},{"id":839,"depth":830,"text":840},{"id":889,"depth":830,"text":890},{"id":1183,"depth":786,"text":1184},{"id":1252,"depth":786,"text":1253,"children":1915},[1916],{"id":1501,"depth":830,"text":653},{"id":1544,"depth":786,"text":267},{"id":1665,"depth":786,"text":234},{"id":1715,"depth":786,"text":1716},{"id":1848,"depth":786,"text":41},{"id":1883,"depth":786,"text":1884},"Stores each user's settings, such as colour mode or table density, with types, validation and an optional hand-off to other apps.","md",null,{},{"title":221,"description":1922},"nKUg5WdYvBqG2FAtHAWrxI7qeIKxWlikwMDnAPCsc9c",[1929,1931],{"title":217,"path":218,"stem":219,"description":1930,"children":-1},"The roles pages and the Roles and permissions tab on the user page, where staff see why a role holds a permission and assign roles.",{"title":173,"path":226,"stem":227,"description":1932,"children":-1},"Let people sign in to your other apps and services with the account they already have in this app.",1794503148108]