[{"data":1,"prerenderedAt":1704},["ShallowReactive",2],{"navigation_docs":3,"-modules-platform-module-kit-registries-and-menus":587,"-modules-platform-module-kit-registries-and-menus-surround":1699},[4,50,155,441,504],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":49},"Get Started","i-lucide-rocket","\u002Fget-started","1.get-started",[10,15,20,25,30,35,40,45],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fget-started\u002Fintroduction","1.get-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fget-started\u002Finstallation","1.get-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Project structure","\u002Fget-started\u002Fproject-structure","1.get-started\u002F3.project-structure","i-lucide-folder-tree",{"title":26,"path":27,"stem":28,"icon":29},"Configuration","\u002Fget-started\u002Fconfiguration","1.get-started\u002F4.configuration","i-lucide-settings",{"title":31,"path":32,"stem":33,"icon":34},"Authentication","\u002Fget-started\u002Fauthentication","1.get-started\u002F5.authentication","i-lucide-lock",{"title":36,"path":37,"stem":38,"icon":39},"Adding modules","\u002Fget-started\u002Fadding-modules","1.get-started\u002F6.adding-modules","i-lucide-puzzle",{"title":41,"path":42,"stem":43,"icon":44},"Database","\u002Fget-started\u002Fdatabase","1.get-started\u002F7.database","i-lucide-database",{"title":46,"path":47,"stem":48,"icon":6},"Deployment","\u002Fget-started\u002Fdeployment","1.get-started\u002F8.deployment",false,{"title":51,"icon":52,"path":53,"stem":54,"children":55,"page":49},"Guide","i-lucide-book-open","\u002Fguide","2.guide",[56,90,115,125],{"title":57,"icon":49,"path":58,"stem":59,"children":60,"page":49},"Concepts","\u002Fguide\u002Fconcepts","2.guide\u002F1.concepts",[61,66,71,76,80,85],{"title":62,"path":63,"stem":64,"icon":65},"Architecture","\u002Fguide\u002Fconcepts\u002Farchitecture","2.guide\u002F1.concepts\u002F1.architecture","i-lucide-blocks",{"title":67,"path":68,"stem":69,"icon":70},"Access control","\u002Fguide\u002Fconcepts\u002Fauth-and-scopes","2.guide\u002F1.concepts\u002F2.auth-and-scopes","i-lucide-shield-check",{"title":72,"path":73,"stem":74,"icon":75},"Extension points","\u002Fguide\u002Fconcepts\u002Fextension-points","2.guide\u002F1.concepts\u002F3.extension-points","i-lucide-plug",{"title":77,"path":78,"stem":79,"icon":44},"Database extensions","\u002Fguide\u002Fconcepts\u002Fdatabase-extensions","2.guide\u002F1.concepts\u002F4.database-extensions",{"title":81,"path":82,"stem":83,"icon":84},"Identity","\u002Fguide\u002Fconcepts\u002Fidentity","2.guide\u002F1.concepts\u002F5.identity","i-lucide-fingerprint",{"title":86,"path":87,"stem":88,"icon":89},"Glossary","\u002Fguide\u002Fconcepts\u002Fglossary","2.guide\u002F1.concepts\u002F6.glossary","i-lucide-book-a",{"title":91,"icon":49,"path":92,"stem":93,"children":94,"page":49},"UX patterns","\u002Fguide\u002Fux-patterns","2.guide\u002F2.ux-patterns",[95,100,105,110],{"title":96,"path":97,"stem":98,"icon":99},"Layouts and navigation","\u002Fguide\u002Fux-patterns\u002Flayouts-and-navigation","2.guide\u002F2.ux-patterns\u002F1.layouts-and-navigation","i-lucide-layout-template",{"title":101,"path":102,"stem":103,"icon":104},"Pages","\u002Fguide\u002Fux-patterns\u002Fpages","2.guide\u002F2.ux-patterns\u002F2.pages","i-lucide-table",{"title":106,"path":107,"stem":108,"icon":109},"Forms and actions","\u002Fguide\u002Fux-patterns\u002Fforms-and-actions","2.guide\u002F2.ux-patterns\u002F3.forms-and-actions","i-lucide-square-pen",{"title":111,"path":112,"stem":113,"icon":114},"Text and formatting","\u002Fguide\u002Fux-patterns\u002Ftext-and-formatting","2.guide\u002F2.ux-patterns\u002F4.text-and-formatting","i-lucide-type",{"title":116,"icon":49,"path":117,"stem":118,"children":119,"page":49},"Best practices","\u002Fguide\u002Fbest-practices","2.guide\u002F3.best-practices",[120],{"title":121,"path":122,"stem":123,"icon":124},"HTTP routes","\u002Fguide\u002Fbest-practices\u002Fhttp-routes","2.guide\u002F3.best-practices\u002F1.http-routes","i-lucide-route",{"title":126,"icon":49,"path":127,"stem":128,"children":129,"page":49},"Going further","\u002Fguide\u002Fgoing-further","2.guide\u002F4.going-further",[130,135,140,145,150],{"title":131,"path":132,"stem":133,"icon":134},"Use your own OAuth server","\u002Fguide\u002Fgoing-further\u002Fown-oauth-server","2.guide\u002F4.going-further\u002F1.own-oauth-server","i-lucide-key-round",{"title":136,"path":137,"stem":138,"icon":139},"Create an OAuth application","\u002Fguide\u002Fgoing-further\u002Foauth-application","2.guide\u002F4.going-further\u002F2.oauth-application","i-lucide-app-window",{"title":141,"path":142,"stem":143,"icon":144},"Signing keys","\u002Fguide\u002Fgoing-further\u002Fsigning-keys","2.guide\u002F4.going-further\u002F3.signing-keys","i-lucide-key-square",{"title":146,"path":147,"stem":148,"icon":149},"Stripe setup","\u002Fguide\u002Fgoing-further\u002Fstripe-setup","2.guide\u002F4.going-further\u002F4.stripe-setup","i-lucide-credit-card",{"title":151,"path":152,"stem":153,"icon":154},"Migrate to the permission model","\u002Fguide\u002Fgoing-further\u002Fmigrate-access-control","2.guide\u002F4.going-further\u002F5.migrate-access-control","i-lucide-arrow-right-left",{"title":156,"icon":157,"path":158,"stem":159,"children":160},"Modules","i-lucide-boxes","\u002Fmodules","3.modules",[161,163,244,273,320,375],{"title":156,"path":158,"stem":162},"3.modules\u002Findex",{"title":81,"icon":49,"path":164,"stem":165,"children":166,"page":49},"\u002Fmodules\u002Fidentity","3.modules\u002F1.identity",[167,190,194,198,220,224,240],{"title":168,"path":169,"stem":170,"children":171},"Auth","\u002Fmodules\u002Fidentity\u002Fauth","3.modules\u002F1.identity\u002F1.auth\u002Findex",[172,174,178,182,186],{"title":173,"path":169,"stem":170},"Overview",{"title":175,"path":176,"stem":177},"Server API","\u002Fmodules\u002Fidentity\u002Fauth\u002Fserver","3.modules\u002F1.identity\u002F1.auth\u002F2.server",{"title":179,"path":180,"stem":181},"Reference","\u002Fmodules\u002Fidentity\u002Fauth\u002Freference","3.modules\u002F1.identity\u002F1.auth\u002F3.reference",{"title":183,"path":184,"stem":185},"Client mode","\u002Fmodules\u002Fidentity\u002Fauth\u002Fclient-mode","3.modules\u002F1.identity\u002F1.auth\u002F4.client-mode",{"title":187,"path":188,"stem":189},"OAuth providers","\u002Fmodules\u002Fidentity\u002Fauth\u002Foauth-providers","3.modules\u002F1.identity\u002F1.auth\u002F5.oauth-providers",{"title":191,"path":192,"stem":193},"Users","\u002Fmodules\u002Fidentity\u002Fusers","3.modules\u002F1.identity\u002F2.users",{"title":195,"path":196,"stem":197},"Account","\u002Fmodules\u002Fidentity\u002Faccount","3.modules\u002F1.identity\u002F3.account",{"title":199,"path":200,"stem":201,"children":202},"Authorization","\u002Fmodules\u002Fidentity\u002Fauthorization","3.modules\u002F1.identity\u002F4.authorization\u002Findex",[203,204,208,212,216],{"title":173,"path":200,"stem":201},{"title":205,"path":206,"stem":207},"Roles and requirements","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Froles-and-requirements","3.modules\u002F1.identity\u002F4.authorization\u002F2.roles-and-requirements",{"title":209,"path":210,"stem":211},"Policies","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fpolicies","3.modules\u002F1.identity\u002F4.authorization\u002F3.policies",{"title":213,"path":214,"stem":215},"Client","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fclient","3.modules\u002F1.identity\u002F4.authorization\u002F4.client",{"title":217,"path":218,"stem":219},"Admin","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fadmin","3.modules\u002F1.identity\u002F4.authorization\u002F5.admin",{"title":221,"path":222,"stem":223},"Preferences","\u002Fmodules\u002Fidentity\u002Fpreferences","3.modules\u002F1.identity\u002F5.preferences",{"title":225,"path":226,"stem":227,"children":228},"OAuth Server","\u002Fmodules\u002Fidentity\u002Foauth-server","3.modules\u002F1.identity\u002F6.oauth-server\u002Findex",[229,230,233,237],{"title":173,"path":226,"stem":227},{"title":175,"path":231,"stem":232},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fserver","3.modules\u002F1.identity\u002F6.oauth-server\u002F2.server",{"title":234,"path":235,"stem":236},"Hooks","\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fhooks","3.modules\u002F1.identity\u002F6.oauth-server\u002F3.hooks",{"title":179,"path":238,"stem":239},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients","3.modules\u002F1.identity\u002F6.oauth-server\u002F4.routes-and-clients",{"title":241,"path":242,"stem":243},"OAuth Resource","\u002Fmodules\u002Fidentity\u002Foauth-resource","3.modules\u002F1.identity\u002F8.oauth-resource",{"title":245,"icon":49,"path":246,"stem":247,"children":248,"page":49},"Commerce","\u002Fmodules\u002Fcommerce","3.modules\u002F2.commerce",[249,253,257],{"title":250,"path":251,"stem":252},"Stripe","\u002Fmodules\u002Fcommerce\u002Fstripe","3.modules\u002F2.commerce\u002F1.stripe",{"title":254,"path":255,"stem":256},"Payments","\u002Fmodules\u002Fcommerce\u002Fpayments","3.modules\u002F2.commerce\u002F2.payments",{"title":258,"path":259,"stem":260,"children":261},"Subscriptions","\u002Fmodules\u002Fcommerce\u002Fsubscriptions","3.modules\u002F2.commerce\u002F3.subscriptions\u002Findex",[262,263,266,270],{"title":173,"path":259,"stem":260},{"title":175,"path":264,"stem":265},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fserver","3.modules\u002F2.commerce\u002F3.subscriptions\u002F2.server",{"title":267,"path":268,"stem":269},"App","\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fapp","3.modules\u002F2.commerce\u002F3.subscriptions\u002F3.app",{"title":179,"path":271,"stem":272},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Freference","3.modules\u002F2.commerce\u002F3.subscriptions\u002F4.reference",{"title":274,"icon":49,"path":275,"stem":276,"children":277,"page":49},"Features","\u002Fmodules\u002Ffeatures","3.modules\u002F3.features",[278,293,312,316],{"title":279,"path":280,"stem":281,"children":282},"Events","\u002Fmodules\u002Ffeatures\u002Fevents","3.modules\u002F3.features\u002F1.events\u002Findex",[283,284,287,290],{"title":173,"path":280,"stem":281},{"title":175,"path":285,"stem":286},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fserver","3.modules\u002F3.features\u002F1.events\u002F2.server",{"title":267,"path":288,"stem":289},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fapp","3.modules\u002F3.features\u002F1.events\u002F3.app",{"title":179,"path":291,"stem":292},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Freference","3.modules\u002F3.features\u002F1.events\u002F4.reference",{"title":294,"path":295,"stem":296,"children":297},"Forms","\u002Fmodules\u002Ffeatures\u002Fforms","3.modules\u002F3.features\u002F2.forms\u002Findex",[298,299,303,306,309],{"title":173,"path":295,"stem":296},{"title":300,"path":301,"stem":302},"Definition","\u002Fmodules\u002Ffeatures\u002Fforms\u002Fdefinition","3.modules\u002F3.features\u002F2.forms\u002F2.definition",{"title":175,"path":304,"stem":305},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fserver","3.modules\u002F3.features\u002F2.forms\u002F3.server",{"title":267,"path":307,"stem":308},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fapp","3.modules\u002F3.features\u002F2.forms\u002F4.app",{"title":179,"path":310,"stem":311},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Freference","3.modules\u002F3.features\u002F2.forms\u002F5.reference",{"title":313,"path":314,"stem":315},"Cookie Consent","\u002Fmodules\u002Ffeatures\u002Fcookie-consent","3.modules\u002F3.features\u002F3.cookie-consent",{"title":317,"path":318,"stem":319},"MCP","\u002Fmodules\u002Ffeatures\u002Fmcp","3.modules\u002F3.features\u002F4.mcp",{"title":321,"icon":49,"path":322,"stem":323,"children":324,"page":49},"Interface","\u002Fmodules\u002Finterface","3.modules\u002F4.interface",[325,350,353,357,361],{"title":326,"path":327,"stem":328,"children":329},"UI","\u002Fmodules\u002Finterface\u002Fui","3.modules\u002F4.interface\u002F1.ui\u002Findex",[330,331,335,339,343,347],{"title":173,"path":327,"stem":328},{"title":332,"path":333,"stem":334},"Page components","\u002Fmodules\u002Finterface\u002Fui\u002Fpage-components","3.modules\u002F4.interface\u002F1.ui\u002F2.page-components",{"title":336,"path":337,"stem":338},"App shell","\u002Fmodules\u002Finterface\u002Fui\u002Fapp-shell","3.modules\u002F4.interface\u002F1.ui\u002F3.app-shell",{"title":340,"path":341,"stem":342},"Form inputs","\u002Fmodules\u002Finterface\u002Fui\u002Fform-inputs","3.modules\u002F4.interface\u002F1.ui\u002F4.form-inputs",{"title":344,"path":345,"stem":346},"Composables and helpers","\u002Fmodules\u002Finterface\u002Fui\u002Fcomposables","3.modules\u002F4.interface\u002F1.ui\u002F5.composables",{"title":179,"path":348,"stem":349},"\u002Fmodules\u002Finterface\u002Fui\u002Freference","3.modules\u002F4.interface\u002F1.ui\u002F6.reference",{"title":217,"path":351,"stem":352},"\u002Fmodules\u002Finterface\u002Fadmin","3.modules\u002F4.interface\u002F2.admin",{"title":354,"path":355,"stem":356},"Menu","\u002Fmodules\u002Finterface\u002Fmenu","3.modules\u002F4.interface\u002F3.menu",{"title":358,"path":359,"stem":360},"Widget","\u002Fmodules\u002Finterface\u002Fwidget","3.modules\u002F4.interface\u002F4.widget",{"title":362,"path":363,"stem":364,"children":365},"Mobile","\u002Fmodules\u002Finterface\u002Fmobile","3.modules\u002F4.interface\u002F5.mobile\u002Findex",[366,367,371],{"title":173,"path":363,"stem":364},{"title":368,"path":369,"stem":370},"CLI and devices","\u002Fmodules\u002Finterface\u002Fmobile\u002Fcli-and-devices","3.modules\u002F4.interface\u002F5.mobile\u002F2.cli-and-devices",{"title":372,"path":373,"stem":374},"Splash screen","\u002Fmodules\u002Finterface\u002Fmobile\u002Fsplash-screen","3.modules\u002F4.interface\u002F5.mobile\u002F3.splash-screen",{"title":376,"icon":49,"path":377,"stem":378,"children":379,"page":49},"Platform","\u002Fmodules\u002Fplatform","3.modules\u002F5.platform",[380,402,406,423],{"title":381,"path":382,"stem":383,"children":384},"Module Kit","\u002Fmodules\u002Fplatform\u002Fmodule-kit","3.modules\u002F5.platform\u002F1.module-kit\u002Findex",[385,386,390,394,398],{"title":173,"path":382,"stem":383},{"title":387,"path":388,"stem":389},"Server toolkit","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fserver-toolkit","3.modules\u002F5.platform\u002F1.module-kit\u002F2.server-toolkit",{"title":391,"path":392,"stem":393},"Registries and menus","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fregistries-and-menus","3.modules\u002F5.platform\u002F1.module-kit\u002F3.registries-and-menus",{"title":395,"path":396,"stem":397},"Translations","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fi18n","3.modules\u002F5.platform\u002F1.module-kit\u002F4.i18n",{"title":399,"path":400,"stem":401},"Database helpers","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fdatabase","3.modules\u002F5.platform\u002F1.module-kit\u002F5.database",{"title":403,"path":404,"stem":405},"Notify","\u002Fmodules\u002Fplatform\u002Fnotify","3.modules\u002F5.platform\u002F2.notify",{"title":407,"path":408,"stem":409,"children":410},"Email Templates","\u002Fmodules\u002Fplatform\u002Femail-templates","3.modules\u002F5.platform\u002F3.email-templates\u002Findex",[411,412,416,419],{"title":173,"path":408,"stem":409},{"title":413,"path":414,"stem":415},"Email components","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fcomponents","3.modules\u002F5.platform\u002F3.email-templates\u002F2.components",{"title":175,"path":417,"stem":418},"\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fserver","3.modules\u002F5.platform\u002F3.email-templates\u002F3.server",{"title":420,"path":421,"stem":422},"Module emails","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fmodule-emails","3.modules\u002F5.platform\u002F3.email-templates\u002F4.module-emails",{"title":424,"path":425,"stem":426,"children":427},"Base Layer","\u002Fmodules\u002Fplatform\u002Fbase-layer","3.modules\u002F5.platform\u002F4.base-layer\u002Findex",[428,429,433,437],{"title":173,"path":425,"stem":426},{"title":430,"path":431,"stem":432},"Content collections","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcontent-collections","3.modules\u002F5.platform\u002F4.base-layer\u002F2.content-collections",{"title":434,"path":435,"stem":436},"Layouts and routing","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Flayouts-and-routing","3.modules\u002F5.platform\u002F4.base-layer\u002F3.layouts-and-routing",{"title":438,"path":439,"stem":440},"Composables and utils","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcomposables-and-utils","3.modules\u002F5.platform\u002F4.base-layer\u002F4.composables-and-utils",{"title":442,"icon":443,"path":444,"stem":445,"children":446,"page":49},"Examples","i-lucide-code-xml","\u002Fexamples","4.examples",[447,466,476],{"title":448,"icon":49,"path":449,"stem":450,"children":451,"page":49},"Starters","\u002Fexamples\u002Fstarters","4.examples\u002F1.starters",[452,456,461],{"title":453,"path":454,"stem":455,"icon":6},"Workspace starter","\u002Fexamples\u002Fstarters\u002Fworkspace","4.examples\u002F1.starters\u002F1.workspace",{"title":457,"path":458,"stem":459,"icon":460},"Mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile","4.examples\u002F1.starters\u002F2.mobile","i-lucide-smartphone",{"title":462,"path":463,"stem":464,"icon":465},"Standalone mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile-standalone","4.examples\u002F1.starters\u002F3.mobile-standalone","i-lucide-tablet-smartphone",{"title":467,"icon":49,"path":468,"stem":469,"children":470,"page":49},"Apps","\u002Fexamples\u002Fapps","4.examples\u002F2.apps",[471],{"title":472,"path":473,"stem":474,"icon":475},"Frigear website app","\u002Fexamples\u002Fapps\u002Ffrigear-nu-website","4.examples\u002F2.apps\u002F1.frigear-nu-website","i-lucide-layout-dashboard",{"title":477,"icon":49,"path":478,"stem":479,"children":480,"page":49},"Tasks","\u002Fexamples\u002Ftasks","4.examples\u002F3.tasks",[481,485,489,494,499],{"title":482,"path":483,"stem":484,"icon":70},"Protect a route","\u002Fexamples\u002Ftasks\u002Fprotect-a-route","4.examples\u002F3.tasks\u002F1.protect-a-route",{"title":486,"path":487,"stem":488,"icon":475},"Add an admin page","\u002Fexamples\u002Ftasks\u002Fadd-an-admin-page","4.examples\u002F3.tasks\u002F2.add-an-admin-page",{"title":490,"path":491,"stem":492,"icon":493},"Sell event tickets","\u002Fexamples\u002Ftasks\u002Fsell-event-tickets","4.examples\u002F3.tasks\u002F3.sell-event-tickets","i-lucide-ticket",{"title":495,"path":496,"stem":497,"icon":498},"Build a form","\u002Fexamples\u002Ftasks\u002Fbuild-a-form","4.examples\u002F3.tasks\u002F4.build-a-form","i-lucide-clipboard-list",{"title":500,"path":501,"stem":502,"icon":503},"Send an email","\u002Fexamples\u002Ftasks\u002Fsend-an-email","4.examples\u002F3.tasks\u002F5.send-an-email","i-lucide-mail",{"title":505,"icon":506,"path":507,"stem":508,"children":509,"page":49},"Contribute","i-lucide-git-pull-request","\u002Fcontribute","5.contribute",[510,513,518,544,549,552,556,571],{"title":173,"path":511,"stem":512,"icon":506},"\u002Fcontribute\u002Foverview","5.contribute\u002F1.overview",{"title":514,"path":515,"stem":516,"icon":517},"Local development","\u002Fcontribute\u002Flocal-development","5.contribute\u002F2.local-development","i-lucide-terminal",{"title":519,"icon":49,"path":520,"stem":521,"children":522,"page":49},"Writing a module","\u002Fcontribute\u002Fwriting-a-module","5.contribute\u002F3.writing-a-module",[523,527,532,536,541],{"title":524,"path":525,"stem":526,"icon":39},"Scaffold a module","\u002Fcontribute\u002Fwriting-a-module\u002Fscaffold","5.contribute\u002F3.writing-a-module\u002F1.scaffold",{"title":528,"path":529,"stem":530,"icon":531},"Setup checklist","\u002Fcontribute\u002Fwriting-a-module\u002Fsetup-checklist","5.contribute\u002F3.writing-a-module\u002F2.setup-checklist","i-lucide-list-checks",{"title":533,"path":534,"stem":535,"icon":44},"Database tables","\u002Fcontribute\u002Fwriting-a-module\u002Fdatabase-tables","5.contribute\u002F3.writing-a-module\u002F3.database-tables",{"title":537,"path":538,"stem":539,"icon":540},"Testing","\u002Fcontribute\u002Fwriting-a-module\u002Ftesting","5.contribute\u002F3.writing-a-module\u002F4.testing","i-lucide-flask-conical",{"title":67,"path":542,"stem":543,"icon":70},"\u002Fcontribute\u002Fwriting-a-module\u002Faccess-control","5.contribute\u002F3.writing-a-module\u002F5.access-control",{"title":545,"path":546,"stem":547,"icon":548},"Publishing","\u002Fcontribute\u002Fpublishing","5.contribute\u002F4.publishing","i-lucide-package-check",{"title":448,"path":550,"stem":551,"icon":6},"\u002Fcontribute\u002Fstarters","5.contribute\u002F5.starters",{"title":553,"path":554,"stem":555,"icon":52},"Documentation","\u002Fcontribute\u002Fdocumentation","5.contribute\u002F6.documentation",{"title":557,"icon":49,"path":558,"stem":559,"children":560,"page":49},"Tooling","\u002Fcontribute\u002Ftooling","5.contribute\u002F7.tooling",[561,566],{"title":562,"path":563,"stem":564,"icon":565},"CLI","\u002Fcontribute\u002Ftooling\u002Fcli","5.contribute\u002F7.tooling\u002F1.cli","i-lucide-square-terminal",{"title":567,"path":568,"stem":569,"icon":570},"ESLint config","\u002Fcontribute\u002Ftooling\u002Feslint-config","5.contribute\u002F7.tooling\u002F2.eslint-config","i-lucide-spell-check",{"title":572,"icon":49,"path":573,"stem":574,"children":575},"Decisions","\u002Fcontribute\u002Fdecisions","5.contribute\u002F8.decisions\u002Findex",[576,578,583],{"title":572,"path":573,"stem":574,"icon":577},"i-lucide-scale",{"title":579,"path":580,"stem":581,"icon":582},"Session lifetimes per OAuth client","\u002Fcontribute\u002Fdecisions\u002Foauth-token-lifetimes","5.contribute\u002F8.decisions\u002F1.oauth-token-lifetimes","i-lucide-timer",{"title":584,"path":585,"stem":586,"icon":70},"One permission model","\u002Fcontribute\u002Fdecisions\u002Fpermission-model","5.contribute\u002F8.decisions\u002F2.permission-model",{"id":588,"title":589,"body":590,"description":1692,"extension":1693,"links":1694,"meta":1695,"navigation":1696,"path":392,"seo":1697,"stem":393,"__hash__":1698},"docs\u002F3.modules\u002F5.platform\u002F1.module-kit\u002F3.registries-and-menus.md","Module Kit registries and menus",{"type":591,"value":592,"toc":1684},"minimark",[593,605,613,618,624,678,827,834,849,874,878,894,1122,1126,1133,1144,1281,1284,1396,1436,1517,1523,1528,1627,1649,1653,1656,1660,1680],[594,595,596,597,601,602,604],"p",{},"This page shows how your module adds to another module without importing it: menu items, entries in a\n",[598,599,600],"a",{"href":87},"registry",", and data for an area's single bootstrap request. It is for module authors.\nSet up the module first: ",[598,603,173],{"href":382},".",[594,606,607,609,610,604],{},[598,608,72],{"href":73}," explains when to use a registry and when a\n",[598,611,612],{"href":87},"hook",[614,615,617],"h2",{"id":616},"menu-helpers","Menu helpers",[594,619,620,621,623],{},"These helpers add items to a ",[598,622,354],{"href":355}," without importing it.",[625,626,627,643],"table",{},[628,629,630],"thead",{},[631,632,633,637,640],"tr",{},[634,635,636],"th",{},"Helper",[634,638,639],{},"Signature",[634,641,642],{},"Purpose",[644,645,646,663],"tbody",{},[631,647,648,655,660],{},[649,650,651],"td",{},[652,653,654],"code",{},"addMenuSource",[649,656,657],{},[652,658,659],{},"(nuxt: Nuxt, options: MenuSourceOptions) => void",[649,661,662],{},"Registers a menu source file. Duplicates are ignored.",[631,664,665,670,675],{},[649,666,667],{},[652,668,669],{},"addOptionalMenuSource",[649,671,672],{},[652,673,674],{},"(nuxt: Nuxt, options: MenuSourceOptions) => boolean",[649,676,677],{},"The same, only when Menu is installed. Returns whether it registered.",[679,680,685],"pre",{"className":681,"code":682,"language":683,"meta":684,"style":684},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","interface MenuSourceOptions {\n  \u002F** The menu the items belong to, for example `dashboard.account`. *\u002F\n  menu: string\n  \u002F** Absolute path of the source file (a `defineMenuSource` default export). *\u002F\n  file: string\n}\n\naddOptionalMenuSource(nuxt, {\n  menu: 'dashboard.account',\n  file: resolver.resolve('.\u002Fruntime\u002Fmenus'),\n})\n","ts","",[652,686,687,704,711,724,730,740,746,753,768,788,818],{"__ignoreMap":684},[688,689,692,696,700],"span",{"class":690,"line":691},"line",1,[688,693,695],{"class":694},"spNyl","interface",[688,697,699],{"class":698},"sBMFI"," MenuSourceOptions",[688,701,703],{"class":702},"sMK4o"," {\n",[688,705,707],{"class":690,"line":706},2,[688,708,710],{"class":709},"sHwdD","  \u002F** The menu the items belong to, for example `dashboard.account`. *\u002F\n",[688,712,714,718,721],{"class":690,"line":713},3,[688,715,717],{"class":716},"swJcz","  menu",[688,719,720],{"class":702},":",[688,722,723],{"class":698}," string\n",[688,725,727],{"class":690,"line":726},4,[688,728,729],{"class":709},"  \u002F** Absolute path of the source file (a `defineMenuSource` default export). *\u002F\n",[688,731,733,736,738],{"class":690,"line":732},5,[688,734,735],{"class":716},"  file",[688,737,720],{"class":702},[688,739,723],{"class":698},[688,741,743],{"class":690,"line":742},6,[688,744,745],{"class":702},"}\n",[688,747,749],{"class":690,"line":748},7,[688,750,752],{"emptyLinePlaceholder":751},true,"\n",[688,754,756,759,763,766],{"class":690,"line":755},8,[688,757,669],{"class":758},"s2Zo4",[688,760,762],{"class":761},"sTEyZ","(nuxt",[688,764,765],{"class":702},",",[688,767,703],{"class":702},[688,769,771,773,775,778,782,785],{"class":690,"line":770},9,[688,772,717],{"class":716},[688,774,720],{"class":702},[688,776,777],{"class":702}," '",[688,779,781],{"class":780},"sfazB","dashboard.account",[688,783,784],{"class":702},"'",[688,786,787],{"class":702},",\n",[688,789,791,793,795,798,800,803,806,808,811,813,816],{"class":690,"line":790},10,[688,792,735],{"class":716},[688,794,720],{"class":702},[688,796,797],{"class":761}," resolver",[688,799,604],{"class":702},[688,801,802],{"class":758},"resolve",[688,804,805],{"class":761},"(",[688,807,784],{"class":702},[688,809,810],{"class":780},".\u002Fruntime\u002Fmenus",[688,812,784],{"class":702},[688,814,815],{"class":761},")",[688,817,787],{"class":702},[688,819,821,824],{"class":690,"line":820},11,[688,822,823],{"class":702},"}",[688,825,826],{"class":761},")\n",[594,828,829,830,833],{},"Menu reads the sources once every module is done. The source file imports ",[652,831,832],{},"@frigear-nu\u002Fmenu\u002Futils"," itself, which\nresolves only when the file runs.",[835,836,837,838,840,841,844,845,848],"tip",{},"Use ",[652,839,669],{},", and declare ",[652,842,843],{},"@frigear-nu\u002Fmenu"," as an optional ",[652,846,847],{},"moduleDependencies"," entry and an optional\npeer dependency. Your module then works without Menu.",[594,850,851,852,854,855,858,859,862,863,866,867,870,871,604],{},"Module Kit depends on neither Menu nor ",[598,853,358],{"href":359},". For widgets and tabs, guard the call in\n",[652,856,857],{},"setup()"," yourself: check ",[652,860,861],{},"hasNuxtModule('@frigear-nu\u002Fwidget')",", then ",[652,864,865],{},"await import('@frigear-nu\u002Fwidget\u002Futils')"," and\ncall ",[652,868,869],{},"extendWidgets"," or ",[652,872,873],{},"extendTabs",[614,875,877],{"id":876},"registries","Registries",[594,879,880,883,884,886,887,890,891,893],{},[652,881,882],{},"defineVirtualRegistry"," lets your module collect entries from other modules at build time. Other modules register\nentries during their own ",[652,885,857],{},", in any order. Once every module is done (",[652,888,889],{},"modules:done","), the entries are bundled\ninto one virtual module that your runtime code imports. Nothing is scanned at runtime, so it works on Cloudflare\nWorkers. Call it from the ",[652,892,857],{}," of the module that owns the registry.",[679,895,897],{"className":681,"code":896,"language":683,"meta":684,"style":684},"function defineVirtualRegistry\u003CT>(nuxt: Nuxt, options: VirtualRegistryOptions\u003CT>): void\n\ninterface VirtualRegistryOptions\u003CT> {\n  \u002F** Template file name, for example `#widgets\u002Fregistry.mjs`. *\u002F\n  filename: string\n  \u002F** `app` writes the template and aliases it; `server` adds a Nitro virtual module. Defaults to `app`. *\u002F\n  target?: 'app' | 'server'\n  \u002F** The import path of the virtual module (`app` target only), for example `#widgets\u002Fregistry`. *\u002F\n  alias?: string\n  \u002F** Reads what modules registered during their own `setup()`. *\u002F\n  collect: () => T\n  \u002F** The source of the virtual module. *\u002F\n  contents: (data: T) => string\n  \u002F** Called with the collected data after the template is registered. *\u002F\n  resolved?: (data: T) => void | Promise\u003Cvoid>\n}\n",[652,898,899,945,949,964,969,978,983,1009,1014,1023,1028,1044,1050,1075,1081,1117],{"__ignoreMap":684},[688,900,901,904,907,910,913,916,920,922,925,927,930,932,935,937,939,942],{"class":690,"line":691},[688,902,903],{"class":694},"function",[688,905,906],{"class":758}," defineVirtualRegistry",[688,908,909],{"class":702},"\u003C",[688,911,912],{"class":698},"T",[688,914,915],{"class":702},">(",[688,917,919],{"class":918},"sHdIc","nuxt",[688,921,720],{"class":702},[688,923,924],{"class":698}," Nuxt",[688,926,765],{"class":702},[688,928,929],{"class":918}," options",[688,931,720],{"class":702},[688,933,934],{"class":698}," VirtualRegistryOptions",[688,936,909],{"class":702},[688,938,912],{"class":698},[688,940,941],{"class":702},">):",[688,943,944],{"class":698}," void\n",[688,946,947],{"class":690,"line":706},[688,948,752],{"emptyLinePlaceholder":751},[688,950,951,953,955,957,959,962],{"class":690,"line":713},[688,952,695],{"class":694},[688,954,934],{"class":698},[688,956,909],{"class":702},[688,958,912],{"class":698},[688,960,961],{"class":702},">",[688,963,703],{"class":702},[688,965,966],{"class":690,"line":726},[688,967,968],{"class":709},"  \u002F** Template file name, for example `#widgets\u002Fregistry.mjs`. *\u002F\n",[688,970,971,974,976],{"class":690,"line":732},[688,972,973],{"class":716},"  filename",[688,975,720],{"class":702},[688,977,723],{"class":698},[688,979,980],{"class":690,"line":742},[688,981,982],{"class":709},"  \u002F** `app` writes the template and aliases it; `server` adds a Nitro virtual module. Defaults to `app`. *\u002F\n",[688,984,985,988,991,993,996,998,1001,1003,1006],{"class":690,"line":748},[688,986,987],{"class":716},"  target",[688,989,990],{"class":702},"?:",[688,992,777],{"class":702},[688,994,995],{"class":780},"app",[688,997,784],{"class":702},[688,999,1000],{"class":702}," |",[688,1002,777],{"class":702},[688,1004,1005],{"class":780},"server",[688,1007,1008],{"class":702},"'\n",[688,1010,1011],{"class":690,"line":755},[688,1012,1013],{"class":709},"  \u002F** The import path of the virtual module (`app` target only), for example `#widgets\u002Fregistry`. *\u002F\n",[688,1015,1016,1019,1021],{"class":690,"line":770},[688,1017,1018],{"class":716},"  alias",[688,1020,990],{"class":702},[688,1022,723],{"class":698},[688,1024,1025],{"class":690,"line":790},[688,1026,1027],{"class":709},"  \u002F** Reads what modules registered during their own `setup()`. *\u002F\n",[688,1029,1030,1033,1035,1038,1041],{"class":690,"line":820},[688,1031,1032],{"class":716},"  collect",[688,1034,720],{"class":702},[688,1036,1037],{"class":702}," ()",[688,1039,1040],{"class":694}," =>",[688,1042,1043],{"class":698}," T\n",[688,1045,1047],{"class":690,"line":1046},12,[688,1048,1049],{"class":709},"  \u002F** The source of the virtual module. *\u002F\n",[688,1051,1053,1056,1058,1061,1064,1066,1069,1071,1073],{"class":690,"line":1052},13,[688,1054,1055],{"class":716},"  contents",[688,1057,720],{"class":702},[688,1059,1060],{"class":702}," (",[688,1062,1063],{"class":918},"data",[688,1065,720],{"class":702},[688,1067,1068],{"class":698}," T",[688,1070,815],{"class":702},[688,1072,1040],{"class":694},[688,1074,723],{"class":698},[688,1076,1078],{"class":690,"line":1077},14,[688,1079,1080],{"class":709},"  \u002F** Called with the collected data after the template is registered. *\u002F\n",[688,1082,1084,1087,1089,1091,1093,1095,1097,1099,1101,1104,1106,1109,1111,1114],{"class":690,"line":1083},15,[688,1085,1086],{"class":716},"  resolved",[688,1088,990],{"class":702},[688,1090,1060],{"class":702},[688,1092,1063],{"class":918},[688,1094,720],{"class":702},[688,1096,1068],{"class":698},[688,1098,815],{"class":702},[688,1100,1040],{"class":694},[688,1102,1103],{"class":698}," void",[688,1105,1000],{"class":702},[688,1107,1108],{"class":698}," Promise",[688,1110,909],{"class":702},[688,1112,1113],{"class":698},"void",[688,1115,1116],{"class":702},">\n",[688,1118,1120],{"class":690,"line":1119},16,[688,1121,745],{"class":702},[614,1123,1125],{"id":1124},"bootstrap-providers","Bootstrap providers",[594,1127,1128,1129,1132],{},"A bootstrap provider adds your module's data to an area's single request, so your composable needs no request of its\nown. An area such as the account pages shows data from several modules for the\n",[598,1130,1131],{"href":87},"signed-in user",". Without providers, each module's composable makes its own request.",[594,1134,1135,1136,1139,1140,1143],{},"The area loads ",[652,1137,1138],{},"GET \u002Fapi\u002Fauth\u002Fbootstrap?scope=\u003Cscope>"," before its pages set up. That request primes the\n",[652,1141,1142],{},"useCachedFetch"," cache under each provider's key.",[679,1145,1147],{"className":681,"code":1146,"language":683,"meta":684,"style":684},"function registerBootstrapProvider(nuxt: Nuxt, provider: {\n  \u002F** The area, e.g. `account`. *\u002F\n  scope: string\n  \u002F** The response key, and the `useCachedFetch` key your composable already uses for the same data. *\u002F\n  key: string\n  \u002F** Server file whose default export is `(event: H3Event) => Promise\u003Cdata>`; absolute or relative to rootDir. *\u002F\n  handler: string\n}): void\n\ngetBootstrapProviders(nuxt: Nuxt, scope?: string): BootstrapProvider[] \u002F\u002F what is registered so far\ndefineBootstrapRegistry(nuxt: Nuxt): void \u002F\u002F bundles them into `#bootstrap\u002Fproviders` (called by @frigear-nu\u002Fauth)\n",[652,1148,1149,1173,1178,1187,1192,1201,1206,1215,1222,1226,1261],{"__ignoreMap":684},[688,1150,1151,1153,1156,1158,1160,1162,1164,1166,1169,1171],{"class":690,"line":691},[688,1152,903],{"class":694},[688,1154,1155],{"class":758}," registerBootstrapProvider",[688,1157,805],{"class":702},[688,1159,919],{"class":918},[688,1161,720],{"class":702},[688,1163,924],{"class":698},[688,1165,765],{"class":702},[688,1167,1168],{"class":918}," provider",[688,1170,720],{"class":702},[688,1172,703],{"class":702},[688,1174,1175],{"class":690,"line":706},[688,1176,1177],{"class":709},"  \u002F** The area, e.g. `account`. *\u002F\n",[688,1179,1180,1183,1185],{"class":690,"line":713},[688,1181,1182],{"class":716},"  scope",[688,1184,720],{"class":702},[688,1186,723],{"class":698},[688,1188,1189],{"class":690,"line":726},[688,1190,1191],{"class":709},"  \u002F** The response key, and the `useCachedFetch` key your composable already uses for the same data. *\u002F\n",[688,1193,1194,1197,1199],{"class":690,"line":732},[688,1195,1196],{"class":716},"  key",[688,1198,720],{"class":702},[688,1200,723],{"class":698},[688,1202,1203],{"class":690,"line":742},[688,1204,1205],{"class":709},"  \u002F** Server file whose default export is `(event: H3Event) => Promise\u003Cdata>`; absolute or relative to rootDir. *\u002F\n",[688,1207,1208,1211,1213],{"class":690,"line":748},[688,1209,1210],{"class":716},"  handler",[688,1212,720],{"class":702},[688,1214,723],{"class":698},[688,1216,1217,1220],{"class":690,"line":755},[688,1218,1219],{"class":702},"}):",[688,1221,944],{"class":698},[688,1223,1224],{"class":690,"line":770},[688,1225,752],{"emptyLinePlaceholder":751},[688,1227,1228,1231,1233,1235,1237,1239,1241,1244,1246,1249,1252,1255,1258],{"class":690,"line":790},[688,1229,1230],{"class":758},"getBootstrapProviders",[688,1232,805],{"class":702},[688,1234,919],{"class":918},[688,1236,720],{"class":702},[688,1238,924],{"class":698},[688,1240,765],{"class":702},[688,1242,1243],{"class":918}," scope",[688,1245,990],{"class":702},[688,1247,1248],{"class":698}," string",[688,1250,1251],{"class":702},"):",[688,1253,1254],{"class":698}," BootstrapProvider",[688,1256,1257],{"class":761},"[] ",[688,1259,1260],{"class":709},"\u002F\u002F what is registered so far\n",[688,1262,1263,1266,1268,1270,1272,1274,1276,1278],{"class":690,"line":820},[688,1264,1265],{"class":758},"defineBootstrapRegistry",[688,1267,805],{"class":702},[688,1269,919],{"class":918},[688,1271,720],{"class":702},[688,1273,924],{"class":698},[688,1275,1251],{"class":702},[688,1277,1103],{"class":698},[688,1279,1280],{"class":709}," \u002F\u002F bundles them into `#bootstrap\u002Fproviders` (called by @frigear-nu\u002Fauth)\n",[594,1282,1283],{},"Share one function between your endpoint and the provider, so both return the same shape. Events does it like this:",[679,1285,1288],{"className":681,"code":1286,"filename":1287,"language":683,"meta":684,"style":684},"export default async function myTickets(event: H3Event): Promise\u003CTicketDto[]> {\n  const { user } = await authorize(event, 'tickets:read')\n  return listUserTickets(user.id)\n}\n","runtime\u002Fserver\u002Fbootstrap\u002Fmy-tickets.ts",[652,1289,1290,1334,1372,1392],{"__ignoreMap":684},[688,1291,1292,1296,1299,1302,1305,1308,1310,1313,1315,1318,1320,1322,1324,1327,1330,1332],{"class":690,"line":691},[688,1293,1295],{"class":1294},"s7zQu","export",[688,1297,1298],{"class":1294}," default",[688,1300,1301],{"class":694}," async",[688,1303,1304],{"class":694}," function",[688,1306,1307],{"class":758}," myTickets",[688,1309,805],{"class":702},[688,1311,1312],{"class":918},"event",[688,1314,720],{"class":702},[688,1316,1317],{"class":698}," H3Event",[688,1319,1251],{"class":702},[688,1321,1108],{"class":698},[688,1323,909],{"class":702},[688,1325,1326],{"class":698},"TicketDto",[688,1328,1329],{"class":761},"[]",[688,1331,961],{"class":702},[688,1333,703],{"class":702},[688,1335,1336,1339,1342,1345,1348,1351,1354,1357,1359,1361,1363,1365,1368,1370],{"class":690,"line":706},[688,1337,1338],{"class":694},"  const",[688,1340,1341],{"class":702}," {",[688,1343,1344],{"class":761}," user",[688,1346,1347],{"class":702}," }",[688,1349,1350],{"class":702}," =",[688,1352,1353],{"class":1294}," await",[688,1355,1356],{"class":758}," authorize",[688,1358,805],{"class":716},[688,1360,1312],{"class":761},[688,1362,765],{"class":702},[688,1364,777],{"class":702},[688,1366,1367],{"class":780},"tickets:read",[688,1369,784],{"class":702},[688,1371,826],{"class":716},[688,1373,1374,1377,1380,1382,1385,1387,1390],{"class":690,"line":713},[688,1375,1376],{"class":1294},"  return",[688,1378,1379],{"class":758}," listUserTickets",[688,1381,805],{"class":716},[688,1383,1384],{"class":761},"user",[688,1386,604],{"class":702},[688,1388,1389],{"class":761},"id",[688,1391,826],{"class":716},[688,1393,1394],{"class":690,"line":726},[688,1395,745],{"class":702},[679,1397,1400],{"className":681,"code":1398,"filename":1399,"language":683,"meta":684,"style":684},"import myTickets from '..\u002F..\u002Fbootstrap\u002Fmy-tickets'\n\nexport default defineEventHandler(myTickets)\n","runtime\u002Fserver\u002Froutes\u002Fpublic\u002Ftickets-me.get.ts",[652,1401,1402,1420,1424],{"__ignoreMap":684},[688,1403,1404,1407,1410,1413,1415,1418],{"class":690,"line":691},[688,1405,1406],{"class":1294},"import",[688,1408,1409],{"class":761}," myTickets ",[688,1411,1412],{"class":1294},"from",[688,1414,777],{"class":702},[688,1416,1417],{"class":780},"..\u002F..\u002Fbootstrap\u002Fmy-tickets",[688,1419,1008],{"class":702},[688,1421,1422],{"class":690,"line":706},[688,1423,752],{"emptyLinePlaceholder":751},[688,1425,1426,1428,1430,1433],{"class":690,"line":713},[688,1427,1295],{"class":1294},[688,1429,1298],{"class":1294},[688,1431,1432],{"class":758}," defineEventHandler",[688,1434,1435],{"class":761},"(myTickets)\n",[679,1437,1440],{"className":681,"code":1438,"filename":1439,"language":683,"meta":684,"style":684},"registerBootstrapProvider(nuxt, {\n  scope: 'account',\n  key: 'events:tickets:mine', \u002F\u002F what useMyTickets() passes to useCachedFetch\n  handler: resolver.resolve('.\u002Fruntime\u002Fserver\u002Fbootstrap\u002Fmy-tickets'),\n})\n","module.ts",[652,1441,1442,1453,1468,1486,1511],{"__ignoreMap":684},[688,1443,1444,1447,1449,1451],{"class":690,"line":691},[688,1445,1446],{"class":758},"registerBootstrapProvider",[688,1448,762],{"class":761},[688,1450,765],{"class":702},[688,1452,703],{"class":702},[688,1454,1455,1457,1459,1461,1464,1466],{"class":690,"line":706},[688,1456,1182],{"class":716},[688,1458,720],{"class":702},[688,1460,777],{"class":702},[688,1462,1463],{"class":780},"account",[688,1465,784],{"class":702},[688,1467,787],{"class":702},[688,1469,1470,1472,1474,1476,1479,1481,1483],{"class":690,"line":713},[688,1471,1196],{"class":716},[688,1473,720],{"class":702},[688,1475,777],{"class":702},[688,1477,1478],{"class":780},"events:tickets:mine",[688,1480,784],{"class":702},[688,1482,765],{"class":702},[688,1484,1485],{"class":709}," \u002F\u002F what useMyTickets() passes to useCachedFetch\n",[688,1487,1488,1490,1492,1494,1496,1498,1500,1502,1505,1507,1509],{"class":690,"line":726},[688,1489,1210],{"class":716},[688,1491,720],{"class":702},[688,1493,797],{"class":761},[688,1495,604],{"class":702},[688,1497,802],{"class":758},[688,1499,805],{"class":761},[688,1501,784],{"class":702},[688,1503,1504],{"class":780},".\u002Fruntime\u002Fserver\u002Fbootstrap\u002Fmy-tickets",[688,1506,784],{"class":702},[688,1508,815],{"class":761},[688,1510,787],{"class":702},[688,1512,1513,1515],{"class":690,"line":732},[688,1514,823],{"class":702},[688,1516,826],{"class":761},[594,1518,1519,1520,1522],{},"Your composable does not change. ",[652,1521,1142],{}," finds the primed entry under its key, on the server, while hydrating\nand on client navigation.",[1524,1525,1527],"h3",{"id":1526},"how-it-fits-together","How it fits together",[625,1529,1530,1540],{},[628,1531,1532],{},[631,1533,1534,1537],{},[634,1535,1536],{},"Part",[634,1538,1539],{},"Behaviour",[644,1541,1542,1557,1583,1598,1606,1618],{},[631,1543,1544,1547],{},[649,1545,1546],{},"The route",[649,1548,1549,1550,1553,1554,604],{},"Auth serves it. It calls ",[652,1551,1552],{},"requireAuth"," once (authentication only), runs the scope's providers side by side and returns ",[652,1555,1556],{},"{ [key]: data }",[631,1558,1559,1562],{},[649,1560,1561],{},"Route errors",[649,1563,1564,1567,1568,1571,1572,1575,1576,1579,1580,604],{},[652,1565,1566],{},"401"," when signed out, ",[652,1569,1570],{},"400"," without ",[652,1573,1574],{},"scope",", ",[652,1577,1578],{},"404"," for a scope with no providers. The response is ",[652,1581,1582],{},"private, no-store",[631,1584,1585,1587],{},[649,1586,199],{},[649,1588,1589,1590,1593,1594,1597],{},"The ",[598,1591,1592],{"href":87},"principal"," is cached on the event. Call ",[652,1595,1596],{},"authorize(event, '\u003Cpermission>')"," in the provider, so a token without the permission gets nothing, as on your own route.",[631,1599,1600,1603],{},[649,1601,1602],{},"Failures",[649,1604,1605],{},"A provider that throws is left out and logged. Your composable then fetches from your own endpoint.",[631,1607,1608,1611],{},[649,1609,1610],{},"The client",[649,1612,1613,1614,1617],{},"The area's owner calls ",[652,1615,1616],{},"loadBootstrap(scope)"," from a route middleware. It refetches when the last load is over a minute old.",[631,1619,1620,1624],{},[649,1621,1589,1622,1243],{},[652,1623,1463],{},[649,1625,1626],{},"Account adds the middleware to every account page and resets it when the signed-in user changes.",[594,1628,1629,1630,1633,1634,1636,1637,1640,1641,1643,1644,1648],{},"Module Kit cannot serve the route itself, because Auth already depends on Module Kit. Today Subscriptions\n(",[652,1631,1632],{},"subscriptions:me","), Events (",[652,1635,1478],{},") and OAuth Server (",[652,1638,1639],{},"oauth-server:mine",") provide ",[652,1642,1463],{}," data.\n",[598,1645,1647],{"href":1646},"\u002Fmodules\u002Finterface\u002Fui\u002Fcomposables#one-request-for-an-area-loadbootstrap","One request for an area"," covers the client.",[1650,1651,1652],"warning",{},"Providers share one response. A provider that sets a status or headers changes them for every other provider.",[835,1654,1655],{},"Register only data that a page of the area shows on first render. Data loaded later, and lists that grow without\nbound, belong in your module's own endpoint.",[614,1657,1659],{"id":1658},"next-steps","Next steps",[1661,1662,1663,1670,1675],"ul",{},[1664,1665,1666,1669],"li",{},[598,1667,1668],{"href":388},"Module Kit server toolkit"," – serve data from your own routes.",[1664,1671,1672,1674],{},[598,1673,354],{"href":355}," – write the menu source file your module registers.",[1664,1676,1677,1679],{},[598,1678,358],{"href":359}," – add widgets and tabs to another module's pages.",[1681,1682,1683],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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 .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 .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .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}",{"title":684,"searchDepth":706,"depth":706,"links":1685},[1686,1687,1688,1691],{"id":616,"depth":706,"text":617},{"id":876,"depth":706,"text":877},{"id":1124,"depth":706,"text":1125,"children":1689},[1690],{"id":1526,"depth":713,"text":1527},{"id":1658,"depth":706,"text":1659},"Let your module add menu items, registry entries and account data to other modules without importing them.","md",null,{},{"title":391},{"title":589,"description":1692},"xdUIVvD76ai5xB_49BLG1B3vVC_LNkEgQJ8bUq58lyE",[1700,1702],{"title":387,"path":388,"stem":389,"description":1701,"children":-1},"The helpers a module's server routes use for errors, parameters, pagination, responses, CORS and tests.",{"title":395,"path":396,"stem":397,"description":1703,"children":-1},"Ship a module's strings as locale files, and override any module string from your app.",1794503156622]