[{"data":1,"prerenderedAt":2026},["ShallowReactive",2],{"navigation_docs":3,"-modules-platform-module-kit-server-toolkit":587,"-modules-platform-module-kit-server-toolkit-surround":2021},[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":2014,"extension":2015,"links":2016,"meta":2017,"navigation":2018,"path":388,"seo":2019,"stem":389,"__hash__":2020},"docs\u002F3.modules\u002F5.platform\u002F1.module-kit\u002F2.server-toolkit.md","Module Kit server toolkit",{"type":591,"value":592,"toc":2004},"minimark",[593,604,612,617,634,797,832,836,855,920,924,930,964,1084,1088,1099,1202,1246,1254,1272,1276,1283,1396,1399,1410,1725,1834,1872,1886,1890,1905,1972,1978,1982,2000],[594,595,596,597,600,601,603],"p",{},"This page lists the helpers your module's route handlers use, so every module's API answers the same way. It is for\nmodule authors, and the rules for using them are in ",[598,599,121],"a",{"href":122},". Set up the module\nfirst: ",[598,602,173],{"href":382},".",[594,605,606,607,611],{},"Import the helpers from ",[608,609,610],"code",{},"@frigear-nu\u002Fmodule-kit\u002Fserver",". They are not auto-imported, so they never clash with h3's own\nhelpers.",[613,614,616],"h2",{"id":615},"registering-routes","Registering routes",[594,618,619,622,623,626,627,630,631,603],{},[608,620,621],{},"addModuleRoutes"," registers all of a module's routes from one table in ",[608,624,625],{},"setup()",". It comes from\n",[608,628,629],{},"@frigear-nu\u002Fmodule-kit\u002Futils",", not ",[608,632,633],{},"\u002Fserver",[635,636,641],"pre",{"className":637,"code":638,"language":639,"meta":640,"style":640},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","function addModuleRoutes(\n  resolver: Resolver,\n  routes: Array\u003C{ method: 'get' | 'post' | 'put' | 'patch' | 'delete', path: string, file: string }>,\n  options: { base: string },\n): void\n","ts","",[608,642,643,660,677,767,788],{"__ignoreMap":640},[644,645,648,652,656],"span",{"class":646,"line":647},"line",1,[644,649,651],{"class":650},"spNyl","function",[644,653,655],{"class":654},"s2Zo4"," addModuleRoutes",[644,657,659],{"class":658},"sMK4o","(\n",[644,661,663,667,670,674],{"class":646,"line":662},2,[644,664,666],{"class":665},"sHdIc","  resolver",[644,668,669],{"class":658},":",[644,671,673],{"class":672},"sBMFI"," Resolver",[644,675,676],{"class":658},",\n",[644,678,680,683,685,688,691,695,697,700,704,707,710,712,715,717,719,721,724,726,728,730,733,735,737,739,742,744,747,750,752,755,757,760,762,764],{"class":646,"line":679},3,[644,681,682],{"class":665},"  routes",[644,684,669],{"class":658},[644,686,687],{"class":672}," Array",[644,689,690],{"class":658},"\u003C{",[644,692,694],{"class":693},"swJcz"," method",[644,696,669],{"class":658},[644,698,699],{"class":658}," '",[644,701,703],{"class":702},"sfazB","get",[644,705,706],{"class":658},"'",[644,708,709],{"class":658}," |",[644,711,699],{"class":658},[644,713,714],{"class":702},"post",[644,716,706],{"class":658},[644,718,709],{"class":658},[644,720,699],{"class":658},[644,722,723],{"class":702},"put",[644,725,706],{"class":658},[644,727,709],{"class":658},[644,729,699],{"class":658},[644,731,732],{"class":702},"patch",[644,734,706],{"class":658},[644,736,709],{"class":658},[644,738,699],{"class":658},[644,740,741],{"class":702},"delete",[644,743,706],{"class":658},[644,745,746],{"class":658},",",[644,748,749],{"class":693}," path",[644,751,669],{"class":658},[644,753,754],{"class":672}," string",[644,756,746],{"class":658},[644,758,759],{"class":693}," file",[644,761,669],{"class":658},[644,763,754],{"class":672},[644,765,766],{"class":658}," }>,\n",[644,768,770,773,775,778,781,783,785],{"class":646,"line":769},4,[644,771,772],{"class":665},"  options",[644,774,669],{"class":658},[644,776,777],{"class":658}," {",[644,779,780],{"class":693}," base",[644,782,669],{"class":658},[644,784,754],{"class":672},[644,786,787],{"class":658}," },\n",[644,789,791,794],{"class":646,"line":790},5,[644,792,793],{"class":658},"):",[644,795,796],{"class":672}," void\n",[594,798,799,802,803,806,807,810,811,814,815,818,819,821,822,825,826,806,828,831],{},[608,800,801],{},"file"," is relative to ",[608,804,805],{},".\u002Fruntime\u002Fserver\u002Froutes\u002F",". ",[608,808,809],{},"path"," is joined onto ",[608,812,813],{},"base",", ",[608,816,817],{},"''"," is ",[608,820,813],{}," itself, and a path that\nstarts with ",[608,823,824],{},"\u002F"," ignores ",[608,827,813],{},[598,829,616],{"href":830},"\u002Fguide\u002Fbest-practices\u002Fhttp-routes#registering-routes"," has a full\nexample.",[613,833,835],{"id":834},"errors","Errors",[594,837,838,839,842,843,846,847,850,851,854],{},"Each helper returns an h3 error to ",[608,840,841],{},"throw",", with the message in ",[608,844,845],{},"statusMessage"," and a snake_case code in ",[608,848,849],{},"data.code",".\n",[598,852,835],{"href":853},"\u002Fguide\u002Fbest-practices\u002Fhttp-routes#errors"," has the status and code of each, and examples.",[856,857,858,871],"table",{},[859,860,861],"thead",{},[862,863,864,868],"tr",{},[865,866,867],"th",{},"Helper",[865,869,870],{},"Purpose",[872,873,874,885,907],"tbody",{},[862,875,876,882],{},[877,878,879],"td",{},[608,880,881],{},"apiError(status, code, message, data?)",[877,883,884],{},"Any status and code.",[862,886,887,904],{},[877,888,889,814,892,814,895,814,898,814,901],{},[608,890,891],{},"badRequest",[608,893,894],{},"forbidden",[608,896,897],{},"notFound",[608,899,900],{},"conflict",[608,902,903],{},"notConfigured",[877,905,906],{},"One status each, each with a default message.",[862,908,909,914],{},[877,910,911],{},[608,912,913],{},"validationError(issues, message?)",[877,915,916,917,603],{},"A 400 with one issue per field in ",[608,918,919],{},"data.issues",[613,921,923],{"id":922},"params","Params",[594,925,926,927,603],{},"Two zod schemas validate ids the same way in every module. Pass them to h3's ",[608,928,929],{},"getValidatedRouterParams",[856,931,932,942],{},[859,933,934],{},[862,935,936,939],{},[865,937,938],{},"Schema",[865,940,941],{},"Accepts",[872,943,944,954],{},[862,945,946,951],{},[877,947,948],{},[608,949,950],{},"idParams(name = 'id')",[877,952,953],{},"A non-empty string.",[862,955,956,961],{},[877,957,958],{},[608,959,960],{},"intIdParams(name = 'id')",[877,962,963],{},"A positive integer, coerced from the path.",[635,965,967],{"className":637,"code":966,"language":639,"meta":640,"style":640},"const { id } = await getValidatedRouterParams(event, idParams().parse)\nconst { tokenId } = await getValidatedRouterParams(event, idParams('tokenId').parse)\nconst { id: userId } = await getValidatedRouterParams(event, intIdParams().parse)\n",[608,968,969,1009,1049],{"__ignoreMap":640},[644,970,971,974,976,980,983,986,990,993,996,998,1001,1004,1006],{"class":646,"line":647},[644,972,973],{"class":650},"const",[644,975,777],{"class":658},[644,977,979],{"class":978},"sTEyZ"," id ",[644,981,982],{"class":658},"}",[644,984,985],{"class":658}," =",[644,987,989],{"class":988},"s7zQu"," await",[644,991,992],{"class":654}," getValidatedRouterParams",[644,994,995],{"class":978},"(event",[644,997,746],{"class":658},[644,999,1000],{"class":654}," idParams",[644,1002,1003],{"class":978},"()",[644,1005,603],{"class":658},[644,1007,1008],{"class":978},"parse)\n",[644,1010,1011,1013,1015,1018,1020,1022,1024,1026,1028,1030,1032,1035,1037,1040,1042,1045,1047],{"class":646,"line":662},[644,1012,973],{"class":650},[644,1014,777],{"class":658},[644,1016,1017],{"class":978}," tokenId ",[644,1019,982],{"class":658},[644,1021,985],{"class":658},[644,1023,989],{"class":988},[644,1025,992],{"class":654},[644,1027,995],{"class":978},[644,1029,746],{"class":658},[644,1031,1000],{"class":654},[644,1033,1034],{"class":978},"(",[644,1036,706],{"class":658},[644,1038,1039],{"class":702},"tokenId",[644,1041,706],{"class":658},[644,1043,1044],{"class":978},")",[644,1046,603],{"class":658},[644,1048,1008],{"class":978},[644,1050,1051,1053,1055,1058,1060,1063,1065,1067,1069,1071,1073,1075,1078,1080,1082],{"class":646,"line":679},[644,1052,973],{"class":650},[644,1054,777],{"class":658},[644,1056,1057],{"class":693}," id",[644,1059,669],{"class":658},[644,1061,1062],{"class":978}," userId ",[644,1064,982],{"class":658},[644,1066,985],{"class":658},[644,1068,989],{"class":988},[644,1070,992],{"class":654},[644,1072,995],{"class":978},[644,1074,746],{"class":658},[644,1076,1077],{"class":654}," intIdParams",[644,1079,1003],{"class":978},[644,1081,603],{"class":658},[644,1083,1008],{"class":978},[613,1085,1087],{"id":1086},"pagination","Pagination",[594,1089,1090,1091,1094,1095,1098],{},"These helpers turn a list query into a page, in the query keys that ",[608,1092,1093],{},"useTableQuery"," sends.\n",[598,1096,1087],{"href":1097},"\u002Fguide\u002Fbest-practices\u002Fhttp-routes#pagination"," has a full list handler.",[856,1100,1101,1110],{},[859,1102,1103],{},[862,1104,1105,1107],{},[865,1106,867],{},[865,1108,1109],{},"Returns",[872,1111,1112,1122,1135,1151,1172,1182],{},[862,1113,1114,1119],{},[877,1115,1116],{},[608,1117,1118],{},"pageQuery({ sort, defaultSort?, defaultOrder?, defaultPageSize?, maxPageSize?, filters? })",[877,1120,1121],{},"The zod schema of a list query.",[862,1123,1124,1129],{},[877,1125,1126],{},[608,1127,1128],{},"pageRange(query)",[877,1130,1131,1134],{},[608,1132,1133],{},"{ limit, offset }"," for the query's page.",[862,1136,1137,1142],{},[877,1138,1139],{},[608,1140,1141],{},"paginate({ items, total, query })",[877,1143,1144,1147,1148,603],{},[608,1145,1146],{},"Page\u003CT>",": ",[608,1149,1150],{},"{ items, total, page, pageSize }",[862,1152,1153,1158],{},[877,1154,1155],{},[608,1156,1157],{},"orderByQuery(columns, query, { tiebreaker })",[877,1159,1160,1161,1164,1165,1168,1169,603],{},"An ",[608,1162,1163],{},"orderBy"," from ",[608,1166,1167],{},"query.sort"," and ",[608,1170,1171],{},"query.order",[862,1173,1174,1179],{},[877,1175,1176],{},[608,1177,1178],{},"likeContains(column, value)",[877,1180,1181],{},"A case-insensitive \"contains\" search.",[862,1183,1184,1192],{},[877,1185,1186,814,1189],{},[608,1187,1188],{},"likeEscaped(column, pattern)",[608,1190,1191],{},"escapeLike(value)",[877,1193,1194,1195,1168,1198,1201],{},"The search behind it, with ",[608,1196,1197],{},"%",[608,1199,1200],{},"_"," escaped.",[594,1203,1204,1210,1211,1214,1215,1218,1219,814,1222,814,1225,1228,1229,1232,1233,1235,1236,1239,1240,1242,1243,603],{},[1205,1206,1207],"strong",{},[608,1208,1209],{},"pageQuery"," accepts ",[608,1212,1213],{},"page"," (from 1), ",[608,1216,1217],{},"pageSize"," (default 20, at most 100), ",[608,1220,1221],{},"q",[608,1223,1224],{},"sort",[608,1226,1227],{},"order"," and your ",[608,1230,1231],{},"filters","\nkeys. ",[608,1234,1224],{}," defaults to ",[608,1237,1238],{},"defaultSort"," or the first name, and ",[608,1241,1227],{}," to ",[608,1244,1245],{},"desc",[594,1247,1248,1253],{},[1205,1249,1250],{},[608,1251,1252],{},"orderByQuery"," always sorts by the tiebreaker last, descending, so pages stay stable. Pass the id.",[594,1255,1256,1261,1262,1265,1266,1268,1269,1271],{},[1205,1257,1258],{},[608,1259,1260],{},"likeContains"," works on both ",[598,1263,1264],{"href":87},"dialects",". A ",[608,1267,1197],{}," or ",[608,1270,1200],{}," in the search is matched literally.",[613,1273,1275],{"id":1274},"responses-and-helpers","Responses and helpers",[594,1277,1278,1282],{},[598,1279,1281],{"href":1280},"\u002Fguide\u002Fbest-practices\u002Fhttp-routes#responses","Responses"," explains when to use each response helper.",[856,1284,1285,1293],{},[859,1286,1287],{},[862,1288,1289,1291],{},[865,1290,867],{},[865,1292,870],{},[872,1294,1295,1311,1328,1346,1359,1373],{},[862,1296,1297,1308],{},[877,1298,1299,814,1302,814,1305],{},[608,1300,1301],{},"created(event, dto)",[608,1303,1304],{},"noContent(event)",[608,1306,1307],{},"isoDate(value)",[877,1309,1310],{},"201 with a DTO, 204 with no body, and dates as ISO strings.",[862,1312,1313,1318],{},[877,1314,1315],{},[608,1316,1317],{},"uniqueCopySlug(base, exists)",[877,1319,1320,1321,814,1324,1327],{},"The first free ",[608,1322,1323],{},"\u003Cbase>-copy",[608,1325,1326],{},"\u003Cbase>-copy-2",", and so on.",[862,1329,1330,1335],{},[877,1331,1332],{},[608,1333,1334],{},"resolveSameOriginUrl(event, url, { fallback?, name? })",[877,1336,1337,1338,1341,1342,1345],{},"A return URL on the request's origin, ",[608,1339,1340],{},"fallback"," when empty, ",[608,1343,1344],{},"400"," for another origin.",[862,1347,1348,1353],{},[877,1349,1350],{},[608,1351,1352],{},"sameOriginUrl(input, origin)",[877,1354,1355,1356,603],{},"The same check without an event. Returns the normalised URL, or ",[608,1357,1358],{},"null",[862,1360,1361,1366],{},[877,1362,1363],{},[608,1364,1365],{},"applyBearerCors(event, options)",[877,1367,1368,1369,603],{},"CORS for callers with an access token on other origins. See ",[598,1370,1372],{"href":1371},"#bearer-cors","Bearer CORS",[862,1374,1375,1380],{},[877,1376,1377],{},[608,1378,1379],{},"matchesPathPrefix(pathname, prefixes)",[877,1381,1382,1383,1386,1387,1168,1390,630,1393,603],{},"Whether a path is under a prefix. ",[608,1384,1385],{},"\u002Fapi\u002F"," matches ",[608,1388,1389],{},"\u002Fapi",[608,1391,1392],{},"\u002Fapi\u002Fx",[608,1394,1395],{},"\u002Fapis",[613,1397,1372],{"id":1398},"bearer-cors",[594,1400,1401,1402,1405,1406,1409],{},"A browser app on another origin needs CORS headers to call your API with an access token. Examples are the\n",[608,1403,1404],{},"capacitor:\u002F\u002Flocalhost"," webview of a mobile app, or a single-page app. It must never get cookies across origins.\n",[608,1407,1408],{},"applyBearerCors"," adds exactly those headers, from a middleware, for the paths you choose:",[635,1411,1414],{"className":637,"code":1412,"filename":1413,"language":639,"meta":640,"style":640},"import { applyBearerCors, matchesPathPrefix } from '@frigear-nu\u002Fmodule-kit\u002Fserver'\n\nexport default defineEventHandler((event) => {\n  if (!matchesPathPrefix(getRequestURL(event).pathname, ['\u002Fapi\u002F'])) return\n  const preflight = applyBearerCors(event, {\n    origins: ['capacitor:\u002F\u002Flocalhost', 'https:\u002F\u002Flocalhost'],\n    methods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],\n    allowHeaders: ['authorization', 'content-type', 'accept'],\n    exposeHeaders: ['www-authenticate'],\n  })\n  if (preflight) return ''\n})\n","server\u002Fmiddleware\u002Fapi-cors.ts",[608,1415,1416,1444,1450,1476,1523,1543,1573,1630,1669,1690,1699,1718],{"__ignoreMap":640},[644,1417,1418,1421,1423,1426,1428,1431,1434,1437,1439,1441],{"class":646,"line":647},[644,1419,1420],{"class":988},"import",[644,1422,777],{"class":658},[644,1424,1425],{"class":978}," applyBearerCors",[644,1427,746],{"class":658},[644,1429,1430],{"class":978}," matchesPathPrefix",[644,1432,1433],{"class":658}," }",[644,1435,1436],{"class":988}," from",[644,1438,699],{"class":658},[644,1440,610],{"class":702},[644,1442,1443],{"class":658},"'\n",[644,1445,1446],{"class":646,"line":662},[644,1447,1449],{"emptyLinePlaceholder":1448},true,"\n",[644,1451,1452,1455,1458,1461,1463,1465,1468,1470,1473],{"class":646,"line":679},[644,1453,1454],{"class":988},"export",[644,1456,1457],{"class":988}," default",[644,1459,1460],{"class":654}," defineEventHandler",[644,1462,1034],{"class":978},[644,1464,1034],{"class":658},[644,1466,1467],{"class":665},"event",[644,1469,1044],{"class":658},[644,1471,1472],{"class":650}," =>",[644,1474,1475],{"class":658}," {\n",[644,1477,1478,1481,1484,1487,1490,1492,1495,1497,1499,1501,1503,1506,1508,1511,1513,1515,1517,1520],{"class":646,"line":769},[644,1479,1480],{"class":988},"  if",[644,1482,1483],{"class":693}," (",[644,1485,1486],{"class":658},"!",[644,1488,1489],{"class":654},"matchesPathPrefix",[644,1491,1034],{"class":693},[644,1493,1494],{"class":654},"getRequestURL",[644,1496,1034],{"class":693},[644,1498,1467],{"class":978},[644,1500,1044],{"class":693},[644,1502,603],{"class":658},[644,1504,1505],{"class":978},"pathname",[644,1507,746],{"class":658},[644,1509,1510],{"class":693}," [",[644,1512,706],{"class":658},[644,1514,1385],{"class":702},[644,1516,706],{"class":658},[644,1518,1519],{"class":693},"])) ",[644,1521,1522],{"class":988},"return\n",[644,1524,1525,1528,1531,1533,1535,1537,1539,1541],{"class":646,"line":790},[644,1526,1527],{"class":650},"  const",[644,1529,1530],{"class":978}," preflight",[644,1532,985],{"class":658},[644,1534,1425],{"class":654},[644,1536,1034],{"class":693},[644,1538,1467],{"class":978},[644,1540,746],{"class":658},[644,1542,1475],{"class":658},[644,1544,1546,1549,1551,1553,1555,1557,1559,1561,1563,1566,1568,1571],{"class":646,"line":1545},6,[644,1547,1548],{"class":693},"    origins",[644,1550,669],{"class":658},[644,1552,1510],{"class":693},[644,1554,706],{"class":658},[644,1556,1404],{"class":702},[644,1558,706],{"class":658},[644,1560,746],{"class":658},[644,1562,699],{"class":658},[644,1564,1565],{"class":702},"https:\u002F\u002Flocalhost",[644,1567,706],{"class":658},[644,1569,1570],{"class":693},"]",[644,1572,676],{"class":658},[644,1574,1576,1579,1581,1583,1585,1588,1590,1592,1594,1597,1599,1601,1603,1606,1608,1610,1612,1615,1617,1619,1621,1624,1626,1628],{"class":646,"line":1575},7,[644,1577,1578],{"class":693},"    methods",[644,1580,669],{"class":658},[644,1582,1510],{"class":693},[644,1584,706],{"class":658},[644,1586,1587],{"class":702},"GET",[644,1589,706],{"class":658},[644,1591,746],{"class":658},[644,1593,699],{"class":658},[644,1595,1596],{"class":702},"POST",[644,1598,706],{"class":658},[644,1600,746],{"class":658},[644,1602,699],{"class":658},[644,1604,1605],{"class":702},"PATCH",[644,1607,706],{"class":658},[644,1609,746],{"class":658},[644,1611,699],{"class":658},[644,1613,1614],{"class":702},"DELETE",[644,1616,706],{"class":658},[644,1618,746],{"class":658},[644,1620,699],{"class":658},[644,1622,1623],{"class":702},"OPTIONS",[644,1625,706],{"class":658},[644,1627,1570],{"class":693},[644,1629,676],{"class":658},[644,1631,1633,1636,1638,1640,1642,1645,1647,1649,1651,1654,1656,1658,1660,1663,1665,1667],{"class":646,"line":1632},8,[644,1634,1635],{"class":693},"    allowHeaders",[644,1637,669],{"class":658},[644,1639,1510],{"class":693},[644,1641,706],{"class":658},[644,1643,1644],{"class":702},"authorization",[644,1646,706],{"class":658},[644,1648,746],{"class":658},[644,1650,699],{"class":658},[644,1652,1653],{"class":702},"content-type",[644,1655,706],{"class":658},[644,1657,746],{"class":658},[644,1659,699],{"class":658},[644,1661,1662],{"class":702},"accept",[644,1664,706],{"class":658},[644,1666,1570],{"class":693},[644,1668,676],{"class":658},[644,1670,1672,1675,1677,1679,1681,1684,1686,1688],{"class":646,"line":1671},9,[644,1673,1674],{"class":693},"    exposeHeaders",[644,1676,669],{"class":658},[644,1678,1510],{"class":693},[644,1680,706],{"class":658},[644,1682,1683],{"class":702},"www-authenticate",[644,1685,706],{"class":658},[644,1687,1570],{"class":693},[644,1689,676],{"class":658},[644,1691,1693,1696],{"class":646,"line":1692},10,[644,1694,1695],{"class":658},"  }",[644,1697,1698],{"class":693},")\n",[644,1700,1702,1704,1706,1709,1712,1715],{"class":646,"line":1701},11,[644,1703,1480],{"class":988},[644,1705,1483],{"class":693},[644,1707,1708],{"class":978},"preflight",[644,1710,1711],{"class":693},") ",[644,1713,1714],{"class":988},"return",[644,1716,1717],{"class":658}," ''\n",[644,1719,1721,1723],{"class":646,"line":1720},12,[644,1722,982],{"class":658},[644,1724,1698],{"class":978},[856,1726,1727,1740],{},[859,1728,1729],{},[862,1730,1731,1734,1737],{},[865,1732,1733],{},"Option",[865,1735,1736],{},"Default",[865,1738,1739],{},"Header",[872,1741,1742,1766,1781,1798,1816],{},[862,1743,1744,1749,1752],{},[877,1745,1746],{},[608,1747,1748],{},"origins",[877,1750,1751],{},"required",[877,1753,1754,1757,1758,1761,1762,1765],{},[608,1755,1756],{},"Access-Control-Allow-Origin",": the request's ",[608,1759,1760],{},"Origin",", when listed exactly. ",[608,1763,1764],{},"*"," never matches.",[862,1767,1768,1773,1775],{},[877,1769,1770],{},[608,1771,1772],{},"methods",[877,1774,1751],{},[877,1776,1777,1780],{},[608,1778,1779],{},"Access-Control-Allow-Methods",", as an array or a string.",[862,1782,1783,1788,1793],{},[877,1784,1785],{},[608,1786,1787],{},"allowHeaders",[877,1789,1790],{},[608,1791,1792],{},"authorization, content-type",[877,1794,1795,603],{},[608,1796,1797],{},"Access-Control-Allow-Headers",[862,1799,1800,1805,1808],{},[877,1801,1802],{},[608,1803,1804],{},"exposeHeaders",[877,1806,1807],{},"none",[877,1809,1810,1813,1814,603],{},[608,1811,1812],{},"Access-Control-Expose-Headers",", such as ",[608,1815,1683],{},[862,1817,1818,1823,1828],{},[877,1819,1820],{},[608,1821,1822],{},"maxAge",[877,1824,1825],{},[608,1826,1827],{},"600",[877,1829,1830,1833],{},[608,1831,1832],{},"Access-Control-Max-Age",", in seconds.",[1835,1836,1837,1845,1848,1854],"ul",{},[1838,1839,1840,1841,1844],"li",{},"It always adds ",[608,1842,1843],{},"Vary: Origin",", so caches keep one response per origin.",[1838,1846,1847],{},"It sets the CORS headers only for a listed origin.",[1838,1849,1850,1851,603],{},"It never sends ",[608,1852,1853],{},"Access-Control-Allow-Credentials",[1838,1855,1856,1857,1859,1860,1863,1864,1867,1868,1871],{},"It answers an ",[608,1858,1623],{}," request from a listed origin with ",[608,1861,1862],{},"204"," and returns ",[608,1865,1866],{},"true",", so the middleware ends it. Any\nother request returns ",[608,1869,1870],{},"false"," and continues.",[594,1873,1874,1875,1878,1879,1881,1882,1885],{},"The ",[608,1876,1877],{},"cors.paths"," option of ",[598,1880,225],{"href":226}," and\n",[598,1883,241],{"href":1884},"\u002Fmodules\u002Fidentity\u002Foauth-resource#cors"," both use it.",[613,1887,1889],{"id":1888},"testing-routes","Testing routes",[594,1891,1892,1895,1896,1899,1900,1164,1902,603],{},[608,1893,1894],{},"@frigear-nu\u002Fmodule-kit\u002Ftesting"," has two helpers for end-to-end tests against a\n",[598,1897,1898],{"href":87},"test fixture"," started with ",[608,1901,625],{},[608,1903,1904],{},"@nuxt\u002Ftest-utils\u002Fe2e",[856,1906,1907,1916],{},[859,1908,1909],{},[862,1910,1911,1913],{},[865,1912,867],{},[865,1914,1915],{},"What it does",[872,1917,1918,1928,1941,1955],{},[862,1919,1920,1925],{},[877,1921,1922],{},[608,1923,1924],{},"apiClient({ cookie?, bearer? })",[877,1926,1927],{},"Acts as one caller.",[862,1929,1930,1935],{},[877,1931,1932],{},[608,1933,1934],{},".json\u003CT>(method, path, body?)",[877,1936,1937,1938,1940],{},"Resolves with the parsed body of a 2xx response, or ",[608,1939,1358],{}," for 204. Rejects otherwise.",[862,1942,1943,1948],{},[877,1944,1945],{},[608,1946,1947],{},".fetch(method, path, body?)",[877,1949,1950,1951,1954],{},"Resolves with the raw ",[608,1952,1953],{},"Response",", whatever its status.",[862,1956,1957,1962],{},[877,1958,1959],{},[608,1960,1961],{},"expectApiError(promise, status, code?)",[877,1963,1964,1965,1968,1969,1971],{},"Asserts the request failed with ",[608,1966,1967],{},"status",", and ",[608,1970,849],{}," when given. Resolves with the error body.",[594,1973,1974,1977],{},[598,1975,1889],{"href":1976},"\u002Fguide\u002Fbest-practices\u002Fhttp-routes#testing-routes"," has an example.",[613,1979,1981],{"id":1980},"next-steps","Next steps",[1835,1983,1984,1989,1995],{},[1838,1985,1986,1988],{},[598,1987,121],{"href":122}," – the URL, handler order and response rules these helpers serve.",[1838,1990,1991,1994],{},[598,1992,1993],{"href":400},"Module Kit database helpers"," – give your routes a table to read.",[1838,1996,1997,1999],{},[598,1998,537],{"href":538}," – boot a test fixture for your route tests.",[2001,2002,2003],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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":640,"searchDepth":662,"depth":662,"links":2005},[2006,2007,2008,2009,2010,2011,2012,2013],{"id":615,"depth":662,"text":616},{"id":834,"depth":662,"text":835},{"id":922,"depth":662,"text":923},{"id":1086,"depth":662,"text":1087},{"id":1274,"depth":662,"text":1275},{"id":1398,"depth":662,"text":1372},{"id":1888,"depth":662,"text":1889},{"id":1980,"depth":662,"text":1981},"The helpers a module's server routes use for errors, parameters, pagination, responses, CORS and tests.","md",null,{},{"title":387},{"title":589,"description":2014},"MShbDEGnR1KxYTqtqgL142gbvhwakTHI1SwaA6pAHCA",[2022,2024],{"title":173,"path":382,"stem":383,"description":2023,"children":-1},"The shared helpers every Frigear module is built on, so modules register pages, routes and tables the same way.",{"title":391,"path":392,"stem":393,"description":2025,"children":-1},"Let your module add menu items, registry entries and account data to other modules without importing them.",1794503157642]