[{"data":1,"prerenderedAt":8113},["ShallowReactive",2],{"navLinks":3,"sidebar_docs_navigation_\u002Fdocs\u002Fiam":64,"navigation":257,"navLinks_footer":837,"\u002Fdocs\u002Fiam\u002Fguides\u002Frbac_page":850,"\u002Fdocs\u002Fiam\u002Fguides\u002Frbac_surround":4772,"\u002Fdocs\u002Fiam\u002Fguides\u002Frbac":4775},{"id":4,"extension":5,"links":6,"meta":61,"stem":62,"__hash__":63},"navigationMenu\u002Fnavigation.json","json",[7,52,57],{"nested":8,"label":9,"icon":10,"to":11,"children":12},true,"Docs","i-lucide-book-open","\u002Fdocs\u002Fgetting-started",[13,19,26,32,39,45],{"label":14,"icon":15,"to":11,"description":16,"github":17,"badge":18},"Getting Started","i-lucide-rocket","An introduction to help you understand the core components.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fdocshub","Start Here",{"label":20,"icon":21,"to":22,"description":23,"github":24,"badge":25},"Auth H3 Client","i-lucide-key-round","\u002Fdocs\u002Fauth-h3client","Seamlessly enforce OAuth 2.0 authentication and session management integrated directly as the client of the IAM module.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fauth-h3client","Core",{"label":27,"icon":28,"to":29,"description":30,"github":31,"badge":25},"IAM","i-lucide-shield-check","\u002Fdocs\u002Fiam","Identity and Access Management featuring granular roles, permissions, and security policies.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fauth",{"label":33,"icon":34,"to":35,"description":36,"github":37,"badge":38},"Bot Detection","i-lucide-cpu","\u002Fdocs\u002Fbot-detection","Advanced behavioral analysis and request fingerprinting to stop malicious automated traffic.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fbot-detector","Security",{"label":40,"icon":41,"to":42,"description":43,"github":44,"badge":38},"Shield Base","i-lucide-database-zap","\u002Fdocs\u002Fshield-base","CLI and programmatic toolkit for compiling offline-ready IP intelligence databases from BGP, GeoIP, Tor, FireHOL, and other public threat feeds.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fshield-base-cli",{"label":46,"icon":47,"to":48,"description":49,"github":50,"badge":51},"Utils","i-lucide-wrench","\u002Fdocs\u002Futils","A standard library of highly optimized helpers for formatting, validation, and core logic.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Futils","Library",{"nested":53,"label":54,"icon":55,"to":56},false,"Blog","i-lucide-pen-line","\u002Fblog",{"nested":53,"label":58,"icon":59,"to":60},"Website","lucide:app-window-mac","https:\u002F\u002Friavzon.com",{},"navigation","gkaQ0xRGxSLrLyM3kttLe0oBwkrR1EBjlepF8LSbwF8",[65],{"title":9,"path":66,"stem":67,"children":68,"page":53},"\u002Fdocs","docs",[69],{"title":27,"path":29,"stem":70,"children":71},"docs\u002Fiam\u002Findex",[72,73,76,216,219,236,240],{"title":27,"path":29,"stem":70},{"title":14,"path":74,"stem":75},"\u002Fdocs\u002Fiam\u002Fgetting-started","docs\u002Fiam\u002F00.getting-started",{"title":77,"path":78,"stem":79,"children":80},"Essentials","\u002Fdocs\u002Fiam\u002Fessentials","docs\u002Fiam\u002F01.essentials\u002Findex",[81,82,86,90,94,98,102,106,110,114,118,122,126,130,134,138,142,146,150,154,158,162,166],{"title":77,"path":78,"stem":79},{"title":83,"path":84,"stem":85},"Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Ftokens","docs\u002Fiam\u002F01.essentials\u002F00.tokens",{"title":87,"path":88,"stem":89},"Access Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Faccess-tokens","docs\u002Fiam\u002F01.essentials\u002F01.access-tokens",{"title":91,"path":92,"stem":93},"Refresh Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Frefresh-tokens","docs\u002Fiam\u002F01.essentials\u002F02.refresh-tokens",{"title":95,"path":96,"stem":97},"Anomaly Detection","\u002Fdocs\u002Fiam\u002Fessentials\u002Fanomalies","docs\u002Fiam\u002F01.essentials\u002F03.anomalies",{"title":99,"path":100,"stem":101},"Signup","\u002Fdocs\u002Fiam\u002Fessentials\u002Fsignup","docs\u002Fiam\u002F01.essentials\u002F04.signup",{"title":103,"path":104,"stem":105},"Login","\u002Fdocs\u002Fiam\u002Fessentials\u002Flogin","docs\u002Fiam\u002F01.essentials\u002F05.login",{"title":107,"path":108,"stem":109},"Logout","\u002Fdocs\u002Fiam\u002Fessentials\u002Flogout","docs\u002Fiam\u002F01.essentials\u002F06.logout",{"title":111,"path":112,"stem":113},"OAuth","\u002Fdocs\u002Fiam\u002Fessentials\u002Foauth","docs\u002Fiam\u002F01.essentials\u002F07.oauth",{"title":115,"path":116,"stem":117},"Magic Links","\u002Fdocs\u002Fiam\u002Fessentials\u002Fmagic-links","docs\u002Fiam\u002F01.essentials\u002F08.magic-links",{"title":119,"path":120,"stem":121},"Emails","\u002Fdocs\u002Fiam\u002Fessentials\u002Femails","docs\u002Fiam\u002F01.essentials\u002F09.emails",{"title":123,"path":124,"stem":125},"MFA","\u002Fdocs\u002Fiam\u002Fessentials\u002Fmfa","docs\u002Fiam\u002F01.essentials\u002F10.mfa",{"title":127,"path":128,"stem":129},"Fingerprinting","\u002Fdocs\u002Fiam\u002Fessentials\u002Ffingerprinting","docs\u002Fiam\u002F01.essentials\u002F11.fingerprinting",{"title":131,"path":132,"stem":133},"Backend for Frontend","\u002Fdocs\u002Fiam\u002Fessentials\u002Fbff","docs\u002Fiam\u002F01.essentials\u002F12.bff",{"title":135,"path":136,"stem":137},"HMAC Authentication","\u002Fdocs\u002Fiam\u002Fessentials\u002Fhmac","docs\u002Fiam\u002F01.essentials\u002F13.hmac",{"title":139,"path":140,"stem":141},"XSS Protection","\u002Fdocs\u002Fiam\u002Fessentials\u002Fxss","docs\u002Fiam\u002F01.essentials\u002F14.xss",{"title":143,"path":144,"stem":145},"Logging","\u002Fdocs\u002Fiam\u002Fessentials\u002Flogging","docs\u002Fiam\u002F01.essentials\u002F15.logging",{"title":147,"path":148,"stem":149},"Rate Limiting","\u002Fdocs\u002Fiam\u002Fessentials\u002Frate-limiting","docs\u002Fiam\u002F01.essentials\u002F16.rate-limiting",{"title":151,"path":152,"stem":153},"Database","\u002Fdocs\u002Fiam\u002Fessentials\u002Fdatabase","docs\u002Fiam\u002F01.essentials\u002F17.database",{"title":155,"path":156,"stem":157},"Cookies","\u002Fdocs\u002Fiam\u002Fessentials\u002Fcookies","docs\u002Fiam\u002F01.essentials\u002F18.cookies",{"title":159,"path":160,"stem":161},"Service Startup","\u002Fdocs\u002Fiam\u002Fessentials\u002Fservice","docs\u002Fiam\u002F01.essentials\u002F19.service",{"title":163,"path":164,"stem":165},"Password Reset","\u002Fdocs\u002Fiam\u002Fessentials\u002Fpassword-reset","docs\u002Fiam\u002F01.essentials\u002F20.password-reset",{"title":167,"path":168,"stem":169,"children":170},"API Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi","docs\u002Fiam\u002F01.essentials\u002F21.api\u002Findex",[171,172,176,180,210,213],{"title":167,"path":168,"stem":169},{"title":173,"path":174,"stem":175},"Creating Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fcreation","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F00.creation",{"title":177,"path":178,"stem":179},"Verifying Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fverification","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F01.verification",{"title":181,"path":182,"stem":183,"children":184},"Manage Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002Findex",[185,186,190,194,198,202,206],{"title":181,"path":182,"stem":183},{"title":187,"path":188,"stem":189},"Privileges","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Fprivilege","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F00.privilege",{"title":191,"path":192,"stem":193},"Revocation","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Frevocation","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F01.revocation",{"title":195,"path":196,"stem":197},"Rotation","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Frotation","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F02.rotation",{"title":199,"path":200,"stem":201},"IP Restriction","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Fip-updates","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F03.ip-updates",{"title":203,"path":204,"stem":205},"Metadata","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Fmetadata","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F04.metadata",{"title":207,"path":208,"stem":209},"Token Listing","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Flist","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F05.list",{"title":147,"path":211,"stem":212},"\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Frate-limiting","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F03.rate-limiting",{"title":38,"path":214,"stem":215},"\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fsecurity","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F04.security",{"title":38,"path":217,"stem":218},"\u002Fdocs\u002Fiam\u002Fsecurity","docs\u002Fiam\u002F02.security",{"title":220,"path":221,"stem":222,"children":223,"page":53},"Guides","\u002Fdocs\u002Fiam\u002Fguides","docs\u002Fiam\u002F03.guides",[224,228,232],{"title":225,"path":226,"stem":227},"Deployment","\u002Fdocs\u002Fiam\u002Fguides\u002Fdeployment","docs\u002Fiam\u002F03.guides\u002Fdeployment",{"title":229,"path":230,"stem":231},"Operation Scripts","\u002Fdocs\u002Fiam\u002Fguides\u002Foperation-scripts","docs\u002Fiam\u002F03.guides\u002Foperation-scripts",{"title":233,"path":234,"stem":235},"Role-Based Access Control","\u002Fdocs\u002Fiam\u002Fguides\u002Frbac","docs\u002Fiam\u002F03.guides\u002Frbac",{"title":237,"path":238,"stem":239},"Configuration","\u002Fdocs\u002Fiam\u002Fconfiguration","docs\u002Fiam\u002F04.configuration",{"title":241,"path":242,"stem":243,"children":244,"page":53},"Api","\u002Fdocs\u002Fiam\u002Fapi","docs\u002Fiam\u002F05.API",[245,249,253],{"title":246,"path":247,"stem":248},"API Reference","\u002Fdocs\u002Fiam\u002Fapi\u002Fapi","docs\u002Fiam\u002F05.API\u002F00.api",{"title":250,"path":251,"stem":252},"Middleware Reference","\u002Fdocs\u002Fiam\u002Fapi\u002Fmiddlewares","docs\u002Fiam\u002F05.API\u002F02.middlewares",{"title":254,"path":255,"stem":256},"Routes Reference","\u002Fdocs\u002Fiam\u002Fapi\u002Froutes","docs\u002Fiam\u002F05.API\u002F03.routes",[258],{"title":9,"path":66,"stem":67,"children":259,"page":53},[260,398,516,521,577,644],{"title":20,"path":22,"stem":261,"children":262},"docs\u002Fauth-h3client\u002Findex",[263,264,273,307,331,353,356,376,379],{"title":20,"path":22,"stem":261},{"title":14,"path":265,"stem":266,"children":267},"\u002Fdocs\u002Fauth-h3client\u002Fgetting-started","docs\u002Fauth-h3client\u002F00.getting-started\u002Findex",[268,269],{"title":14,"path":265,"stem":266},{"title":270,"path":271,"stem":272},"Nuxt Module","\u002Fdocs\u002Fauth-h3client\u002Fgetting-started\u002Fnuxt","docs\u002Fauth-h3client\u002F00.getting-started\u002F00.nuxt",{"title":77,"path":274,"stem":275,"children":276},"\u002Fdocs\u002Fauth-h3client\u002Fessentials","docs\u002Fauth-h3client\u002F01.essentials\u002Findex",[277,278,282,286,290,294,298,301,304],{"title":77,"path":274,"stem":275},{"title":279,"path":280,"stem":281},"Session Management","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fsession","docs\u002Fauth-h3client\u002F01.essentials\u002F00.session",{"title":283,"path":284,"stem":285},"Route Protection","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Froute-protection","docs\u002Fauth-h3client\u002F01.essentials\u002F01.route-protection",{"title":287,"path":288,"stem":289},"CSRF Protection","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fcsrf","docs\u002Fauth-h3client\u002F01.essentials\u002F02.csrf",{"title":291,"path":292,"stem":293},"Auth Flows","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fauth-flows","docs\u002Fauth-h3client\u002F01.essentials\u002F03.auth-flows",{"title":295,"path":296,"stem":297},"OAuth and OIDC","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Foauth","docs\u002Fauth-h3client\u002F01.essentials\u002F04.oauth",{"title":33,"path":299,"stem":300},"\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fbot-detection","docs\u002Fauth-h3client\u002F01.essentials\u002F05.bot-detection",{"title":155,"path":302,"stem":303},"\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fcookies","docs\u002Fauth-h3client\u002F01.essentials\u002F06.cookies",{"title":143,"path":305,"stem":306},"\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Flogging","docs\u002Fauth-h3client\u002F01.essentials\u002F07.logging",{"title":123,"path":308,"stem":309,"children":310},"\u002Fdocs\u002Fauth-h3client\u002Fmfa","docs\u002Fauth-h3client\u002F02.mfa\u002Findex",[311,312,316,319,323,327],{"title":123,"path":308,"stem":309},{"title":313,"path":314,"stem":315},"Built-in MFA","\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Fbuilt-in-flow","docs\u002Fauth-h3client\u002F02.mfa\u002F01.built-in-flow",{"title":163,"path":317,"stem":318},"\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Fpassword-reset","docs\u002Fauth-h3client\u002F02.mfa\u002F02.password-reset",{"title":320,"path":321,"stem":322},"Email Change","\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Femail-change","docs\u002Fauth-h3client\u002F02.mfa\u002F03.email-change",{"title":324,"path":325,"stem":326},"Custom MFA Flow","\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Fcustom-flow","docs\u002Fauth-h3client\u002F02.mfa\u002F04.custom-flow",{"title":328,"path":329,"stem":330},"Client-Side MFA","\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Fclient-side","docs\u002Fauth-h3client\u002F02.mfa\u002F05.client-side",{"title":332,"path":333,"stem":334,"children":335},"Client-side","\u002Fdocs\u002Fauth-h3client\u002Fclient","docs\u002Fauth-h3client\u002F03.client\u002Findex",[336,337,341,345,349],{"title":332,"path":333,"stem":334},{"title":338,"path":339,"stem":340},"useAuthData","\u002Fdocs\u002Fauth-h3client\u002Fclient\u002Fuse-auth-data","docs\u002Fauth-h3client\u002F03.client\u002F00.use-auth-data",{"title":342,"path":343,"stem":344},"useMagicLink","\u002Fdocs\u002Fauth-h3client\u002Fclient\u002Fuse-magic-link","docs\u002Fauth-h3client\u002F03.client\u002F01.use-magic-link",{"title":346,"path":347,"stem":348},"executeRequest","\u002Fdocs\u002Fauth-h3client\u002Fclient\u002Fexecute-request","docs\u002Fauth-h3client\u002F03.client\u002F02.execute-request",{"title":350,"path":351,"stem":352},"getCsrfToken","\u002Fdocs\u002Fauth-h3client\u002Fclient\u002Fget-csrf-token","docs\u002Fauth-h3client\u002F03.client\u002F03.get-csrf-token",{"title":38,"path":354,"stem":355},"\u002Fdocs\u002Fauth-h3client\u002Fsecurity","docs\u002Fauth-h3client\u002F04.security",{"title":220,"path":357,"stem":358,"children":359,"page":53},"\u002Fdocs\u002Fauth-h3client\u002Fguides","docs\u002Fauth-h3client\u002F05.guides",[360,364,368,372],{"title":361,"path":362,"stem":363},"H3 and Nitro Setup","\u002Fdocs\u002Fauth-h3client\u002Fguides\u002Fh3-nitro","docs\u002Fauth-h3client\u002F05.guides\u002F00.h3-nitro",{"title":365,"path":366,"stem":367},"HMAC Inter-service Auth","\u002Fdocs\u002Fauth-h3client\u002Fguides\u002Fhmac","docs\u002Fauth-h3client\u002F05.guides\u002Fhmac",{"title":369,"path":370,"stem":371},"Image Upload","\u002Fdocs\u002Fauth-h3client\u002Fguides\u002Fimage-upload","docs\u002Fauth-h3client\u002F05.guides\u002Fimage-upload",{"title":373,"path":374,"stem":375},"mTLS Configuration","\u002Fdocs\u002Fauth-h3client\u002Fguides\u002Fmtls","docs\u002Fauth-h3client\u002F05.guides\u002Fmtls",{"title":237,"path":377,"stem":378},"\u002Fdocs\u002Fauth-h3client\u002Fconfiguration","docs\u002Fauth-h3client\u002F06.configuration",{"title":246,"path":380,"stem":381,"children":382},"\u002Fdocs\u002Fauth-h3client\u002Fapi","docs\u002Fauth-h3client\u002F07.api\u002Findex",[383,384,387,390,394],{"title":246,"path":380,"stem":381},{"title":254,"path":385,"stem":386},"\u002Fdocs\u002Fauth-h3client\u002Fapi\u002Fcontrollers","docs\u002Fauth-h3client\u002F07.api\u002F00.controllers",{"title":250,"path":388,"stem":389},"\u002Fdocs\u002Fauth-h3client\u002Fapi\u002Fmiddleware","docs\u002Fauth-h3client\u002F07.api\u002F01.middleware",{"title":391,"path":392,"stem":393},"Client-side Reference","\u002Fdocs\u002Fauth-h3client\u002Fapi\u002Fcomposables","docs\u002Fauth-h3client\u002F07.api\u002F02.composables",{"title":395,"path":396,"stem":397},"Utilities","\u002Fdocs\u002Fauth-h3client\u002Fapi\u002Futilities","docs\u002Fauth-h3client\u002F07.api\u002F03.utilities",{"title":399,"path":35,"stem":400,"children":401},"Bot Detector","docs\u002Fbot-detection\u002Findex",[402,403,406,410,414,433,507,510,513],{"title":399,"path":35,"stem":400},{"title":14,"path":404,"stem":405},"\u002Fdocs\u002Fbot-detection\u002Fgetting-started","docs\u002Fbot-detection\u002F00.getting-started",{"title":407,"path":408,"stem":409},"CLI","\u002Fdocs\u002Fbot-detection\u002Fcli","docs\u002Fbot-detection\u002F01.cli",{"title":411,"path":412,"stem":413},"Data Sources","\u002Fdocs\u002Fbot-detection\u002Fdata-sources","docs\u002Fbot-detection\u002F02.data-sources",{"title":220,"path":415,"stem":416,"children":417,"page":53},"\u002Fdocs\u002Fbot-detection\u002Fguides","docs\u002Fbot-detection\u002F03.guides",[418,422,426,429],{"title":419,"path":420,"stem":421},"Custom Checkers","\u002Fdocs\u002Fbot-detection\u002Fguides\u002Fcustom","docs\u002Fbot-detection\u002F03.guides\u002FCUSTOM",{"title":423,"path":424,"stem":425},"Scheduling Database Generation","\u002Fdocs\u002Fbot-detection\u002Fguides\u002Fgenerate","docs\u002Fbot-detection\u002F03.guides\u002FGENERATE",{"title":143,"path":427,"stem":428},"\u002Fdocs\u002Fbot-detection\u002Fguides\u002Flogging","docs\u002Fbot-detection\u002F03.guides\u002FLOGGING",{"title":430,"path":431,"stem":432},"Score Modes and Reputation Healing","\u002Fdocs\u002Fbot-detection\u002Fguides\u002Fscore","docs\u002Fbot-detection\u002F03.guides\u002FSCORE",{"title":434,"path":435,"stem":436,"children":437},"Checkers","\u002Fdocs\u002Fbot-detection\u002Fcheckers","docs\u002Fbot-detection\u002F04.checkers\u002Findex",[438,439,443,447,451,455,459,463,467,471,475,479,483,487,491,495,499,503],{"title":434,"path":435,"stem":436},{"title":440,"path":441,"stem":442},"IP Validation","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fip-validation","docs\u002Fbot-detection\u002F04.checkers\u002F01.ip-validation",{"title":444,"path":445,"stem":446},"Good \u002F Bad Bot Verification","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fgood-bots","docs\u002Fbot-detection\u002F04.checkers\u002F02.good-bots",{"title":448,"path":449,"stem":450},"Browser & Device Fingerprint","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fbrowser-device","docs\u002Fbot-detection\u002F04.checkers\u002F03.browser-device",{"title":452,"path":453,"stem":454},"Locale Map","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Flocale-map","docs\u002Fbot-detection\u002F04.checkers\u002F04.locale-map",{"title":456,"path":457,"stem":458},"Known Threats","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fknown-threats","docs\u002Fbot-detection\u002F04.checkers\u002F05.known-threats",{"title":460,"path":461,"stem":462},"ASN Classification","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fasn-classification","docs\u002Fbot-detection\u002F04.checkers\u002F06.asn-classification",{"title":464,"path":465,"stem":466},"Tor Analysis","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Ftor-analysis","docs\u002Fbot-detection\u002F04.checkers\u002F07.tor-analysis",{"title":468,"path":469,"stem":470},"Timezone Consistency","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Ftimezone-consistency","docs\u002Fbot-detection\u002F04.checkers\u002F08.timezone-consistency",{"title":472,"path":473,"stem":474},"Honeypot","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fhoneypot","docs\u002Fbot-detection\u002F04.checkers\u002F09.honeypot",{"title":476,"path":477,"stem":478},"Known Bad IPs","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fknown-bad-ips","docs\u002Fbot-detection\u002F04.checkers\u002F10.known-bad-ips",{"title":480,"path":481,"stem":482},"Behavior Rate","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fbehavior-rate","docs\u002Fbot-detection\u002F04.checkers\u002F11.behavior-rate",{"title":484,"path":485,"stem":486},"Proxy \u002F ISP \u002F Cookie","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fproxy-isp-cookies","docs\u002Fbot-detection\u002F04.checkers\u002F12.proxy-isp-cookies",{"title":488,"path":489,"stem":490},"Session Coherence","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fsession-coherence","docs\u002Fbot-detection\u002F04.checkers\u002F13.session-coherence",{"title":492,"path":493,"stem":494},"Velocity Fingerprint","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fvelocity-fingerprint","docs\u002Fbot-detection\u002F04.checkers\u002F14.velocity-fingerprint",{"title":496,"path":497,"stem":498},"UA & Header Analysis","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fua-header","docs\u002Fbot-detection\u002F04.checkers\u002F15.ua-header",{"title":500,"path":501,"stem":502},"Geolocation","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fgeolocation","docs\u002Fbot-detection\u002F04.checkers\u002F16.geolocation",{"title":504,"path":505,"stem":506},"Known Bad User-Agents","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fknown-bad-ua","docs\u002Fbot-detection\u002F04.checkers\u002F17.known-bad-ua",{"title":38,"path":508,"stem":509},"\u002Fdocs\u002Fbot-detection\u002Fsecurity","docs\u002Fbot-detection\u002F04.security",{"title":246,"path":511,"stem":512},"\u002Fdocs\u002Fbot-detection\u002Fapi","docs\u002Fbot-detection\u002F05.api",{"title":237,"path":514,"stem":515},"\u002Fdocs\u002Fbot-detection\u002Fconfiguration","docs\u002Fbot-detection\u002F06.configuration",{"title":517,"path":11,"stem":518,"children":519},"Introduction","docs\u002Fgetting-started\u002Findex",[520],{"title":517,"path":11,"stem":518},{"title":27,"path":29,"stem":70,"children":522},[523,524,525,565,566,571,572],{"title":27,"path":29,"stem":70},{"title":14,"path":74,"stem":75},{"title":77,"path":78,"stem":79,"children":526},[527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549],{"title":77,"path":78,"stem":79},{"title":83,"path":84,"stem":85},{"title":87,"path":88,"stem":89},{"title":91,"path":92,"stem":93},{"title":95,"path":96,"stem":97},{"title":99,"path":100,"stem":101},{"title":103,"path":104,"stem":105},{"title":107,"path":108,"stem":109},{"title":111,"path":112,"stem":113},{"title":115,"path":116,"stem":117},{"title":119,"path":120,"stem":121},{"title":123,"path":124,"stem":125},{"title":127,"path":128,"stem":129},{"title":131,"path":132,"stem":133},{"title":135,"path":136,"stem":137},{"title":139,"path":140,"stem":141},{"title":143,"path":144,"stem":145},{"title":147,"path":148,"stem":149},{"title":151,"path":152,"stem":153},{"title":155,"path":156,"stem":157},{"title":159,"path":160,"stem":161},{"title":163,"path":164,"stem":165},{"title":167,"path":168,"stem":169,"children":550},[551,552,553,554,563,564],{"title":167,"path":168,"stem":169},{"title":173,"path":174,"stem":175},{"title":177,"path":178,"stem":179},{"title":181,"path":182,"stem":183,"children":555},[556,557,558,559,560,561,562],{"title":181,"path":182,"stem":183},{"title":187,"path":188,"stem":189},{"title":191,"path":192,"stem":193},{"title":195,"path":196,"stem":197},{"title":199,"path":200,"stem":201},{"title":203,"path":204,"stem":205},{"title":207,"path":208,"stem":209},{"title":147,"path":211,"stem":212},{"title":38,"path":214,"stem":215},{"title":38,"path":217,"stem":218},{"title":220,"path":221,"stem":222,"children":567,"page":53},[568,569,570],{"title":225,"path":226,"stem":227},{"title":229,"path":230,"stem":231},{"title":233,"path":234,"stem":235},{"title":237,"path":238,"stem":239},{"title":241,"path":242,"stem":243,"children":573,"page":53},[574,575,576],{"title":246,"path":247,"stem":248},{"title":250,"path":251,"stem":252},{"title":254,"path":255,"stem":256},{"title":40,"path":42,"stem":578,"children":579},"docs\u002Fshield-base\u002Findex",[580,581,584,588,629,633,637,641],{"title":40,"path":42,"stem":578},{"title":14,"path":582,"stem":583},"\u002Fdocs\u002Fshield-base\u002Fgetting-started","docs\u002Fshield-base\u002F00.getting-started",{"title":585,"path":586,"stem":587},"CLI Reference","\u002Fdocs\u002Fshield-base\u002Fcli","docs\u002Fshield-base\u002F01.cli",{"title":411,"path":589,"stem":590,"children":591},"\u002Fdocs\u002Fshield-base\u002Fdata-sources","docs\u002Fshield-base\u002F02.data-sources\u002Findex",[592,593,597,601,605,609,613,617,621,625],{"title":411,"path":589,"stem":590},{"title":594,"path":595,"stem":596},"BGP \u002F ASN","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fbgp","docs\u002Fshield-base\u002F02.data-sources\u002Fbgp",{"title":598,"path":599,"stem":600},"City Geolocation","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fcity","docs\u002Fshield-base\u002F02.data-sources\u002Fcity",{"title":602,"path":603,"stem":604},"Country Geolocation","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fcountry","docs\u002Fshield-base\u002F02.data-sources\u002Fcountry",{"title":606,"path":607,"stem":608},"Verified Crawlers","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fcrawlers","docs\u002Fshield-base\u002F02.data-sources\u002Fcrawlers",{"title":610,"path":611,"stem":612},"Disposable Emails","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Femail","docs\u002Fshield-base\u002F02.data-sources\u002Femail",{"title":614,"path":615,"stem":616},"FireHOL Threat Intelligence","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Ffirehol","docs\u002Fshield-base\u002F02.data-sources\u002Ffirehol",{"title":618,"path":619,"stem":620},"Proxy Detection","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fproxy","docs\u002Fshield-base\u002F02.data-sources\u002Fproxy",{"title":622,"path":623,"stem":624},"Tor Nodes","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Ftor","docs\u002Fshield-base\u002F02.data-sources\u002Ftor",{"title":626,"path":627,"stem":628},"Suspicious User-Agents","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fuseragent","docs\u002Fshield-base\u002F02.data-sources\u002Fuseragent",{"title":630,"path":631,"stem":632},"Programmatic Usage","\u002Fdocs\u002Fshield-base\u002Fusage","docs\u002Fshield-base\u002F03.usage",{"title":634,"path":635,"stem":636},"Custom Data Sources","\u002Fdocs\u002Fshield-base\u002Fcustom-data-sources","docs\u002Fshield-base\u002F04.custom-data-sources",{"title":638,"path":639,"stem":640},"TypeScript Types","\u002Fdocs\u002Fshield-base\u002Ftypes","docs\u002Fshield-base\u002F05.types",{"title":246,"path":642,"stem":643},"\u002Fdocs\u002Fshield-base\u002Fapi","docs\u002Fshield-base\u002F06.api",{"title":395,"path":48,"stem":645,"children":646},"docs\u002Futils\u002Findex",[647,648,665,698,795],{"title":395,"path":48,"stem":645},{"title":649,"path":650,"stem":651,"children":652,"page":53},"Eslint","\u002Fdocs\u002Futils\u002Feslint","docs\u002Futils\u002Feslint",[653,657,661],{"title":654,"path":655,"stem":656},"React Config","\u002Fdocs\u002Futils\u002Feslint\u002Freact","docs\u002Futils\u002Feslint\u002Freact",{"title":658,"path":659,"stem":660},"TypeScript Config","\u002Fdocs\u002Futils\u002Feslint\u002Ftypescript","docs\u002Futils\u002Feslint\u002Ftypescript",{"title":662,"path":663,"stem":664},"Vue Config","\u002Fdocs\u002Futils\u002Feslint\u002Fvue","docs\u002Futils\u002Feslint\u002Fvue",{"title":666,"path":667,"stem":668,"children":669,"page":53},"Server","\u002Fdocs\u002Futils\u002Fserver","docs\u002Futils\u002Fserver",[670,674,678,682,686,690,694],{"title":671,"path":672,"stem":673},"Encryption","\u002Fdocs\u002Futils\u002Fserver\u002Fencryption","docs\u002Futils\u002Fserver\u002Fencryption",{"title":675,"path":676,"stem":677},"Path Resolver","\u002Fdocs\u002Futils\u002Fserver\u002Fpathresolver","docs\u002Futils\u002Fserver\u002FpathResolver",{"title":679,"path":680,"stem":681},"File Replacements","\u002Fdocs\u002Futils\u002Fserver\u002Freplace","docs\u002Futils\u002Fserver\u002Freplace",{"title":683,"path":684,"stem":685},"run","\u002Fdocs\u002Futils\u002Fserver\u002Frun","docs\u002Futils\u002Fserver\u002Frun",{"title":687,"path":688,"stem":689},"scheduleTask","\u002Fdocs\u002Futils\u002Fserver\u002Fscheduletask","docs\u002Futils\u002Fserver\u002FscheduleTask",{"title":691,"path":692,"stem":693},"spawnRun","\u002Fdocs\u002Futils\u002Fserver\u002Fspawnrun","docs\u002Futils\u002Fserver\u002FspawnRun",{"title":695,"path":696,"stem":697},"uploadCsv","\u002Fdocs\u002Futils\u002Fserver\u002Fuploadcsv","docs\u002Futils\u002Fserver\u002FuploadCsv",{"title":699,"path":700,"stem":701,"children":702,"page":53},"Shared","\u002Fdocs\u002Futils\u002Fshared","docs\u002Futils\u002Fshared",[703,707,711,715,719,723,727,731,735,739,743,747,751,755,759,763,767,771,775,779,783,787,791],{"title":704,"path":705,"stem":706},"BatchQueue","\u002Fdocs\u002Futils\u002Fshared\u002Fbatchqueue","docs\u002Futils\u002Fshared\u002FbatchQueue",{"title":708,"path":709,"stem":710},"capitalize","\u002Fdocs\u002Futils\u002Fshared\u002Fcapitalize","docs\u002Futils\u002Fshared\u002Fcapitalize",{"title":712,"path":713,"stem":714},"chunkProcess","\u002Fdocs\u002Futils\u002Fshared\u002Fchunkprocess","docs\u002Futils\u002Fshared\u002FchunkProcess",{"title":716,"path":717,"stem":718},"cleanObject","\u002Fdocs\u002Futils\u002Fshared\u002Fcleanobject","docs\u002Futils\u002Fshared\u002FcleanObject",{"title":720,"path":721,"stem":722},"createConfigManager","\u002Fdocs\u002Futils\u002Fshared\u002Fconfigurationdefiner","docs\u002Futils\u002Fshared\u002FconfigurationDefiner",{"title":724,"path":725,"stem":726},"debounce","\u002Fdocs\u002Futils\u002Fshared\u002Fdebounce","docs\u002Futils\u002Fshared\u002Fdebounce",{"title":728,"path":729,"stem":730},"ensureArray","\u002Fdocs\u002Futils\u002Fshared\u002Fensurearray","docs\u002Futils\u002Fshared\u002FensureArray",{"title":732,"path":733,"stem":734},"fetchWithRetry","\u002Fdocs\u002Futils\u002Fshared\u002Ffetchwithretry","docs\u002Futils\u002Fshared\u002FfetchWithRetry",{"title":736,"path":737,"stem":738},"filterEmptyValues","\u002Fdocs\u002Futils\u002Fshared\u002Ffilteremptyvalues","docs\u002Futils\u002Fshared\u002FfilterEmptyValues",{"title":740,"path":741,"stem":742},"findStringsInObject","\u002Fdocs\u002Futils\u002Fshared\u002Ffindobjectvalues","docs\u002Futils\u002Fshared\u002FfindObjectValues",{"title":744,"path":745,"stem":746},"fisherYatesShuffle","\u002Fdocs\u002Futils\u002Fshared\u002Ffisheryatesshuffle","docs\u002Futils\u002Fshared\u002FfisherYatesShuffle",{"title":748,"path":749,"stem":750},"getRandomImage","\u002Fdocs\u002Futils\u002Fshared\u002Fgetrandomimage","docs\u002Futils\u002Fshared\u002FgetRandomImage",{"title":752,"path":753,"stem":754},"isObjectHasValues","\u002Fdocs\u002Futils\u002Fshared\u002Fisobjecthasvalues","docs\u002Futils\u002Fshared\u002FisObjectHasValues",{"title":756,"path":757,"stem":758},"isAsyncOrPromise","\u002Fdocs\u002Futils\u002Fshared\u002Fispromise","docs\u002Futils\u002Fshared\u002FisPromise",{"title":760,"path":761,"stem":762},"MiniCache","\u002Fdocs\u002Futils\u002Fshared\u002Fminicache","docs\u002Futils\u002Fshared\u002FminiCache",{"title":764,"path":765,"stem":766},"parseCookies","\u002Fdocs\u002Futils\u002Fshared\u002Fparserawcookies","docs\u002Futils\u002Fshared\u002FparseRawCookies",{"title":768,"path":769,"stem":770},"safeAction","\u002Fdocs\u002Futils\u002Fshared\u002Fpromiselocker","docs\u002Futils\u002Fshared\u002FpromiseLocker",{"title":772,"path":773,"stem":774},"Random","\u002Fdocs\u002Futils\u002Fshared\u002Frandom","docs\u002Futils\u002Fshared\u002Frandom",{"title":776,"path":777,"stem":778},"range","\u002Fdocs\u002Futils\u002Fshared\u002Frange","docs\u002Futils\u002Fshared\u002Frange",{"title":780,"path":781,"stem":782},"rateLimiters","\u002Fdocs\u002Futils\u002Fshared\u002Fratelimiters","docs\u002Futils\u002Fshared\u002FrateLimiters",{"title":784,"path":785,"stem":786},"safeObjectMerge","\u002Fdocs\u002Futils\u002Fshared\u002Fsafemerge","docs\u002Futils\u002Fshared\u002FsafeMerge",{"title":788,"path":789,"stem":790},"textTruncation","\u002Fdocs\u002Futils\u002Fshared\u002Ftexttruncation","docs\u002Futils\u002Fshared\u002FtextTruncation",{"title":792,"path":793,"stem":794},"validateZodSchema","\u002Fdocs\u002Futils\u002Fshared\u002Fvalidatezodschema","docs\u002Futils\u002Fshared\u002FvalidateZodSchema",{"title":796,"path":797,"stem":798,"children":799},"Utility Types","\u002Fdocs\u002Futils\u002Ftypes","docs\u002Futils\u002Ftypes\u002Findex",[800,801,805,809,813,817,821,825,829,833],{"title":796,"path":797,"stem":798},{"title":802,"path":803,"stem":804},"Brand","\u002Fdocs\u002Futils\u002Ftypes\u002Fbrand","docs\u002Futils\u002Ftypes\u002FBrand",{"title":806,"path":807,"stem":808},"DeepPartial","\u002Fdocs\u002Futils\u002Ftypes\u002Fdeeppartial","docs\u002Futils\u002Ftypes\u002FDeepPartial",{"title":810,"path":811,"stem":812},"Merge","\u002Fdocs\u002Futils\u002Ftypes\u002Fmerge","docs\u002Futils\u002Ftypes\u002FMerge",{"title":814,"path":815,"stem":816},"NonNullable","\u002Fdocs\u002Futils\u002Ftypes\u002Fnonnullable","docs\u002Futils\u002Ftypes\u002FNonNullable",{"title":818,"path":819,"stem":820},"Prettify","\u002Fdocs\u002Futils\u002Ftypes\u002Fprettify","docs\u002Futils\u002Ftypes\u002FPrettify",{"title":822,"path":823,"stem":824},"PromiseType","\u002Fdocs\u002Futils\u002Ftypes\u002Fpromisetype","docs\u002Futils\u002Ftypes\u002FPromiseType",{"title":826,"path":827,"stem":828},"RequireKeys","\u002Fdocs\u002Futils\u002Ftypes\u002Frequirekeys","docs\u002Futils\u002Ftypes\u002FRequireKeys",{"title":830,"path":831,"stem":832},"StandardResponse","\u002Fdocs\u002Futils\u002Ftypes\u002Fstandardresponse","docs\u002Futils\u002Ftypes\u002FStandardResponse",{"title":834,"path":835,"stem":836},"ValueOf","\u002Fdocs\u002Futils\u002Ftypes\u002Fvalueof","docs\u002Futils\u002Ftypes\u002FValueOf",{"id":4,"extension":5,"links":838,"meta":849,"stem":62,"__hash__":63},[839,847,848],{"nested":8,"label":9,"icon":10,"to":11,"children":840},[841,842,843,844,845,846],{"label":14,"icon":15,"to":11,"description":16,"github":17,"badge":18},{"label":20,"icon":21,"to":22,"description":23,"github":24,"badge":25},{"label":27,"icon":28,"to":29,"description":30,"github":31,"badge":25},{"label":33,"icon":34,"to":35,"description":36,"github":37,"badge":38},{"label":40,"icon":41,"to":42,"description":43,"github":44,"badge":38},{"label":46,"icon":47,"to":48,"description":49,"github":50,"badge":51},{"nested":53,"label":54,"icon":55,"to":56},{"nested":53,"label":58,"icon":59,"to":60},{},{"id":851,"title":233,"body":852,"description":4765,"extension":4766,"icon":28,"meta":4767,"module":4768,"navigation":8,"path":234,"rawbody":4769,"seo":4770,"stem":235,"__hash__":4771},"docs\u002Fdocs\u002Fiam\u002F03.guides\u002Frbac.md",{"type":853,"value":854,"toc":4747},"minimark",[855,868,871,876,891,900,910,912,916,919,924,935,1096,1105,1109,1116,2369,2373,2379,2509,2515,2517,2521,2529,2540,2543,2548,2702,2714,2716,2720,2724,2732,2963,3154,3158,3161,3387,3469,3473,3476,3697,3699,3703,3706,4090,4092,4096,4108,4216,4219,4222,4476,4487,4489,4493,4496,4499,4548,4557,4560,4632,4634,4638,4743],[856,857,858,859,863,864,867],"p",{},"Role-based access control (RBAC) in the IAM service is built on top of the JWT access token. Roles are embedded at signing time, cached alongside the token, verified for integrity on every use, and exposed on ",[860,861,862],"code",{},"req.user.roles"," after ",[860,865,866],{},"protectRoute"," runs. This guide covers how to attach roles to tokens, how integrity enforcement works, and how to build route guards and custom authorization logic.",[869,870],"hr",{},[872,873,875],"h2",{"id":874},"how-roles-work","How roles work",[856,877,878,879,882,883,886,887,890],{},"When the IAM service generates an access token, it embeds the user's roles as a ",[860,880,881],{},"roles"," claim in the JWT payload. Simultaneously, the same roles are recorded in the in-memory token cache entry. On every subsequent ",[860,884,885],{},"verifyAccessToken"," call, ",[860,888,889],{},"compareRoles"," confirms that the roles in the JWT payload exactly match the roles stored in the cache. Any mismatch causes verification to fail, preventing a client from tampering with role claims in the token string.",[856,892,893,894,896,897,899],{},"After ",[860,895,866],{}," runs successfully, ",[860,898,862],{}," holds the verified role array for the current request. Route handlers and custom middleware read roles exclusively from this field.",[901,902,907],"pre",{"className":903,"code":905,"language":906},[904],"language-text","generateAccessToken({ role: ['editor'] })\n       │\n       ├── JWT payload: { roles: ['editor'], sub: '42', ... }\n       └── Cache entry: { roles: ['editor'], valid: true, ... }\n\nverifyAccessToken(token)\n       │\n       ├── Cache lookup → roles: ['editor']\n       ├── JWT decode   → roles: ['editor']\n       └── compareRoles(['editor'], ['editor']) → { valid: true }\n\nprotectRoute\n       └── req.user.roles = ['editor']\n","text",[860,908,905],{"__ignoreMap":909},"",[869,911],{},[872,913,915],{"id":914},"attaching-roles-to-tokens","Attaching roles to tokens",[856,917,918],{},"The built-in login, signup, and OAuth controllers issue tokens without roles by default. You have three options for attaching roles.",[920,921,923],"h3",{"id":922},"static-payload-via-configuration","Static payload via configuration",[856,925,926,927,930,931,934],{},"Add a ",[860,928,929],{},"payload"," object under ",[860,932,933],{},"jwt.access_tokens"," in the configuration. Every token issued by the service merges this object into the payload at signing time. Use this for roles that apply to every user uniformly.",[901,936,940],{"className":937,"code":938,"filename":939,"language":5,"meta":909,"style":909},"language-json shiki shiki-themes light-plus light-plus dracula","{\n  \"jwt\": {\n    \"jwt_secret_key\": \"your-secret\",\n    \"access_tokens\": {\n      \"expiresIn\": \"15m\",\n      \"payload\": {\n        \"roles\": [\"user\"]\n      }\n    }\n  }\n}\n","config.json",[860,941,942,951,972,998,1012,1034,1047,1072,1078,1084,1090],{"__ignoreMap":909},[943,944,947],"span",{"class":945,"line":946},"line",1,[943,948,950],{"class":949},"sDd4n","{\n",[943,952,954,958,962,965,969],{"class":945,"line":953},2,[943,955,957],{"class":956},"saJyd","  \"",[943,959,961],{"class":960},"s_W10","jwt",[943,963,964],{"class":956},"\"",[943,966,968],{"class":967},"saOXh",":",[943,970,971],{"class":949}," {\n",[943,973,975,978,981,983,985,989,993,995],{"class":945,"line":974},3,[943,976,977],{"class":956},"    \"",[943,979,980],{"class":960},"jwt_secret_key",[943,982,964],{"class":956},[943,984,968],{"class":967},[943,986,988],{"class":987},"sFkSl"," \"",[943,990,992],{"class":991},"sFB1V","your-secret",[943,994,964],{"class":987},[943,996,997],{"class":949},",\n",[943,999,1001,1003,1006,1008,1010],{"class":945,"line":1000},4,[943,1002,977],{"class":956},[943,1004,1005],{"class":960},"access_tokens",[943,1007,964],{"class":956},[943,1009,968],{"class":967},[943,1011,971],{"class":949},[943,1013,1015,1018,1021,1023,1025,1027,1030,1032],{"class":945,"line":1014},5,[943,1016,1017],{"class":956},"      \"",[943,1019,1020],{"class":960},"expiresIn",[943,1022,964],{"class":956},[943,1024,968],{"class":967},[943,1026,988],{"class":987},[943,1028,1029],{"class":991},"15m",[943,1031,964],{"class":987},[943,1033,997],{"class":949},[943,1035,1037,1039,1041,1043,1045],{"class":945,"line":1036},6,[943,1038,1017],{"class":956},[943,1040,929],{"class":960},[943,1042,964],{"class":956},[943,1044,968],{"class":967},[943,1046,971],{"class":949},[943,1048,1050,1053,1055,1057,1059,1062,1064,1067,1069],{"class":945,"line":1049},7,[943,1051,1052],{"class":956},"        \"",[943,1054,881],{"class":960},[943,1056,964],{"class":956},[943,1058,968],{"class":967},[943,1060,1061],{"class":949}," [",[943,1063,964],{"class":987},[943,1065,1066],{"class":991},"user",[943,1068,964],{"class":987},[943,1070,1071],{"class":949},"]\n",[943,1073,1075],{"class":945,"line":1074},8,[943,1076,1077],{"class":949},"      }\n",[943,1079,1081],{"class":945,"line":1080},9,[943,1082,1083],{"class":949},"    }\n",[943,1085,1087],{"class":945,"line":1086},10,[943,1088,1089],{"class":949},"  }\n",[943,1091,1093],{"class":945,"line":1092},11,[943,1094,1095],{"class":949},"}\n",[1097,1098,1099],"warning",{},[856,1100,1101,1102,1104],{},"The ",[860,1103,929],{}," field adds the same roles to every token. It is not suitable for per-user roles. Use it only for a universal default role that every authenticated user should have.",[920,1106,1108],{"id":1107},"custom-login-controller","Custom login controller",[856,1110,1111,1112,1115],{},"Build a login handler that queries the user's roles from your database and passes them to ",[860,1113,1114],{},"generateAccessToken",". This is the standard approach for per-user RBAC.",[901,1117,1122],{"className":1118,"code":1119,"filename":1120,"language":1121,"meta":909,"style":909},"language-ts shiki shiki-themes light-plus light-plus dracula","import {\n  generateAccessToken,\n  generateRefreshToken,\n  validateZodSchema,\n  makeSanitizedZodString,\n  verifyPassword,\n  hashPassword,\n  makeCookie,\n  getLogger,\n} from '@riavzon\u002Fauth'\nimport { getPool, getConfiguration } from '@riavzon\u002Fauth'\nimport { z } from 'zod'\nimport crypto from 'node:crypto'\n\nconst loginSchema = z.object({\n  email: makeSanitizedZodString({ min: 5, max: 80 }),\n  password: makeSanitizedZodString({ min: 12, max: 64 }),\n})\n\nrouter.post('\u002Flogin', async (req, res) => {\n  const log = getLogger().child({ route: '\u002Flogin' })\n  const result = await validateZodSchema(loginSchema, req.body, req, log)\n\n  if ('valid' in result && !result.valid) {\n    return res.status(result.errors === 'XSS attempt' ? 403 : 400).json({ error: result.errors })\n  }\n  if (!result.success) {\n    return res.status(422).json(result.error.format())\n  }\n\n  const { email, password } = result.data\n  const pool = getPool()\n  const config = getConfiguration()\n\n  \u002F\u002F Fetch user and their roles from the database\n  const [rows] = await pool.execute(\n    `SELECT u.id, u.visitor_id, u.password_hash,\n            GROUP_CONCAT(r.name ORDER BY r.name) AS roles\n     FROM users u\n     LEFT JOIN user_roles ur ON ur.user_id = u.id\n     LEFT JOIN roles r ON r.id = ur.role_id\n     WHERE u.email = ? AND u.active_user = 1\n     GROUP BY u.id\n     LIMIT 1`,\n    [email]\n  )\n\n  const user = rows[0]\n  if (!user) return res.status(401).json({ error: 'Invalid credentials' })\n\n  const valid = await verifyPassword(user.password_hash, password)\n  if (!valid) return res.status(401).json({ error: 'Invalid credentials' })\n\n  const roles: string[] = user.roles ? user.roles.split(',') : []\n\n  const refreshToken = await generateRefreshToken(config.jwt.refresh_tokens.refresh_ttl, user.id)\n  const accessToken = generateAccessToken({\n    id: user.id,\n    visitor_id: user.visitor_id,\n    jti: crypto.randomUUID(),\n    role: roles,\n  })\n\n  makeCookie(res, 'session', refreshToken.raw, {\n    httpOnly: true,\n    secure: true,\n    sameSite: 'strict',\n    domain: config.jwt.refresh_tokens.domain,\n    path: '\u002F',\n    expires: refreshToken.expiresAt,\n  })\n\n  res.status(200).json({ accessToken })\n})\n","server\u002Froutes\u002Flogin.ts","ts",[860,1123,1124,1132,1140,1147,1154,1161,1168,1175,1182,1189,1206,1233,1254,1272,1278,1305,1342,1372,1378,1383,1430,1466,1508,1513,1549,1614,1619,1638,1674,1679,1684,1711,1727,1742,1747,1754,1781,1787,1793,1799,1805,1811,1817,1823,1831,1841,1847,1852,1873,1919,1924,1954,1997,2002,2056,2061,2106,2121,2137,2154,2172,2184,2190,2195,2226,2240,2252,2269,2294,2311,2328,2333,2338,2364],{"__ignoreMap":909},[943,1125,1126,1130],{"class":945,"line":946},[943,1127,1129],{"class":1128},"sZ328","import",[943,1131,971],{"class":949},[943,1133,1134,1138],{"class":945,"line":953},[943,1135,1137],{"class":1136},"sjsA6","  generateAccessToken",[943,1139,997],{"class":949},[943,1141,1142,1145],{"class":945,"line":974},[943,1143,1144],{"class":1136},"  generateRefreshToken",[943,1146,997],{"class":949},[943,1148,1149,1152],{"class":945,"line":1000},[943,1150,1151],{"class":1136},"  validateZodSchema",[943,1153,997],{"class":949},[943,1155,1156,1159],{"class":945,"line":1014},[943,1157,1158],{"class":1136},"  makeSanitizedZodString",[943,1160,997],{"class":949},[943,1162,1163,1166],{"class":945,"line":1036},[943,1164,1165],{"class":1136},"  verifyPassword",[943,1167,997],{"class":949},[943,1169,1170,1173],{"class":945,"line":1049},[943,1171,1172],{"class":1136},"  hashPassword",[943,1174,997],{"class":949},[943,1176,1177,1180],{"class":945,"line":1074},[943,1178,1179],{"class":1136},"  makeCookie",[943,1181,997],{"class":949},[943,1183,1184,1187],{"class":945,"line":1080},[943,1185,1186],{"class":1136},"  getLogger",[943,1188,997],{"class":949},[943,1190,1191,1194,1197,1200,1203],{"class":945,"line":1086},[943,1192,1193],{"class":949},"} ",[943,1195,1196],{"class":1128},"from",[943,1198,1199],{"class":987}," '",[943,1201,1202],{"class":991},"@riavzon\u002Fauth",[943,1204,1205],{"class":987},"'\n",[943,1207,1208,1210,1213,1216,1219,1222,1225,1227,1229,1231],{"class":945,"line":1092},[943,1209,1129],{"class":1128},[943,1211,1212],{"class":949}," { ",[943,1214,1215],{"class":1136},"getPool",[943,1217,1218],{"class":949},", ",[943,1220,1221],{"class":1136},"getConfiguration",[943,1223,1224],{"class":949}," } ",[943,1226,1196],{"class":1128},[943,1228,1199],{"class":987},[943,1230,1202],{"class":991},[943,1232,1205],{"class":987},[943,1234,1236,1238,1240,1243,1245,1247,1249,1252],{"class":945,"line":1235},12,[943,1237,1129],{"class":1128},[943,1239,1212],{"class":949},[943,1241,1242],{"class":1136},"z",[943,1244,1224],{"class":949},[943,1246,1196],{"class":1128},[943,1248,1199],{"class":987},[943,1250,1251],{"class":991},"zod",[943,1253,1205],{"class":987},[943,1255,1257,1259,1262,1265,1267,1270],{"class":945,"line":1256},13,[943,1258,1129],{"class":1128},[943,1260,1261],{"class":1136}," crypto",[943,1263,1264],{"class":1128}," from",[943,1266,1199],{"class":987},[943,1268,1269],{"class":991},"node:crypto",[943,1271,1205],{"class":987},[943,1273,1275],{"class":945,"line":1274},14,[943,1276,1277],{"emptyLinePlaceholder":8},"\n",[943,1279,1281,1285,1289,1292,1295,1298,1302],{"class":945,"line":1280},15,[943,1282,1284],{"class":1283},"sl46w","const",[943,1286,1288],{"class":1287},"s3JHE"," loginSchema",[943,1290,1291],{"class":967}," =",[943,1293,1294],{"class":1136}," z",[943,1296,1297],{"class":949},".",[943,1299,1301],{"class":1300},"sHOzp","object",[943,1303,1304],{"class":949},"({\n",[943,1306,1308,1311,1314,1317,1320,1323,1325,1329,1331,1334,1336,1339],{"class":945,"line":1307},16,[943,1309,1310],{"class":1136},"  email",[943,1312,968],{"class":1313},"s34zl",[943,1315,1316],{"class":1300}," makeSanitizedZodString",[943,1318,1319],{"class":949},"({ ",[943,1321,1322],{"class":1136},"min",[943,1324,968],{"class":1313},[943,1326,1328],{"class":1327},"spgvN"," 5",[943,1330,1218],{"class":949},[943,1332,1333],{"class":1136},"max",[943,1335,968],{"class":1313},[943,1337,1338],{"class":1327}," 80",[943,1340,1341],{"class":949}," }),\n",[943,1343,1345,1348,1350,1352,1354,1356,1358,1361,1363,1365,1367,1370],{"class":945,"line":1344},17,[943,1346,1347],{"class":1136},"  password",[943,1349,968],{"class":1313},[943,1351,1316],{"class":1300},[943,1353,1319],{"class":949},[943,1355,1322],{"class":1136},[943,1357,968],{"class":1313},[943,1359,1360],{"class":1327}," 12",[943,1362,1218],{"class":949},[943,1364,1333],{"class":1136},[943,1366,968],{"class":1313},[943,1368,1369],{"class":1327}," 64",[943,1371,1341],{"class":949},[943,1373,1375],{"class":945,"line":1374},18,[943,1376,1377],{"class":949},"})\n",[943,1379,1381],{"class":945,"line":1380},19,[943,1382,1277],{"emptyLinePlaceholder":8},[943,1384,1386,1389,1391,1394,1397,1400,1403,1405,1407,1410,1413,1417,1419,1422,1425,1428],{"class":945,"line":1385},20,[943,1387,1388],{"class":1136},"router",[943,1390,1297],{"class":949},[943,1392,1393],{"class":1300},"post",[943,1395,1396],{"class":949},"(",[943,1398,1399],{"class":987},"'",[943,1401,1402],{"class":991},"\u002Flogin",[943,1404,1399],{"class":987},[943,1406,1218],{"class":949},[943,1408,1409],{"class":1283},"async",[943,1411,1412],{"class":949}," (",[943,1414,1416],{"class":1415},"sygFZ","req",[943,1418,1218],{"class":949},[943,1420,1421],{"class":1415},"res",[943,1423,1424],{"class":949},") ",[943,1426,1427],{"class":1283},"=>",[943,1429,971],{"class":949},[943,1431,1433,1436,1439,1441,1444,1447,1450,1452,1455,1457,1459,1461,1463],{"class":945,"line":1432},21,[943,1434,1435],{"class":1283},"  const",[943,1437,1438],{"class":1287}," log",[943,1440,1291],{"class":967},[943,1442,1443],{"class":1300}," getLogger",[943,1445,1446],{"class":949},"().",[943,1448,1449],{"class":1300},"child",[943,1451,1319],{"class":949},[943,1453,1454],{"class":1136},"route",[943,1456,968],{"class":1313},[943,1458,1199],{"class":987},[943,1460,1402],{"class":991},[943,1462,1399],{"class":987},[943,1464,1465],{"class":949}," })\n",[943,1467,1469,1471,1474,1476,1479,1482,1484,1487,1489,1491,1493,1496,1498,1500,1502,1505],{"class":945,"line":1468},22,[943,1470,1435],{"class":1283},[943,1472,1473],{"class":1287}," result",[943,1475,1291],{"class":967},[943,1477,1478],{"class":1128}," await",[943,1480,1481],{"class":1300}," validateZodSchema",[943,1483,1396],{"class":949},[943,1485,1486],{"class":1136},"loginSchema",[943,1488,1218],{"class":949},[943,1490,1416],{"class":1136},[943,1492,1297],{"class":949},[943,1494,1495],{"class":1136},"body",[943,1497,1218],{"class":949},[943,1499,1416],{"class":1136},[943,1501,1218],{"class":949},[943,1503,1504],{"class":1136},"log",[943,1506,1507],{"class":949},")\n",[943,1509,1511],{"class":945,"line":1510},23,[943,1512,1277],{"emptyLinePlaceholder":8},[943,1514,1516,1519,1521,1523,1526,1528,1531,1533,1536,1539,1542,1544,1546],{"class":945,"line":1515},24,[943,1517,1518],{"class":1128},"  if",[943,1520,1412],{"class":949},[943,1522,1399],{"class":987},[943,1524,1525],{"class":991},"valid",[943,1527,1399],{"class":987},[943,1529,1530],{"class":1283}," in",[943,1532,1473],{"class":1136},[943,1534,1535],{"class":967}," &&",[943,1537,1538],{"class":967}," !",[943,1540,1541],{"class":1136},"result",[943,1543,1297],{"class":949},[943,1545,1525],{"class":1136},[943,1547,1548],{"class":949},") {\n",[943,1550,1552,1555,1558,1560,1563,1565,1567,1569,1572,1575,1577,1580,1582,1585,1588,1591,1594,1597,1599,1601,1604,1606,1608,1610,1612],{"class":945,"line":1551},25,[943,1553,1554],{"class":1128},"    return",[943,1556,1557],{"class":1136}," res",[943,1559,1297],{"class":949},[943,1561,1562],{"class":1300},"status",[943,1564,1396],{"class":949},[943,1566,1541],{"class":1136},[943,1568,1297],{"class":949},[943,1570,1571],{"class":1136},"errors",[943,1573,1574],{"class":967}," ===",[943,1576,1199],{"class":987},[943,1578,1579],{"class":991},"XSS attempt",[943,1581,1399],{"class":987},[943,1583,1584],{"class":967}," ?",[943,1586,1587],{"class":1327}," 403",[943,1589,1590],{"class":967}," :",[943,1592,1593],{"class":1327}," 400",[943,1595,1596],{"class":949},").",[943,1598,5],{"class":1300},[943,1600,1319],{"class":949},[943,1602,1603],{"class":1136},"error",[943,1605,968],{"class":1313},[943,1607,1473],{"class":1136},[943,1609,1297],{"class":949},[943,1611,1571],{"class":1136},[943,1613,1465],{"class":949},[943,1615,1617],{"class":945,"line":1616},26,[943,1618,1089],{"class":949},[943,1620,1622,1624,1626,1629,1631,1633,1636],{"class":945,"line":1621},27,[943,1623,1518],{"class":1128},[943,1625,1412],{"class":949},[943,1627,1628],{"class":967},"!",[943,1630,1541],{"class":1136},[943,1632,1297],{"class":949},[943,1634,1635],{"class":1136},"success",[943,1637,1548],{"class":949},[943,1639,1641,1643,1645,1647,1649,1651,1654,1656,1658,1660,1662,1664,1666,1668,1671],{"class":945,"line":1640},28,[943,1642,1554],{"class":1128},[943,1644,1557],{"class":1136},[943,1646,1297],{"class":949},[943,1648,1562],{"class":1300},[943,1650,1396],{"class":949},[943,1652,1653],{"class":1327},"422",[943,1655,1596],{"class":949},[943,1657,5],{"class":1300},[943,1659,1396],{"class":949},[943,1661,1541],{"class":1136},[943,1663,1297],{"class":949},[943,1665,1603],{"class":1136},[943,1667,1297],{"class":949},[943,1669,1670],{"class":1300},"format",[943,1672,1673],{"class":949},"())\n",[943,1675,1677],{"class":945,"line":1676},29,[943,1678,1089],{"class":949},[943,1680,1682],{"class":945,"line":1681},30,[943,1683,1277],{"emptyLinePlaceholder":8},[943,1685,1687,1689,1691,1694,1696,1699,1701,1704,1706,1708],{"class":945,"line":1686},31,[943,1688,1435],{"class":1283},[943,1690,1212],{"class":949},[943,1692,1693],{"class":1287},"email",[943,1695,1218],{"class":949},[943,1697,1698],{"class":1287},"password",[943,1700,1224],{"class":949},[943,1702,1703],{"class":967},"=",[943,1705,1473],{"class":1136},[943,1707,1297],{"class":949},[943,1709,1710],{"class":1136},"data\n",[943,1712,1714,1716,1719,1721,1724],{"class":945,"line":1713},32,[943,1715,1435],{"class":1283},[943,1717,1718],{"class":1287}," pool",[943,1720,1291],{"class":967},[943,1722,1723],{"class":1300}," getPool",[943,1725,1726],{"class":949},"()\n",[943,1728,1730,1732,1735,1737,1740],{"class":945,"line":1729},33,[943,1731,1435],{"class":1283},[943,1733,1734],{"class":1287}," config",[943,1736,1291],{"class":967},[943,1738,1739],{"class":1300}," getConfiguration",[943,1741,1726],{"class":949},[943,1743,1745],{"class":945,"line":1744},34,[943,1746,1277],{"emptyLinePlaceholder":8},[943,1748,1750],{"class":945,"line":1749},35,[943,1751,1753],{"class":1752},"sghk6","  \u002F\u002F Fetch user and their roles from the database\n",[943,1755,1757,1759,1761,1764,1767,1769,1771,1773,1775,1778],{"class":945,"line":1756},36,[943,1758,1435],{"class":1283},[943,1760,1061],{"class":949},[943,1762,1763],{"class":1287},"rows",[943,1765,1766],{"class":949},"] ",[943,1768,1703],{"class":967},[943,1770,1478],{"class":1128},[943,1772,1718],{"class":1136},[943,1774,1297],{"class":949},[943,1776,1777],{"class":1300},"execute",[943,1779,1780],{"class":949},"(\n",[943,1782,1784],{"class":945,"line":1783},37,[943,1785,1786],{"class":991},"    `SELECT u.id, u.visitor_id, u.password_hash,\n",[943,1788,1790],{"class":945,"line":1789},38,[943,1791,1792],{"class":991},"            GROUP_CONCAT(r.name ORDER BY r.name) AS roles\n",[943,1794,1796],{"class":945,"line":1795},39,[943,1797,1798],{"class":991},"     FROM users u\n",[943,1800,1802],{"class":945,"line":1801},40,[943,1803,1804],{"class":991},"     LEFT JOIN user_roles ur ON ur.user_id = u.id\n",[943,1806,1808],{"class":945,"line":1807},41,[943,1809,1810],{"class":991},"     LEFT JOIN roles r ON r.id = ur.role_id\n",[943,1812,1814],{"class":945,"line":1813},42,[943,1815,1816],{"class":991},"     WHERE u.email = ? AND u.active_user = 1\n",[943,1818,1820],{"class":945,"line":1819},43,[943,1821,1822],{"class":991},"     GROUP BY u.id\n",[943,1824,1826,1829],{"class":945,"line":1825},44,[943,1827,1828],{"class":991},"     LIMIT 1`",[943,1830,997],{"class":949},[943,1832,1834,1837,1839],{"class":945,"line":1833},45,[943,1835,1836],{"class":949},"    [",[943,1838,1693],{"class":1136},[943,1840,1071],{"class":949},[943,1842,1844],{"class":945,"line":1843},46,[943,1845,1846],{"class":949},"  )\n",[943,1848,1850],{"class":945,"line":1849},47,[943,1851,1277],{"emptyLinePlaceholder":8},[943,1853,1855,1857,1860,1862,1865,1868,1871],{"class":945,"line":1854},48,[943,1856,1435],{"class":1283},[943,1858,1859],{"class":1287}," user",[943,1861,1291],{"class":967},[943,1863,1864],{"class":1136}," rows",[943,1866,1867],{"class":949},"[",[943,1869,1870],{"class":1327},"0",[943,1872,1071],{"class":949},[943,1874,1876,1878,1880,1882,1884,1886,1889,1891,1893,1895,1897,1900,1902,1904,1906,1908,1910,1912,1915,1917],{"class":945,"line":1875},49,[943,1877,1518],{"class":1128},[943,1879,1412],{"class":949},[943,1881,1628],{"class":967},[943,1883,1066],{"class":1136},[943,1885,1424],{"class":949},[943,1887,1888],{"class":1128},"return",[943,1890,1557],{"class":1136},[943,1892,1297],{"class":949},[943,1894,1562],{"class":1300},[943,1896,1396],{"class":949},[943,1898,1899],{"class":1327},"401",[943,1901,1596],{"class":949},[943,1903,5],{"class":1300},[943,1905,1319],{"class":949},[943,1907,1603],{"class":1136},[943,1909,968],{"class":1313},[943,1911,1199],{"class":987},[943,1913,1914],{"class":991},"Invalid credentials",[943,1916,1399],{"class":987},[943,1918,1465],{"class":949},[943,1920,1922],{"class":945,"line":1921},50,[943,1923,1277],{"emptyLinePlaceholder":8},[943,1925,1927,1929,1932,1934,1936,1939,1941,1943,1945,1948,1950,1952],{"class":945,"line":1926},51,[943,1928,1435],{"class":1283},[943,1930,1931],{"class":1287}," valid",[943,1933,1291],{"class":967},[943,1935,1478],{"class":1128},[943,1937,1938],{"class":1300}," verifyPassword",[943,1940,1396],{"class":949},[943,1942,1066],{"class":1136},[943,1944,1297],{"class":949},[943,1946,1947],{"class":1136},"password_hash",[943,1949,1218],{"class":949},[943,1951,1698],{"class":1136},[943,1953,1507],{"class":949},[943,1955,1957,1959,1961,1963,1965,1967,1969,1971,1973,1975,1977,1979,1981,1983,1985,1987,1989,1991,1993,1995],{"class":945,"line":1956},52,[943,1958,1518],{"class":1128},[943,1960,1412],{"class":949},[943,1962,1628],{"class":967},[943,1964,1525],{"class":1136},[943,1966,1424],{"class":949},[943,1968,1888],{"class":1128},[943,1970,1557],{"class":1136},[943,1972,1297],{"class":949},[943,1974,1562],{"class":1300},[943,1976,1396],{"class":949},[943,1978,1899],{"class":1327},[943,1980,1596],{"class":949},[943,1982,5],{"class":1300},[943,1984,1319],{"class":949},[943,1986,1603],{"class":1136},[943,1988,968],{"class":1313},[943,1990,1199],{"class":987},[943,1992,1914],{"class":991},[943,1994,1399],{"class":987},[943,1996,1465],{"class":949},[943,1998,2000],{"class":945,"line":1999},53,[943,2001,1277],{"emptyLinePlaceholder":8},[943,2003,2005,2007,2010,2012,2016,2019,2021,2023,2025,2027,2029,2031,2033,2035,2037,2040,2042,2044,2047,2049,2051,2053],{"class":945,"line":2004},54,[943,2006,1435],{"class":1283},[943,2008,2009],{"class":1287}," roles",[943,2011,968],{"class":967},[943,2013,2015],{"class":2014},"sFs1U"," string",[943,2017,2018],{"class":949},"[] ",[943,2020,1703],{"class":967},[943,2022,1859],{"class":1136},[943,2024,1297],{"class":949},[943,2026,881],{"class":1136},[943,2028,1584],{"class":967},[943,2030,1859],{"class":1136},[943,2032,1297],{"class":949},[943,2034,881],{"class":1136},[943,2036,1297],{"class":949},[943,2038,2039],{"class":1300},"split",[943,2041,1396],{"class":949},[943,2043,1399],{"class":987},[943,2045,2046],{"class":991},",",[943,2048,1399],{"class":987},[943,2050,1424],{"class":949},[943,2052,968],{"class":967},[943,2054,2055],{"class":949}," []\n",[943,2057,2059],{"class":945,"line":2058},55,[943,2060,1277],{"emptyLinePlaceholder":8},[943,2062,2064,2066,2069,2071,2073,2076,2078,2081,2083,2085,2087,2090,2092,2095,2097,2099,2101,2104],{"class":945,"line":2063},56,[943,2065,1435],{"class":1283},[943,2067,2068],{"class":1287}," refreshToken",[943,2070,1291],{"class":967},[943,2072,1478],{"class":1128},[943,2074,2075],{"class":1300}," generateRefreshToken",[943,2077,1396],{"class":949},[943,2079,2080],{"class":1136},"config",[943,2082,1297],{"class":949},[943,2084,961],{"class":1136},[943,2086,1297],{"class":949},[943,2088,2089],{"class":1136},"refresh_tokens",[943,2091,1297],{"class":949},[943,2093,2094],{"class":1136},"refresh_ttl",[943,2096,1218],{"class":949},[943,2098,1066],{"class":1136},[943,2100,1297],{"class":949},[943,2102,2103],{"class":1136},"id",[943,2105,1507],{"class":949},[943,2107,2109,2111,2114,2116,2119],{"class":945,"line":2108},57,[943,2110,1435],{"class":1283},[943,2112,2113],{"class":1287}," accessToken",[943,2115,1291],{"class":967},[943,2117,2118],{"class":1300}," generateAccessToken",[943,2120,1304],{"class":949},[943,2122,2124,2127,2129,2131,2133,2135],{"class":945,"line":2123},58,[943,2125,2126],{"class":1136},"    id",[943,2128,968],{"class":1313},[943,2130,1859],{"class":1136},[943,2132,1297],{"class":949},[943,2134,2103],{"class":1136},[943,2136,997],{"class":949},[943,2138,2140,2143,2145,2147,2149,2152],{"class":945,"line":2139},59,[943,2141,2142],{"class":1136},"    visitor_id",[943,2144,968],{"class":1313},[943,2146,1859],{"class":1136},[943,2148,1297],{"class":949},[943,2150,2151],{"class":1136},"visitor_id",[943,2153,997],{"class":949},[943,2155,2157,2160,2162,2164,2166,2169],{"class":945,"line":2156},60,[943,2158,2159],{"class":1136},"    jti",[943,2161,968],{"class":1313},[943,2163,1261],{"class":1136},[943,2165,1297],{"class":949},[943,2167,2168],{"class":1300},"randomUUID",[943,2170,2171],{"class":949},"(),\n",[943,2173,2175,2178,2180,2182],{"class":945,"line":2174},61,[943,2176,2177],{"class":1136},"    role",[943,2179,968],{"class":1313},[943,2181,2009],{"class":1136},[943,2183,997],{"class":949},[943,2185,2187],{"class":945,"line":2186},62,[943,2188,2189],{"class":949},"  })\n",[943,2191,2193],{"class":945,"line":2192},63,[943,2194,1277],{"emptyLinePlaceholder":8},[943,2196,2198,2200,2202,2204,2206,2208,2211,2213,2215,2218,2220,2223],{"class":945,"line":2197},64,[943,2199,1179],{"class":1300},[943,2201,1396],{"class":949},[943,2203,1421],{"class":1136},[943,2205,1218],{"class":949},[943,2207,1399],{"class":987},[943,2209,2210],{"class":991},"session",[943,2212,1399],{"class":987},[943,2214,1218],{"class":949},[943,2216,2217],{"class":1136},"refreshToken",[943,2219,1297],{"class":949},[943,2221,2222],{"class":1136},"raw",[943,2224,2225],{"class":949},", {\n",[943,2227,2229,2232,2234,2238],{"class":945,"line":2228},65,[943,2230,2231],{"class":1136},"    httpOnly",[943,2233,968],{"class":1313},[943,2235,2237],{"class":2236},"sjR7W"," true",[943,2239,997],{"class":949},[943,2241,2243,2246,2248,2250],{"class":945,"line":2242},66,[943,2244,2245],{"class":1136},"    secure",[943,2247,968],{"class":1313},[943,2249,2237],{"class":2236},[943,2251,997],{"class":949},[943,2253,2255,2258,2260,2262,2265,2267],{"class":945,"line":2254},67,[943,2256,2257],{"class":1136},"    sameSite",[943,2259,968],{"class":1313},[943,2261,1199],{"class":987},[943,2263,2264],{"class":991},"strict",[943,2266,1399],{"class":987},[943,2268,997],{"class":949},[943,2270,2272,2275,2277,2279,2281,2283,2285,2287,2289,2292],{"class":945,"line":2271},68,[943,2273,2274],{"class":1136},"    domain",[943,2276,968],{"class":1313},[943,2278,1734],{"class":1136},[943,2280,1297],{"class":949},[943,2282,961],{"class":1136},[943,2284,1297],{"class":949},[943,2286,2089],{"class":1136},[943,2288,1297],{"class":949},[943,2290,2291],{"class":1136},"domain",[943,2293,997],{"class":949},[943,2295,2297,2300,2302,2304,2307,2309],{"class":945,"line":2296},69,[943,2298,2299],{"class":1136},"    path",[943,2301,968],{"class":1313},[943,2303,1199],{"class":987},[943,2305,2306],{"class":991},"\u002F",[943,2308,1399],{"class":987},[943,2310,997],{"class":949},[943,2312,2314,2317,2319,2321,2323,2326],{"class":945,"line":2313},70,[943,2315,2316],{"class":1136},"    expires",[943,2318,968],{"class":1313},[943,2320,2068],{"class":1136},[943,2322,1297],{"class":949},[943,2324,2325],{"class":1136},"expiresAt",[943,2327,997],{"class":949},[943,2329,2331],{"class":945,"line":2330},71,[943,2332,2189],{"class":949},[943,2334,2336],{"class":945,"line":2335},72,[943,2337,1277],{"emptyLinePlaceholder":8},[943,2339,2341,2344,2346,2348,2350,2353,2355,2357,2359,2362],{"class":945,"line":2340},73,[943,2342,2343],{"class":1136},"  res",[943,2345,1297],{"class":949},[943,2347,1562],{"class":1300},[943,2349,1396],{"class":949},[943,2351,2352],{"class":1327},"200",[943,2354,1596],{"class":949},[943,2356,5],{"class":1300},[943,2358,1319],{"class":949},[943,2360,2361],{"class":1136},"accessToken",[943,2363,1465],{"class":949},[943,2365,2367],{"class":945,"line":2366},74,[943,2368,1377],{"class":949},[920,2370,2372],{"id":2371},"issuing-tokens-in-custom-flows","Issuing tokens in custom flows",[856,2374,2375,2376,2378],{},"When issuing tokens outside of the standard login flow (for example, after completing a custom MFA verification or promoting a user to a new role), call ",[860,2377,1114],{}," directly with the role array.",[901,2380,2382],{"className":1118,"code":2381,"language":1121,"meta":909,"style":909},"import { generateAccessToken } from '@riavzon\u002Fauth'\nimport crypto from 'node:crypto'\n\nconst accessToken = generateAccessToken({\n  id: user.id,\n  visitor_id: user.visitor_id,\n  jti: crypto.randomUUID(),\n  role: ['admin', 'editor'],\n})\n",[860,2383,2384,2402,2416,2420,2432,2447,2462,2477,2505],{"__ignoreMap":909},[943,2385,2386,2388,2390,2392,2394,2396,2398,2400],{"class":945,"line":946},[943,2387,1129],{"class":1128},[943,2389,1212],{"class":949},[943,2391,1114],{"class":1136},[943,2393,1224],{"class":949},[943,2395,1196],{"class":1128},[943,2397,1199],{"class":987},[943,2399,1202],{"class":991},[943,2401,1205],{"class":987},[943,2403,2404,2406,2408,2410,2412,2414],{"class":945,"line":953},[943,2405,1129],{"class":1128},[943,2407,1261],{"class":1136},[943,2409,1264],{"class":1128},[943,2411,1199],{"class":987},[943,2413,1269],{"class":991},[943,2415,1205],{"class":987},[943,2417,2418],{"class":945,"line":974},[943,2419,1277],{"emptyLinePlaceholder":8},[943,2421,2422,2424,2426,2428,2430],{"class":945,"line":1000},[943,2423,1284],{"class":1283},[943,2425,2113],{"class":1287},[943,2427,1291],{"class":967},[943,2429,2118],{"class":1300},[943,2431,1304],{"class":949},[943,2433,2434,2437,2439,2441,2443,2445],{"class":945,"line":1014},[943,2435,2436],{"class":1136},"  id",[943,2438,968],{"class":1313},[943,2440,1859],{"class":1136},[943,2442,1297],{"class":949},[943,2444,2103],{"class":1136},[943,2446,997],{"class":949},[943,2448,2449,2452,2454,2456,2458,2460],{"class":945,"line":1036},[943,2450,2451],{"class":1136},"  visitor_id",[943,2453,968],{"class":1313},[943,2455,1859],{"class":1136},[943,2457,1297],{"class":949},[943,2459,2151],{"class":1136},[943,2461,997],{"class":949},[943,2463,2464,2467,2469,2471,2473,2475],{"class":945,"line":1049},[943,2465,2466],{"class":1136},"  jti",[943,2468,968],{"class":1313},[943,2470,1261],{"class":1136},[943,2472,1297],{"class":949},[943,2474,2168],{"class":1300},[943,2476,2171],{"class":949},[943,2478,2479,2482,2484,2486,2488,2491,2493,2495,2497,2500,2502],{"class":945,"line":1074},[943,2480,2481],{"class":1136},"  role",[943,2483,968],{"class":1313},[943,2485,1061],{"class":949},[943,2487,1399],{"class":987},[943,2489,2490],{"class":991},"admin",[943,2492,1399],{"class":987},[943,2494,1218],{"class":949},[943,2496,1399],{"class":987},[943,2498,2499],{"class":991},"editor",[943,2501,1399],{"class":987},[943,2503,2504],{"class":949},"],\n",[943,2506,2507],{"class":945,"line":1080},[943,2508,1377],{"class":949},[2510,2511,2512],"tip",{},[856,2513,2514],{},"Always fetch roles from the database at the moment of token issuance, not from the previous token's payload. A user's roles may have changed since their last login.",[869,2516],{},[872,2518,2520],{"id":2519},"role-integrity-enforcement","Role integrity enforcement",[856,2522,2523,2525,2526,2528],{},[860,2524,889],{}," runs inside ",[860,2527,885],{}," on every token verification. It compares the roles in the JWT payload against the roles recorded in the token cache entry when the token was generated.",[856,2530,2531,2532,2535,2536,2539],{},"The comparison is an exact set check: both arrays must contain the same strings with no extras and no omissions. Duplicates before and after normalization cause a ",[860,2533,2534],{},"MalformedPayload"," failure. A discrepancy between the JWT payload and the cache causes an ",[860,2537,2538],{},"InvalidRoles"," failure, which rejects the token entirely.",[856,2541,2542],{},"This design means a client cannot elevate privileges by modifying the JWT payload. Even if the signature is somehow forged, the cache entry remains authoritative. The only way to legitimately hold a role in a request is to have received a token that was signed with that role at issuance.",[856,2544,2545,2547],{},[860,2546,889],{}," is also exported for use in custom authorization logic that compares two known role arrays.",[901,2549,2551],{"className":1118,"code":2550,"language":1121,"meta":909,"style":909},"import { compareRoles, getLogger } from '@riavzon\u002Fauth'\n\nconst log = getLogger()\n\nconst result = compareRoles(['admin'], req.user.roles, log)\n\nif (!result.valid) {\n  \u002F\u002F result.errorType is 'MalformedPayload' or 'InvalidRoles'\n  res.status(403).json({ error: 'Insufficient permissions' })\n  return\n}\n",[860,2552,2553,2576,2580,2592,2596,2635,2639,2656,2661,2693,2698],{"__ignoreMap":909},[943,2554,2555,2557,2559,2561,2563,2566,2568,2570,2572,2574],{"class":945,"line":946},[943,2556,1129],{"class":1128},[943,2558,1212],{"class":949},[943,2560,889],{"class":1136},[943,2562,1218],{"class":949},[943,2564,2565],{"class":1136},"getLogger",[943,2567,1224],{"class":949},[943,2569,1196],{"class":1128},[943,2571,1199],{"class":987},[943,2573,1202],{"class":991},[943,2575,1205],{"class":987},[943,2577,2578],{"class":945,"line":953},[943,2579,1277],{"emptyLinePlaceholder":8},[943,2581,2582,2584,2586,2588,2590],{"class":945,"line":974},[943,2583,1284],{"class":1283},[943,2585,1438],{"class":1287},[943,2587,1291],{"class":967},[943,2589,1443],{"class":1300},[943,2591,1726],{"class":949},[943,2593,2594],{"class":945,"line":1000},[943,2595,1277],{"emptyLinePlaceholder":8},[943,2597,2598,2600,2602,2604,2607,2610,2612,2614,2616,2619,2621,2623,2625,2627,2629,2631,2633],{"class":945,"line":1014},[943,2599,1284],{"class":1283},[943,2601,1473],{"class":1287},[943,2603,1291],{"class":967},[943,2605,2606],{"class":1300}," compareRoles",[943,2608,2609],{"class":949},"([",[943,2611,1399],{"class":987},[943,2613,2490],{"class":991},[943,2615,1399],{"class":987},[943,2617,2618],{"class":949},"], ",[943,2620,1416],{"class":1136},[943,2622,1297],{"class":949},[943,2624,1066],{"class":1136},[943,2626,1297],{"class":949},[943,2628,881],{"class":1136},[943,2630,1218],{"class":949},[943,2632,1504],{"class":1136},[943,2634,1507],{"class":949},[943,2636,2637],{"class":945,"line":1036},[943,2638,1277],{"emptyLinePlaceholder":8},[943,2640,2641,2644,2646,2648,2650,2652,2654],{"class":945,"line":1049},[943,2642,2643],{"class":1128},"if",[943,2645,1412],{"class":949},[943,2647,1628],{"class":967},[943,2649,1541],{"class":1136},[943,2651,1297],{"class":949},[943,2653,1525],{"class":1136},[943,2655,1548],{"class":949},[943,2657,2658],{"class":945,"line":1074},[943,2659,2660],{"class":1752},"  \u002F\u002F result.errorType is 'MalformedPayload' or 'InvalidRoles'\n",[943,2662,2663,2665,2667,2669,2671,2674,2676,2678,2680,2682,2684,2686,2689,2691],{"class":945,"line":1080},[943,2664,2343],{"class":1136},[943,2666,1297],{"class":949},[943,2668,1562],{"class":1300},[943,2670,1396],{"class":949},[943,2672,2673],{"class":1327},"403",[943,2675,1596],{"class":949},[943,2677,5],{"class":1300},[943,2679,1319],{"class":949},[943,2681,1603],{"class":1136},[943,2683,968],{"class":1313},[943,2685,1199],{"class":987},[943,2687,2688],{"class":991},"Insufficient permissions",[943,2690,1399],{"class":987},[943,2692,1465],{"class":949},[943,2694,2695],{"class":945,"line":1086},[943,2696,2697],{"class":1128},"  return\n",[943,2699,2700],{"class":945,"line":1092},[943,2701,1095],{"class":949},[2703,2704,2705],"note",{},[856,2706,2707,2709,2710,2713],{},[860,2708,889],{}," checks for exact set equality. If you need to check whether a user has at least one required role from a set of alternatives, use ",[860,2711,2712],{},"req.user.roles.includes()"," or build a custom guard as shown in the next section.",[869,2715],{},[872,2717,2719],{"id":2718},"building-role-guards","Building role guards",[920,2721,2723],{"id":2722},"single-role-requirement","Single-role requirement",[856,2725,2726,2727,2729,2730,1297],{},"The simplest guard checks that ",[860,2728,862],{}," includes a specific role. Mount it after ",[860,2731,866],{},[901,2733,2736],{"className":1118,"code":2734,"filename":2735,"language":1121,"meta":909,"style":909},"import type { Request, Response, NextFunction } from 'express'\n\nexport function requireRole(role: string) {\n  return (req: Request, res: Response, next: NextFunction) => {\n    const roles = req.user?.roles\n\n    if (!Array.isArray(roles) || !roles.includes(role)) {\n      res.status(403).json({ error: 'Insufficient permissions' })\n      return\n    }\n\n    next()\n  }\n}\n","server\u002Fmiddleware\u002FrequireRole.ts",[860,2737,2738,2771,2775,2797,2836,2858,2862,2904,2935,2940,2944,2948,2955,2959],{"__ignoreMap":909},[943,2739,2740,2742,2745,2747,2750,2752,2755,2757,2760,2762,2764,2766,2769],{"class":945,"line":946},[943,2741,1129],{"class":1128},[943,2743,2744],{"class":1128}," type",[943,2746,1212],{"class":949},[943,2748,2749],{"class":1136},"Request",[943,2751,1218],{"class":949},[943,2753,2754],{"class":1136},"Response",[943,2756,1218],{"class":949},[943,2758,2759],{"class":1136},"NextFunction",[943,2761,1224],{"class":949},[943,2763,1196],{"class":1128},[943,2765,1199],{"class":987},[943,2767,2768],{"class":991},"express",[943,2770,1205],{"class":987},[943,2772,2773],{"class":945,"line":953},[943,2774,1277],{"emptyLinePlaceholder":8},[943,2776,2777,2780,2783,2786,2788,2791,2793,2795],{"class":945,"line":974},[943,2778,2779],{"class":1128},"export",[943,2781,2782],{"class":1283}," function",[943,2784,2785],{"class":1300}," requireRole",[943,2787,1396],{"class":949},[943,2789,2790],{"class":1415},"role",[943,2792,968],{"class":967},[943,2794,2015],{"class":2014},[943,2796,1548],{"class":949},[943,2798,2799,2802,2804,2806,2808,2811,2813,2815,2817,2820,2822,2825,2827,2830,2832,2834],{"class":945,"line":1000},[943,2800,2801],{"class":1128},"  return",[943,2803,1412],{"class":949},[943,2805,1416],{"class":1415},[943,2807,968],{"class":967},[943,2809,2810],{"class":2014}," Request",[943,2812,1218],{"class":949},[943,2814,1421],{"class":1415},[943,2816,968],{"class":967},[943,2818,2819],{"class":2014}," Response",[943,2821,1218],{"class":949},[943,2823,2824],{"class":1415},"next",[943,2826,968],{"class":967},[943,2828,2829],{"class":2014}," NextFunction",[943,2831,1424],{"class":949},[943,2833,1427],{"class":1283},[943,2835,971],{"class":949},[943,2837,2838,2841,2843,2845,2848,2850,2852,2855],{"class":945,"line":1014},[943,2839,2840],{"class":1283},"    const",[943,2842,2009],{"class":1287},[943,2844,1291],{"class":967},[943,2846,2847],{"class":1136}," req",[943,2849,1297],{"class":949},[943,2851,1066],{"class":1136},[943,2853,2854],{"class":949},"?.",[943,2856,2857],{"class":1136},"roles\n",[943,2859,2860],{"class":945,"line":1036},[943,2861,1277],{"emptyLinePlaceholder":8},[943,2863,2864,2867,2869,2871,2874,2876,2879,2881,2883,2885,2888,2890,2892,2894,2897,2899,2901],{"class":945,"line":1049},[943,2865,2866],{"class":1128},"    if",[943,2868,1412],{"class":949},[943,2870,1628],{"class":967},[943,2872,2873],{"class":1136},"Array",[943,2875,1297],{"class":949},[943,2877,2878],{"class":1300},"isArray",[943,2880,1396],{"class":949},[943,2882,881],{"class":1136},[943,2884,1424],{"class":949},[943,2886,2887],{"class":967},"||",[943,2889,1538],{"class":967},[943,2891,881],{"class":1136},[943,2893,1297],{"class":949},[943,2895,2896],{"class":1300},"includes",[943,2898,1396],{"class":949},[943,2900,2790],{"class":1136},[943,2902,2903],{"class":949},")) {\n",[943,2905,2906,2909,2911,2913,2915,2917,2919,2921,2923,2925,2927,2929,2931,2933],{"class":945,"line":1074},[943,2907,2908],{"class":1136},"      res",[943,2910,1297],{"class":949},[943,2912,1562],{"class":1300},[943,2914,1396],{"class":949},[943,2916,2673],{"class":1327},[943,2918,1596],{"class":949},[943,2920,5],{"class":1300},[943,2922,1319],{"class":949},[943,2924,1603],{"class":1136},[943,2926,968],{"class":1313},[943,2928,1199],{"class":987},[943,2930,2688],{"class":991},[943,2932,1399],{"class":987},[943,2934,1465],{"class":949},[943,2936,2937],{"class":945,"line":1080},[943,2938,2939],{"class":1128},"      return\n",[943,2941,2942],{"class":945,"line":1086},[943,2943,1083],{"class":949},[943,2945,2946],{"class":945,"line":1092},[943,2947,1277],{"emptyLinePlaceholder":8},[943,2949,2950,2953],{"class":945,"line":1235},[943,2951,2952],{"class":1300},"    next",[943,2954,1726],{"class":949},[943,2956,2957],{"class":945,"line":1256},[943,2958,1089],{"class":949},[943,2960,2961],{"class":945,"line":1274},[943,2962,1095],{"class":949},[901,2964,2967],{"className":1118,"code":2965,"filename":2966,"language":1121,"meta":909,"style":909},"import {\n  requireAccessToken,\n  requireRefreshToken,\n  getFingerPrint,\n  protectRoute,\n} from '@riavzon\u002Fauth'\nimport { requireRole } from '..\u002Fmiddleware\u002FrequireRole'\n\nrouter.get(\n  '\u002Fadmin\u002Fdashboard',\n  requireAccessToken,\n  requireRefreshToken,\n  getFingerPrint,\n  protectRoute,\n  requireRole('admin'),\n  async (req, res) => {\n    res.json({ message: 'Welcome to the admin dashboard' })\n  }\n)\n","server\u002Froutes\u002Fadmin.ts",[860,2968,2969,2975,2982,2989,2996,3003,3015,3035,3039,3050,3062,3068,3074,3080,3086,3102,3121,3146,3150],{"__ignoreMap":909},[943,2970,2971,2973],{"class":945,"line":946},[943,2972,1129],{"class":1128},[943,2974,971],{"class":949},[943,2976,2977,2980],{"class":945,"line":953},[943,2978,2979],{"class":1136},"  requireAccessToken",[943,2981,997],{"class":949},[943,2983,2984,2987],{"class":945,"line":974},[943,2985,2986],{"class":1136},"  requireRefreshToken",[943,2988,997],{"class":949},[943,2990,2991,2994],{"class":945,"line":1000},[943,2992,2993],{"class":1136},"  getFingerPrint",[943,2995,997],{"class":949},[943,2997,2998,3001],{"class":945,"line":1014},[943,2999,3000],{"class":1136},"  protectRoute",[943,3002,997],{"class":949},[943,3004,3005,3007,3009,3011,3013],{"class":945,"line":1036},[943,3006,1193],{"class":949},[943,3008,1196],{"class":1128},[943,3010,1199],{"class":987},[943,3012,1202],{"class":991},[943,3014,1205],{"class":987},[943,3016,3017,3019,3021,3024,3026,3028,3030,3033],{"class":945,"line":1049},[943,3018,1129],{"class":1128},[943,3020,1212],{"class":949},[943,3022,3023],{"class":1136},"requireRole",[943,3025,1224],{"class":949},[943,3027,1196],{"class":1128},[943,3029,1199],{"class":987},[943,3031,3032],{"class":991},"..\u002Fmiddleware\u002FrequireRole",[943,3034,1205],{"class":987},[943,3036,3037],{"class":945,"line":1074},[943,3038,1277],{"emptyLinePlaceholder":8},[943,3040,3041,3043,3045,3048],{"class":945,"line":1080},[943,3042,1388],{"class":1136},[943,3044,1297],{"class":949},[943,3046,3047],{"class":1300},"get",[943,3049,1780],{"class":949},[943,3051,3052,3055,3058,3060],{"class":945,"line":1086},[943,3053,3054],{"class":987},"  '",[943,3056,3057],{"class":991},"\u002Fadmin\u002Fdashboard",[943,3059,1399],{"class":987},[943,3061,997],{"class":949},[943,3063,3064,3066],{"class":945,"line":1092},[943,3065,2979],{"class":1136},[943,3067,997],{"class":949},[943,3069,3070,3072],{"class":945,"line":1235},[943,3071,2986],{"class":1136},[943,3073,997],{"class":949},[943,3075,3076,3078],{"class":945,"line":1256},[943,3077,2993],{"class":1136},[943,3079,997],{"class":949},[943,3081,3082,3084],{"class":945,"line":1274},[943,3083,3000],{"class":1136},[943,3085,997],{"class":949},[943,3087,3088,3091,3093,3095,3097,3099],{"class":945,"line":1280},[943,3089,3090],{"class":1300},"  requireRole",[943,3092,1396],{"class":949},[943,3094,1399],{"class":987},[943,3096,2490],{"class":991},[943,3098,1399],{"class":987},[943,3100,3101],{"class":949},"),\n",[943,3103,3104,3107,3109,3111,3113,3115,3117,3119],{"class":945,"line":1307},[943,3105,3106],{"class":1283},"  async",[943,3108,1412],{"class":949},[943,3110,1416],{"class":1415},[943,3112,1218],{"class":949},[943,3114,1421],{"class":1415},[943,3116,1424],{"class":949},[943,3118,1427],{"class":1283},[943,3120,971],{"class":949},[943,3122,3123,3126,3128,3130,3132,3135,3137,3139,3142,3144],{"class":945,"line":1344},[943,3124,3125],{"class":1136},"    res",[943,3127,1297],{"class":949},[943,3129,5],{"class":1300},[943,3131,1319],{"class":949},[943,3133,3134],{"class":1136},"message",[943,3136,968],{"class":1313},[943,3138,1199],{"class":987},[943,3140,3141],{"class":991},"Welcome to the admin dashboard",[943,3143,1399],{"class":987},[943,3145,1465],{"class":949},[943,3147,3148],{"class":945,"line":1374},[943,3149,1089],{"class":949},[943,3151,3152],{"class":945,"line":1380},[943,3153,1507],{"class":949},[920,3155,3157],{"id":3156},"any-of-roles-requirement","Any-of-roles requirement",[856,3159,3160],{},"Allow access when the user holds at least one role from a set.",[901,3162,3165],{"className":1118,"code":3163,"filename":3164,"language":1121,"meta":909,"style":909},"import type { Request, Response, NextFunction } from 'express'\n\nexport function requireAnyRole(...allowedRoles: string[]) {\n  return (req: Request, res: Response, next: NextFunction) => {\n    const roles = req.user?.roles\n\n    if (!Array.isArray(roles) || !allowedRoles.some(r => roles.includes(r))) {\n      res.status(403).json({ error: 'Insufficient permissions' })\n      return\n    }\n\n    next()\n  }\n}\n","server\u002Fmiddleware\u002FrequireAnyRole.ts",[860,3166,3167,3195,3199,3223,3257,3275,3279,3331,3361,3365,3369,3373,3379,3383],{"__ignoreMap":909},[943,3168,3169,3171,3173,3175,3177,3179,3181,3183,3185,3187,3189,3191,3193],{"class":945,"line":946},[943,3170,1129],{"class":1128},[943,3172,2744],{"class":1128},[943,3174,1212],{"class":949},[943,3176,2749],{"class":1136},[943,3178,1218],{"class":949},[943,3180,2754],{"class":1136},[943,3182,1218],{"class":949},[943,3184,2759],{"class":1136},[943,3186,1224],{"class":949},[943,3188,1196],{"class":1128},[943,3190,1199],{"class":987},[943,3192,2768],{"class":991},[943,3194,1205],{"class":987},[943,3196,3197],{"class":945,"line":953},[943,3198,1277],{"emptyLinePlaceholder":8},[943,3200,3201,3203,3205,3208,3210,3213,3216,3218,3220],{"class":945,"line":974},[943,3202,2779],{"class":1128},[943,3204,2782],{"class":1283},[943,3206,3207],{"class":1300}," requireAnyRole",[943,3209,1396],{"class":949},[943,3211,3212],{"class":967},"...",[943,3214,3215],{"class":1415},"allowedRoles",[943,3217,968],{"class":967},[943,3219,2015],{"class":2014},[943,3221,3222],{"class":949},"[]) {\n",[943,3224,3225,3227,3229,3231,3233,3235,3237,3239,3241,3243,3245,3247,3249,3251,3253,3255],{"class":945,"line":1000},[943,3226,2801],{"class":1128},[943,3228,1412],{"class":949},[943,3230,1416],{"class":1415},[943,3232,968],{"class":967},[943,3234,2810],{"class":2014},[943,3236,1218],{"class":949},[943,3238,1421],{"class":1415},[943,3240,968],{"class":967},[943,3242,2819],{"class":2014},[943,3244,1218],{"class":949},[943,3246,2824],{"class":1415},[943,3248,968],{"class":967},[943,3250,2829],{"class":2014},[943,3252,1424],{"class":949},[943,3254,1427],{"class":1283},[943,3256,971],{"class":949},[943,3258,3259,3261,3263,3265,3267,3269,3271,3273],{"class":945,"line":1014},[943,3260,2840],{"class":1283},[943,3262,2009],{"class":1287},[943,3264,1291],{"class":967},[943,3266,2847],{"class":1136},[943,3268,1297],{"class":949},[943,3270,1066],{"class":1136},[943,3272,2854],{"class":949},[943,3274,2857],{"class":1136},[943,3276,3277],{"class":945,"line":1036},[943,3278,1277],{"emptyLinePlaceholder":8},[943,3280,3281,3283,3285,3287,3289,3291,3293,3295,3297,3299,3301,3303,3305,3307,3310,3312,3315,3318,3320,3322,3324,3326,3328],{"class":945,"line":1049},[943,3282,2866],{"class":1128},[943,3284,1412],{"class":949},[943,3286,1628],{"class":967},[943,3288,2873],{"class":1136},[943,3290,1297],{"class":949},[943,3292,2878],{"class":1300},[943,3294,1396],{"class":949},[943,3296,881],{"class":1136},[943,3298,1424],{"class":949},[943,3300,2887],{"class":967},[943,3302,1538],{"class":967},[943,3304,3215],{"class":1136},[943,3306,1297],{"class":949},[943,3308,3309],{"class":1300},"some",[943,3311,1396],{"class":949},[943,3313,3314],{"class":1415},"r",[943,3316,3317],{"class":1283}," =>",[943,3319,2009],{"class":1136},[943,3321,1297],{"class":949},[943,3323,2896],{"class":1300},[943,3325,1396],{"class":949},[943,3327,3314],{"class":1136},[943,3329,3330],{"class":949},"))) {\n",[943,3332,3333,3335,3337,3339,3341,3343,3345,3347,3349,3351,3353,3355,3357,3359],{"class":945,"line":1074},[943,3334,2908],{"class":1136},[943,3336,1297],{"class":949},[943,3338,1562],{"class":1300},[943,3340,1396],{"class":949},[943,3342,2673],{"class":1327},[943,3344,1596],{"class":949},[943,3346,5],{"class":1300},[943,3348,1319],{"class":949},[943,3350,1603],{"class":1136},[943,3352,968],{"class":1313},[943,3354,1199],{"class":987},[943,3356,2688],{"class":991},[943,3358,1399],{"class":987},[943,3360,1465],{"class":949},[943,3362,3363],{"class":945,"line":1080},[943,3364,2939],{"class":1128},[943,3366,3367],{"class":945,"line":1086},[943,3368,1083],{"class":949},[943,3370,3371],{"class":945,"line":1092},[943,3372,1277],{"emptyLinePlaceholder":8},[943,3374,3375,3377],{"class":945,"line":1235},[943,3376,2952],{"class":1300},[943,3378,1726],{"class":949},[943,3380,3381],{"class":945,"line":1256},[943,3382,1089],{"class":949},[943,3384,3385],{"class":945,"line":1274},[943,3386,1095],{"class":949},[901,3388,3390],{"className":1118,"code":3389,"language":1121,"meta":909,"style":909},"router.post(\n  '\u002Fposts',\n  requireAccessToken,\n  requireRefreshToken,\n  getFingerPrint,\n  protectRoute,\n  requireAnyRole('editor', 'admin'),\n  createPostHandler\n)\n",[860,3391,3392,3402,3413,3419,3425,3431,3437,3460,3465],{"__ignoreMap":909},[943,3393,3394,3396,3398,3400],{"class":945,"line":946},[943,3395,1388],{"class":1136},[943,3397,1297],{"class":949},[943,3399,1393],{"class":1300},[943,3401,1780],{"class":949},[943,3403,3404,3406,3409,3411],{"class":945,"line":953},[943,3405,3054],{"class":987},[943,3407,3408],{"class":991},"\u002Fposts",[943,3410,1399],{"class":987},[943,3412,997],{"class":949},[943,3414,3415,3417],{"class":945,"line":974},[943,3416,2979],{"class":1136},[943,3418,997],{"class":949},[943,3420,3421,3423],{"class":945,"line":1000},[943,3422,2986],{"class":1136},[943,3424,997],{"class":949},[943,3426,3427,3429],{"class":945,"line":1014},[943,3428,2993],{"class":1136},[943,3430,997],{"class":949},[943,3432,3433,3435],{"class":945,"line":1036},[943,3434,3000],{"class":1136},[943,3436,997],{"class":949},[943,3438,3439,3442,3444,3446,3448,3450,3452,3454,3456,3458],{"class":945,"line":1049},[943,3440,3441],{"class":1300},"  requireAnyRole",[943,3443,1396],{"class":949},[943,3445,1399],{"class":987},[943,3447,2499],{"class":991},[943,3449,1399],{"class":987},[943,3451,1218],{"class":949},[943,3453,1399],{"class":987},[943,3455,2490],{"class":991},[943,3457,1399],{"class":987},[943,3459,3101],{"class":949},[943,3461,3462],{"class":945,"line":1074},[943,3463,3464],{"class":1136},"  createPostHandler\n",[943,3466,3467],{"class":945,"line":1080},[943,3468,1507],{"class":949},[920,3470,3472],{"id":3471},"all-roles-requirement","All-roles requirement",[856,3474,3475],{},"Require the user to hold every role in a set simultaneously.",[901,3477,3480],{"className":1118,"code":3478,"filename":3479,"language":1121,"meta":909,"style":909},"import type { Request, Response, NextFunction } from 'express'\n\nexport function requireAllRoles(...requiredRoles: string[]) {\n  return (req: Request, res: Response, next: NextFunction) => {\n    const roles = req.user?.roles\n\n    if (!Array.isArray(roles) || !requiredRoles.every(r => roles.includes(r))) {\n      res.status(403).json({ error: 'Insufficient permissions' })\n      return\n    }\n\n    next()\n  }\n}\n","server\u002Fmiddleware\u002FrequireAllRoles.ts",[860,3481,3482,3510,3514,3536,3570,3588,3592,3641,3671,3675,3679,3683,3689,3693],{"__ignoreMap":909},[943,3483,3484,3486,3488,3490,3492,3494,3496,3498,3500,3502,3504,3506,3508],{"class":945,"line":946},[943,3485,1129],{"class":1128},[943,3487,2744],{"class":1128},[943,3489,1212],{"class":949},[943,3491,2749],{"class":1136},[943,3493,1218],{"class":949},[943,3495,2754],{"class":1136},[943,3497,1218],{"class":949},[943,3499,2759],{"class":1136},[943,3501,1224],{"class":949},[943,3503,1196],{"class":1128},[943,3505,1199],{"class":987},[943,3507,2768],{"class":991},[943,3509,1205],{"class":987},[943,3511,3512],{"class":945,"line":953},[943,3513,1277],{"emptyLinePlaceholder":8},[943,3515,3516,3518,3520,3523,3525,3527,3530,3532,3534],{"class":945,"line":974},[943,3517,2779],{"class":1128},[943,3519,2782],{"class":1283},[943,3521,3522],{"class":1300}," requireAllRoles",[943,3524,1396],{"class":949},[943,3526,3212],{"class":967},[943,3528,3529],{"class":1415},"requiredRoles",[943,3531,968],{"class":967},[943,3533,2015],{"class":2014},[943,3535,3222],{"class":949},[943,3537,3538,3540,3542,3544,3546,3548,3550,3552,3554,3556,3558,3560,3562,3564,3566,3568],{"class":945,"line":1000},[943,3539,2801],{"class":1128},[943,3541,1412],{"class":949},[943,3543,1416],{"class":1415},[943,3545,968],{"class":967},[943,3547,2810],{"class":2014},[943,3549,1218],{"class":949},[943,3551,1421],{"class":1415},[943,3553,968],{"class":967},[943,3555,2819],{"class":2014},[943,3557,1218],{"class":949},[943,3559,2824],{"class":1415},[943,3561,968],{"class":967},[943,3563,2829],{"class":2014},[943,3565,1424],{"class":949},[943,3567,1427],{"class":1283},[943,3569,971],{"class":949},[943,3571,3572,3574,3576,3578,3580,3582,3584,3586],{"class":945,"line":1014},[943,3573,2840],{"class":1283},[943,3575,2009],{"class":1287},[943,3577,1291],{"class":967},[943,3579,2847],{"class":1136},[943,3581,1297],{"class":949},[943,3583,1066],{"class":1136},[943,3585,2854],{"class":949},[943,3587,2857],{"class":1136},[943,3589,3590],{"class":945,"line":1036},[943,3591,1277],{"emptyLinePlaceholder":8},[943,3593,3594,3596,3598,3600,3602,3604,3606,3608,3610,3612,3614,3616,3618,3620,3623,3625,3627,3629,3631,3633,3635,3637,3639],{"class":945,"line":1049},[943,3595,2866],{"class":1128},[943,3597,1412],{"class":949},[943,3599,1628],{"class":967},[943,3601,2873],{"class":1136},[943,3603,1297],{"class":949},[943,3605,2878],{"class":1300},[943,3607,1396],{"class":949},[943,3609,881],{"class":1136},[943,3611,1424],{"class":949},[943,3613,2887],{"class":967},[943,3615,1538],{"class":967},[943,3617,3529],{"class":1136},[943,3619,1297],{"class":949},[943,3621,3622],{"class":1300},"every",[943,3624,1396],{"class":949},[943,3626,3314],{"class":1415},[943,3628,3317],{"class":1283},[943,3630,2009],{"class":1136},[943,3632,1297],{"class":949},[943,3634,2896],{"class":1300},[943,3636,1396],{"class":949},[943,3638,3314],{"class":1136},[943,3640,3330],{"class":949},[943,3642,3643,3645,3647,3649,3651,3653,3655,3657,3659,3661,3663,3665,3667,3669],{"class":945,"line":1074},[943,3644,2908],{"class":1136},[943,3646,1297],{"class":949},[943,3648,1562],{"class":1300},[943,3650,1396],{"class":949},[943,3652,2673],{"class":1327},[943,3654,1596],{"class":949},[943,3656,5],{"class":1300},[943,3658,1319],{"class":949},[943,3660,1603],{"class":1136},[943,3662,968],{"class":1313},[943,3664,1199],{"class":987},[943,3666,2688],{"class":991},[943,3668,1399],{"class":987},[943,3670,1465],{"class":949},[943,3672,3673],{"class":945,"line":1080},[943,3674,2939],{"class":1128},[943,3676,3677],{"class":945,"line":1086},[943,3678,1083],{"class":949},[943,3680,3681],{"class":945,"line":1092},[943,3682,1277],{"emptyLinePlaceholder":8},[943,3684,3685,3687],{"class":945,"line":1235},[943,3686,2952],{"class":1300},[943,3688,1726],{"class":949},[943,3690,3691],{"class":945,"line":1256},[943,3692,1089],{"class":949},[943,3694,3695],{"class":945,"line":1274},[943,3696,1095],{"class":949},[869,3698],{},[872,3700,3702],{"id":3701},"per-resource-authorization","Per-resource authorization",[856,3704,3705],{},"For resources that are owned by specific users, combine role checks with ownership checks inside the handler. Do not rely on roles alone when a resource belongs to a single user.",[901,3707,3710],{"className":1118,"code":3708,"filename":3709,"language":1121,"meta":909,"style":909},"router.put(\n  '\u002Fposts\u002F:id',\n  requireAccessToken,\n  requireRefreshToken,\n  getFingerPrint,\n  protectRoute,\n  async (req, res) => {\n    const { userId, roles } = req.user!\n    const pool = getPool()\n\n    const [rows] = await pool.execute(\n      'SELECT author_id FROM posts WHERE id = ? LIMIT 1',\n      [req.params.id]\n    )\n\n    const post = rows[0]\n    if (!post) return res.status(404).json({ error: 'Post not found' })\n\n    const isOwner = post.author_id === Number(userId)\n    const isAdmin = Array.isArray(roles) && roles.includes('admin')\n\n    if (!isOwner && !isAdmin) {\n      return res.status(403).json({ error: 'Insufficient permissions' })\n    }\n\n    \u002F\u002F Proceed with the update\n  }\n)\n","server\u002Froutes\u002Fposts.ts",[860,3711,3712,3723,3734,3740,3746,3752,3758,3776,3802,3814,3818,3840,3852,3870,3875,3879,3896,3940,3944,3971,4012,4016,4036,4069,4073,4077,4082,4086],{"__ignoreMap":909},[943,3713,3714,3716,3718,3721],{"class":945,"line":946},[943,3715,1388],{"class":1136},[943,3717,1297],{"class":949},[943,3719,3720],{"class":1300},"put",[943,3722,1780],{"class":949},[943,3724,3725,3727,3730,3732],{"class":945,"line":953},[943,3726,3054],{"class":987},[943,3728,3729],{"class":991},"\u002Fposts\u002F:id",[943,3731,1399],{"class":987},[943,3733,997],{"class":949},[943,3735,3736,3738],{"class":945,"line":974},[943,3737,2979],{"class":1136},[943,3739,997],{"class":949},[943,3741,3742,3744],{"class":945,"line":1000},[943,3743,2986],{"class":1136},[943,3745,997],{"class":949},[943,3747,3748,3750],{"class":945,"line":1014},[943,3749,2993],{"class":1136},[943,3751,997],{"class":949},[943,3753,3754,3756],{"class":945,"line":1036},[943,3755,3000],{"class":1136},[943,3757,997],{"class":949},[943,3759,3760,3762,3764,3766,3768,3770,3772,3774],{"class":945,"line":1049},[943,3761,3106],{"class":1283},[943,3763,1412],{"class":949},[943,3765,1416],{"class":1415},[943,3767,1218],{"class":949},[943,3769,1421],{"class":1415},[943,3771,1424],{"class":949},[943,3773,1427],{"class":1283},[943,3775,971],{"class":949},[943,3777,3778,3780,3782,3785,3787,3789,3791,3793,3795,3797,3799],{"class":945,"line":1074},[943,3779,2840],{"class":1283},[943,3781,1212],{"class":949},[943,3783,3784],{"class":1287},"userId",[943,3786,1218],{"class":949},[943,3788,881],{"class":1287},[943,3790,1224],{"class":949},[943,3792,1703],{"class":967},[943,3794,2847],{"class":1136},[943,3796,1297],{"class":949},[943,3798,1066],{"class":1136},[943,3800,3801],{"class":967},"!\n",[943,3803,3804,3806,3808,3810,3812],{"class":945,"line":1080},[943,3805,2840],{"class":1283},[943,3807,1718],{"class":1287},[943,3809,1291],{"class":967},[943,3811,1723],{"class":1300},[943,3813,1726],{"class":949},[943,3815,3816],{"class":945,"line":1086},[943,3817,1277],{"emptyLinePlaceholder":8},[943,3819,3820,3822,3824,3826,3828,3830,3832,3834,3836,3838],{"class":945,"line":1092},[943,3821,2840],{"class":1283},[943,3823,1061],{"class":949},[943,3825,1763],{"class":1287},[943,3827,1766],{"class":949},[943,3829,1703],{"class":967},[943,3831,1478],{"class":1128},[943,3833,1718],{"class":1136},[943,3835,1297],{"class":949},[943,3837,1777],{"class":1300},[943,3839,1780],{"class":949},[943,3841,3842,3845,3848,3850],{"class":945,"line":1235},[943,3843,3844],{"class":987},"      '",[943,3846,3847],{"class":991},"SELECT author_id FROM posts WHERE id = ? LIMIT 1",[943,3849,1399],{"class":987},[943,3851,997],{"class":949},[943,3853,3854,3857,3859,3861,3864,3866,3868],{"class":945,"line":1256},[943,3855,3856],{"class":949},"      [",[943,3858,1416],{"class":1136},[943,3860,1297],{"class":949},[943,3862,3863],{"class":1136},"params",[943,3865,1297],{"class":949},[943,3867,2103],{"class":1136},[943,3869,1071],{"class":949},[943,3871,3872],{"class":945,"line":1274},[943,3873,3874],{"class":949},"    )\n",[943,3876,3877],{"class":945,"line":1280},[943,3878,1277],{"emptyLinePlaceholder":8},[943,3880,3881,3883,3886,3888,3890,3892,3894],{"class":945,"line":1307},[943,3882,2840],{"class":1283},[943,3884,3885],{"class":1287}," post",[943,3887,1291],{"class":967},[943,3889,1864],{"class":1136},[943,3891,1867],{"class":949},[943,3893,1870],{"class":1327},[943,3895,1071],{"class":949},[943,3897,3898,3900,3902,3904,3906,3908,3910,3912,3914,3916,3918,3921,3923,3925,3927,3929,3931,3933,3936,3938],{"class":945,"line":1344},[943,3899,2866],{"class":1128},[943,3901,1412],{"class":949},[943,3903,1628],{"class":967},[943,3905,1393],{"class":1136},[943,3907,1424],{"class":949},[943,3909,1888],{"class":1128},[943,3911,1557],{"class":1136},[943,3913,1297],{"class":949},[943,3915,1562],{"class":1300},[943,3917,1396],{"class":949},[943,3919,3920],{"class":1327},"404",[943,3922,1596],{"class":949},[943,3924,5],{"class":1300},[943,3926,1319],{"class":949},[943,3928,1603],{"class":1136},[943,3930,968],{"class":1313},[943,3932,1199],{"class":987},[943,3934,3935],{"class":991},"Post not found",[943,3937,1399],{"class":987},[943,3939,1465],{"class":949},[943,3941,3942],{"class":945,"line":1374},[943,3943,1277],{"emptyLinePlaceholder":8},[943,3945,3946,3948,3951,3953,3955,3957,3960,3962,3965,3967,3969],{"class":945,"line":1380},[943,3947,2840],{"class":1283},[943,3949,3950],{"class":1287}," isOwner",[943,3952,1291],{"class":967},[943,3954,3885],{"class":1136},[943,3956,1297],{"class":949},[943,3958,3959],{"class":1136},"author_id",[943,3961,1574],{"class":967},[943,3963,3964],{"class":1300}," Number",[943,3966,1396],{"class":949},[943,3968,3784],{"class":1136},[943,3970,1507],{"class":949},[943,3972,3973,3975,3978,3980,3983,3985,3987,3989,3991,3993,3996,3998,4000,4002,4004,4006,4008,4010],{"class":945,"line":1385},[943,3974,2840],{"class":1283},[943,3976,3977],{"class":1287}," isAdmin",[943,3979,1291],{"class":967},[943,3981,3982],{"class":1136}," Array",[943,3984,1297],{"class":949},[943,3986,2878],{"class":1300},[943,3988,1396],{"class":949},[943,3990,881],{"class":1136},[943,3992,1424],{"class":949},[943,3994,3995],{"class":967},"&&",[943,3997,2009],{"class":1136},[943,3999,1297],{"class":949},[943,4001,2896],{"class":1300},[943,4003,1396],{"class":949},[943,4005,1399],{"class":987},[943,4007,2490],{"class":991},[943,4009,1399],{"class":987},[943,4011,1507],{"class":949},[943,4013,4014],{"class":945,"line":1432},[943,4015,1277],{"emptyLinePlaceholder":8},[943,4017,4018,4020,4022,4024,4027,4029,4031,4034],{"class":945,"line":1468},[943,4019,2866],{"class":1128},[943,4021,1412],{"class":949},[943,4023,1628],{"class":967},[943,4025,4026],{"class":1136},"isOwner",[943,4028,1535],{"class":967},[943,4030,1538],{"class":967},[943,4032,4033],{"class":1136},"isAdmin",[943,4035,1548],{"class":949},[943,4037,4038,4041,4043,4045,4047,4049,4051,4053,4055,4057,4059,4061,4063,4065,4067],{"class":945,"line":1510},[943,4039,4040],{"class":1128},"      return",[943,4042,1557],{"class":1136},[943,4044,1297],{"class":949},[943,4046,1562],{"class":1300},[943,4048,1396],{"class":949},[943,4050,2673],{"class":1327},[943,4052,1596],{"class":949},[943,4054,5],{"class":1300},[943,4056,1319],{"class":949},[943,4058,1603],{"class":1136},[943,4060,968],{"class":1313},[943,4062,1199],{"class":987},[943,4064,2688],{"class":991},[943,4066,1399],{"class":987},[943,4068,1465],{"class":949},[943,4070,4071],{"class":945,"line":1515},[943,4072,1083],{"class":949},[943,4074,4075],{"class":945,"line":1551},[943,4076,1277],{"emptyLinePlaceholder":8},[943,4078,4079],{"class":945,"line":1616},[943,4080,4081],{"class":1752},"    \u002F\u002F Proceed with the update\n",[943,4083,4084],{"class":945,"line":1621},[943,4085,1089],{"class":949},[943,4087,4088],{"class":945,"line":1640},[943,4089,1507],{"class":949},[869,4091],{},[872,4093,4095],{"id":4094},"roles-in-the-bff-pattern","Roles in the BFF pattern",[856,4097,4098,4099,4103,4104,4107],{},"When using the ",[4100,4101,4102],"a",{"href":132},"BFF pattern",", the IAM service returns the user's roles on every ",[860,4105,4106],{},"GET \u002Fsecret\u002Fdata"," response.",[901,4109,4111],{"className":937,"code":4110,"language":5,"meta":909,"style":909},"{\n  \"authorized\": true,\n  \"userId\": 42,\n  \"roles\": [\"admin\", \"editor\"],\n  \"ipAddress\": \"...\",\n  \"date\": \"...\"\n}\n",[860,4112,4113,4117,4132,4147,4175,4194,4212],{"__ignoreMap":909},[943,4114,4115],{"class":945,"line":946},[943,4116,950],{"class":949},[943,4118,4119,4121,4124,4126,4128,4130],{"class":945,"line":953},[943,4120,957],{"class":956},[943,4122,4123],{"class":960},"authorized",[943,4125,964],{"class":956},[943,4127,968],{"class":967},[943,4129,2237],{"class":2236},[943,4131,997],{"class":949},[943,4133,4134,4136,4138,4140,4142,4145],{"class":945,"line":974},[943,4135,957],{"class":956},[943,4137,3784],{"class":960},[943,4139,964],{"class":956},[943,4141,968],{"class":967},[943,4143,4144],{"class":1327}," 42",[943,4146,997],{"class":949},[943,4148,4149,4151,4153,4155,4157,4159,4161,4163,4165,4167,4169,4171,4173],{"class":945,"line":1000},[943,4150,957],{"class":956},[943,4152,881],{"class":960},[943,4154,964],{"class":956},[943,4156,968],{"class":967},[943,4158,1061],{"class":949},[943,4160,964],{"class":987},[943,4162,2490],{"class":991},[943,4164,964],{"class":987},[943,4166,1218],{"class":949},[943,4168,964],{"class":987},[943,4170,2499],{"class":991},[943,4172,964],{"class":987},[943,4174,2504],{"class":949},[943,4176,4177,4179,4182,4184,4186,4188,4190,4192],{"class":945,"line":1014},[943,4178,957],{"class":956},[943,4180,4181],{"class":960},"ipAddress",[943,4183,964],{"class":956},[943,4185,968],{"class":967},[943,4187,988],{"class":987},[943,4189,3212],{"class":991},[943,4191,964],{"class":987},[943,4193,997],{"class":949},[943,4195,4196,4198,4201,4203,4205,4207,4209],{"class":945,"line":1036},[943,4197,957],{"class":956},[943,4199,4200],{"class":960},"date",[943,4202,964],{"class":956},[943,4204,968],{"class":967},[943,4206,988],{"class":987},[943,4208,3212],{"class":991},[943,4210,4211],{"class":987},"\"\n",[943,4213,4214],{"class":945,"line":1049},[943,4215,1095],{"class":949},[856,4217,4218],{},"The BFF proxy reads this response and decides whether to allow the original browser request to proceed. Role enforcement lives entirely on the server side. The browser never sees or stores the role list directly.",[856,4220,4221],{},"A typical BFF proxy handler:",[901,4223,4226],{"className":1118,"code":4224,"filename":4225,"language":1121,"meta":909,"style":909},"\u002F\u002F Example using H3 or Nitro syntax\nexport default defineEventHandler(async (event) => {\n  const iamResponse = await $fetch('https:\u002F\u002Fiam.internal\u002Fsecret\u002Fdata', {\n    headers: { Authorization: `Bearer ${accessToken}` },\n    headers: { Cookie: `session=${session}; canary_id=${canaryId}` },\n  })\n\n  if (!iamResponse.authorized) {\n    throw createError({ statusCode: 401 })\n  }\n\n  if (!iamResponse.roles?.includes('admin')) {\n    throw createError({ statusCode: 403, message: 'Insufficient permissions' })\n  }\n\n  \u002F\u002F Proceed with the protected resource\n})\n","server\u002Fapi\u002Fadmin\u002Fdashboard.get.ts",[860,4227,4228,4233,4258,4283,4314,4350,4354,4358,4375,4395,4399,4403,4431,4459,4463,4467,4472],{"__ignoreMap":909},[943,4229,4230],{"class":945,"line":946},[943,4231,4232],{"class":1752},"\u002F\u002F Example using H3 or Nitro syntax\n",[943,4234,4235,4237,4240,4243,4245,4247,4249,4252,4254,4256],{"class":945,"line":953},[943,4236,2779],{"class":1128},[943,4238,4239],{"class":1128}," default",[943,4241,4242],{"class":1300}," defineEventHandler",[943,4244,1396],{"class":949},[943,4246,1409],{"class":1283},[943,4248,1412],{"class":949},[943,4250,4251],{"class":1415},"event",[943,4253,1424],{"class":949},[943,4255,1427],{"class":1283},[943,4257,971],{"class":949},[943,4259,4260,4262,4265,4267,4269,4272,4274,4276,4279,4281],{"class":945,"line":974},[943,4261,1435],{"class":1283},[943,4263,4264],{"class":1287}," iamResponse",[943,4266,1291],{"class":967},[943,4268,1478],{"class":1128},[943,4270,4271],{"class":1300}," $fetch",[943,4273,1396],{"class":949},[943,4275,1399],{"class":987},[943,4277,4278],{"class":991},"https:\u002F\u002Fiam.internal\u002Fsecret\u002Fdata",[943,4280,1399],{"class":987},[943,4282,2225],{"class":949},[943,4284,4285,4288,4290,4292,4295,4297,4300,4303,4305,4308,4311],{"class":945,"line":1000},[943,4286,4287],{"class":1136},"    headers",[943,4289,968],{"class":1313},[943,4291,1212],{"class":949},[943,4293,4294],{"class":1136},"Authorization",[943,4296,968],{"class":1313},[943,4298,4299],{"class":991}," `Bearer ",[943,4301,4302],{"class":1283},"${",[943,4304,2361],{"class":1136},[943,4306,4307],{"class":1283},"}",[943,4309,4310],{"class":991},"`",[943,4312,4313],{"class":949}," },\n",[943,4315,4316,4318,4320,4322,4325,4327,4330,4332,4334,4336,4339,4341,4344,4346,4348],{"class":945,"line":1014},[943,4317,4287],{"class":1136},[943,4319,968],{"class":1313},[943,4321,1212],{"class":949},[943,4323,4324],{"class":1136},"Cookie",[943,4326,968],{"class":1313},[943,4328,4329],{"class":991}," `session=",[943,4331,4302],{"class":1283},[943,4333,2210],{"class":1136},[943,4335,4307],{"class":1283},[943,4337,4338],{"class":991},"; canary_id=",[943,4340,4302],{"class":1283},[943,4342,4343],{"class":1136},"canaryId",[943,4345,4307],{"class":1283},[943,4347,4310],{"class":991},[943,4349,4313],{"class":949},[943,4351,4352],{"class":945,"line":1036},[943,4353,2189],{"class":949},[943,4355,4356],{"class":945,"line":1049},[943,4357,1277],{"emptyLinePlaceholder":8},[943,4359,4360,4362,4364,4366,4369,4371,4373],{"class":945,"line":1074},[943,4361,1518],{"class":1128},[943,4363,1412],{"class":949},[943,4365,1628],{"class":967},[943,4367,4368],{"class":1136},"iamResponse",[943,4370,1297],{"class":949},[943,4372,4123],{"class":1136},[943,4374,1548],{"class":949},[943,4376,4377,4380,4383,4385,4388,4390,4393],{"class":945,"line":1080},[943,4378,4379],{"class":1128},"    throw",[943,4381,4382],{"class":1300}," createError",[943,4384,1319],{"class":949},[943,4386,4387],{"class":1136},"statusCode",[943,4389,968],{"class":1313},[943,4391,4392],{"class":1327}," 401",[943,4394,1465],{"class":949},[943,4396,4397],{"class":945,"line":1086},[943,4398,1089],{"class":949},[943,4400,4401],{"class":945,"line":1092},[943,4402,1277],{"emptyLinePlaceholder":8},[943,4404,4405,4407,4409,4411,4413,4415,4417,4419,4421,4423,4425,4427,4429],{"class":945,"line":1235},[943,4406,1518],{"class":1128},[943,4408,1412],{"class":949},[943,4410,1628],{"class":967},[943,4412,4368],{"class":1136},[943,4414,1297],{"class":949},[943,4416,881],{"class":1136},[943,4418,2854],{"class":949},[943,4420,2896],{"class":1300},[943,4422,1396],{"class":949},[943,4424,1399],{"class":987},[943,4426,2490],{"class":991},[943,4428,1399],{"class":987},[943,4430,2903],{"class":949},[943,4432,4433,4435,4437,4439,4441,4443,4445,4447,4449,4451,4453,4455,4457],{"class":945,"line":1256},[943,4434,4379],{"class":1128},[943,4436,4382],{"class":1300},[943,4438,1319],{"class":949},[943,4440,4387],{"class":1136},[943,4442,968],{"class":1313},[943,4444,1587],{"class":1327},[943,4446,1218],{"class":949},[943,4448,3134],{"class":1136},[943,4450,968],{"class":1313},[943,4452,1199],{"class":987},[943,4454,2688],{"class":991},[943,4456,1399],{"class":987},[943,4458,1465],{"class":949},[943,4460,4461],{"class":945,"line":1274},[943,4462,1089],{"class":949},[943,4464,4465],{"class":945,"line":1280},[943,4466,1277],{"emptyLinePlaceholder":8},[943,4468,4469],{"class":945,"line":1307},[943,4470,4471],{"class":1752},"  \u002F\u002F Proceed with the protected resource\n",[943,4473,4474],{"class":945,"line":1344},[943,4475,1377],{"class":949},[2510,4477,4478],{},[856,4479,4480,4483,4484,4486],{},[4100,4481,4482],{"href":22},"auth-h3client"," handles the BFF call and session forwarding automatically. It exposes the ",[860,4485,881],{}," array from the IAM response to your route handlers without requiring manual fetch calls.",[869,4488],{},[872,4490,4492],{"id":4491},"token-rotation-and-role-updates","Token rotation and role updates",[856,4494,4495],{},"When a user's roles change in the database, existing access tokens continue to carry the old roles until they expire. The cache entry matches the JWT payload, so verification passes, but the roles reflect what was true at issuance.",[856,4497,4498],{},"To force an immediate role update, revoke the user's current access token:",[901,4500,4502],{"className":1118,"code":4501,"language":1121,"meta":909,"style":909},"import { tokenCache } from '@riavzon\u002Fauth'\n\n\u002F\u002F Remove the token from the cache — the next request will require re-authentication\ntokenCache().delete(rawAccessToken)\n",[860,4503,4504,4523,4527,4532],{"__ignoreMap":909},[943,4505,4506,4508,4510,4513,4515,4517,4519,4521],{"class":945,"line":946},[943,4507,1129],{"class":1128},[943,4509,1212],{"class":949},[943,4511,4512],{"class":1136},"tokenCache",[943,4514,1224],{"class":949},[943,4516,1196],{"class":1128},[943,4518,1199],{"class":987},[943,4520,1202],{"class":991},[943,4522,1205],{"class":987},[943,4524,4525],{"class":945,"line":953},[943,4526,1277],{"emptyLinePlaceholder":8},[943,4528,4529],{"class":945,"line":974},[943,4530,4531],{"class":1752},"\u002F\u002F Remove the token from the cache — the next request will require re-authentication\n",[943,4533,4534,4536,4538,4541,4543,4546],{"class":945,"line":1000},[943,4535,4512],{"class":1300},[943,4537,1446],{"class":949},[943,4539,4540],{"class":1300},"delete",[943,4542,1396],{"class":949},[943,4544,4545],{"class":1136},"rawAccessToken",[943,4547,1507],{"class":949},[856,4549,4550,4551,4554,4555,1297],{},"If the user's refresh token is still valid, ",[860,4552,4553],{},"POST \u002Fauth\u002Fuser\u002Frefresh-session"," issues a new access token. At that point, your rotation controller should fetch fresh roles from the database and pass them to ",[860,4556,1114],{},[856,4558,4559],{},"For a full re-login (roles change requiring immediate effect across all sessions), revoke all of the user's refresh tokens:",[901,4561,4563],{"className":1118,"code":4562,"language":1121,"meta":909,"style":909},"import { revokeRefreshToken } from '@riavzon\u002Fauth'\n\n\u002F\u002F Revoke each active session — user must log in again to receive updated roles\nfor (const token of userTokens) {\n  await revokeRefreshToken(token)\n}\n",[860,4564,4565,4584,4588,4593,4613,4628],{"__ignoreMap":909},[943,4566,4567,4569,4571,4574,4576,4578,4580,4582],{"class":945,"line":946},[943,4568,1129],{"class":1128},[943,4570,1212],{"class":949},[943,4572,4573],{"class":1136},"revokeRefreshToken",[943,4575,1224],{"class":949},[943,4577,1196],{"class":1128},[943,4579,1199],{"class":987},[943,4581,1202],{"class":991},[943,4583,1205],{"class":987},[943,4585,4586],{"class":945,"line":953},[943,4587,1277],{"emptyLinePlaceholder":8},[943,4589,4590],{"class":945,"line":974},[943,4591,4592],{"class":1752},"\u002F\u002F Revoke each active session — user must log in again to receive updated roles\n",[943,4594,4595,4598,4600,4602,4605,4608,4611],{"class":945,"line":1000},[943,4596,4597],{"class":1128},"for",[943,4599,1412],{"class":949},[943,4601,1284],{"class":1283},[943,4603,4604],{"class":1287}," token",[943,4606,4607],{"class":1283}," of",[943,4609,4610],{"class":1136}," userTokens",[943,4612,1548],{"class":949},[943,4614,4615,4618,4621,4623,4626],{"class":945,"line":1014},[943,4616,4617],{"class":1128},"  await",[943,4619,4620],{"class":1300}," revokeRefreshToken",[943,4622,1396],{"class":949},[943,4624,4625],{"class":1136},"token",[943,4627,1507],{"class":949},[943,4629,4630],{"class":945,"line":1036},[943,4631,1095],{"class":949},[869,4633],{},[872,4635,4637],{"id":4636},"summary","Summary",[4639,4640,4641,4654],"table",{},[4642,4643,4644],"thead",{},[4645,4646,4647,4651],"tr",{},[4648,4649,4650],"th",{},"Concept",[4648,4652,4653],{},"Where it happens",[4655,4656,4657,4669,4680,4695,4707,4719,4732],"tbody",{},[4645,4658,4659,4663],{},[4660,4661,4662],"td",{},"Role assignment",[4660,4664,4665,4668],{},[860,4666,4667],{},"generateAccessToken({ role: [...] })"," at login or token issuance",[4645,4670,4671,4674],{},[4660,4672,4673],{},"Role storage",[4660,4675,4676,4677,4679],{},"JWT payload claim ",[860,4678,881],{}," and in-memory token cache entry",[4645,4681,4682,4685],{},[4660,4683,4684],{},"Role integrity",[4660,4686,4687,4689,4690,4692,4693],{},[860,4688,889],{}," inside ",[860,4691,885],{},", called automatically by ",[860,4694,866],{},[4645,4696,4697,4700],{},[4660,4698,4699],{},"Role access",[4660,4701,4702,863,4704,4706],{},[860,4703,862],{},[860,4705,866],{}," completes",[4645,4708,4709,4712],{},[4660,4710,4711],{},"Route guard",[4660,4713,4714,4715,863,4717],{},"Custom middleware reading ",[860,4716,862],{},[860,4718,866],{},[4645,4720,4721,4724],{},[4660,4722,4723],{},"BFF roles",[4660,4725,4726,4728,4729,4731],{},[860,4727,881],{}," field in the ",[860,4730,4106],{}," JSON response",[4645,4733,4734,4737],{},[4660,4735,4736],{},"Role revocation",[4660,4738,4739,4740],{},"Delete the cache entry via ",[860,4741,4742],{},"tokenCache().delete(rawToken)",[4744,4745,4746],"style",{},"html pre.shiki code .sDd4n, html code.shiki .sDd4n{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#F8F8F2}html pre.shiki code .saJyd, html code.shiki .saJyd{--shiki-light:#0451A5;--shiki-default:#0451A5;--shiki-dark:#8BE9FE}html pre.shiki code .s_W10, html code.shiki .s_W10{--shiki-light:#0451A5;--shiki-default:#0451A5;--shiki-dark:#8BE9FD}html pre.shiki code .saOXh, html code.shiki .saOXh{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#FF79C6}html pre.shiki code .sFkSl, html code.shiki .sFkSl{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#E9F284}html pre.shiki code .sFB1V, html code.shiki .sFB1V{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#F1FA8C}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 .sZ328, html code.shiki .sZ328{--shiki-light:#AF00DB;--shiki-default:#AF00DB;--shiki-dark:#FF79C6}html pre.shiki code .sjsA6, html code.shiki .sjsA6{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#F8F8F2}html pre.shiki code .sl46w, html code.shiki .sl46w{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#FF79C6}html pre.shiki code .s3JHE, html code.shiki .s3JHE{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#F8F8F2}html pre.shiki code .sHOzp, html code.shiki .sHOzp{--shiki-light:#795E26;--shiki-default:#795E26;--shiki-dark:#50FA7B}html pre.shiki code .s34zl, html code.shiki .s34zl{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#FF79C6}html pre.shiki code .spgvN, html code.shiki .spgvN{--shiki-light:#098658;--shiki-default:#098658;--shiki-dark:#BD93F9}html pre.shiki code .sygFZ, html code.shiki .sygFZ{--shiki-light:#001080;--shiki-light-font-style:inherit;--shiki-default:#001080;--shiki-default-font-style:inherit;--shiki-dark:#FFB86C;--shiki-dark-font-style:italic}html pre.shiki code .sghk6, html code.shiki .sghk6{--shiki-light:#008000;--shiki-default:#008000;--shiki-dark:#6272A4}html pre.shiki code .sFs1U, html code.shiki .sFs1U{--shiki-light:#267F99;--shiki-light-font-style:inherit;--shiki-default:#267F99;--shiki-default-font-style:inherit;--shiki-dark:#8BE9FD;--shiki-dark-font-style:italic}html pre.shiki code .sjR7W, html code.shiki .sjR7W{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#BD93F9}",{"title":909,"searchDepth":953,"depth":953,"links":4748},[4749,4750,4755,4756,4761,4762,4763,4764],{"id":874,"depth":953,"text":875},{"id":914,"depth":953,"text":915,"children":4751},[4752,4753,4754],{"id":922,"depth":974,"text":923},{"id":1107,"depth":974,"text":1108},{"id":2371,"depth":974,"text":2372},{"id":2519,"depth":953,"text":2520},{"id":2718,"depth":953,"text":2719,"children":4757},[4758,4759,4760],{"id":2722,"depth":974,"text":2723},{"id":3156,"depth":974,"text":3157},{"id":3471,"depth":974,"text":3472},{"id":3701,"depth":953,"text":3702},{"id":4094,"depth":953,"text":4095},{"id":4491,"depth":953,"text":4492},{"id":4636,"depth":953,"text":4637},"How roles flow from database to JWT to request context, and how to build route guards, role-checking middleware, and per-resource authorization using the IAM service as a library.","md",{},null,"---\ntitle: Role-Based Access Control\ndescription: How roles flow from database to JWT to request context, and how to build route guards, role-checking middleware, and per-resource authorization using the IAM service as a library.\nicon: i-lucide-shield-check\n---\n\nRole-based access control (RBAC) in the IAM service is built on top of the JWT access token. Roles are embedded at signing time, cached alongside the token, verified for integrity on every use, and exposed on `req.user.roles` after `protectRoute` runs. This guide covers how to attach roles to tokens, how integrity enforcement works, and how to build route guards and custom authorization logic.\n\n---\n\n## How roles work\n\nWhen the IAM service generates an access token, it embeds the user's roles as a `roles` claim in the JWT payload. Simultaneously, the same roles are recorded in the in-memory token cache entry. On every subsequent `verifyAccessToken` call, `compareRoles` confirms that the roles in the JWT payload exactly match the roles stored in the cache. Any mismatch causes verification to fail, preventing a client from tampering with role claims in the token string.\n\nAfter `protectRoute` runs successfully, `req.user.roles` holds the verified role array for the current request. Route handlers and custom middleware read roles exclusively from this field.\n\n```\ngenerateAccessToken({ role: ['editor'] })\n       │\n       ├── JWT payload: { roles: ['editor'], sub: '42', ... }\n       └── Cache entry: { roles: ['editor'], valid: true, ... }\n\nverifyAccessToken(token)\n       │\n       ├── Cache lookup → roles: ['editor']\n       ├── JWT decode   → roles: ['editor']\n       └── compareRoles(['editor'], ['editor']) → { valid: true }\n\nprotectRoute\n       └── req.user.roles = ['editor']\n```\n\n---\n\n## Attaching roles to tokens\n\nThe built-in login, signup, and OAuth controllers issue tokens without roles by default. You have three options for attaching roles.\n\n### Static payload via configuration\n\nAdd a `payload` object under `jwt.access_tokens` in the configuration. Every token issued by the service merges this object into the payload at signing time. Use this for roles that apply to every user uniformly.\n\n```json [config.json]\n{\n  \"jwt\": {\n    \"jwt_secret_key\": \"your-secret\",\n    \"access_tokens\": {\n      \"expiresIn\": \"15m\",\n      \"payload\": {\n        \"roles\": [\"user\"]\n      }\n    }\n  }\n}\n```\n\n::warning\nThe `payload` field adds the same roles to every token. It is not suitable for per-user roles. Use it only for a universal default role that every authenticated user should have.\n::\n\n### Custom login controller\n\nBuild a login handler that queries the user's roles from your database and passes them to `generateAccessToken`. This is the standard approach for per-user RBAC.\n\n```ts [server\u002Froutes\u002Flogin.ts]\nimport {\n  generateAccessToken,\n  generateRefreshToken,\n  validateZodSchema,\n  makeSanitizedZodString,\n  verifyPassword,\n  hashPassword,\n  makeCookie,\n  getLogger,\n} from '@riavzon\u002Fauth'\nimport { getPool, getConfiguration } from '@riavzon\u002Fauth'\nimport { z } from 'zod'\nimport crypto from 'node:crypto'\n\nconst loginSchema = z.object({\n  email: makeSanitizedZodString({ min: 5, max: 80 }),\n  password: makeSanitizedZodString({ min: 12, max: 64 }),\n})\n\nrouter.post('\u002Flogin', async (req, res) => {\n  const log = getLogger().child({ route: '\u002Flogin' })\n  const result = await validateZodSchema(loginSchema, req.body, req, log)\n\n  if ('valid' in result && !result.valid) {\n    return res.status(result.errors === 'XSS attempt' ? 403 : 400).json({ error: result.errors })\n  }\n  if (!result.success) {\n    return res.status(422).json(result.error.format())\n  }\n\n  const { email, password } = result.data\n  const pool = getPool()\n  const config = getConfiguration()\n\n  \u002F\u002F Fetch user and their roles from the database\n  const [rows] = await pool.execute(\n    `SELECT u.id, u.visitor_id, u.password_hash,\n            GROUP_CONCAT(r.name ORDER BY r.name) AS roles\n     FROM users u\n     LEFT JOIN user_roles ur ON ur.user_id = u.id\n     LEFT JOIN roles r ON r.id = ur.role_id\n     WHERE u.email = ? AND u.active_user = 1\n     GROUP BY u.id\n     LIMIT 1`,\n    [email]\n  )\n\n  const user = rows[0]\n  if (!user) return res.status(401).json({ error: 'Invalid credentials' })\n\n  const valid = await verifyPassword(user.password_hash, password)\n  if (!valid) return res.status(401).json({ error: 'Invalid credentials' })\n\n  const roles: string[] = user.roles ? user.roles.split(',') : []\n\n  const refreshToken = await generateRefreshToken(config.jwt.refresh_tokens.refresh_ttl, user.id)\n  const accessToken = generateAccessToken({\n    id: user.id,\n    visitor_id: user.visitor_id,\n    jti: crypto.randomUUID(),\n    role: roles,\n  })\n\n  makeCookie(res, 'session', refreshToken.raw, {\n    httpOnly: true,\n    secure: true,\n    sameSite: 'strict',\n    domain: config.jwt.refresh_tokens.domain,\n    path: '\u002F',\n    expires: refreshToken.expiresAt,\n  })\n\n  res.status(200).json({ accessToken })\n})\n```\n\n### Issuing tokens in custom flows\n\nWhen issuing tokens outside of the standard login flow (for example, after completing a custom MFA verification or promoting a user to a new role), call `generateAccessToken` directly with the role array.\n\n```ts\nimport { generateAccessToken } from '@riavzon\u002Fauth'\nimport crypto from 'node:crypto'\n\nconst accessToken = generateAccessToken({\n  id: user.id,\n  visitor_id: user.visitor_id,\n  jti: crypto.randomUUID(),\n  role: ['admin', 'editor'],\n})\n```\n\n::tip\nAlways fetch roles from the database at the moment of token issuance, not from the previous token's payload. A user's roles may have changed since their last login.\n::\n\n---\n\n## Role integrity enforcement\n\n`compareRoles` runs inside `verifyAccessToken` on every token verification. It compares the roles in the JWT payload against the roles recorded in the token cache entry when the token was generated.\n\nThe comparison is an exact set check: both arrays must contain the same strings with no extras and no omissions. Duplicates before and after normalization cause a `MalformedPayload` failure. A discrepancy between the JWT payload and the cache causes an `InvalidRoles` failure, which rejects the token entirely.\n\nThis design means a client cannot elevate privileges by modifying the JWT payload. Even if the signature is somehow forged, the cache entry remains authoritative. The only way to legitimately hold a role in a request is to have received a token that was signed with that role at issuance.\n\n`compareRoles` is also exported for use in custom authorization logic that compares two known role arrays.\n\n```ts\nimport { compareRoles, getLogger } from '@riavzon\u002Fauth'\n\nconst log = getLogger()\n\nconst result = compareRoles(['admin'], req.user.roles, log)\n\nif (!result.valid) {\n  \u002F\u002F result.errorType is 'MalformedPayload' or 'InvalidRoles'\n  res.status(403).json({ error: 'Insufficient permissions' })\n  return\n}\n```\n\n::note\n`compareRoles` checks for exact set equality. If you need to check whether a user has at least one required role from a set of alternatives, use `req.user.roles.includes()` or build a custom guard as shown in the next section.\n::\n\n---\n\n## Building role guards\n\n### Single-role requirement\n\nThe simplest guard checks that `req.user.roles` includes a specific role. Mount it after `protectRoute`.\n\n```ts [server\u002Fmiddleware\u002FrequireRole.ts]\nimport type { Request, Response, NextFunction } from 'express'\n\nexport function requireRole(role: string) {\n  return (req: Request, res: Response, next: NextFunction) => {\n    const roles = req.user?.roles\n\n    if (!Array.isArray(roles) || !roles.includes(role)) {\n      res.status(403).json({ error: 'Insufficient permissions' })\n      return\n    }\n\n    next()\n  }\n}\n```\n\n```ts [server\u002Froutes\u002Fadmin.ts]\nimport {\n  requireAccessToken,\n  requireRefreshToken,\n  getFingerPrint,\n  protectRoute,\n} from '@riavzon\u002Fauth'\nimport { requireRole } from '..\u002Fmiddleware\u002FrequireRole'\n\nrouter.get(\n  '\u002Fadmin\u002Fdashboard',\n  requireAccessToken,\n  requireRefreshToken,\n  getFingerPrint,\n  protectRoute,\n  requireRole('admin'),\n  async (req, res) => {\n    res.json({ message: 'Welcome to the admin dashboard' })\n  }\n)\n```\n\n### Any-of-roles requirement\n\nAllow access when the user holds at least one role from a set.\n\n```ts [server\u002Fmiddleware\u002FrequireAnyRole.ts]\nimport type { Request, Response, NextFunction } from 'express'\n\nexport function requireAnyRole(...allowedRoles: string[]) {\n  return (req: Request, res: Response, next: NextFunction) => {\n    const roles = req.user?.roles\n\n    if (!Array.isArray(roles) || !allowedRoles.some(r => roles.includes(r))) {\n      res.status(403).json({ error: 'Insufficient permissions' })\n      return\n    }\n\n    next()\n  }\n}\n```\n\n```ts\nrouter.post(\n  '\u002Fposts',\n  requireAccessToken,\n  requireRefreshToken,\n  getFingerPrint,\n  protectRoute,\n  requireAnyRole('editor', 'admin'),\n  createPostHandler\n)\n```\n\n### All-roles requirement\n\nRequire the user to hold every role in a set simultaneously.\n\n```ts [server\u002Fmiddleware\u002FrequireAllRoles.ts]\nimport type { Request, Response, NextFunction } from 'express'\n\nexport function requireAllRoles(...requiredRoles: string[]) {\n  return (req: Request, res: Response, next: NextFunction) => {\n    const roles = req.user?.roles\n\n    if (!Array.isArray(roles) || !requiredRoles.every(r => roles.includes(r))) {\n      res.status(403).json({ error: 'Insufficient permissions' })\n      return\n    }\n\n    next()\n  }\n}\n```\n\n---\n\n## Per-resource authorization\n\nFor resources that are owned by specific users, combine role checks with ownership checks inside the handler. Do not rely on roles alone when a resource belongs to a single user.\n\n```ts [server\u002Froutes\u002Fposts.ts]\nrouter.put(\n  '\u002Fposts\u002F:id',\n  requireAccessToken,\n  requireRefreshToken,\n  getFingerPrint,\n  protectRoute,\n  async (req, res) => {\n    const { userId, roles } = req.user!\n    const pool = getPool()\n\n    const [rows] = await pool.execute(\n      'SELECT author_id FROM posts WHERE id = ? LIMIT 1',\n      [req.params.id]\n    )\n\n    const post = rows[0]\n    if (!post) return res.status(404).json({ error: 'Post not found' })\n\n    const isOwner = post.author_id === Number(userId)\n    const isAdmin = Array.isArray(roles) && roles.includes('admin')\n\n    if (!isOwner && !isAdmin) {\n      return res.status(403).json({ error: 'Insufficient permissions' })\n    }\n\n    \u002F\u002F Proceed with the update\n  }\n)\n```\n\n---\n\n## Roles in the BFF pattern\n\nWhen using the [BFF pattern](\u002Fdocs\u002Fiam\u002Fessentials\u002Fbff), the IAM service returns the user's roles on every `GET \u002Fsecret\u002Fdata` response.\n\n```json\n{\n  \"authorized\": true,\n  \"userId\": 42,\n  \"roles\": [\"admin\", \"editor\"],\n  \"ipAddress\": \"...\",\n  \"date\": \"...\"\n}\n```\n\nThe BFF proxy reads this response and decides whether to allow the original browser request to proceed. Role enforcement lives entirely on the server side. The browser never sees or stores the role list directly.\n\nA typical BFF proxy handler:\n\n```ts [server\u002Fapi\u002Fadmin\u002Fdashboard.get.ts]\n\u002F\u002F Example using H3 or Nitro syntax\nexport default defineEventHandler(async (event) => {\n  const iamResponse = await $fetch('https:\u002F\u002Fiam.internal\u002Fsecret\u002Fdata', {\n    headers: { Authorization: `Bearer ${accessToken}` },\n    headers: { Cookie: `session=${session}; canary_id=${canaryId}` },\n  })\n\n  if (!iamResponse.authorized) {\n    throw createError({ statusCode: 401 })\n  }\n\n  if (!iamResponse.roles?.includes('admin')) {\n    throw createError({ statusCode: 403, message: 'Insufficient permissions' })\n  }\n\n  \u002F\u002F Proceed with the protected resource\n})\n```\n\n::tip\n[auth-h3client](\u002Fdocs\u002Fauth-h3client) handles the BFF call and session forwarding automatically. It exposes the `roles` array from the IAM response to your route handlers without requiring manual fetch calls.\n::\n\n---\n\n## Token rotation and role updates\n\nWhen a user's roles change in the database, existing access tokens continue to carry the old roles until they expire. The cache entry matches the JWT payload, so verification passes, but the roles reflect what was true at issuance.\n\nTo force an immediate role update, revoke the user's current access token:\n\n```ts\nimport { tokenCache } from '@riavzon\u002Fauth'\n\n\u002F\u002F Remove the token from the cache — the next request will require re-authentication\ntokenCache().delete(rawAccessToken)\n```\n\nIf the user's refresh token is still valid, `POST \u002Fauth\u002Fuser\u002Frefresh-session` issues a new access token. At that point, your rotation controller should fetch fresh roles from the database and pass them to `generateAccessToken`.\n\nFor a full re-login (roles change requiring immediate effect across all sessions), revoke all of the user's refresh tokens:\n\n```ts\nimport { revokeRefreshToken } from '@riavzon\u002Fauth'\n\n\u002F\u002F Revoke each active session — user must log in again to receive updated roles\nfor (const token of userTokens) {\n  await revokeRefreshToken(token)\n}\n```\n\n---\n\n## Summary\n\n| Concept | Where it happens |\n|---|---|\n| Role assignment | `generateAccessToken({ role: [...] })` at login or token issuance |\n| Role storage | JWT payload claim `roles` and in-memory token cache entry |\n| Role integrity | `compareRoles` inside `verifyAccessToken`, called automatically by `protectRoute` |\n| Role access | `req.user.roles` after `protectRoute` completes |\n| Route guard | Custom middleware reading `req.user.roles` after `protectRoute` |\n| BFF roles | `roles` field in the `GET \u002Fsecret\u002Fdata` JSON response |\n| Role revocation | Delete the cache entry via `tokenCache().delete(rawToken)` |\n",{"title":233,"description":4765},"UvC-8L51vei52np78_6Nm-IqtihAndONb8uMyscSkSQ",[4773,4774],{"title":229,"path":230,"stem":231,"children":-1},{"title":237,"path":238,"stem":239,"children":-1},{"id":851,"title":233,"body":4776,"description":4765,"extension":4766,"icon":28,"meta":8111,"module":4768,"navigation":8,"path":234,"rawbody":4769,"seo":8112,"stem":235,"__hash__":4771},{"type":853,"value":4777,"toc":8093},[4778,4784,4786,4788,4796,4802,4807,4809,4811,4813,4815,4821,4937,4943,4945,4949,5957,5959,5963,6085,6089,6091,6093,6099,6105,6107,6111,6255,6263,6265,6267,6269,6275,6477,6651,6653,6655,6871,6949,6951,6953,7169,7171,7173,7175,7535,7537,7539,7545,7647,7649,7651,7879,7887,7889,7891,7893,7895,7939,7945,7947,8009,8011,8013,8091],[856,4779,858,4780,863,4782,867],{},[860,4781,862],{},[860,4783,866],{},[869,4785],{},[872,4787,875],{"id":874},[856,4789,878,4790,882,4792,886,4794,890],{},[860,4791,881],{},[860,4793,885],{},[860,4795,889],{},[856,4797,893,4798,896,4800,899],{},[860,4799,866],{},[860,4801,862],{},[901,4803,4805],{"className":4804,"code":905,"language":906},[904],[860,4806,905],{"__ignoreMap":909},[869,4808],{},[872,4810,915],{"id":914},[856,4812,918],{},[920,4814,923],{"id":922},[856,4816,926,4817,930,4819,934],{},[860,4818,929],{},[860,4820,933],{},[901,4822,4823],{"className":937,"code":938,"filename":939,"language":5,"meta":909,"style":909},[860,4824,4825,4829,4841,4859,4871,4889,4901,4921,4925,4929,4933],{"__ignoreMap":909},[943,4826,4827],{"class":945,"line":946},[943,4828,950],{"class":949},[943,4830,4831,4833,4835,4837,4839],{"class":945,"line":953},[943,4832,957],{"class":956},[943,4834,961],{"class":960},[943,4836,964],{"class":956},[943,4838,968],{"class":967},[943,4840,971],{"class":949},[943,4842,4843,4845,4847,4849,4851,4853,4855,4857],{"class":945,"line":974},[943,4844,977],{"class":956},[943,4846,980],{"class":960},[943,4848,964],{"class":956},[943,4850,968],{"class":967},[943,4852,988],{"class":987},[943,4854,992],{"class":991},[943,4856,964],{"class":987},[943,4858,997],{"class":949},[943,4860,4861,4863,4865,4867,4869],{"class":945,"line":1000},[943,4862,977],{"class":956},[943,4864,1005],{"class":960},[943,4866,964],{"class":956},[943,4868,968],{"class":967},[943,4870,971],{"class":949},[943,4872,4873,4875,4877,4879,4881,4883,4885,4887],{"class":945,"line":1014},[943,4874,1017],{"class":956},[943,4876,1020],{"class":960},[943,4878,964],{"class":956},[943,4880,968],{"class":967},[943,4882,988],{"class":987},[943,4884,1029],{"class":991},[943,4886,964],{"class":987},[943,4888,997],{"class":949},[943,4890,4891,4893,4895,4897,4899],{"class":945,"line":1036},[943,4892,1017],{"class":956},[943,4894,929],{"class":960},[943,4896,964],{"class":956},[943,4898,968],{"class":967},[943,4900,971],{"class":949},[943,4902,4903,4905,4907,4909,4911,4913,4915,4917,4919],{"class":945,"line":1049},[943,4904,1052],{"class":956},[943,4906,881],{"class":960},[943,4908,964],{"class":956},[943,4910,968],{"class":967},[943,4912,1061],{"class":949},[943,4914,964],{"class":987},[943,4916,1066],{"class":991},[943,4918,964],{"class":987},[943,4920,1071],{"class":949},[943,4922,4923],{"class":945,"line":1074},[943,4924,1077],{"class":949},[943,4926,4927],{"class":945,"line":1080},[943,4928,1083],{"class":949},[943,4930,4931],{"class":945,"line":1086},[943,4932,1089],{"class":949},[943,4934,4935],{"class":945,"line":1092},[943,4936,1095],{"class":949},[1097,4938,4939],{},[856,4940,1101,4941,1104],{},[860,4942,929],{},[920,4944,1108],{"id":1107},[856,4946,1111,4947,1115],{},[860,4948,1114],{},[901,4950,4951],{"className":1118,"code":1119,"filename":1120,"language":1121,"meta":909,"style":909},[860,4952,4953,4959,4965,4971,4977,4983,4989,4995,5001,5007,5019,5041,5059,5073,5077,5093,5119,5145,5149,5153,5187,5215,5249,5253,5281,5333,5337,5353,5385,5389,5393,5415,5427,5439,5443,5447,5469,5473,5477,5481,5485,5489,5493,5497,5503,5511,5515,5519,5535,5577,5581,5607,5649,5653,5699,5703,5741,5753,5767,5781,5795,5805,5809,5813,5839,5849,5859,5873,5895,5909,5923,5927,5931,5953],{"__ignoreMap":909},[943,4954,4955,4957],{"class":945,"line":946},[943,4956,1129],{"class":1128},[943,4958,971],{"class":949},[943,4960,4961,4963],{"class":945,"line":953},[943,4962,1137],{"class":1136},[943,4964,997],{"class":949},[943,4966,4967,4969],{"class":945,"line":974},[943,4968,1144],{"class":1136},[943,4970,997],{"class":949},[943,4972,4973,4975],{"class":945,"line":1000},[943,4974,1151],{"class":1136},[943,4976,997],{"class":949},[943,4978,4979,4981],{"class":945,"line":1014},[943,4980,1158],{"class":1136},[943,4982,997],{"class":949},[943,4984,4985,4987],{"class":945,"line":1036},[943,4986,1165],{"class":1136},[943,4988,997],{"class":949},[943,4990,4991,4993],{"class":945,"line":1049},[943,4992,1172],{"class":1136},[943,4994,997],{"class":949},[943,4996,4997,4999],{"class":945,"line":1074},[943,4998,1179],{"class":1136},[943,5000,997],{"class":949},[943,5002,5003,5005],{"class":945,"line":1080},[943,5004,1186],{"class":1136},[943,5006,997],{"class":949},[943,5008,5009,5011,5013,5015,5017],{"class":945,"line":1086},[943,5010,1193],{"class":949},[943,5012,1196],{"class":1128},[943,5014,1199],{"class":987},[943,5016,1202],{"class":991},[943,5018,1205],{"class":987},[943,5020,5021,5023,5025,5027,5029,5031,5033,5035,5037,5039],{"class":945,"line":1092},[943,5022,1129],{"class":1128},[943,5024,1212],{"class":949},[943,5026,1215],{"class":1136},[943,5028,1218],{"class":949},[943,5030,1221],{"class":1136},[943,5032,1224],{"class":949},[943,5034,1196],{"class":1128},[943,5036,1199],{"class":987},[943,5038,1202],{"class":991},[943,5040,1205],{"class":987},[943,5042,5043,5045,5047,5049,5051,5053,5055,5057],{"class":945,"line":1235},[943,5044,1129],{"class":1128},[943,5046,1212],{"class":949},[943,5048,1242],{"class":1136},[943,5050,1224],{"class":949},[943,5052,1196],{"class":1128},[943,5054,1199],{"class":987},[943,5056,1251],{"class":991},[943,5058,1205],{"class":987},[943,5060,5061,5063,5065,5067,5069,5071],{"class":945,"line":1256},[943,5062,1129],{"class":1128},[943,5064,1261],{"class":1136},[943,5066,1264],{"class":1128},[943,5068,1199],{"class":987},[943,5070,1269],{"class":991},[943,5072,1205],{"class":987},[943,5074,5075],{"class":945,"line":1274},[943,5076,1277],{"emptyLinePlaceholder":8},[943,5078,5079,5081,5083,5085,5087,5089,5091],{"class":945,"line":1280},[943,5080,1284],{"class":1283},[943,5082,1288],{"class":1287},[943,5084,1291],{"class":967},[943,5086,1294],{"class":1136},[943,5088,1297],{"class":949},[943,5090,1301],{"class":1300},[943,5092,1304],{"class":949},[943,5094,5095,5097,5099,5101,5103,5105,5107,5109,5111,5113,5115,5117],{"class":945,"line":1307},[943,5096,1310],{"class":1136},[943,5098,968],{"class":1313},[943,5100,1316],{"class":1300},[943,5102,1319],{"class":949},[943,5104,1322],{"class":1136},[943,5106,968],{"class":1313},[943,5108,1328],{"class":1327},[943,5110,1218],{"class":949},[943,5112,1333],{"class":1136},[943,5114,968],{"class":1313},[943,5116,1338],{"class":1327},[943,5118,1341],{"class":949},[943,5120,5121,5123,5125,5127,5129,5131,5133,5135,5137,5139,5141,5143],{"class":945,"line":1344},[943,5122,1347],{"class":1136},[943,5124,968],{"class":1313},[943,5126,1316],{"class":1300},[943,5128,1319],{"class":949},[943,5130,1322],{"class":1136},[943,5132,968],{"class":1313},[943,5134,1360],{"class":1327},[943,5136,1218],{"class":949},[943,5138,1333],{"class":1136},[943,5140,968],{"class":1313},[943,5142,1369],{"class":1327},[943,5144,1341],{"class":949},[943,5146,5147],{"class":945,"line":1374},[943,5148,1377],{"class":949},[943,5150,5151],{"class":945,"line":1380},[943,5152,1277],{"emptyLinePlaceholder":8},[943,5154,5155,5157,5159,5161,5163,5165,5167,5169,5171,5173,5175,5177,5179,5181,5183,5185],{"class":945,"line":1385},[943,5156,1388],{"class":1136},[943,5158,1297],{"class":949},[943,5160,1393],{"class":1300},[943,5162,1396],{"class":949},[943,5164,1399],{"class":987},[943,5166,1402],{"class":991},[943,5168,1399],{"class":987},[943,5170,1218],{"class":949},[943,5172,1409],{"class":1283},[943,5174,1412],{"class":949},[943,5176,1416],{"class":1415},[943,5178,1218],{"class":949},[943,5180,1421],{"class":1415},[943,5182,1424],{"class":949},[943,5184,1427],{"class":1283},[943,5186,971],{"class":949},[943,5188,5189,5191,5193,5195,5197,5199,5201,5203,5205,5207,5209,5211,5213],{"class":945,"line":1432},[943,5190,1435],{"class":1283},[943,5192,1438],{"class":1287},[943,5194,1291],{"class":967},[943,5196,1443],{"class":1300},[943,5198,1446],{"class":949},[943,5200,1449],{"class":1300},[943,5202,1319],{"class":949},[943,5204,1454],{"class":1136},[943,5206,968],{"class":1313},[943,5208,1199],{"class":987},[943,5210,1402],{"class":991},[943,5212,1399],{"class":987},[943,5214,1465],{"class":949},[943,5216,5217,5219,5221,5223,5225,5227,5229,5231,5233,5235,5237,5239,5241,5243,5245,5247],{"class":945,"line":1468},[943,5218,1435],{"class":1283},[943,5220,1473],{"class":1287},[943,5222,1291],{"class":967},[943,5224,1478],{"class":1128},[943,5226,1481],{"class":1300},[943,5228,1396],{"class":949},[943,5230,1486],{"class":1136},[943,5232,1218],{"class":949},[943,5234,1416],{"class":1136},[943,5236,1297],{"class":949},[943,5238,1495],{"class":1136},[943,5240,1218],{"class":949},[943,5242,1416],{"class":1136},[943,5244,1218],{"class":949},[943,5246,1504],{"class":1136},[943,5248,1507],{"class":949},[943,5250,5251],{"class":945,"line":1510},[943,5252,1277],{"emptyLinePlaceholder":8},[943,5254,5255,5257,5259,5261,5263,5265,5267,5269,5271,5273,5275,5277,5279],{"class":945,"line":1515},[943,5256,1518],{"class":1128},[943,5258,1412],{"class":949},[943,5260,1399],{"class":987},[943,5262,1525],{"class":991},[943,5264,1399],{"class":987},[943,5266,1530],{"class":1283},[943,5268,1473],{"class":1136},[943,5270,1535],{"class":967},[943,5272,1538],{"class":967},[943,5274,1541],{"class":1136},[943,5276,1297],{"class":949},[943,5278,1525],{"class":1136},[943,5280,1548],{"class":949},[943,5282,5283,5285,5287,5289,5291,5293,5295,5297,5299,5301,5303,5305,5307,5309,5311,5313,5315,5317,5319,5321,5323,5325,5327,5329,5331],{"class":945,"line":1551},[943,5284,1554],{"class":1128},[943,5286,1557],{"class":1136},[943,5288,1297],{"class":949},[943,5290,1562],{"class":1300},[943,5292,1396],{"class":949},[943,5294,1541],{"class":1136},[943,5296,1297],{"class":949},[943,5298,1571],{"class":1136},[943,5300,1574],{"class":967},[943,5302,1199],{"class":987},[943,5304,1579],{"class":991},[943,5306,1399],{"class":987},[943,5308,1584],{"class":967},[943,5310,1587],{"class":1327},[943,5312,1590],{"class":967},[943,5314,1593],{"class":1327},[943,5316,1596],{"class":949},[943,5318,5],{"class":1300},[943,5320,1319],{"class":949},[943,5322,1603],{"class":1136},[943,5324,968],{"class":1313},[943,5326,1473],{"class":1136},[943,5328,1297],{"class":949},[943,5330,1571],{"class":1136},[943,5332,1465],{"class":949},[943,5334,5335],{"class":945,"line":1616},[943,5336,1089],{"class":949},[943,5338,5339,5341,5343,5345,5347,5349,5351],{"class":945,"line":1621},[943,5340,1518],{"class":1128},[943,5342,1412],{"class":949},[943,5344,1628],{"class":967},[943,5346,1541],{"class":1136},[943,5348,1297],{"class":949},[943,5350,1635],{"class":1136},[943,5352,1548],{"class":949},[943,5354,5355,5357,5359,5361,5363,5365,5367,5369,5371,5373,5375,5377,5379,5381,5383],{"class":945,"line":1640},[943,5356,1554],{"class":1128},[943,5358,1557],{"class":1136},[943,5360,1297],{"class":949},[943,5362,1562],{"class":1300},[943,5364,1396],{"class":949},[943,5366,1653],{"class":1327},[943,5368,1596],{"class":949},[943,5370,5],{"class":1300},[943,5372,1396],{"class":949},[943,5374,1541],{"class":1136},[943,5376,1297],{"class":949},[943,5378,1603],{"class":1136},[943,5380,1297],{"class":949},[943,5382,1670],{"class":1300},[943,5384,1673],{"class":949},[943,5386,5387],{"class":945,"line":1676},[943,5388,1089],{"class":949},[943,5390,5391],{"class":945,"line":1681},[943,5392,1277],{"emptyLinePlaceholder":8},[943,5394,5395,5397,5399,5401,5403,5405,5407,5409,5411,5413],{"class":945,"line":1686},[943,5396,1435],{"class":1283},[943,5398,1212],{"class":949},[943,5400,1693],{"class":1287},[943,5402,1218],{"class":949},[943,5404,1698],{"class":1287},[943,5406,1224],{"class":949},[943,5408,1703],{"class":967},[943,5410,1473],{"class":1136},[943,5412,1297],{"class":949},[943,5414,1710],{"class":1136},[943,5416,5417,5419,5421,5423,5425],{"class":945,"line":1713},[943,5418,1435],{"class":1283},[943,5420,1718],{"class":1287},[943,5422,1291],{"class":967},[943,5424,1723],{"class":1300},[943,5426,1726],{"class":949},[943,5428,5429,5431,5433,5435,5437],{"class":945,"line":1729},[943,5430,1435],{"class":1283},[943,5432,1734],{"class":1287},[943,5434,1291],{"class":967},[943,5436,1739],{"class":1300},[943,5438,1726],{"class":949},[943,5440,5441],{"class":945,"line":1744},[943,5442,1277],{"emptyLinePlaceholder":8},[943,5444,5445],{"class":945,"line":1749},[943,5446,1753],{"class":1752},[943,5448,5449,5451,5453,5455,5457,5459,5461,5463,5465,5467],{"class":945,"line":1756},[943,5450,1435],{"class":1283},[943,5452,1061],{"class":949},[943,5454,1763],{"class":1287},[943,5456,1766],{"class":949},[943,5458,1703],{"class":967},[943,5460,1478],{"class":1128},[943,5462,1718],{"class":1136},[943,5464,1297],{"class":949},[943,5466,1777],{"class":1300},[943,5468,1780],{"class":949},[943,5470,5471],{"class":945,"line":1783},[943,5472,1786],{"class":991},[943,5474,5475],{"class":945,"line":1789},[943,5476,1792],{"class":991},[943,5478,5479],{"class":945,"line":1795},[943,5480,1798],{"class":991},[943,5482,5483],{"class":945,"line":1801},[943,5484,1804],{"class":991},[943,5486,5487],{"class":945,"line":1807},[943,5488,1810],{"class":991},[943,5490,5491],{"class":945,"line":1813},[943,5492,1816],{"class":991},[943,5494,5495],{"class":945,"line":1819},[943,5496,1822],{"class":991},[943,5498,5499,5501],{"class":945,"line":1825},[943,5500,1828],{"class":991},[943,5502,997],{"class":949},[943,5504,5505,5507,5509],{"class":945,"line":1833},[943,5506,1836],{"class":949},[943,5508,1693],{"class":1136},[943,5510,1071],{"class":949},[943,5512,5513],{"class":945,"line":1843},[943,5514,1846],{"class":949},[943,5516,5517],{"class":945,"line":1849},[943,5518,1277],{"emptyLinePlaceholder":8},[943,5520,5521,5523,5525,5527,5529,5531,5533],{"class":945,"line":1854},[943,5522,1435],{"class":1283},[943,5524,1859],{"class":1287},[943,5526,1291],{"class":967},[943,5528,1864],{"class":1136},[943,5530,1867],{"class":949},[943,5532,1870],{"class":1327},[943,5534,1071],{"class":949},[943,5536,5537,5539,5541,5543,5545,5547,5549,5551,5553,5555,5557,5559,5561,5563,5565,5567,5569,5571,5573,5575],{"class":945,"line":1875},[943,5538,1518],{"class":1128},[943,5540,1412],{"class":949},[943,5542,1628],{"class":967},[943,5544,1066],{"class":1136},[943,5546,1424],{"class":949},[943,5548,1888],{"class":1128},[943,5550,1557],{"class":1136},[943,5552,1297],{"class":949},[943,5554,1562],{"class":1300},[943,5556,1396],{"class":949},[943,5558,1899],{"class":1327},[943,5560,1596],{"class":949},[943,5562,5],{"class":1300},[943,5564,1319],{"class":949},[943,5566,1603],{"class":1136},[943,5568,968],{"class":1313},[943,5570,1199],{"class":987},[943,5572,1914],{"class":991},[943,5574,1399],{"class":987},[943,5576,1465],{"class":949},[943,5578,5579],{"class":945,"line":1921},[943,5580,1277],{"emptyLinePlaceholder":8},[943,5582,5583,5585,5587,5589,5591,5593,5595,5597,5599,5601,5603,5605],{"class":945,"line":1926},[943,5584,1435],{"class":1283},[943,5586,1931],{"class":1287},[943,5588,1291],{"class":967},[943,5590,1478],{"class":1128},[943,5592,1938],{"class":1300},[943,5594,1396],{"class":949},[943,5596,1066],{"class":1136},[943,5598,1297],{"class":949},[943,5600,1947],{"class":1136},[943,5602,1218],{"class":949},[943,5604,1698],{"class":1136},[943,5606,1507],{"class":949},[943,5608,5609,5611,5613,5615,5617,5619,5621,5623,5625,5627,5629,5631,5633,5635,5637,5639,5641,5643,5645,5647],{"class":945,"line":1956},[943,5610,1518],{"class":1128},[943,5612,1412],{"class":949},[943,5614,1628],{"class":967},[943,5616,1525],{"class":1136},[943,5618,1424],{"class":949},[943,5620,1888],{"class":1128},[943,5622,1557],{"class":1136},[943,5624,1297],{"class":949},[943,5626,1562],{"class":1300},[943,5628,1396],{"class":949},[943,5630,1899],{"class":1327},[943,5632,1596],{"class":949},[943,5634,5],{"class":1300},[943,5636,1319],{"class":949},[943,5638,1603],{"class":1136},[943,5640,968],{"class":1313},[943,5642,1199],{"class":987},[943,5644,1914],{"class":991},[943,5646,1399],{"class":987},[943,5648,1465],{"class":949},[943,5650,5651],{"class":945,"line":1999},[943,5652,1277],{"emptyLinePlaceholder":8},[943,5654,5655,5657,5659,5661,5663,5665,5667,5669,5671,5673,5675,5677,5679,5681,5683,5685,5687,5689,5691,5693,5695,5697],{"class":945,"line":2004},[943,5656,1435],{"class":1283},[943,5658,2009],{"class":1287},[943,5660,968],{"class":967},[943,5662,2015],{"class":2014},[943,5664,2018],{"class":949},[943,5666,1703],{"class":967},[943,5668,1859],{"class":1136},[943,5670,1297],{"class":949},[943,5672,881],{"class":1136},[943,5674,1584],{"class":967},[943,5676,1859],{"class":1136},[943,5678,1297],{"class":949},[943,5680,881],{"class":1136},[943,5682,1297],{"class":949},[943,5684,2039],{"class":1300},[943,5686,1396],{"class":949},[943,5688,1399],{"class":987},[943,5690,2046],{"class":991},[943,5692,1399],{"class":987},[943,5694,1424],{"class":949},[943,5696,968],{"class":967},[943,5698,2055],{"class":949},[943,5700,5701],{"class":945,"line":2058},[943,5702,1277],{"emptyLinePlaceholder":8},[943,5704,5705,5707,5709,5711,5713,5715,5717,5719,5721,5723,5725,5727,5729,5731,5733,5735,5737,5739],{"class":945,"line":2063},[943,5706,1435],{"class":1283},[943,5708,2068],{"class":1287},[943,5710,1291],{"class":967},[943,5712,1478],{"class":1128},[943,5714,2075],{"class":1300},[943,5716,1396],{"class":949},[943,5718,2080],{"class":1136},[943,5720,1297],{"class":949},[943,5722,961],{"class":1136},[943,5724,1297],{"class":949},[943,5726,2089],{"class":1136},[943,5728,1297],{"class":949},[943,5730,2094],{"class":1136},[943,5732,1218],{"class":949},[943,5734,1066],{"class":1136},[943,5736,1297],{"class":949},[943,5738,2103],{"class":1136},[943,5740,1507],{"class":949},[943,5742,5743,5745,5747,5749,5751],{"class":945,"line":2108},[943,5744,1435],{"class":1283},[943,5746,2113],{"class":1287},[943,5748,1291],{"class":967},[943,5750,2118],{"class":1300},[943,5752,1304],{"class":949},[943,5754,5755,5757,5759,5761,5763,5765],{"class":945,"line":2123},[943,5756,2126],{"class":1136},[943,5758,968],{"class":1313},[943,5760,1859],{"class":1136},[943,5762,1297],{"class":949},[943,5764,2103],{"class":1136},[943,5766,997],{"class":949},[943,5768,5769,5771,5773,5775,5777,5779],{"class":945,"line":2139},[943,5770,2142],{"class":1136},[943,5772,968],{"class":1313},[943,5774,1859],{"class":1136},[943,5776,1297],{"class":949},[943,5778,2151],{"class":1136},[943,5780,997],{"class":949},[943,5782,5783,5785,5787,5789,5791,5793],{"class":945,"line":2156},[943,5784,2159],{"class":1136},[943,5786,968],{"class":1313},[943,5788,1261],{"class":1136},[943,5790,1297],{"class":949},[943,5792,2168],{"class":1300},[943,5794,2171],{"class":949},[943,5796,5797,5799,5801,5803],{"class":945,"line":2174},[943,5798,2177],{"class":1136},[943,5800,968],{"class":1313},[943,5802,2009],{"class":1136},[943,5804,997],{"class":949},[943,5806,5807],{"class":945,"line":2186},[943,5808,2189],{"class":949},[943,5810,5811],{"class":945,"line":2192},[943,5812,1277],{"emptyLinePlaceholder":8},[943,5814,5815,5817,5819,5821,5823,5825,5827,5829,5831,5833,5835,5837],{"class":945,"line":2197},[943,5816,1179],{"class":1300},[943,5818,1396],{"class":949},[943,5820,1421],{"class":1136},[943,5822,1218],{"class":949},[943,5824,1399],{"class":987},[943,5826,2210],{"class":991},[943,5828,1399],{"class":987},[943,5830,1218],{"class":949},[943,5832,2217],{"class":1136},[943,5834,1297],{"class":949},[943,5836,2222],{"class":1136},[943,5838,2225],{"class":949},[943,5840,5841,5843,5845,5847],{"class":945,"line":2228},[943,5842,2231],{"class":1136},[943,5844,968],{"class":1313},[943,5846,2237],{"class":2236},[943,5848,997],{"class":949},[943,5850,5851,5853,5855,5857],{"class":945,"line":2242},[943,5852,2245],{"class":1136},[943,5854,968],{"class":1313},[943,5856,2237],{"class":2236},[943,5858,997],{"class":949},[943,5860,5861,5863,5865,5867,5869,5871],{"class":945,"line":2254},[943,5862,2257],{"class":1136},[943,5864,968],{"class":1313},[943,5866,1199],{"class":987},[943,5868,2264],{"class":991},[943,5870,1399],{"class":987},[943,5872,997],{"class":949},[943,5874,5875,5877,5879,5881,5883,5885,5887,5889,5891,5893],{"class":945,"line":2271},[943,5876,2274],{"class":1136},[943,5878,968],{"class":1313},[943,5880,1734],{"class":1136},[943,5882,1297],{"class":949},[943,5884,961],{"class":1136},[943,5886,1297],{"class":949},[943,5888,2089],{"class":1136},[943,5890,1297],{"class":949},[943,5892,2291],{"class":1136},[943,5894,997],{"class":949},[943,5896,5897,5899,5901,5903,5905,5907],{"class":945,"line":2296},[943,5898,2299],{"class":1136},[943,5900,968],{"class":1313},[943,5902,1199],{"class":987},[943,5904,2306],{"class":991},[943,5906,1399],{"class":987},[943,5908,997],{"class":949},[943,5910,5911,5913,5915,5917,5919,5921],{"class":945,"line":2313},[943,5912,2316],{"class":1136},[943,5914,968],{"class":1313},[943,5916,2068],{"class":1136},[943,5918,1297],{"class":949},[943,5920,2325],{"class":1136},[943,5922,997],{"class":949},[943,5924,5925],{"class":945,"line":2330},[943,5926,2189],{"class":949},[943,5928,5929],{"class":945,"line":2335},[943,5930,1277],{"emptyLinePlaceholder":8},[943,5932,5933,5935,5937,5939,5941,5943,5945,5947,5949,5951],{"class":945,"line":2340},[943,5934,2343],{"class":1136},[943,5936,1297],{"class":949},[943,5938,1562],{"class":1300},[943,5940,1396],{"class":949},[943,5942,2352],{"class":1327},[943,5944,1596],{"class":949},[943,5946,5],{"class":1300},[943,5948,1319],{"class":949},[943,5950,2361],{"class":1136},[943,5952,1465],{"class":949},[943,5954,5955],{"class":945,"line":2366},[943,5956,1377],{"class":949},[920,5958,2372],{"id":2371},[856,5960,2375,5961,2378],{},[860,5962,1114],{},[901,5964,5965],{"className":1118,"code":2381,"language":1121,"meta":909,"style":909},[860,5966,5967,5985,5999,6003,6015,6029,6043,6057,6081],{"__ignoreMap":909},[943,5968,5969,5971,5973,5975,5977,5979,5981,5983],{"class":945,"line":946},[943,5970,1129],{"class":1128},[943,5972,1212],{"class":949},[943,5974,1114],{"class":1136},[943,5976,1224],{"class":949},[943,5978,1196],{"class":1128},[943,5980,1199],{"class":987},[943,5982,1202],{"class":991},[943,5984,1205],{"class":987},[943,5986,5987,5989,5991,5993,5995,5997],{"class":945,"line":953},[943,5988,1129],{"class":1128},[943,5990,1261],{"class":1136},[943,5992,1264],{"class":1128},[943,5994,1199],{"class":987},[943,5996,1269],{"class":991},[943,5998,1205],{"class":987},[943,6000,6001],{"class":945,"line":974},[943,6002,1277],{"emptyLinePlaceholder":8},[943,6004,6005,6007,6009,6011,6013],{"class":945,"line":1000},[943,6006,1284],{"class":1283},[943,6008,2113],{"class":1287},[943,6010,1291],{"class":967},[943,6012,2118],{"class":1300},[943,6014,1304],{"class":949},[943,6016,6017,6019,6021,6023,6025,6027],{"class":945,"line":1014},[943,6018,2436],{"class":1136},[943,6020,968],{"class":1313},[943,6022,1859],{"class":1136},[943,6024,1297],{"class":949},[943,6026,2103],{"class":1136},[943,6028,997],{"class":949},[943,6030,6031,6033,6035,6037,6039,6041],{"class":945,"line":1036},[943,6032,2451],{"class":1136},[943,6034,968],{"class":1313},[943,6036,1859],{"class":1136},[943,6038,1297],{"class":949},[943,6040,2151],{"class":1136},[943,6042,997],{"class":949},[943,6044,6045,6047,6049,6051,6053,6055],{"class":945,"line":1049},[943,6046,2466],{"class":1136},[943,6048,968],{"class":1313},[943,6050,1261],{"class":1136},[943,6052,1297],{"class":949},[943,6054,2168],{"class":1300},[943,6056,2171],{"class":949},[943,6058,6059,6061,6063,6065,6067,6069,6071,6073,6075,6077,6079],{"class":945,"line":1074},[943,6060,2481],{"class":1136},[943,6062,968],{"class":1313},[943,6064,1061],{"class":949},[943,6066,1399],{"class":987},[943,6068,2490],{"class":991},[943,6070,1399],{"class":987},[943,6072,1218],{"class":949},[943,6074,1399],{"class":987},[943,6076,2499],{"class":991},[943,6078,1399],{"class":987},[943,6080,2504],{"class":949},[943,6082,6083],{"class":945,"line":1080},[943,6084,1377],{"class":949},[2510,6086,6087],{},[856,6088,2514],{},[869,6090],{},[872,6092,2520],{"id":2519},[856,6094,6095,2525,6097,2528],{},[860,6096,889],{},[860,6098,885],{},[856,6100,2531,6101,2535,6103,2539],{},[860,6102,2534],{},[860,6104,2538],{},[856,6106,2542],{},[856,6108,6109,2547],{},[860,6110,889],{},[901,6112,6113],{"className":1118,"code":2550,"language":1121,"meta":909,"style":909},[860,6114,6115,6137,6141,6153,6157,6193,6197,6213,6217,6247,6251],{"__ignoreMap":909},[943,6116,6117,6119,6121,6123,6125,6127,6129,6131,6133,6135],{"class":945,"line":946},[943,6118,1129],{"class":1128},[943,6120,1212],{"class":949},[943,6122,889],{"class":1136},[943,6124,1218],{"class":949},[943,6126,2565],{"class":1136},[943,6128,1224],{"class":949},[943,6130,1196],{"class":1128},[943,6132,1199],{"class":987},[943,6134,1202],{"class":991},[943,6136,1205],{"class":987},[943,6138,6139],{"class":945,"line":953},[943,6140,1277],{"emptyLinePlaceholder":8},[943,6142,6143,6145,6147,6149,6151],{"class":945,"line":974},[943,6144,1284],{"class":1283},[943,6146,1438],{"class":1287},[943,6148,1291],{"class":967},[943,6150,1443],{"class":1300},[943,6152,1726],{"class":949},[943,6154,6155],{"class":945,"line":1000},[943,6156,1277],{"emptyLinePlaceholder":8},[943,6158,6159,6161,6163,6165,6167,6169,6171,6173,6175,6177,6179,6181,6183,6185,6187,6189,6191],{"class":945,"line":1014},[943,6160,1284],{"class":1283},[943,6162,1473],{"class":1287},[943,6164,1291],{"class":967},[943,6166,2606],{"class":1300},[943,6168,2609],{"class":949},[943,6170,1399],{"class":987},[943,6172,2490],{"class":991},[943,6174,1399],{"class":987},[943,6176,2618],{"class":949},[943,6178,1416],{"class":1136},[943,6180,1297],{"class":949},[943,6182,1066],{"class":1136},[943,6184,1297],{"class":949},[943,6186,881],{"class":1136},[943,6188,1218],{"class":949},[943,6190,1504],{"class":1136},[943,6192,1507],{"class":949},[943,6194,6195],{"class":945,"line":1036},[943,6196,1277],{"emptyLinePlaceholder":8},[943,6198,6199,6201,6203,6205,6207,6209,6211],{"class":945,"line":1049},[943,6200,2643],{"class":1128},[943,6202,1412],{"class":949},[943,6204,1628],{"class":967},[943,6206,1541],{"class":1136},[943,6208,1297],{"class":949},[943,6210,1525],{"class":1136},[943,6212,1548],{"class":949},[943,6214,6215],{"class":945,"line":1074},[943,6216,2660],{"class":1752},[943,6218,6219,6221,6223,6225,6227,6229,6231,6233,6235,6237,6239,6241,6243,6245],{"class":945,"line":1080},[943,6220,2343],{"class":1136},[943,6222,1297],{"class":949},[943,6224,1562],{"class":1300},[943,6226,1396],{"class":949},[943,6228,2673],{"class":1327},[943,6230,1596],{"class":949},[943,6232,5],{"class":1300},[943,6234,1319],{"class":949},[943,6236,1603],{"class":1136},[943,6238,968],{"class":1313},[943,6240,1199],{"class":987},[943,6242,2688],{"class":991},[943,6244,1399],{"class":987},[943,6246,1465],{"class":949},[943,6248,6249],{"class":945,"line":1086},[943,6250,2697],{"class":1128},[943,6252,6253],{"class":945,"line":1092},[943,6254,1095],{"class":949},[2703,6256,6257],{},[856,6258,6259,2709,6261,2713],{},[860,6260,889],{},[860,6262,2712],{},[869,6264],{},[872,6266,2719],{"id":2718},[920,6268,2723],{"id":2722},[856,6270,2726,6271,2729,6273,1297],{},[860,6272,862],{},[860,6274,866],{},[901,6276,6277],{"className":1118,"code":2734,"filename":2735,"language":1121,"meta":909,"style":909},[860,6278,6279,6307,6311,6329,6363,6381,6385,6421,6451,6455,6459,6463,6469,6473],{"__ignoreMap":909},[943,6280,6281,6283,6285,6287,6289,6291,6293,6295,6297,6299,6301,6303,6305],{"class":945,"line":946},[943,6282,1129],{"class":1128},[943,6284,2744],{"class":1128},[943,6286,1212],{"class":949},[943,6288,2749],{"class":1136},[943,6290,1218],{"class":949},[943,6292,2754],{"class":1136},[943,6294,1218],{"class":949},[943,6296,2759],{"class":1136},[943,6298,1224],{"class":949},[943,6300,1196],{"class":1128},[943,6302,1199],{"class":987},[943,6304,2768],{"class":991},[943,6306,1205],{"class":987},[943,6308,6309],{"class":945,"line":953},[943,6310,1277],{"emptyLinePlaceholder":8},[943,6312,6313,6315,6317,6319,6321,6323,6325,6327],{"class":945,"line":974},[943,6314,2779],{"class":1128},[943,6316,2782],{"class":1283},[943,6318,2785],{"class":1300},[943,6320,1396],{"class":949},[943,6322,2790],{"class":1415},[943,6324,968],{"class":967},[943,6326,2015],{"class":2014},[943,6328,1548],{"class":949},[943,6330,6331,6333,6335,6337,6339,6341,6343,6345,6347,6349,6351,6353,6355,6357,6359,6361],{"class":945,"line":1000},[943,6332,2801],{"class":1128},[943,6334,1412],{"class":949},[943,6336,1416],{"class":1415},[943,6338,968],{"class":967},[943,6340,2810],{"class":2014},[943,6342,1218],{"class":949},[943,6344,1421],{"class":1415},[943,6346,968],{"class":967},[943,6348,2819],{"class":2014},[943,6350,1218],{"class":949},[943,6352,2824],{"class":1415},[943,6354,968],{"class":967},[943,6356,2829],{"class":2014},[943,6358,1424],{"class":949},[943,6360,1427],{"class":1283},[943,6362,971],{"class":949},[943,6364,6365,6367,6369,6371,6373,6375,6377,6379],{"class":945,"line":1014},[943,6366,2840],{"class":1283},[943,6368,2009],{"class":1287},[943,6370,1291],{"class":967},[943,6372,2847],{"class":1136},[943,6374,1297],{"class":949},[943,6376,1066],{"class":1136},[943,6378,2854],{"class":949},[943,6380,2857],{"class":1136},[943,6382,6383],{"class":945,"line":1036},[943,6384,1277],{"emptyLinePlaceholder":8},[943,6386,6387,6389,6391,6393,6395,6397,6399,6401,6403,6405,6407,6409,6411,6413,6415,6417,6419],{"class":945,"line":1049},[943,6388,2866],{"class":1128},[943,6390,1412],{"class":949},[943,6392,1628],{"class":967},[943,6394,2873],{"class":1136},[943,6396,1297],{"class":949},[943,6398,2878],{"class":1300},[943,6400,1396],{"class":949},[943,6402,881],{"class":1136},[943,6404,1424],{"class":949},[943,6406,2887],{"class":967},[943,6408,1538],{"class":967},[943,6410,881],{"class":1136},[943,6412,1297],{"class":949},[943,6414,2896],{"class":1300},[943,6416,1396],{"class":949},[943,6418,2790],{"class":1136},[943,6420,2903],{"class":949},[943,6422,6423,6425,6427,6429,6431,6433,6435,6437,6439,6441,6443,6445,6447,6449],{"class":945,"line":1074},[943,6424,2908],{"class":1136},[943,6426,1297],{"class":949},[943,6428,1562],{"class":1300},[943,6430,1396],{"class":949},[943,6432,2673],{"class":1327},[943,6434,1596],{"class":949},[943,6436,5],{"class":1300},[943,6438,1319],{"class":949},[943,6440,1603],{"class":1136},[943,6442,968],{"class":1313},[943,6444,1199],{"class":987},[943,6446,2688],{"class":991},[943,6448,1399],{"class":987},[943,6450,1465],{"class":949},[943,6452,6453],{"class":945,"line":1080},[943,6454,2939],{"class":1128},[943,6456,6457],{"class":945,"line":1086},[943,6458,1083],{"class":949},[943,6460,6461],{"class":945,"line":1092},[943,6462,1277],{"emptyLinePlaceholder":8},[943,6464,6465,6467],{"class":945,"line":1235},[943,6466,2952],{"class":1300},[943,6468,1726],{"class":949},[943,6470,6471],{"class":945,"line":1256},[943,6472,1089],{"class":949},[943,6474,6475],{"class":945,"line":1274},[943,6476,1095],{"class":949},[901,6478,6479],{"className":1118,"code":2965,"filename":2966,"language":1121,"meta":909,"style":909},[860,6480,6481,6487,6493,6499,6505,6511,6523,6541,6545,6555,6565,6571,6577,6583,6589,6603,6621,6643,6647],{"__ignoreMap":909},[943,6482,6483,6485],{"class":945,"line":946},[943,6484,1129],{"class":1128},[943,6486,971],{"class":949},[943,6488,6489,6491],{"class":945,"line":953},[943,6490,2979],{"class":1136},[943,6492,997],{"class":949},[943,6494,6495,6497],{"class":945,"line":974},[943,6496,2986],{"class":1136},[943,6498,997],{"class":949},[943,6500,6501,6503],{"class":945,"line":1000},[943,6502,2993],{"class":1136},[943,6504,997],{"class":949},[943,6506,6507,6509],{"class":945,"line":1014},[943,6508,3000],{"class":1136},[943,6510,997],{"class":949},[943,6512,6513,6515,6517,6519,6521],{"class":945,"line":1036},[943,6514,1193],{"class":949},[943,6516,1196],{"class":1128},[943,6518,1199],{"class":987},[943,6520,1202],{"class":991},[943,6522,1205],{"class":987},[943,6524,6525,6527,6529,6531,6533,6535,6537,6539],{"class":945,"line":1049},[943,6526,1129],{"class":1128},[943,6528,1212],{"class":949},[943,6530,3023],{"class":1136},[943,6532,1224],{"class":949},[943,6534,1196],{"class":1128},[943,6536,1199],{"class":987},[943,6538,3032],{"class":991},[943,6540,1205],{"class":987},[943,6542,6543],{"class":945,"line":1074},[943,6544,1277],{"emptyLinePlaceholder":8},[943,6546,6547,6549,6551,6553],{"class":945,"line":1080},[943,6548,1388],{"class":1136},[943,6550,1297],{"class":949},[943,6552,3047],{"class":1300},[943,6554,1780],{"class":949},[943,6556,6557,6559,6561,6563],{"class":945,"line":1086},[943,6558,3054],{"class":987},[943,6560,3057],{"class":991},[943,6562,1399],{"class":987},[943,6564,997],{"class":949},[943,6566,6567,6569],{"class":945,"line":1092},[943,6568,2979],{"class":1136},[943,6570,997],{"class":949},[943,6572,6573,6575],{"class":945,"line":1235},[943,6574,2986],{"class":1136},[943,6576,997],{"class":949},[943,6578,6579,6581],{"class":945,"line":1256},[943,6580,2993],{"class":1136},[943,6582,997],{"class":949},[943,6584,6585,6587],{"class":945,"line":1274},[943,6586,3000],{"class":1136},[943,6588,997],{"class":949},[943,6590,6591,6593,6595,6597,6599,6601],{"class":945,"line":1280},[943,6592,3090],{"class":1300},[943,6594,1396],{"class":949},[943,6596,1399],{"class":987},[943,6598,2490],{"class":991},[943,6600,1399],{"class":987},[943,6602,3101],{"class":949},[943,6604,6605,6607,6609,6611,6613,6615,6617,6619],{"class":945,"line":1307},[943,6606,3106],{"class":1283},[943,6608,1412],{"class":949},[943,6610,1416],{"class":1415},[943,6612,1218],{"class":949},[943,6614,1421],{"class":1415},[943,6616,1424],{"class":949},[943,6618,1427],{"class":1283},[943,6620,971],{"class":949},[943,6622,6623,6625,6627,6629,6631,6633,6635,6637,6639,6641],{"class":945,"line":1344},[943,6624,3125],{"class":1136},[943,6626,1297],{"class":949},[943,6628,5],{"class":1300},[943,6630,1319],{"class":949},[943,6632,3134],{"class":1136},[943,6634,968],{"class":1313},[943,6636,1199],{"class":987},[943,6638,3141],{"class":991},[943,6640,1399],{"class":987},[943,6642,1465],{"class":949},[943,6644,6645],{"class":945,"line":1374},[943,6646,1089],{"class":949},[943,6648,6649],{"class":945,"line":1380},[943,6650,1507],{"class":949},[920,6652,3157],{"id":3156},[856,6654,3160],{},[901,6656,6657],{"className":1118,"code":3163,"filename":3164,"language":1121,"meta":909,"style":909},[860,6658,6659,6687,6691,6711,6745,6763,6767,6815,6845,6849,6853,6857,6863,6867],{"__ignoreMap":909},[943,6660,6661,6663,6665,6667,6669,6671,6673,6675,6677,6679,6681,6683,6685],{"class":945,"line":946},[943,6662,1129],{"class":1128},[943,6664,2744],{"class":1128},[943,6666,1212],{"class":949},[943,6668,2749],{"class":1136},[943,6670,1218],{"class":949},[943,6672,2754],{"class":1136},[943,6674,1218],{"class":949},[943,6676,2759],{"class":1136},[943,6678,1224],{"class":949},[943,6680,1196],{"class":1128},[943,6682,1199],{"class":987},[943,6684,2768],{"class":991},[943,6686,1205],{"class":987},[943,6688,6689],{"class":945,"line":953},[943,6690,1277],{"emptyLinePlaceholder":8},[943,6692,6693,6695,6697,6699,6701,6703,6705,6707,6709],{"class":945,"line":974},[943,6694,2779],{"class":1128},[943,6696,2782],{"class":1283},[943,6698,3207],{"class":1300},[943,6700,1396],{"class":949},[943,6702,3212],{"class":967},[943,6704,3215],{"class":1415},[943,6706,968],{"class":967},[943,6708,2015],{"class":2014},[943,6710,3222],{"class":949},[943,6712,6713,6715,6717,6719,6721,6723,6725,6727,6729,6731,6733,6735,6737,6739,6741,6743],{"class":945,"line":1000},[943,6714,2801],{"class":1128},[943,6716,1412],{"class":949},[943,6718,1416],{"class":1415},[943,6720,968],{"class":967},[943,6722,2810],{"class":2014},[943,6724,1218],{"class":949},[943,6726,1421],{"class":1415},[943,6728,968],{"class":967},[943,6730,2819],{"class":2014},[943,6732,1218],{"class":949},[943,6734,2824],{"class":1415},[943,6736,968],{"class":967},[943,6738,2829],{"class":2014},[943,6740,1424],{"class":949},[943,6742,1427],{"class":1283},[943,6744,971],{"class":949},[943,6746,6747,6749,6751,6753,6755,6757,6759,6761],{"class":945,"line":1014},[943,6748,2840],{"class":1283},[943,6750,2009],{"class":1287},[943,6752,1291],{"class":967},[943,6754,2847],{"class":1136},[943,6756,1297],{"class":949},[943,6758,1066],{"class":1136},[943,6760,2854],{"class":949},[943,6762,2857],{"class":1136},[943,6764,6765],{"class":945,"line":1036},[943,6766,1277],{"emptyLinePlaceholder":8},[943,6768,6769,6771,6773,6775,6777,6779,6781,6783,6785,6787,6789,6791,6793,6795,6797,6799,6801,6803,6805,6807,6809,6811,6813],{"class":945,"line":1049},[943,6770,2866],{"class":1128},[943,6772,1412],{"class":949},[943,6774,1628],{"class":967},[943,6776,2873],{"class":1136},[943,6778,1297],{"class":949},[943,6780,2878],{"class":1300},[943,6782,1396],{"class":949},[943,6784,881],{"class":1136},[943,6786,1424],{"class":949},[943,6788,2887],{"class":967},[943,6790,1538],{"class":967},[943,6792,3215],{"class":1136},[943,6794,1297],{"class":949},[943,6796,3309],{"class":1300},[943,6798,1396],{"class":949},[943,6800,3314],{"class":1415},[943,6802,3317],{"class":1283},[943,6804,2009],{"class":1136},[943,6806,1297],{"class":949},[943,6808,2896],{"class":1300},[943,6810,1396],{"class":949},[943,6812,3314],{"class":1136},[943,6814,3330],{"class":949},[943,6816,6817,6819,6821,6823,6825,6827,6829,6831,6833,6835,6837,6839,6841,6843],{"class":945,"line":1074},[943,6818,2908],{"class":1136},[943,6820,1297],{"class":949},[943,6822,1562],{"class":1300},[943,6824,1396],{"class":949},[943,6826,2673],{"class":1327},[943,6828,1596],{"class":949},[943,6830,5],{"class":1300},[943,6832,1319],{"class":949},[943,6834,1603],{"class":1136},[943,6836,968],{"class":1313},[943,6838,1199],{"class":987},[943,6840,2688],{"class":991},[943,6842,1399],{"class":987},[943,6844,1465],{"class":949},[943,6846,6847],{"class":945,"line":1080},[943,6848,2939],{"class":1128},[943,6850,6851],{"class":945,"line":1086},[943,6852,1083],{"class":949},[943,6854,6855],{"class":945,"line":1092},[943,6856,1277],{"emptyLinePlaceholder":8},[943,6858,6859,6861],{"class":945,"line":1235},[943,6860,2952],{"class":1300},[943,6862,1726],{"class":949},[943,6864,6865],{"class":945,"line":1256},[943,6866,1089],{"class":949},[943,6868,6869],{"class":945,"line":1274},[943,6870,1095],{"class":949},[901,6872,6873],{"className":1118,"code":3389,"language":1121,"meta":909,"style":909},[860,6874,6875,6885,6895,6901,6907,6913,6919,6941,6945],{"__ignoreMap":909},[943,6876,6877,6879,6881,6883],{"class":945,"line":946},[943,6878,1388],{"class":1136},[943,6880,1297],{"class":949},[943,6882,1393],{"class":1300},[943,6884,1780],{"class":949},[943,6886,6887,6889,6891,6893],{"class":945,"line":953},[943,6888,3054],{"class":987},[943,6890,3408],{"class":991},[943,6892,1399],{"class":987},[943,6894,997],{"class":949},[943,6896,6897,6899],{"class":945,"line":974},[943,6898,2979],{"class":1136},[943,6900,997],{"class":949},[943,6902,6903,6905],{"class":945,"line":1000},[943,6904,2986],{"class":1136},[943,6906,997],{"class":949},[943,6908,6909,6911],{"class":945,"line":1014},[943,6910,2993],{"class":1136},[943,6912,997],{"class":949},[943,6914,6915,6917],{"class":945,"line":1036},[943,6916,3000],{"class":1136},[943,6918,997],{"class":949},[943,6920,6921,6923,6925,6927,6929,6931,6933,6935,6937,6939],{"class":945,"line":1049},[943,6922,3441],{"class":1300},[943,6924,1396],{"class":949},[943,6926,1399],{"class":987},[943,6928,2499],{"class":991},[943,6930,1399],{"class":987},[943,6932,1218],{"class":949},[943,6934,1399],{"class":987},[943,6936,2490],{"class":991},[943,6938,1399],{"class":987},[943,6940,3101],{"class":949},[943,6942,6943],{"class":945,"line":1074},[943,6944,3464],{"class":1136},[943,6946,6947],{"class":945,"line":1080},[943,6948,1507],{"class":949},[920,6950,3472],{"id":3471},[856,6952,3475],{},[901,6954,6955],{"className":1118,"code":3478,"filename":3479,"language":1121,"meta":909,"style":909},[860,6956,6957,6985,6989,7009,7043,7061,7065,7113,7143,7147,7151,7155,7161,7165],{"__ignoreMap":909},[943,6958,6959,6961,6963,6965,6967,6969,6971,6973,6975,6977,6979,6981,6983],{"class":945,"line":946},[943,6960,1129],{"class":1128},[943,6962,2744],{"class":1128},[943,6964,1212],{"class":949},[943,6966,2749],{"class":1136},[943,6968,1218],{"class":949},[943,6970,2754],{"class":1136},[943,6972,1218],{"class":949},[943,6974,2759],{"class":1136},[943,6976,1224],{"class":949},[943,6978,1196],{"class":1128},[943,6980,1199],{"class":987},[943,6982,2768],{"class":991},[943,6984,1205],{"class":987},[943,6986,6987],{"class":945,"line":953},[943,6988,1277],{"emptyLinePlaceholder":8},[943,6990,6991,6993,6995,6997,6999,7001,7003,7005,7007],{"class":945,"line":974},[943,6992,2779],{"class":1128},[943,6994,2782],{"class":1283},[943,6996,3522],{"class":1300},[943,6998,1396],{"class":949},[943,7000,3212],{"class":967},[943,7002,3529],{"class":1415},[943,7004,968],{"class":967},[943,7006,2015],{"class":2014},[943,7008,3222],{"class":949},[943,7010,7011,7013,7015,7017,7019,7021,7023,7025,7027,7029,7031,7033,7035,7037,7039,7041],{"class":945,"line":1000},[943,7012,2801],{"class":1128},[943,7014,1412],{"class":949},[943,7016,1416],{"class":1415},[943,7018,968],{"class":967},[943,7020,2810],{"class":2014},[943,7022,1218],{"class":949},[943,7024,1421],{"class":1415},[943,7026,968],{"class":967},[943,7028,2819],{"class":2014},[943,7030,1218],{"class":949},[943,7032,2824],{"class":1415},[943,7034,968],{"class":967},[943,7036,2829],{"class":2014},[943,7038,1424],{"class":949},[943,7040,1427],{"class":1283},[943,7042,971],{"class":949},[943,7044,7045,7047,7049,7051,7053,7055,7057,7059],{"class":945,"line":1014},[943,7046,2840],{"class":1283},[943,7048,2009],{"class":1287},[943,7050,1291],{"class":967},[943,7052,2847],{"class":1136},[943,7054,1297],{"class":949},[943,7056,1066],{"class":1136},[943,7058,2854],{"class":949},[943,7060,2857],{"class":1136},[943,7062,7063],{"class":945,"line":1036},[943,7064,1277],{"emptyLinePlaceholder":8},[943,7066,7067,7069,7071,7073,7075,7077,7079,7081,7083,7085,7087,7089,7091,7093,7095,7097,7099,7101,7103,7105,7107,7109,7111],{"class":945,"line":1049},[943,7068,2866],{"class":1128},[943,7070,1412],{"class":949},[943,7072,1628],{"class":967},[943,7074,2873],{"class":1136},[943,7076,1297],{"class":949},[943,7078,2878],{"class":1300},[943,7080,1396],{"class":949},[943,7082,881],{"class":1136},[943,7084,1424],{"class":949},[943,7086,2887],{"class":967},[943,7088,1538],{"class":967},[943,7090,3529],{"class":1136},[943,7092,1297],{"class":949},[943,7094,3622],{"class":1300},[943,7096,1396],{"class":949},[943,7098,3314],{"class":1415},[943,7100,3317],{"class":1283},[943,7102,2009],{"class":1136},[943,7104,1297],{"class":949},[943,7106,2896],{"class":1300},[943,7108,1396],{"class":949},[943,7110,3314],{"class":1136},[943,7112,3330],{"class":949},[943,7114,7115,7117,7119,7121,7123,7125,7127,7129,7131,7133,7135,7137,7139,7141],{"class":945,"line":1074},[943,7116,2908],{"class":1136},[943,7118,1297],{"class":949},[943,7120,1562],{"class":1300},[943,7122,1396],{"class":949},[943,7124,2673],{"class":1327},[943,7126,1596],{"class":949},[943,7128,5],{"class":1300},[943,7130,1319],{"class":949},[943,7132,1603],{"class":1136},[943,7134,968],{"class":1313},[943,7136,1199],{"class":987},[943,7138,2688],{"class":991},[943,7140,1399],{"class":987},[943,7142,1465],{"class":949},[943,7144,7145],{"class":945,"line":1080},[943,7146,2939],{"class":1128},[943,7148,7149],{"class":945,"line":1086},[943,7150,1083],{"class":949},[943,7152,7153],{"class":945,"line":1092},[943,7154,1277],{"emptyLinePlaceholder":8},[943,7156,7157,7159],{"class":945,"line":1235},[943,7158,2952],{"class":1300},[943,7160,1726],{"class":949},[943,7162,7163],{"class":945,"line":1256},[943,7164,1089],{"class":949},[943,7166,7167],{"class":945,"line":1274},[943,7168,1095],{"class":949},[869,7170],{},[872,7172,3702],{"id":3701},[856,7174,3705],{},[901,7176,7177],{"className":1118,"code":3708,"filename":3709,"language":1121,"meta":909,"style":909},[860,7178,7179,7189,7199,7205,7211,7217,7223,7241,7265,7277,7281,7303,7313,7329,7333,7337,7353,7395,7399,7423,7461,7465,7483,7515,7519,7523,7527,7531],{"__ignoreMap":909},[943,7180,7181,7183,7185,7187],{"class":945,"line":946},[943,7182,1388],{"class":1136},[943,7184,1297],{"class":949},[943,7186,3720],{"class":1300},[943,7188,1780],{"class":949},[943,7190,7191,7193,7195,7197],{"class":945,"line":953},[943,7192,3054],{"class":987},[943,7194,3729],{"class":991},[943,7196,1399],{"class":987},[943,7198,997],{"class":949},[943,7200,7201,7203],{"class":945,"line":974},[943,7202,2979],{"class":1136},[943,7204,997],{"class":949},[943,7206,7207,7209],{"class":945,"line":1000},[943,7208,2986],{"class":1136},[943,7210,997],{"class":949},[943,7212,7213,7215],{"class":945,"line":1014},[943,7214,2993],{"class":1136},[943,7216,997],{"class":949},[943,7218,7219,7221],{"class":945,"line":1036},[943,7220,3000],{"class":1136},[943,7222,997],{"class":949},[943,7224,7225,7227,7229,7231,7233,7235,7237,7239],{"class":945,"line":1049},[943,7226,3106],{"class":1283},[943,7228,1412],{"class":949},[943,7230,1416],{"class":1415},[943,7232,1218],{"class":949},[943,7234,1421],{"class":1415},[943,7236,1424],{"class":949},[943,7238,1427],{"class":1283},[943,7240,971],{"class":949},[943,7242,7243,7245,7247,7249,7251,7253,7255,7257,7259,7261,7263],{"class":945,"line":1074},[943,7244,2840],{"class":1283},[943,7246,1212],{"class":949},[943,7248,3784],{"class":1287},[943,7250,1218],{"class":949},[943,7252,881],{"class":1287},[943,7254,1224],{"class":949},[943,7256,1703],{"class":967},[943,7258,2847],{"class":1136},[943,7260,1297],{"class":949},[943,7262,1066],{"class":1136},[943,7264,3801],{"class":967},[943,7266,7267,7269,7271,7273,7275],{"class":945,"line":1080},[943,7268,2840],{"class":1283},[943,7270,1718],{"class":1287},[943,7272,1291],{"class":967},[943,7274,1723],{"class":1300},[943,7276,1726],{"class":949},[943,7278,7279],{"class":945,"line":1086},[943,7280,1277],{"emptyLinePlaceholder":8},[943,7282,7283,7285,7287,7289,7291,7293,7295,7297,7299,7301],{"class":945,"line":1092},[943,7284,2840],{"class":1283},[943,7286,1061],{"class":949},[943,7288,1763],{"class":1287},[943,7290,1766],{"class":949},[943,7292,1703],{"class":967},[943,7294,1478],{"class":1128},[943,7296,1718],{"class":1136},[943,7298,1297],{"class":949},[943,7300,1777],{"class":1300},[943,7302,1780],{"class":949},[943,7304,7305,7307,7309,7311],{"class":945,"line":1235},[943,7306,3844],{"class":987},[943,7308,3847],{"class":991},[943,7310,1399],{"class":987},[943,7312,997],{"class":949},[943,7314,7315,7317,7319,7321,7323,7325,7327],{"class":945,"line":1256},[943,7316,3856],{"class":949},[943,7318,1416],{"class":1136},[943,7320,1297],{"class":949},[943,7322,3863],{"class":1136},[943,7324,1297],{"class":949},[943,7326,2103],{"class":1136},[943,7328,1071],{"class":949},[943,7330,7331],{"class":945,"line":1274},[943,7332,3874],{"class":949},[943,7334,7335],{"class":945,"line":1280},[943,7336,1277],{"emptyLinePlaceholder":8},[943,7338,7339,7341,7343,7345,7347,7349,7351],{"class":945,"line":1307},[943,7340,2840],{"class":1283},[943,7342,3885],{"class":1287},[943,7344,1291],{"class":967},[943,7346,1864],{"class":1136},[943,7348,1867],{"class":949},[943,7350,1870],{"class":1327},[943,7352,1071],{"class":949},[943,7354,7355,7357,7359,7361,7363,7365,7367,7369,7371,7373,7375,7377,7379,7381,7383,7385,7387,7389,7391,7393],{"class":945,"line":1344},[943,7356,2866],{"class":1128},[943,7358,1412],{"class":949},[943,7360,1628],{"class":967},[943,7362,1393],{"class":1136},[943,7364,1424],{"class":949},[943,7366,1888],{"class":1128},[943,7368,1557],{"class":1136},[943,7370,1297],{"class":949},[943,7372,1562],{"class":1300},[943,7374,1396],{"class":949},[943,7376,3920],{"class":1327},[943,7378,1596],{"class":949},[943,7380,5],{"class":1300},[943,7382,1319],{"class":949},[943,7384,1603],{"class":1136},[943,7386,968],{"class":1313},[943,7388,1199],{"class":987},[943,7390,3935],{"class":991},[943,7392,1399],{"class":987},[943,7394,1465],{"class":949},[943,7396,7397],{"class":945,"line":1374},[943,7398,1277],{"emptyLinePlaceholder":8},[943,7400,7401,7403,7405,7407,7409,7411,7413,7415,7417,7419,7421],{"class":945,"line":1380},[943,7402,2840],{"class":1283},[943,7404,3950],{"class":1287},[943,7406,1291],{"class":967},[943,7408,3885],{"class":1136},[943,7410,1297],{"class":949},[943,7412,3959],{"class":1136},[943,7414,1574],{"class":967},[943,7416,3964],{"class":1300},[943,7418,1396],{"class":949},[943,7420,3784],{"class":1136},[943,7422,1507],{"class":949},[943,7424,7425,7427,7429,7431,7433,7435,7437,7439,7441,7443,7445,7447,7449,7451,7453,7455,7457,7459],{"class":945,"line":1385},[943,7426,2840],{"class":1283},[943,7428,3977],{"class":1287},[943,7430,1291],{"class":967},[943,7432,3982],{"class":1136},[943,7434,1297],{"class":949},[943,7436,2878],{"class":1300},[943,7438,1396],{"class":949},[943,7440,881],{"class":1136},[943,7442,1424],{"class":949},[943,7444,3995],{"class":967},[943,7446,2009],{"class":1136},[943,7448,1297],{"class":949},[943,7450,2896],{"class":1300},[943,7452,1396],{"class":949},[943,7454,1399],{"class":987},[943,7456,2490],{"class":991},[943,7458,1399],{"class":987},[943,7460,1507],{"class":949},[943,7462,7463],{"class":945,"line":1432},[943,7464,1277],{"emptyLinePlaceholder":8},[943,7466,7467,7469,7471,7473,7475,7477,7479,7481],{"class":945,"line":1468},[943,7468,2866],{"class":1128},[943,7470,1412],{"class":949},[943,7472,1628],{"class":967},[943,7474,4026],{"class":1136},[943,7476,1535],{"class":967},[943,7478,1538],{"class":967},[943,7480,4033],{"class":1136},[943,7482,1548],{"class":949},[943,7484,7485,7487,7489,7491,7493,7495,7497,7499,7501,7503,7505,7507,7509,7511,7513],{"class":945,"line":1510},[943,7486,4040],{"class":1128},[943,7488,1557],{"class":1136},[943,7490,1297],{"class":949},[943,7492,1562],{"class":1300},[943,7494,1396],{"class":949},[943,7496,2673],{"class":1327},[943,7498,1596],{"class":949},[943,7500,5],{"class":1300},[943,7502,1319],{"class":949},[943,7504,1603],{"class":1136},[943,7506,968],{"class":1313},[943,7508,1199],{"class":987},[943,7510,2688],{"class":991},[943,7512,1399],{"class":987},[943,7514,1465],{"class":949},[943,7516,7517],{"class":945,"line":1515},[943,7518,1083],{"class":949},[943,7520,7521],{"class":945,"line":1551},[943,7522,1277],{"emptyLinePlaceholder":8},[943,7524,7525],{"class":945,"line":1616},[943,7526,4081],{"class":1752},[943,7528,7529],{"class":945,"line":1621},[943,7530,1089],{"class":949},[943,7532,7533],{"class":945,"line":1640},[943,7534,1507],{"class":949},[869,7536],{},[872,7538,4095],{"id":4094},[856,7540,4098,7541,4103,7543,4107],{},[4100,7542,4102],{"href":132},[860,7544,4106],{},[901,7546,7547],{"className":937,"code":4110,"language":5,"meta":909,"style":909},[860,7548,7549,7553,7567,7581,7609,7627,7643],{"__ignoreMap":909},[943,7550,7551],{"class":945,"line":946},[943,7552,950],{"class":949},[943,7554,7555,7557,7559,7561,7563,7565],{"class":945,"line":953},[943,7556,957],{"class":956},[943,7558,4123],{"class":960},[943,7560,964],{"class":956},[943,7562,968],{"class":967},[943,7564,2237],{"class":2236},[943,7566,997],{"class":949},[943,7568,7569,7571,7573,7575,7577,7579],{"class":945,"line":974},[943,7570,957],{"class":956},[943,7572,3784],{"class":960},[943,7574,964],{"class":956},[943,7576,968],{"class":967},[943,7578,4144],{"class":1327},[943,7580,997],{"class":949},[943,7582,7583,7585,7587,7589,7591,7593,7595,7597,7599,7601,7603,7605,7607],{"class":945,"line":1000},[943,7584,957],{"class":956},[943,7586,881],{"class":960},[943,7588,964],{"class":956},[943,7590,968],{"class":967},[943,7592,1061],{"class":949},[943,7594,964],{"class":987},[943,7596,2490],{"class":991},[943,7598,964],{"class":987},[943,7600,1218],{"class":949},[943,7602,964],{"class":987},[943,7604,2499],{"class":991},[943,7606,964],{"class":987},[943,7608,2504],{"class":949},[943,7610,7611,7613,7615,7617,7619,7621,7623,7625],{"class":945,"line":1014},[943,7612,957],{"class":956},[943,7614,4181],{"class":960},[943,7616,964],{"class":956},[943,7618,968],{"class":967},[943,7620,988],{"class":987},[943,7622,3212],{"class":991},[943,7624,964],{"class":987},[943,7626,997],{"class":949},[943,7628,7629,7631,7633,7635,7637,7639,7641],{"class":945,"line":1036},[943,7630,957],{"class":956},[943,7632,4200],{"class":960},[943,7634,964],{"class":956},[943,7636,968],{"class":967},[943,7638,988],{"class":987},[943,7640,3212],{"class":991},[943,7642,4211],{"class":987},[943,7644,7645],{"class":945,"line":1049},[943,7646,1095],{"class":949},[856,7648,4218],{},[856,7650,4221],{},[901,7652,7653],{"className":1118,"code":4224,"filename":4225,"language":1121,"meta":909,"style":909},[860,7654,7655,7659,7681,7703,7727,7759,7763,7767,7783,7799,7803,7807,7835,7863,7867,7871,7875],{"__ignoreMap":909},[943,7656,7657],{"class":945,"line":946},[943,7658,4232],{"class":1752},[943,7660,7661,7663,7665,7667,7669,7671,7673,7675,7677,7679],{"class":945,"line":953},[943,7662,2779],{"class":1128},[943,7664,4239],{"class":1128},[943,7666,4242],{"class":1300},[943,7668,1396],{"class":949},[943,7670,1409],{"class":1283},[943,7672,1412],{"class":949},[943,7674,4251],{"class":1415},[943,7676,1424],{"class":949},[943,7678,1427],{"class":1283},[943,7680,971],{"class":949},[943,7682,7683,7685,7687,7689,7691,7693,7695,7697,7699,7701],{"class":945,"line":974},[943,7684,1435],{"class":1283},[943,7686,4264],{"class":1287},[943,7688,1291],{"class":967},[943,7690,1478],{"class":1128},[943,7692,4271],{"class":1300},[943,7694,1396],{"class":949},[943,7696,1399],{"class":987},[943,7698,4278],{"class":991},[943,7700,1399],{"class":987},[943,7702,2225],{"class":949},[943,7704,7705,7707,7709,7711,7713,7715,7717,7719,7721,7723,7725],{"class":945,"line":1000},[943,7706,4287],{"class":1136},[943,7708,968],{"class":1313},[943,7710,1212],{"class":949},[943,7712,4294],{"class":1136},[943,7714,968],{"class":1313},[943,7716,4299],{"class":991},[943,7718,4302],{"class":1283},[943,7720,2361],{"class":1136},[943,7722,4307],{"class":1283},[943,7724,4310],{"class":991},[943,7726,4313],{"class":949},[943,7728,7729,7731,7733,7735,7737,7739,7741,7743,7745,7747,7749,7751,7753,7755,7757],{"class":945,"line":1014},[943,7730,4287],{"class":1136},[943,7732,968],{"class":1313},[943,7734,1212],{"class":949},[943,7736,4324],{"class":1136},[943,7738,968],{"class":1313},[943,7740,4329],{"class":991},[943,7742,4302],{"class":1283},[943,7744,2210],{"class":1136},[943,7746,4307],{"class":1283},[943,7748,4338],{"class":991},[943,7750,4302],{"class":1283},[943,7752,4343],{"class":1136},[943,7754,4307],{"class":1283},[943,7756,4310],{"class":991},[943,7758,4313],{"class":949},[943,7760,7761],{"class":945,"line":1036},[943,7762,2189],{"class":949},[943,7764,7765],{"class":945,"line":1049},[943,7766,1277],{"emptyLinePlaceholder":8},[943,7768,7769,7771,7773,7775,7777,7779,7781],{"class":945,"line":1074},[943,7770,1518],{"class":1128},[943,7772,1412],{"class":949},[943,7774,1628],{"class":967},[943,7776,4368],{"class":1136},[943,7778,1297],{"class":949},[943,7780,4123],{"class":1136},[943,7782,1548],{"class":949},[943,7784,7785,7787,7789,7791,7793,7795,7797],{"class":945,"line":1080},[943,7786,4379],{"class":1128},[943,7788,4382],{"class":1300},[943,7790,1319],{"class":949},[943,7792,4387],{"class":1136},[943,7794,968],{"class":1313},[943,7796,4392],{"class":1327},[943,7798,1465],{"class":949},[943,7800,7801],{"class":945,"line":1086},[943,7802,1089],{"class":949},[943,7804,7805],{"class":945,"line":1092},[943,7806,1277],{"emptyLinePlaceholder":8},[943,7808,7809,7811,7813,7815,7817,7819,7821,7823,7825,7827,7829,7831,7833],{"class":945,"line":1235},[943,7810,1518],{"class":1128},[943,7812,1412],{"class":949},[943,7814,1628],{"class":967},[943,7816,4368],{"class":1136},[943,7818,1297],{"class":949},[943,7820,881],{"class":1136},[943,7822,2854],{"class":949},[943,7824,2896],{"class":1300},[943,7826,1396],{"class":949},[943,7828,1399],{"class":987},[943,7830,2490],{"class":991},[943,7832,1399],{"class":987},[943,7834,2903],{"class":949},[943,7836,7837,7839,7841,7843,7845,7847,7849,7851,7853,7855,7857,7859,7861],{"class":945,"line":1256},[943,7838,4379],{"class":1128},[943,7840,4382],{"class":1300},[943,7842,1319],{"class":949},[943,7844,4387],{"class":1136},[943,7846,968],{"class":1313},[943,7848,1587],{"class":1327},[943,7850,1218],{"class":949},[943,7852,3134],{"class":1136},[943,7854,968],{"class":1313},[943,7856,1199],{"class":987},[943,7858,2688],{"class":991},[943,7860,1399],{"class":987},[943,7862,1465],{"class":949},[943,7864,7865],{"class":945,"line":1274},[943,7866,1089],{"class":949},[943,7868,7869],{"class":945,"line":1280},[943,7870,1277],{"emptyLinePlaceholder":8},[943,7872,7873],{"class":945,"line":1307},[943,7874,4471],{"class":1752},[943,7876,7877],{"class":945,"line":1344},[943,7878,1377],{"class":949},[2510,7880,7881],{},[856,7882,7883,4483,7885,4486],{},[4100,7884,4482],{"href":22},[860,7886,881],{},[869,7888],{},[872,7890,4492],{"id":4491},[856,7892,4495],{},[856,7894,4498],{},[901,7896,7897],{"className":1118,"code":4501,"language":1121,"meta":909,"style":909},[860,7898,7899,7917,7921,7925],{"__ignoreMap":909},[943,7900,7901,7903,7905,7907,7909,7911,7913,7915],{"class":945,"line":946},[943,7902,1129],{"class":1128},[943,7904,1212],{"class":949},[943,7906,4512],{"class":1136},[943,7908,1224],{"class":949},[943,7910,1196],{"class":1128},[943,7912,1199],{"class":987},[943,7914,1202],{"class":991},[943,7916,1205],{"class":987},[943,7918,7919],{"class":945,"line":953},[943,7920,1277],{"emptyLinePlaceholder":8},[943,7922,7923],{"class":945,"line":974},[943,7924,4531],{"class":1752},[943,7926,7927,7929,7931,7933,7935,7937],{"class":945,"line":1000},[943,7928,4512],{"class":1300},[943,7930,1446],{"class":949},[943,7932,4540],{"class":1300},[943,7934,1396],{"class":949},[943,7936,4545],{"class":1136},[943,7938,1507],{"class":949},[856,7940,4550,7941,4554,7943,1297],{},[860,7942,4553],{},[860,7944,1114],{},[856,7946,4559],{},[901,7948,7949],{"className":1118,"code":4562,"language":1121,"meta":909,"style":909},[860,7950,7951,7969,7973,7977,7993,8005],{"__ignoreMap":909},[943,7952,7953,7955,7957,7959,7961,7963,7965,7967],{"class":945,"line":946},[943,7954,1129],{"class":1128},[943,7956,1212],{"class":949},[943,7958,4573],{"class":1136},[943,7960,1224],{"class":949},[943,7962,1196],{"class":1128},[943,7964,1199],{"class":987},[943,7966,1202],{"class":991},[943,7968,1205],{"class":987},[943,7970,7971],{"class":945,"line":953},[943,7972,1277],{"emptyLinePlaceholder":8},[943,7974,7975],{"class":945,"line":974},[943,7976,4592],{"class":1752},[943,7978,7979,7981,7983,7985,7987,7989,7991],{"class":945,"line":1000},[943,7980,4597],{"class":1128},[943,7982,1412],{"class":949},[943,7984,1284],{"class":1283},[943,7986,4604],{"class":1287},[943,7988,4607],{"class":1283},[943,7990,4610],{"class":1136},[943,7992,1548],{"class":949},[943,7994,7995,7997,7999,8001,8003],{"class":945,"line":1014},[943,7996,4617],{"class":1128},[943,7998,4620],{"class":1300},[943,8000,1396],{"class":949},[943,8002,4625],{"class":1136},[943,8004,1507],{"class":949},[943,8006,8007],{"class":945,"line":1036},[943,8008,1095],{"class":949},[869,8010],{},[872,8012,4637],{"id":4636},[4639,8014,8015,8023],{},[4642,8016,8017],{},[4645,8018,8019,8021],{},[4648,8020,4650],{},[4648,8022,4653],{},[4655,8024,8025,8033,8041,8053,8063,8073,8083],{},[4645,8026,8027,8029],{},[4660,8028,4662],{},[4660,8030,8031,4668],{},[860,8032,4667],{},[4645,8034,8035,8037],{},[4660,8036,4673],{},[4660,8038,4676,8039,4679],{},[860,8040,881],{},[4645,8042,8043,8045],{},[4660,8044,4684],{},[4660,8046,8047,4689,8049,4692,8051],{},[860,8048,889],{},[860,8050,885],{},[860,8052,866],{},[4645,8054,8055,8057],{},[4660,8056,4699],{},[4660,8058,8059,863,8061,4706],{},[860,8060,862],{},[860,8062,866],{},[4645,8064,8065,8067],{},[4660,8066,4711],{},[4660,8068,4714,8069,863,8071],{},[860,8070,862],{},[860,8072,866],{},[4645,8074,8075,8077],{},[4660,8076,4723],{},[4660,8078,8079,4728,8081,4731],{},[860,8080,881],{},[860,8082,4106],{},[4645,8084,8085,8087],{},[4660,8086,4736],{},[4660,8088,4739,8089],{},[860,8090,4742],{},[4744,8092,4746],{},{"title":909,"searchDepth":953,"depth":953,"links":8094},[8095,8096,8101,8102,8107,8108,8109,8110],{"id":874,"depth":953,"text":875},{"id":914,"depth":953,"text":915,"children":8097},[8098,8099,8100],{"id":922,"depth":974,"text":923},{"id":1107,"depth":974,"text":1108},{"id":2371,"depth":974,"text":2372},{"id":2519,"depth":953,"text":2520},{"id":2718,"depth":953,"text":2719,"children":8103},[8104,8105,8106],{"id":2722,"depth":974,"text":2723},{"id":3156,"depth":974,"text":3157},{"id":3471,"depth":974,"text":3472},{"id":3701,"depth":953,"text":3702},{"id":4094,"depth":953,"text":4095},{"id":4491,"depth":953,"text":4492},{"id":4636,"depth":953,"text":4637},{},{"title":233,"description":4765},1780436278917]