[{"data":1,"prerenderedAt":5186},["ShallowReactive",2],{"navLinks":3,"sidebar_docs_navigation_\u002Fdocs\u002Fiam":64,"navigation":257,"navLinks_footer":837,"\u002Fdocs\u002Fiam\u002Fessentials\u002Fdatabase_page":850,"\u002Fdocs\u002Fiam\u002Fessentials\u002Fdatabase_surround":3284,"\u002Fdocs\u002Fiam\u002Fessentials\u002Fdatabase":3287},{"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":151,"body":852,"description":3276,"extension":3277,"icon":3278,"meta":3279,"module":3280,"navigation":8,"path":152,"rawbody":3281,"seo":3282,"stem":153,"__hash__":3283},"docs\u002Fdocs\u002Fiam\u002F01.essentials\u002F17.database.md",{"type":853,"value":854,"toc":3251},"minimark",[855,888,898,907,910,915,920,923,993,1000,1050,1054,1057,1065,1069,1076,1110,1116,1176,1178,1182,1188,1197,1618,1624,1634,1644,1658,1662,1668,1695,1697,1702,1709,1968,1974,1980,1986,1990,1993,2054,2078,2080,2085,2092,2267,2272,2278,2283,2301,2303,2308,2313,2475,2478,2481,2532,2536,2542,2545,2558,2560,2566,2577,2903,2927,2929,2933,2936,2939,2960,2963,2988,2993,2995,2999,3002,3008,3015,3111,3114,3120,3123,3165,3174,3176,3180,3186,3192,3244,3247],[856,857,858,859,863,864,867,868,871,872,875,876,879,880,884,885,887],"p",{},"The IAM service stores all persistent auth state in MySQL. The IAM schema\nincludes four tables: ",[860,861,862],"code",{},"users"," for account data, ",[860,865,866],{},"api_tokens"," for\nmachine-to-machine credentials, ",[860,869,870],{},"refresh_tokens"," for session credentials, and\n",[860,873,874],{},"mfa_codes"," for pending multi-factor authentication challenges. A fifth related\ntable, ",[860,877,878],{},"visitors",", is created and managed by the\n",[881,882,883],"a",{"href":35},"bot-detector"," service but referenced by a foreign key\nfrom ",[860,886,862],{},".",[856,889,890,891,897],{},"Access tokens are not stored in the database. They live exclusively in an in-memory ",[881,892,896],{"href":893,"rel":894},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCache_replacement_policies#Least_recently_used_(LRU)",[895],"nofollow","LRU cache"," with a configurable maximum size and TTL. This keeps token verification fast and makes individual token revocation immediate without database writes.",[856,899,900,901,906],{},"The service maintains two MySQL connection pools: a promise-based pool for all auth operations and a callback-based pool for rate limiting. A third data store, an ",[881,902,905],{"href":903,"rel":904},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FLightning_Memory-Mapped_Database",[895],"LMDB"," key-value database, holds a read-only list of disposable email domains used during signup validation.",[908,909],"hr",{},[911,912,914],"h2",{"id":913},"connection-architecture","Connection Architecture",[916,917,919],"h3",{"id":918},"pool-types","Pool Types",[856,921,922],{},"The service creates two separate MySQL pools at startup. They serve different purposes and use different MySQL2 APIs.",[924,925,926,942],"table",{},[927,928,929],"thead",{},[930,931,932,936,939],"tr",{},[933,934,935],"th",{},"Pool",[933,937,938],{},"API",[933,940,941],{},"Purpose",[943,944,945,973],"tbody",{},[930,946,947,954,959],{},[948,949,950],"td",{},[951,952,953],"strong",{},"Main pool",[948,955,956],{},[860,957,958],{},"mysql2\u002Fpromise",[948,960,961,962,965,966,969,970,887],{},"All authentication queries: user lookups, token operations, MFA codes. Supports ",[860,963,964],{},"async","\u002F",[860,967,968],{},"await"," and transactions via ",[860,971,972],{},"pool.getConnection()",[930,974,975,980,986],{},[948,976,977],{},[951,978,979],{},"Limiter pool",[948,981,982,985],{},[860,983,984],{},"mysql2"," (callback)",[948,987,988,989,992],{},"Rate limiting storage. Uses the callback API because the rate limiter library (",[860,990,991],{},"rate-limiter-flexible",") requires a callback-style MySQL connection.",[856,994,995,996,999],{},"Both pools are configured from the ",[860,997,998],{},"store"," section of the service configuration:",[1001,1002,1003,1037,1043],"field-group",{},[1004,1005,1009],"field",{"name":1006,"type":1007,":required":1008},"store.main","mysql.PoolOptions","true",[856,1010,1011,1012,1015,1016,1015,1019,1015,1022,1015,1025,1015,1028,1031,1032,887],{},"MySQL2 pool options for the main authentication pool. Includes ",[860,1013,1014],{},"host",", ",[860,1017,1018],{},"port",[860,1020,1021],{},"user",[860,1023,1024],{},"password",[860,1026,1027],{},"database",[860,1029,1030],{},"connectionLimit",", and any other ",[881,1033,1036],{"href":1034,"rel":1035},"https:\u002F\u002Fsidorares.github.io\u002Fnode-mysql2\u002Fdocs\u002Fdocumentation\u002Fconnections#pool-options",[895],"mysql2 pool option",[1004,1038,1040],{"name":1039,"type":1007,":required":1008},"store.rate_limiters_pool.store",[856,1041,1042],{},"MySQL2 pool options for the rate limiter pool. Same option format as the main pool, but typically points to a separate database to isolate rate limit state from auth data.",[1004,1044,1047],{"name":1045,"type":1046,":required":1008},"store.rate_limiters_pool.dbName","string",[856,1048,1049],{},"The database name used by the rate limiter pool. The service uses this value to create the database if it does not exist.",[916,1051,1053],{"id":1052},"disposable-email-store","Disposable Email Store",[856,1055,1056],{},"The third data connection is an LMDB database opened in read-only, compressed mode. It contains a precomputed list of disposable email domains (services like Mailinator, Guerrilla Mail, etc.). During signup, the service extracts the domain from the user's email address and checks it against this store. If the domain is found, the signup request is rejected.",[856,1058,1059,1060,1064],{},"LMDB is a memory-mapped key-value store that does not require a separate server process. The data file is bundled with the ",[881,1061,1063],{"href":1062},"\u002Fdocs\u002Fshield-base-cli","shield-base-cli"," package and loaded at startup.",[916,1066,1068],{"id":1067},"initialization-order","Initialization Order",[856,1070,1071,1072,1075],{},"All three stores are initialized inside the ",[860,1073,1074],{},"configuration()"," function, which must be called before any route handler runs:",[1077,1078,1080,1084,1090,1093,1099,1103],"steps",{"level":1079},"4",[1081,1082,953],"h4",{"id":1083},"main-pool",[856,1085,1086,1089],{},[860,1087,1088],{},"mysql2.createPool(config.store.main)"," creates the promise-based pool for all auth queries.",[1081,1091,979],{"id":1092},"limiter-pool",[856,1094,1095,1098],{},[860,1096,1097],{},"mysql.createPool(config.store.rate_limiters_pool.store)"," creates the callback-based pool for rate limiting.",[1081,1100,1102],{"id":1101},"email-list-database","Email list database",[856,1104,1105,1106,1109],{},"LMDB ",[860,1107,1108],{},"open()"," loads the disposable email domain list in read-only mode.",[856,1111,1112,1113,1115],{},"The service exports accessor functions for each store. All three throw if called before ",[860,1114,1074],{}," has run:",[924,1117,1118,1131],{},[927,1119,1120],{},[930,1121,1122,1125,1128],{},[933,1123,1124],{},"Function",[933,1126,1127],{},"Returns",[933,1129,1130],{},"Throws if",[943,1132,1133,1148,1162],{},[930,1134,1135,1140,1143],{},[948,1136,1137],{},[860,1138,1139],{},"getPool()",[948,1141,1142],{},"Main promise pool",[948,1144,1145,1147],{},[860,1146,1074],{}," not called",[930,1149,1150,1155,1158],{},[948,1151,1152],{},[860,1153,1154],{},"poolForLibrary()",[948,1156,1157],{},"Limiter callback pool",[948,1159,1160,1147],{},[860,1161,1074],{},[930,1163,1164,1169,1172],{},[948,1165,1166],{},[860,1167,1168],{},"getDisposableEmailList()",[948,1170,1171],{},"LMDB database instance",[948,1173,1174,1147],{},[860,1175,1074],{},[908,1177],{},[911,1179,1181],{"id":1180},"schema","Schema",[916,1183,1185,1187],{"id":1184},"users-table",[860,1186,862],{}," Table",[856,1189,1190,1191,1193,1194,1196],{},"The ",[860,1192,862],{}," table stores account credentials, profile data, OAuth provider references, and a foreign key to the ",[860,1195,878],{}," table managed by the bot-detector.",[924,1198,1199,1215],{},[927,1200,1201],{},[930,1202,1203,1206,1209,1212],{},[933,1204,1205],{},"Column",[933,1207,1208],{},"Type",[933,1210,1211],{},"Constraints",[933,1213,1214],{},"Description",[943,1216,1217,1237,1257,1275,1295,1313,1331,1359,1377,1401,1420,1438,1456,1476,1492,1508,1524,1540,1556,1579,1599],{},[930,1218,1219,1224,1229,1234],{},[948,1220,1221],{},[860,1222,1223],{},"id",[948,1225,1226],{},[860,1227,1228],{},"INT",[948,1230,1231],{},[860,1232,1233],{},"AUTO_INCREMENT PRIMARY KEY",[948,1235,1236],{},"Unique user identifier",[930,1238,1239,1244,1249,1254],{},[948,1240,1241],{},[860,1242,1243],{},"name",[948,1245,1246],{},[860,1247,1248],{},"VARCHAR(100)",[948,1250,1251],{},[860,1252,1253],{},"NOT NULL",[948,1255,1256],{},"First name",[930,1258,1259,1264,1268,1272],{},[948,1260,1261],{},[860,1262,1263],{},"last_name",[948,1265,1266],{},[860,1267,1248],{},[948,1269,1270],{},[860,1271,1253],{},[948,1273,1274],{},"Last name",[930,1276,1277,1282,1287,1292],{},[948,1278,1279],{},[860,1280,1281],{},"email",[948,1283,1284],{},[860,1285,1286],{},"VARCHAR(255)",[948,1288,1289],{},[860,1290,1291],{},"UNIQUE NOT NULL",[948,1293,1294],{},"Login email. Uniqueness enforced at the database level.",[930,1296,1297,1302,1306,1310],{},[948,1298,1299],{},[860,1300,1301],{},"password_hash",[948,1303,1304],{},[860,1305,1286],{},[948,1307,1308],{},[860,1309,1253],{},[948,1311,1312],{},"Argon2id hash of the user's password",[930,1314,1315,1320,1325,1328],{},[948,1316,1317],{},[860,1318,1319],{},"avatar",[948,1321,1322],{},[860,1323,1324],{},"VARCHAR(200)",[948,1326,1327],{},"Nullable",[948,1329,1330],{},"URL or path to the user's avatar image",[930,1332,1333,1338,1343,1345],{},[948,1334,1335],{},[860,1336,1337],{},"provider",[948,1339,1340],{},[860,1341,1342],{},"VARCHAR(50)",[948,1344,1327],{},[948,1346,1347,1348,1015,1351,1354,1355,1358],{},"OAuth provider name (e.g., ",[860,1349,1350],{},"google",[860,1352,1353],{},"github","). ",[860,1356,1357],{},"NULL"," for email\u002Fpassword accounts.",[930,1360,1361,1366,1370,1372],{},[948,1362,1363],{},[860,1364,1365],{},"provider_id",[948,1367,1368],{},[860,1369,1248],{},[948,1371,1327],{},[948,1373,1374,1375,1358],{},"The user's ID at the OAuth provider. ",[860,1376,1357],{},[930,1378,1379,1384,1389,1394],{},[948,1380,1381],{},[860,1382,1383],{},"active_user",[948,1385,1386],{},[860,1387,1388],{},"BOOLEAN",[948,1390,1391],{},[860,1392,1393],{},"DEFAULT 1",[948,1395,1396,1397,1400],{},"Whether the account is active. ",[860,1398,1399],{},"0"," disables login without deleting the row.",[930,1402,1403,1408,1412,1417],{},[948,1404,1405],{},[860,1406,1407],{},"remember_user",[948,1409,1410],{},[860,1411,1388],{},[948,1413,1414],{},[860,1415,1416],{},"DEFAULT 0",[948,1418,1419],{},"Whether the user opted into persistent sessions",[930,1421,1422,1427,1431,1435],{},[948,1423,1424],{},[860,1425,1426],{},"terms_and_privacy_agreement",[948,1428,1429],{},[860,1430,1388],{},[948,1432,1433],{},[860,1434,1416],{},[948,1436,1437],{},"Whether the user accepted terms of service",[930,1439,1440,1445,1449,1453],{},[948,1441,1442],{},[860,1443,1444],{},"accepts_marketing",[948,1446,1447],{},[860,1448,1388],{},[948,1450,1451],{},[860,1452,1416],{},[948,1454,1455],{},"Whether the user opted into marketing emails",[930,1457,1458,1463,1468,1470],{},[948,1459,1460],{},[860,1461,1462],{},"last_mfa_at",[948,1464,1465],{},[860,1466,1467],{},"DATETIME",[948,1469,1327],{},[948,1471,1472,1473,1475],{},"Timestamp of the last successful MFA verification. Set to ",[860,1474,1357],{}," when a refresh token expires, forcing MFA on the next login.",[930,1477,1478,1483,1487,1489],{},[948,1479,1480],{},[860,1481,1482],{},"country",[948,1484,1485],{},[860,1486,1248],{},[948,1488,1327],{},[948,1490,1491],{},"User's country (profile data)",[930,1493,1494,1499,1503,1505],{},[948,1495,1496],{},[860,1497,1498],{},"city",[948,1500,1501],{},[860,1502,1248],{},[948,1504,1327],{},[948,1506,1507],{},"User's city",[930,1509,1510,1515,1519,1521],{},[948,1511,1512],{},[860,1513,1514],{},"address",[948,1516,1517],{},[860,1518,1324],{},[948,1520,1327],{},[948,1522,1523],{},"Street address",[930,1525,1526,1531,1535,1537],{},[948,1527,1528],{},[860,1529,1530],{},"zip",[948,1532,1533],{},[860,1534,1248],{},[948,1536,1327],{},[948,1538,1539],{},"Postal code",[930,1541,1542,1547,1551,1553],{},[948,1543,1544],{},[860,1545,1546],{},"district",[948,1548,1549],{},[860,1550,1248],{},[948,1552,1327],{},[948,1554,1555],{},"District or region",[930,1557,1558,1563,1568,1572],{},[948,1559,1560],{},[860,1561,1562],{},"visitor_id",[948,1564,1565],{},[860,1566,1567],{},"CHAR(36)",[948,1569,1570],{},[860,1571,1253],{},[948,1573,1574,1575,1578],{},"Foreign key to ",[860,1576,1577],{},"visitors(visitor_id)",". Links the user to their device fingerprint record managed by the bot-detector.",[930,1580,1581,1586,1591,1596],{},[948,1582,1583],{},[860,1584,1585],{},"created_at",[948,1587,1588],{},[860,1589,1590],{},"TIMESTAMP",[948,1592,1593],{},[860,1594,1595],{},"DEFAULT CURRENT_TIMESTAMP",[948,1597,1598],{},"Account creation timestamp",[930,1600,1601,1606,1610,1615],{},[948,1602,1603],{},[860,1604,1605],{},"updated_at",[948,1607,1608],{},[860,1609,1590],{},[948,1611,1612],{},[860,1613,1614],{},"DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP",[948,1616,1617],{},"Last modification timestamp. Updated automatically by MySQL on any column change.",[1081,1619,1621,1622],{"id":1620},"foreign-key-visitor_id","Foreign Key: ",[860,1623,1562],{},[1625,1626,1631],"pre",{"className":1627,"code":1629,"language":1630},[1628],"language-text","FOREIGN KEY (visitor_id) REFERENCES visitors(visitor_id)\n  ON UPDATE CASCADE\n  ON DELETE RESTRICT\n","text",[860,1632,1629],{"__ignoreMap":1633},"",[856,1635,1190,1636,1639,1640,1643],{},[860,1637,1638],{},"ON DELETE RESTRICT"," constraint prevents deleting a visitor record while a user row still references it. The ",[860,1641,1642],{},"ON UPDATE CASCADE"," constraint propagates visitor ID changes (if any) to the user row automatically. This ensures the link between a user and their device fingerprint is never broken.",[1645,1646,1647],"note",{},[856,1648,1190,1649,1651,1652,1654,1655,1657],{},[860,1650,1562],{}," column requires that the visitor already exists in the ",[860,1653,878],{}," table before a user can be created. The bot-detector service creates visitor records during its fingerprinting flow, which runs before signup. If you are running the IAM service without the bot-detector, you must populate the ",[860,1656,878],{}," table manually.",[1081,1659,1661],{"id":1660},"password-hashing","Password Hashing",[856,1663,1664,1665,1667],{},"Passwords are hashed with Argon2id before storage. The ",[860,1666,1024],{}," configuration section controls the hashing parameters:",[1001,1669,1670,1676,1683,1689],{},[1004,1671,1673],{"name":1672,"type":1046,":required":1008},"password.pepper",[856,1674,1675],{},"A server-side secret mixed into every password hash. The pepper is not stored in the database and is the same for all users. If you lose it, all existing password hashes become unverifiable.",[1004,1677,1680],{"name":1678,"type":1679},"password.hashLength","number",[856,1681,1682],{},"Output length of the Argon2id hash in bytes. Optional; defaults to the Argon2 library default.",[1004,1684,1686],{"name":1685,"type":1679},"password.timeCost",[856,1687,1688],{},"Number of Argon2id iterations. Higher values increase resistance to brute force at the cost of CPU time per login. Optional.",[1004,1690,1692],{"name":1691,"type":1679},"password.memoryCost",[856,1693,1694],{},"Memory usage in KiB for each Argon2id hash. Higher values increase resistance to GPU-based attacks. Optional.",[908,1696],{},[916,1698,1700,1187],{"id":1699},"api_tokens-table",[860,1701,866],{},[856,1703,1190,1704,1706,1707,887],{},[860,1705,866],{}," table stores hashed machine-to-machine credentials together\nwith the public identifier and metadata used by the verification and dashboard\nmanagement flows. For the full lifecycle and route behavior, see\n",[881,1708,167],{"href":168},[924,1710,1711,1723],{},[927,1712,1713],{},[930,1714,1715,1717,1719,1721],{},[933,1716,1205],{},[933,1718,1208],{},[933,1720,1211],{},[933,1722,1214],{},[943,1724,1725,1742,1762,1782,1800,1821,1839,1858,1877,1896,1912,1932,1950],{},[930,1726,1727,1731,1735,1739],{},[948,1728,1729],{},[860,1730,1223],{},[948,1732,1733],{},[860,1734,1228],{},[948,1736,1737],{},[860,1738,1233],{},[948,1740,1741],{},"Unique row identifier",[930,1743,1744,1749,1753,1757],{},[948,1745,1746],{},[860,1747,1748],{},"user_id",[948,1750,1751],{},[860,1752,1228],{},[948,1754,1755],{},[860,1756,1253],{},[948,1758,1574,1759],{},[860,1760,1761],{},"users(id)",[930,1763,1764,1769,1774,1779],{},[948,1765,1766],{},[860,1767,1768],{},"api_token",[948,1770,1771],{},[860,1772,1773],{},"VARCHAR(300)",[948,1775,1776],{},[860,1777,1778],{},"NOT NULL UNIQUE",[948,1780,1781],{},"SHA-256 hex hash of the raw API token. The raw token is never stored.",[930,1783,1784,1789,1793,1797],{},[948,1785,1786],{},[860,1787,1788],{},"public_identifier",[948,1790,1791],{},[860,1792,1773],{},[948,1794,1795],{},[860,1796,1778],{},[948,1798,1799],{},"Non-secret public reference used by authenticated management actions",[930,1801,1802,1807,1811,1815],{},[948,1803,1804],{},[860,1805,1806],{},"prefix",[948,1808,1809],{},[860,1810,1342],{},[948,1812,1813],{},[860,1814,1253],{},[948,1816,1817,1818],{},"Prefix segment from the raw token format ",[860,1819,1820],{},"prefix_random_checksum",[930,1822,1823,1827,1832,1836],{},[948,1824,1825],{},[860,1826,1243],{},[948,1828,1829],{},[860,1830,1831],{},"VARCHAR(150)",[948,1833,1834],{},[860,1835,1253],{},[948,1837,1838],{},"Friendly token label shown in dashboards and metadata responses",[930,1840,1841,1845,1850,1855],{},[948,1842,1843],{},[860,1844,1585],{},[948,1846,1847],{},[860,1848,1849],{},"TIMESTAMP(3)",[948,1851,1852],{},[860,1853,1854],{},"DEFAULT CURRENT_TIMESTAMP(3)",[948,1856,1857],{},"When the token row was inserted",[930,1859,1860,1865,1869,1871],{},[948,1861,1862],{},[860,1863,1864],{},"expires_at",[948,1866,1867],{},[860,1868,1849],{},[948,1870,1327],{},[948,1872,1873,1874,1876],{},"Optional expiry timestamp. ",[860,1875,1357],{}," means the token does not expire.",[930,1878,1879,1884,1888,1890],{},[948,1880,1881],{},[860,1882,1883],{},"restricted_to_ip_address",[948,1885,1886],{},[860,1887,1324],{},[948,1889,1327],{},[948,1891,1892,1893,1895],{},"JSON-encoded array of allowed IP addresses, or ",[860,1894,1357],{}," when no host restriction exists",[930,1897,1898,1903,1907,1909],{},[948,1899,1900],{},[860,1901,1902],{},"last_used",[948,1904,1905],{},[860,1906,1849],{},[948,1908,1327],{},[948,1910,1911],{},"Initialized when the token is created and updated after successful external verification",[930,1913,1914,1919,1924,1929],{},[948,1915,1916],{},[860,1917,1918],{},"privilege_type",[948,1920,1921],{},[860,1922,1923],{},"ENUM('demo', 'restricted', 'protected', 'full', 'custom')",[948,1925,1926],{},[860,1927,1928],{},"NOT NULL DEFAULT 'restricted'",[948,1930,1931],{},"Required privilege scope for successful verification",[930,1933,1934,1939,1943,1947],{},[948,1935,1936],{},[860,1937,1938],{},"usage_count",[948,1940,1941],{},[860,1942,1228],{},[948,1944,1945],{},[860,1946,1416],{},[948,1948,1949],{},"Number of successful external verification calls recorded for the token",[930,1951,1952,1957,1961,1965],{},[948,1953,1954],{},[860,1955,1956],{},"valid",[948,1958,1959],{},[860,1960,1388],{},[948,1962,1963],{},[860,1964,1416],{},[948,1966,1967],{},"Whether the token can still be used. New tokens are inserted as valid.",[1081,1969,1971,1972],{"id":1970},"foreign-key-user_id","Foreign key: ",[860,1973,1748],{},[1625,1975,1978],{"className":1976,"code":1977,"language":1630},[1628],"CONSTRAINT users_api_keys\n  FOREIGN KEY (user_id) REFERENCES users(id)\n  ON DELETE CASCADE\n",[860,1979,1977],{"__ignoreMap":1633},[856,1981,1190,1982,1985],{},[860,1983,1984],{},"ON DELETE CASCADE"," constraint ensures that deleting a user automatically\ndeletes all of their API tokens. No orphaned machine-to-machine credentials\nremain after account deletion.",[1081,1987,1989],{"id":1988},"indexes","Indexes",[856,1991,1992],{},"The service creates three explicit indexes for the most common API-token lookup\npatterns:",[924,1994,1995,2007],{},[927,1996,1997],{},[930,1998,1999,2002,2005],{},[933,2000,2001],{},"Index",[933,2003,2004],{},"Columns",[933,2006,941],{},[943,2008,2009,2024,2039],{},[930,2010,2011,2016,2021],{},[948,2012,2013],{},[860,2014,2015],{},"idx_user_api_key_public_identifier",[948,2017,2018],{},[860,2019,2020],{},"(user_id, public_identifier)",[948,2022,2023],{},"Speeds up authenticated token-manager lookups that resolve a user's token from the public identifier",[930,2025,2026,2031,2036],{},[948,2027,2028],{},[860,2029,2030],{},"idx_user_api_key",[948,2032,2033],{},[860,2034,2035],{},"(user_id, id)",[948,2037,2038],{},"Speeds up dashboard actions that resolve a token by owner and token ID",[930,2040,2041,2046,2051],{},[948,2042,2043],{},[860,2044,2045],{},"idx_user_valid_tokens",[948,2047,2048],{},[860,2049,2050],{},"(id, valid)",[948,2052,2053],{},"Speeds up valid-row checks during management actions",[1645,2055,2056],{},[856,2057,1190,2058,2060,2061,2063,2064,2067,2068,2071,2072,2074,2075,887],{},[860,2059,1768],{}," column stores only a SHA-256 hash of the raw token. The\n",[860,2062,1788],{}," is intentionally not hashed because it is not treated as a\nsecret. The ",[860,2065,2066],{},"createApiKey()"," helper inserts new rows with ",[860,2069,2070],{},"valid = 1"," and\ninitializes ",[860,2073,1902],{}," with ",[860,2076,2077],{},"UTC_TIMESTAMP()",[908,2079],{},[916,2081,2083,1187],{"id":2082},"refresh_tokens-table",[860,2084,870],{},[856,2086,1190,2087,2089,2090,887],{},[860,2088,870],{}," table holds hashed refresh tokens, their validity state, and usage metadata. For a full guide on the refresh token lifecycle (generation, verification, consumption, rotation, revocation), see ",[881,2091,91],{"href":92},[924,2093,2094,2106],{},[927,2095,2096],{},[930,2097,2098,2100,2102,2104],{},[933,2099,1205],{},[933,2101,1208],{},[933,2103,1211],{},[933,2105,1214],{},[943,2107,2108,2124,2142,2161,2185,2201,2223,2248],{},[930,2109,2110,2114,2118,2122],{},[948,2111,2112],{},[860,2113,1223],{},[948,2115,2116],{},[860,2117,1228],{},[948,2119,2120],{},[860,2121,1233],{},[948,2123,1741],{},[930,2125,2126,2130,2134,2138],{},[948,2127,2128],{},[860,2129,1748],{},[948,2131,2132],{},[860,2133,1228],{},[948,2135,2136],{},[860,2137,1253],{},[948,2139,1574,2140],{},[860,2141,1761],{},[930,2143,2144,2149,2154,2158],{},[948,2145,2146],{},[860,2147,2148],{},"token",[948,2150,2151],{},[860,2152,2153],{},"VARCHAR(600)",[948,2155,2156],{},[860,2157,1778],{},[948,2159,2160],{},"SHA-256 hex hash of the raw refresh token. The raw token is never stored.",[930,2162,2163,2167,2171,2175],{},[948,2164,2165],{},[860,2166,1956],{},[948,2168,2169],{},[860,2170,1388],{},[948,2172,2173],{},[860,2174,1416],{},[948,2176,2177,2178,2181,2182,2184],{},"Whether the token can still be used. Set to ",[860,2179,2180],{},"1"," on creation, ",[860,2183,1399],{}," on revocation or consumption.",[930,2186,2187,2191,2195,2199],{},[948,2188,2189],{},[860,2190,1585],{},[948,2192,2193],{},[860,2194,1590],{},[948,2196,2197],{},[860,2198,1595],{},[948,2200,1857],{},[930,2202,2203,2208,2212,2216],{},[948,2204,2205],{},[860,2206,2207],{},"expiresAt",[948,2209,2210],{},[860,2211,1590],{},[948,2213,2214],{},[860,2215,1253],{},[948,2217,2218,2219,2222],{},"Computed from the ",[860,2220,2221],{},"refresh_ttl"," configuration at generation time",[930,2224,2225,2229,2233,2237],{},[948,2226,2227],{},[860,2228,1938],{},[948,2230,2231],{},[860,2232,1228],{},[948,2234,2235],{},[860,2236,1416],{},[948,2238,2239,2241,2242,2244,2245,2247],{},[860,2240,1399],{}," means fresh, ",[860,2243,2180],{}," means consumed. Any value above ",[860,2246,2180],{}," triggers reuse detection and revokes all user sessions.",[930,2249,2250,2255,2259,2261],{},[948,2251,2252],{},[860,2253,2254],{},"session_started_at",[948,2256,2257],{},[860,2258,1590],{},[948,2260,1327],{},[948,2262,2263,2264,887],{},"Set once at creation, never updated during rotation. Used to enforce ",[860,2265,2266],{},"MAX_SESSION_LIFE",[1081,2268,1621,2270],{"id":2269},"foreign-key-user_id-1",[860,2271,1748],{},[1625,2273,2276],{"className":2274,"code":2275,"language":1630},[1628],"FOREIGN KEY (user_id) REFERENCES users(id)\n  ON DELETE CASCADE\n",[860,2277,2275],{"__ignoreMap":1633},[856,2279,1190,2280,2282],{},[860,2281,1984],{}," constraint ensures that deleting a user automatically deletes all their refresh tokens. No orphaned sessions remain after account deletion.",[1645,2284,2285],{},[856,2286,1190,2287,2289,2290,2293,2294,2297,2298,2300],{},[860,2288,2148],{}," column stores a SHA-256 hash, not the raw token. The raw token (64 random bytes, hex encoded) is sent to the client exactly once as an ",[860,2291,2292],{},"httpOnly"," cookie named ",[860,2295,2296],{},"session"," and is never stored in plaintext on the server. See ",[881,2299,91],{"href":92}," for the hashing pipeline.",[908,2302],{},[916,2304,2306,1187],{"id":2305},"mfa_codes-table",[860,2307,874],{},[856,2309,1190,2310,2312],{},[860,2311,874],{}," table stores pending MFA verification codes. Each row represents a single challenge that a user must complete to finalize authentication. Rows are deleted after successful verification or when they expire.",[924,2314,2315,2327],{},[927,2316,2317],{},[930,2318,2319,2321,2323,2325],{},[933,2320,1205],{},[933,2322,1208],{},[933,2324,1211],{},[933,2326,1214],{},[943,2328,2329,2345,2368,2385,2404,2423,2440,2458],{},[930,2330,2331,2335,2339,2343],{},[948,2332,2333],{},[860,2334,1223],{},[948,2336,2337],{},[860,2338,1228],{},[948,2340,2341],{},[860,2342,1233],{},[948,2344,1741],{},[930,2346,2347,2351,2355,2359],{},[948,2348,2349],{},[860,2350,1748],{},[948,2352,2353],{},[860,2354,1228],{},[948,2356,2357],{},[860,2358,1778],{},[948,2360,1574,2361,2363,2364,2367],{},[860,2362,1761],{},". The ",[860,2365,2366],{},"UNIQUE"," constraint means each user can have at most one pending MFA code at a time. Creating a new code for the same user replaces the previous one.",[930,2369,2370,2374,2378,2382],{},[948,2371,2372],{},[860,2373,2148],{},[948,2375,2376],{},[860,2377,2153],{},[948,2379,2380],{},[860,2381,1778],{},[948,2383,2384],{},"The refresh token hash associated with this MFA challenge. Links the MFA flow to the session that triggered it.",[930,2386,2387,2392,2397,2401],{},[948,2388,2389],{},[860,2390,2391],{},"jti",[948,2393,2394],{},[860,2395,2396],{},"VARCHAR(500)",[948,2398,2399],{},[860,2400,1778],{},[948,2402,2403],{},"JWT ID of the temporary access token issued during the MFA-pending state. Used to invalidate the temporary token after MFA completes.",[930,2405,2406,2411,2416,2420],{},[948,2407,2408],{},[860,2409,2410],{},"code_hash",[948,2412,2413],{},[860,2414,2415],{},"CHAR(64)",[948,2417,2418],{},[860,2419,1778],{},[948,2421,2422],{},"SHA-256 hash of the 7-digit MFA code sent to the user. The raw code is never stored.",[930,2424,2425,2429,2433,2437],{},[948,2426,2427],{},[860,2428,1864],{},[948,2430,2431],{},[860,2432,1467],{},[948,2434,2435],{},[860,2436,1253],{},[948,2438,2439],{},"When this MFA challenge expires. After this time, the user must request a new code.",[930,2441,2442,2447,2451,2455],{},[948,2443,2444],{},[860,2445,2446],{},"used",[948,2448,2449],{},[860,2450,1388],{},[948,2452,2453],{},[860,2454,1416],{},[948,2456,2457],{},"Whether the code has been successfully verified. Prevents replay of a valid code within the expiry window.",[930,2459,2460,2464,2468,2472],{},[948,2461,2462],{},[860,2463,1585],{},[948,2465,2466],{},[860,2467,1467],{},[948,2469,2470],{},[860,2471,1595],{},[948,2473,2474],{},"When the MFA challenge was created",[1081,2476,1989],{"id":2477},"indexes-1",[856,2479,2480],{},"The table has four indexes beyond the primary key to support the common query patterns:",[924,2482,2483,2491],{},[927,2484,2485],{},[930,2486,2487,2489],{},[933,2488,1205],{},[933,2490,941],{},[943,2492,2493,2502,2511,2523],{},[930,2494,2495,2499],{},[948,2496,2497],{},[860,2498,1748],{},[948,2500,2501],{},"Fast lookup by user when creating or replacing a pending MFA code",[930,2503,2504,2508],{},[948,2505,2506],{},[860,2507,2410],{},[948,2509,2510],{},"Fast verification lookup when a user submits a code",[930,2512,2513,2517],{},[948,2514,2515],{},[860,2516,2148],{},[948,2518,2519,2520,2522],{},"Join with ",[860,2521,870],{}," table to validate the associated session",[930,2524,2525,2529],{},[948,2526,2527],{},[860,2528,2446],{},[948,2530,2531],{},"Filter for unused codes during cleanup",[1081,2533,2535],{"id":2534},"foreign-keys","Foreign Keys",[1625,2537,2540],{"className":2538,"code":2539,"language":1630},[1628],"CONSTRAINT users_mfa\n  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE\n\nCONSTRAINT token_mfa\n  FOREIGN KEY (token) REFERENCES refresh_tokens(token) ON DELETE CASCADE\n",[860,2541,2539],{"__ignoreMap":1633},[856,2543,2544],{},"Both cascade on delete. Deleting a user wipes their pending MFA codes. Deleting (or revoking) the refresh token that initiated the MFA flow also removes the pending code, because the session no longer exists.",[2546,2547,2548],"warning",{},[856,2549,1190,2550,2552,2553,2555,2556,887],{},[860,2551,1748],{}," column has a ",[860,2554,2366],{}," constraint. If a user requests a new MFA code while one is already pending, the service must delete or replace the existing row first. The insertion will fail at the database level if two rows share the same ",[860,2557,1748],{},[908,2559],{},[916,2561,2563,2565],{"id":2562},"visitors-table-external",[860,2564,878],{}," Table (External)",[856,2567,1190,2568,2570,2571,2573,2574,2576],{},[860,2569,878],{}," table is created and managed by the ",[881,2572,883],{"href":35}," service, not by the IAM service. It is documented here because the ",[860,2575,862],{}," table references it through a foreign key.",[924,2578,2579,2589],{},[927,2580,2581],{},[930,2582,2583,2585,2587],{},[933,2584,1205],{},[933,2586,1208],{},[933,2588,1214],{},[943,2590,2591,2614,2632,2647,2662,2686,2703,2720,2740,2763,2786,2803,2823,2839,2856,2870,2887],{},[930,2592,2593,2597,2601],{},[948,2594,2595],{},[860,2596,1562],{},[948,2598,2599],{},[860,2600,1567],{},[948,2602,2603,2604,2607,2608,2611,2612,887],{},"UUID generated by ",[860,2605,2606],{},"DEFAULT (UUID())",". Referenced by ",[860,2609,2610],{},"users.visitor_id",". ",[860,2613,2366],{},[930,2615,2616,2621,2626],{},[948,2617,2618],{},[860,2619,2620],{},"canary_id",[948,2622,2623],{},[860,2624,2625],{},"VARCHAR(64)",[948,2627,2628,2631],{},[951,2629,2630],{},"Primary key",". The fingerprint identifier set as a cookie by the bot-detector.",[930,2633,2634,2639,2644],{},[948,2635,2636],{},[860,2637,2638],{},"ip_address",[948,2640,2641],{},[860,2642,2643],{},"VARCHAR(45)",[948,2645,2646],{},"Client IP (supports IPv6 length)",[930,2648,2649,2654,2659],{},[948,2650,2651],{},[860,2652,2653],{},"user_agent",[948,2655,2656],{},[860,2657,2658],{},"TEXT",[948,2660,2661],{},"Raw User-Agent header",[930,2663,2664,2678,2683],{},[948,2665,2666,1015,2668,1015,2671,1015,2674,1015,2676],{},[860,2667,1482],{},[860,2669,2670],{},"region",[860,2672,2673],{},"region_name",[860,2675,1498],{},[860,2677,1546],{},[948,2679,2680],{},[860,2681,2682],{},"VARCHAR",[948,2684,2685],{},"Geo-IP location data",[930,2687,2688,2696,2700],{},[948,2689,2690,1015,2693],{},[860,2691,2692],{},"lat",[860,2694,2695],{},"lon",[948,2697,2698],{},[860,2699,1831],{},[948,2701,2702],{},"GPS coordinates from geo-IP lookup",[930,2704,2705,2713,2717],{},[948,2706,2707,1015,2710],{},[860,2708,2709],{},"timezone",[860,2711,2712],{},"currency",[948,2714,2715],{},[860,2716,2625],{},[948,2718,2719],{},"Timezone and currency from geo-IP",[930,2721,2722,2733,2737],{},[948,2723,2724,1015,2727,1015,2730],{},[860,2725,2726],{},"isp",[860,2728,2729],{},"org",[860,2731,2732],{},"as_org",[948,2734,2735],{},[860,2736,2625],{},[948,2738,2739],{},"Network information (ISP, organization, AS)",[930,2741,2742,2756,2760],{},[948,2743,2744,1015,2747,1015,2750,1015,2753],{},[860,2745,2746],{},"device_type",[860,2748,2749],{},"browser",[860,2751,2752],{},"browserType",[860,2754,2755],{},"browserVersion",[948,2757,2758],{},[860,2759,2625],{},[948,2761,2762],{},"Device and browser classification",[930,2764,2765,2776,2780],{},[948,2766,2767,1015,2770,1015,2773],{},[860,2768,2769],{},"deviceVendor",[860,2771,2772],{},"deviceModel",[860,2774,2775],{},"os",[948,2777,2778],{},[860,2779,2625],{},[948,2781,2782,2783,887],{},"Device hardware and OS. Default ",[860,2784,2785],{},"'unknown'",[930,2787,2788,2796,2800],{},[948,2789,2790,1015,2793],{},[860,2791,2792],{},"proxy",[860,2794,2795],{},"hosting",[948,2797,2798],{},[860,2799,1388],{},[948,2801,2802],{},"Whether the IP is a known proxy or hosting provider",[930,2804,2805,2813,2817],{},[948,2806,2807,1015,2810],{},[860,2808,2809],{},"proxy_allowed",[860,2811,2812],{},"hosting_allowed",[948,2814,2815],{},[860,2816,1388],{},[948,2818,2819,2820,887],{},"Whether the proxy\u002Fhosting status has been manually allowed. Default ",[860,2821,2822],{},"false",[930,2824,2825,2830,2834],{},[948,2826,2827],{},[860,2828,2829],{},"is_bot",[948,2831,2832],{},[860,2833,1388],{},[948,2835,2836,2837,887],{},"Whether the visitor is classified as a bot. Default ",[860,2838,2822],{},[930,2840,2841,2846,2850],{},[948,2842,2843],{},[860,2844,2845],{},"suspicious_activity_score",[948,2847,2848],{},[860,2849,1228],{},[948,2851,2852,2853,2855],{},"Cumulative suspicion score. Default ",[860,2854,1399],{},". Used by the IAM service's anomaly detection engine.",[930,2857,2858,2863,2867],{},[948,2859,2860],{},[860,2861,2862],{},"first_seen",[948,2864,2865],{},[860,2866,1590],{},[948,2868,2869],{},"When the visitor was first recorded",[930,2871,2872,2877,2881],{},[948,2873,2874],{},[860,2875,2876],{},"last_seen",[948,2878,2879],{},[860,2880,1590],{},[948,2882,2883,2884],{},"Auto-updated on every interaction via ",[860,2885,2886],{},"ON UPDATE CURRENT_TIMESTAMP",[930,2888,2889,2894,2898],{},[948,2890,2891],{},[860,2892,2893],{},"request_count",[948,2895,2896],{},[860,2897,1228],{},[948,2899,2900,2901,887],{},"Total number of requests from this visitor. Default ",[860,2902,2180],{},[1645,2904,2905],{},[856,2906,1190,2907,2909,2910,2912,2913,2363,2915,2917,2918,2920,2921,2923,2924,2926],{},[860,2908,2620],{}," is the primary key of the ",[860,2911,878],{}," table, not ",[860,2914,1562],{},[860,2916,1562],{}," is a separate UUID used as the foreign key target for ",[860,2919,2610],{},". This design allows the bot-detector to identify visitors by their fingerprint cookie (",[860,2922,2620],{},") while giving the IAM service a stable UUID reference (",[860,2925,1562],{},") that does not change when the fingerprint rotates.",[908,2928],{},[911,2930,2932],{"id":2931},"access-token-cache","Access Token Cache",[856,2934,2935],{},"Access tokens are not stored in any database table. Instead, the service maintains an in-memory LRU cache. When an access token is generated, it is added to the cache. When a request arrives with an access token, the service checks the cache first. If the token is present and has not expired, it is valid. If it is not in the cache, the token is verified cryptographically from the JWT signature.",[856,2937,2938],{},"The cache is configured from the JWT configuration section:",[1001,2940,2941,2950],{},[1004,2942,2944],{"name":2943,"type":1679},"jwt.access_tokens.maxCacheEntries",[856,2945,2946,2947,887],{},"Maximum number of access tokens kept in the LRU cache. When the cache is full, the least recently used entry is evicted. Defaults to ",[860,2948,2949],{},"500",[1004,2951,2953],{"name":2952,"type":1679},"jwt.access_tokens.expiresInMs",[856,2954,2955,2956,2959],{},"Time-to-live for each cache entry in milliseconds. Entries older than this value are evicted regardless of access frequency. Defaults to 15 minutes (",[860,2957,2958],{},"900000","). Typically set to match the access token JWT expiry.",[856,2961,2962],{},"The LRU cache provides two benefits:",[2964,2965,2966,2982],"ol",{},[2967,2968,2969,2972,2973,1015,2976,1015,2978,2981],"li",{},[951,2970,2971],{},"Early rejection and metadata binding."," Missing or invalid cache entries\nfail before JWT verification, and valid cache entries provide the expected\n",[860,2974,2975],{},"userId",[860,2977,2391],{},[860,2979,2980],{},"visitorId",", and roles used during claim validation.",[2967,2983,2984,2987],{},[951,2985,2986],{},"Immediate revocation."," Deleting an entry from the cache makes the next\nverification fail immediately, without waiting for JWT expiry.",[2546,2989,2990],{},[856,2991,2992],{},"The LRU cache is per-process and not shared across instances. If you run multiple IAM service instances behind a load balancer, a token revoked on one instance remains valid in the caches of other instances until it expires or is evicted. For single-instance deployments, the cache provides strong revocation guarantees.",[908,2994],{},[911,2996,2998],{"id":2997},"hashing-utilities","Hashing Utilities",[856,3000,3001],{},"The service uses two utility functions for all token hashing operations. Both enforce SHA-256 hex format and are used by refresh token, MFA code, and access token flows.",[916,3003,3005],{"id":3004},"todigesthex",[860,3006,3007],{},"toDigestHex",[856,3009,3010,3011,3014],{},"Accepts any string input and ensures it becomes a SHA-256 hex digest. If the input is already a 64-character hex string matching the SHA-256 pattern, it passes through unchanged. Otherwise, the function computes ",[860,3012,3013],{},"sha256(input)"," and returns the hex digest.",[1625,3016,3020],{"className":3017,"code":3018,"language":3019,"meta":1633,"style":1633},"language-ts shiki shiki-themes light-plus light-plus dracula","import { toDigestHex } from '@riavzon\u002Fauth'\n\nconst result = await toDigestHex(rawToken)\n\u002F\u002F result.input the SHA-256 hex string\n\u002F\u002F result.wasHashed true if the input was already a valid SHA-256 hex,\n\u002F\u002F                    false if the function had to compute the hash\n","ts",[860,3021,3022,3055,3061,3092,3099,3105],{"__ignoreMap":1633},[3023,3024,3027,3031,3035,3038,3041,3044,3048,3052],"span",{"class":3025,"line":3026},"line",1,[3023,3028,3030],{"class":3029},"sZ328","import",[3023,3032,3034],{"class":3033},"sDd4n"," { ",[3023,3036,3007],{"class":3037},"sjsA6",[3023,3039,3040],{"class":3033}," } ",[3023,3042,3043],{"class":3029},"from",[3023,3045,3047],{"class":3046},"sFkSl"," '",[3023,3049,3051],{"class":3050},"sFB1V","@riavzon\u002Fauth",[3023,3053,3054],{"class":3046},"'\n",[3023,3056,3058],{"class":3025,"line":3057},2,[3023,3059,3060],{"emptyLinePlaceholder":8},"\n",[3023,3062,3064,3068,3072,3076,3079,3083,3086,3089],{"class":3025,"line":3063},3,[3023,3065,3067],{"class":3066},"sl46w","const",[3023,3069,3071],{"class":3070},"s3JHE"," result",[3023,3073,3075],{"class":3074},"saOXh"," =",[3023,3077,3078],{"class":3029}," await",[3023,3080,3082],{"class":3081},"sHOzp"," toDigestHex",[3023,3084,3085],{"class":3033},"(",[3023,3087,3088],{"class":3037},"rawToken",[3023,3090,3091],{"class":3033},")\n",[3023,3093,3095],{"class":3025,"line":3094},4,[3023,3096,3098],{"class":3097},"sghk6","\u002F\u002F result.input the SHA-256 hex string\n",[3023,3100,3102],{"class":3025,"line":3101},5,[3023,3103,3104],{"class":3097},"\u002F\u002F result.wasHashed true if the input was already a valid SHA-256 hex,\n",[3023,3106,3108],{"class":3025,"line":3107},6,[3023,3109,3110],{"class":3097},"\u002F\u002F                    false if the function had to compute the hash\n",[856,3112,3113],{},"This function uses Zod validation internally to determine whether the input matches the SHA-256 hex pattern. The idempotent design means you can safely pass either a raw token or an already-hashed value without producing a double hash.",[916,3115,3117],{"id":3116},"ensuresha256hex",[860,3118,3119],{},"ensureSha256Hex",[856,3121,3122],{},"Strict validation function. Checks that the input is already a valid SHA-256 hex string (exactly 64 lowercase hex characters). If the validation fails, it throws an error. This function does not compute a hash; it only validates format.",[1625,3124,3126],{"className":3017,"code":3125,"language":3019,"meta":1633,"style":1633},"import { ensureSha256Hex } from '@riavzon\u002Fauth'\n\nensureSha256Hex(tokenHash) \u002F\u002F throws if not a valid SHA-256 hex string\n",[860,3127,3128,3146,3150],{"__ignoreMap":1633},[3023,3129,3130,3132,3134,3136,3138,3140,3142,3144],{"class":3025,"line":3026},[3023,3131,3030],{"class":3029},[3023,3133,3034],{"class":3033},[3023,3135,3119],{"class":3037},[3023,3137,3040],{"class":3033},[3023,3139,3043],{"class":3029},[3023,3141,3047],{"class":3046},[3023,3143,3051],{"class":3050},[3023,3145,3054],{"class":3046},[3023,3147,3148],{"class":3025,"line":3057},[3023,3149,3060],{"emptyLinePlaceholder":8},[3023,3151,3152,3154,3156,3159,3162],{"class":3025,"line":3063},[3023,3153,3119],{"class":3081},[3023,3155,3085],{"class":3033},[3023,3157,3158],{"class":3037},"tokenHash",[3023,3160,3161],{"class":3033},") ",[3023,3163,3164],{"class":3097},"\u002F\u002F throws if not a valid SHA-256 hex string\n",[856,3166,3167,3168,3170,3171,3173],{},"Used as a guard before database operations to ensure that only properly formatted hashes reach the ",[860,3169,2148],{}," and ",[860,3172,2410],{}," columns.",[908,3175],{},[911,3177,3179],{"id":3178},"entity-relationship","Entity Relationship",[856,3181,3182,3183,3185],{},"The five related tables form a simple hierarchy. The bot-detector's\n",[860,3184,878],{}," table sits at the root and the IAM service owns the other four:",[1625,3187,3190],{"className":3188,"code":3189,"language":1630},[1628],"visitors (bot-detector)\n  └── users (IAM)\n  ├── api_tokens (IAM)\n        ├── refresh_tokens (IAM)\n        │     └── mfa_codes (IAM, via token FK)\n        └── mfa_codes (IAM, via user_id FK)\n",[860,3191,3189],{"__ignoreMap":1633},[3193,3194,3195,3205,3212,3220,3234],"ul",{},[2967,3196,3197,3198,3201,3202,3204],{},"A ",[951,3199,3200],{},"visitor"," can have zero or more ",[951,3203,862],{}," though typically one.",[2967,3206,3197,3207,3201,3209,887],{},[951,3208,1021],{},[951,3210,3211],{},"API tokens",[2967,3213,3197,3214,3201,3216,3219],{},[951,3215,1021],{},[951,3217,3218],{},"refresh tokens"," one per active session\u002Fdevice.",[2967,3221,3197,3222,3224,3225,3228,3229,3231,3232,887],{},[951,3223,1021],{}," can have at most one pending ",[951,3226,3227],{},"MFA code"," enforced by ",[860,3230,2366],{}," on ",[860,3233,1748],{},[2967,3235,3236,3237,3239,3240,3243],{},"An ",[951,3238,3227],{}," is also linked to a specific ",[951,3241,3242],{},"refresh token"," the session that triggered the MFA challenge.",[856,3245,3246],{},"Cascade deletes flow downward: deleting a visitor is blocked, deleting a user\ncascades to their API tokens, refresh tokens, and MFA codes, and deleting a\nrefresh token cascades to any MFA code tied to that session.",[3248,3249,3250],"style",{},"html pre.shiki code .sZ328, html code.shiki .sZ328{--shiki-light:#AF00DB;--shiki-default:#AF00DB;--shiki-dark:#FF79C6}html pre.shiki code .sDd4n, html code.shiki .sDd4n{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#F8F8F2}html pre.shiki code .sjsA6, html code.shiki .sjsA6{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#F8F8F2}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 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 .saOXh, html code.shiki .saOXh{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#FF79C6}html pre.shiki code .sHOzp, html code.shiki .sHOzp{--shiki-light:#795E26;--shiki-default:#795E26;--shiki-dark:#50FA7B}html pre.shiki code .sghk6, html code.shiki .sghk6{--shiki-light:#008000;--shiki-default:#008000;--shiki-dark:#6272A4}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);}",{"title":1633,"searchDepth":3057,"depth":3057,"links":3252},[3253,3258,3270,3271,3275],{"id":913,"depth":3057,"text":914,"children":3254},[3255,3256,3257],{"id":918,"depth":3063,"text":919},{"id":1052,"depth":3063,"text":1053},{"id":1067,"depth":3063,"text":1068},{"id":1180,"depth":3057,"text":1181,"children":3259},[3260,3262,3264,3266,3268],{"id":1184,"depth":3063,"text":3261},"users Table",{"id":1699,"depth":3063,"text":3263},"api_tokens Table",{"id":2082,"depth":3063,"text":3265},"refresh_tokens Table",{"id":2305,"depth":3063,"text":3267},"mfa_codes Table",{"id":2562,"depth":3063,"text":3269},"visitors Table (External)",{"id":2931,"depth":3057,"text":2932},{"id":2997,"depth":3057,"text":2998,"children":3272},[3273,3274],{"id":3004,"depth":3063,"text":3007},{"id":3116,"depth":3063,"text":3119},{"id":3178,"depth":3057,"text":3179},"How the IAM service organizes its MySQL schema, connection pools, hashing utilities, and in-memory caches across four IAM tables, two pool types, and an LRU access token store.","md","i-lucide-database",{},null,"---\ntitle: Database\ndescription: How the IAM service organizes its MySQL schema, connection pools, hashing utilities, and in-memory caches across four IAM tables, two pool types, and an LRU access token store.\nicon: i-lucide-database\n---\n\nThe IAM service stores all persistent auth state in MySQL. The IAM schema\nincludes four tables: `users` for account data, `api_tokens` for\nmachine-to-machine credentials, `refresh_tokens` for session credentials, and\n`mfa_codes` for pending multi-factor authentication challenges. A fifth related\ntable, `visitors`, is created and managed by the\n[bot-detector](\u002Fdocs\u002Fbot-detection) service but referenced by a foreign key\nfrom `users`.\n\nAccess tokens are not stored in the database. They live exclusively in an in-memory [LRU cache](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCache_replacement_policies#Least_recently_used_(LRU)) with a configurable maximum size and TTL. This keeps token verification fast and makes individual token revocation immediate without database writes.\n\nThe service maintains two MySQL connection pools: a promise-based pool for all auth operations and a callback-based pool for rate limiting. A third data store, an [LMDB](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FLightning_Memory-Mapped_Database) key-value database, holds a read-only list of disposable email domains used during signup validation.\n\n---\n\n## Connection Architecture\n\n### Pool Types\n\nThe service creates two separate MySQL pools at startup. They serve different purposes and use different MySQL2 APIs.\n\n| Pool | API | Purpose |\n|---|---|---|\n| **Main pool** | `mysql2\u002Fpromise` | All authentication queries: user lookups, token operations, MFA codes. Supports `async`\u002F`await` and transactions via `pool.getConnection()`. |\n| **Limiter pool** | `mysql2` (callback) | Rate limiting storage. Uses the callback API because the rate limiter library (`rate-limiter-flexible`) requires a callback-style MySQL connection. |\n\nBoth pools are configured from the `store` section of the service configuration:\n\n::field-group\n  ::field{name=\"store.main\" type=\"mysql.PoolOptions\" required}\n  MySQL2 pool options for the main authentication pool. Includes `host`, `port`, `user`, `password`, `database`, `connectionLimit`, and any other [mysql2 pool option](https:\u002F\u002Fsidorares.github.io\u002Fnode-mysql2\u002Fdocs\u002Fdocumentation\u002Fconnections#pool-options).\n  ::\n\n  ::field{name=\"store.rate_limiters_pool.store\" type=\"mysql.PoolOptions\" required}\n  MySQL2 pool options for the rate limiter pool. Same option format as the main pool, but typically points to a separate database to isolate rate limit state from auth data.\n  ::\n\n  ::field{name=\"store.rate_limiters_pool.dbName\" type=\"string\" required}\n  The database name used by the rate limiter pool. The service uses this value to create the database if it does not exist.\n  ::\n::\n\n### Disposable Email Store\n\nThe third data connection is an LMDB database opened in read-only, compressed mode. It contains a precomputed list of disposable email domains (services like Mailinator, Guerrilla Mail, etc.). During signup, the service extracts the domain from the user's email address and checks it against this store. If the domain is found, the signup request is rejected.\n\nLMDB is a memory-mapped key-value store that does not require a separate server process. The data file is bundled with the [shield-base-cli](\u002Fdocs\u002Fshield-base-cli) package and loaded at startup.\n\n### Initialization Order\n\nAll three stores are initialized inside the `configuration()` function, which must be called before any route handler runs:\n\n::steps{level=\"4\"}\n#### Main pool\n`mysql2.createPool(config.store.main)` creates the promise-based pool for all auth queries.\n\n#### Limiter pool\n`mysql.createPool(config.store.rate_limiters_pool.store)` creates the callback-based pool for rate limiting.\n\n#### Email list database\nLMDB `open()` loads the disposable email domain list in read-only mode.\n::\n\nThe service exports accessor functions for each store. All three throw if called before `configuration()` has run:\n\n| Function | Returns | Throws if |\n|---|---|---|\n| `getPool()` | Main promise pool | `configuration()` not called |\n| `poolForLibrary()` | Limiter callback pool | `configuration()` not called |\n| `getDisposableEmailList()` | LMDB database instance | `configuration()` not called |\n\n---\n\n## Schema\n\n### `users` Table\n\nThe `users` table stores account credentials, profile data, OAuth provider references, and a foreign key to the `visitors` table managed by the bot-detector.\n\n| Column | Type | Constraints | Description |\n|---|---|---|---|\n| `id` | `INT` | `AUTO_INCREMENT PRIMARY KEY` | Unique user identifier |\n| `name` | `VARCHAR(100)` | `NOT NULL` | First name |\n| `last_name` | `VARCHAR(100)` | `NOT NULL` | Last name |\n| `email` | `VARCHAR(255)` | `UNIQUE NOT NULL` | Login email. Uniqueness enforced at the database level. |\n| `password_hash` | `VARCHAR(255)` | `NOT NULL` | Argon2id hash of the user's password |\n| `avatar` | `VARCHAR(200)` | Nullable | URL or path to the user's avatar image |\n| `provider` | `VARCHAR(50)` | Nullable | OAuth provider name (e.g., `google`, `github`). `NULL` for email\u002Fpassword accounts. |\n| `provider_id` | `VARCHAR(100)` | Nullable | The user's ID at the OAuth provider. `NULL` for email\u002Fpassword accounts. |\n| `active_user` | `BOOLEAN` | `DEFAULT 1` | Whether the account is active. `0` disables login without deleting the row. |\n| `remember_user` | `BOOLEAN` | `DEFAULT 0` | Whether the user opted into persistent sessions |\n| `terms_and_privacy_agreement` | `BOOLEAN` | `DEFAULT 0` | Whether the user accepted terms of service |\n| `accepts_marketing` | `BOOLEAN` | `DEFAULT 0` | Whether the user opted into marketing emails |\n| `last_mfa_at` | `DATETIME` | Nullable | Timestamp of the last successful MFA verification. Set to `NULL` when a refresh token expires, forcing MFA on the next login. |\n| `country` | `VARCHAR(100)` | Nullable | User's country (profile data) |\n| `city` | `VARCHAR(100)` | Nullable | User's city |\n| `address` | `VARCHAR(200)` | Nullable | Street address |\n| `zip` | `VARCHAR(100)` | Nullable | Postal code |\n| `district` | `VARCHAR(100)` | Nullable | District or region |\n| `visitor_id` | `CHAR(36)` | `NOT NULL` | Foreign key to `visitors(visitor_id)`. Links the user to their device fingerprint record managed by the bot-detector. |\n| `created_at` | `TIMESTAMP` | `DEFAULT CURRENT_TIMESTAMP` | Account creation timestamp |\n| `updated_at` | `TIMESTAMP` | `DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP` | Last modification timestamp. Updated automatically by MySQL on any column change. |\n\n#### Foreign Key: `visitor_id`\n\n```\nFOREIGN KEY (visitor_id) REFERENCES visitors(visitor_id)\n  ON UPDATE CASCADE\n  ON DELETE RESTRICT\n```\n\nThe `ON DELETE RESTRICT` constraint prevents deleting a visitor record while a user row still references it. The `ON UPDATE CASCADE` constraint propagates visitor ID changes (if any) to the user row automatically. This ensures the link between a user and their device fingerprint is never broken.\n\n::note\nThe `visitor_id` column requires that the visitor already exists in the `visitors` table before a user can be created. The bot-detector service creates visitor records during its fingerprinting flow, which runs before signup. If you are running the IAM service without the bot-detector, you must populate the `visitors` table manually.\n::\n\n#### Password Hashing\n\nPasswords are hashed with Argon2id before storage. The `password` configuration section controls the hashing parameters:\n\n::field-group\n  ::field{name=\"password.pepper\" type=\"string\" required}\n  A server-side secret mixed into every password hash. The pepper is not stored in the database and is the same for all users. If you lose it, all existing password hashes become unverifiable.\n  ::\n\n  ::field{name=\"password.hashLength\" type=\"number\"}\n  Output length of the Argon2id hash in bytes. Optional; defaults to the Argon2 library default.\n  ::\n\n  ::field{name=\"password.timeCost\" type=\"number\"}\n  Number of Argon2id iterations. Higher values increase resistance to brute force at the cost of CPU time per login. Optional.\n  ::\n\n  ::field{name=\"password.memoryCost\" type=\"number\"}\n  Memory usage in KiB for each Argon2id hash. Higher values increase resistance to GPU-based attacks. Optional.\n  ::\n::\n\n---\n\n### `api_tokens` Table\n\nThe `api_tokens` table stores hashed machine-to-machine credentials together\nwith the public identifier and metadata used by the verification and dashboard\nmanagement flows. For the full lifecycle and route behavior, see\n[API Tokens](\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi).\n\n| Column | Type | Constraints | Description |\n|---|---|---|---|\n| `id` | `INT` | `AUTO_INCREMENT PRIMARY KEY` | Unique row identifier |\n| `user_id` | `INT` | `NOT NULL` | Foreign key to `users(id)` |\n| `api_token` | `VARCHAR(300)` | `NOT NULL UNIQUE` | SHA-256 hex hash of the raw API token. The raw token is never stored. |\n| `public_identifier` | `VARCHAR(300)` | `NOT NULL UNIQUE` | Non-secret public reference used by authenticated management actions |\n| `prefix` | `VARCHAR(50)` | `NOT NULL` | Prefix segment from the raw token format `prefix_random_checksum` |\n| `name` | `VARCHAR(150)` | `NOT NULL` | Friendly token label shown in dashboards and metadata responses |\n| `created_at` | `TIMESTAMP(3)` | `DEFAULT CURRENT_TIMESTAMP(3)` | When the token row was inserted |\n| `expires_at` | `TIMESTAMP(3)` | Nullable | Optional expiry timestamp. `NULL` means the token does not expire. |\n| `restricted_to_ip_address` | `VARCHAR(200)` | Nullable | JSON-encoded array of allowed IP addresses, or `NULL` when no host restriction exists |\n| `last_used` | `TIMESTAMP(3)` | Nullable | Initialized when the token is created and updated after successful external verification |\n| `privilege_type` | `ENUM('demo', 'restricted', 'protected', 'full', 'custom')` | `NOT NULL DEFAULT 'restricted'` | Required privilege scope for successful verification |\n| `usage_count` | `INT` | `DEFAULT 0` | Number of successful external verification calls recorded for the token |\n| `valid` | `BOOLEAN` | `DEFAULT 0` | Whether the token can still be used. New tokens are inserted as valid. |\n\n#### Foreign key: `user_id`\n\n```\nCONSTRAINT users_api_keys\n  FOREIGN KEY (user_id) REFERENCES users(id)\n  ON DELETE CASCADE\n```\n\nThe `ON DELETE CASCADE` constraint ensures that deleting a user automatically\ndeletes all of their API tokens. No orphaned machine-to-machine credentials\nremain after account deletion.\n\n#### Indexes\n\nThe service creates three explicit indexes for the most common API-token lookup\npatterns:\n\n| Index | Columns | Purpose |\n|---|---|---|\n| `idx_user_api_key_public_identifier` | `(user_id, public_identifier)` | Speeds up authenticated token-manager lookups that resolve a user's token from the public identifier |\n| `idx_user_api_key` | `(user_id, id)` | Speeds up dashboard actions that resolve a token by owner and token ID |\n| `idx_user_valid_tokens` | `(id, valid)` | Speeds up valid-row checks during management actions |\n\n::note\nThe `api_token` column stores only a SHA-256 hash of the raw token. The\n`public_identifier` is intentionally not hashed because it is not treated as a\nsecret. The `createApiKey()` helper inserts new rows with `valid = 1` and\ninitializes `last_used` with `UTC_TIMESTAMP()`.\n::\n\n---\n\n### `refresh_tokens` Table\n\nThe `refresh_tokens` table holds hashed refresh tokens, their validity state, and usage metadata. For a full guide on the refresh token lifecycle (generation, verification, consumption, rotation, revocation), see [Refresh Tokens](\u002Fdocs\u002Fiam\u002Fessentials\u002Frefresh-tokens).\n\n| Column | Type | Constraints | Description |\n|---|---|---|---|\n| `id` | `INT` | `AUTO_INCREMENT PRIMARY KEY` | Unique row identifier |\n| `user_id` | `INT` | `NOT NULL` | Foreign key to `users(id)` |\n| `token` | `VARCHAR(600)` | `NOT NULL UNIQUE` | SHA-256 hex hash of the raw refresh token. The raw token is never stored. |\n| `valid` | `BOOLEAN` | `DEFAULT 0` | Whether the token can still be used. Set to `1` on creation, `0` on revocation or consumption. |\n| `created_at` | `TIMESTAMP` | `DEFAULT CURRENT_TIMESTAMP` | When the token row was inserted |\n| `expiresAt` | `TIMESTAMP` | `NOT NULL` | Computed from the `refresh_ttl` configuration at generation time |\n| `usage_count` | `INT` | `DEFAULT 0` | `0` means fresh, `1` means consumed. Any value above `1` triggers reuse detection and revokes all user sessions. |\n| `session_started_at` | `TIMESTAMP` | Nullable | Set once at creation, never updated during rotation. Used to enforce `MAX_SESSION_LIFE`. |\n\n#### Foreign Key: `user_id`\n\n```\nFOREIGN KEY (user_id) REFERENCES users(id)\n  ON DELETE CASCADE\n```\n\nThe `ON DELETE CASCADE` constraint ensures that deleting a user automatically deletes all their refresh tokens. No orphaned sessions remain after account deletion.\n\n::note\nThe `token` column stores a SHA-256 hash, not the raw token. The raw token (64 random bytes, hex encoded) is sent to the client exactly once as an `httpOnly` cookie named `session` and is never stored in plaintext on the server. See [Refresh Tokens](\u002Fdocs\u002Fiam\u002Fessentials\u002Frefresh-tokens) for the hashing pipeline.\n::\n\n---\n\n### `mfa_codes` Table\n\nThe `mfa_codes` table stores pending MFA verification codes. Each row represents a single challenge that a user must complete to finalize authentication. Rows are deleted after successful verification or when they expire.\n\n| Column | Type | Constraints | Description |\n|---|---|---|---|\n| `id` | `INT` | `AUTO_INCREMENT PRIMARY KEY` | Unique row identifier |\n| `user_id` | `INT` | `NOT NULL UNIQUE` | Foreign key to `users(id)`. The `UNIQUE` constraint means each user can have at most one pending MFA code at a time. Creating a new code for the same user replaces the previous one. |\n| `token` | `VARCHAR(600)` | `NOT NULL UNIQUE` | The refresh token hash associated with this MFA challenge. Links the MFA flow to the session that triggered it. |\n| `jti` | `VARCHAR(500)` | `NOT NULL UNIQUE` | JWT ID of the temporary access token issued during the MFA-pending state. Used to invalidate the temporary token after MFA completes. |\n| `code_hash` | `CHAR(64)` | `NOT NULL UNIQUE` | SHA-256 hash of the 7-digit MFA code sent to the user. The raw code is never stored. |\n| `expires_at` | `DATETIME` | `NOT NULL` | When this MFA challenge expires. After this time, the user must request a new code. |\n| `used` | `BOOLEAN` | `DEFAULT 0` | Whether the code has been successfully verified. Prevents replay of a valid code within the expiry window. |\n| `created_at` | `DATETIME` | `DEFAULT CURRENT_TIMESTAMP` | When the MFA challenge was created |\n\n#### Indexes\n\nThe table has four indexes beyond the primary key to support the common query patterns:\n\n| Column | Purpose |\n|---|---|\n| `user_id` | Fast lookup by user when creating or replacing a pending MFA code |\n| `code_hash` | Fast verification lookup when a user submits a code |\n| `token` | Join with `refresh_tokens` table to validate the associated session |\n| `used` | Filter for unused codes during cleanup |\n\n#### Foreign Keys\n\n```\nCONSTRAINT users_mfa\n  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE\n\nCONSTRAINT token_mfa\n  FOREIGN KEY (token) REFERENCES refresh_tokens(token) ON DELETE CASCADE\n```\n\nBoth cascade on delete. Deleting a user wipes their pending MFA codes. Deleting (or revoking) the refresh token that initiated the MFA flow also removes the pending code, because the session no longer exists.\n\n::warning\nThe `user_id` column has a `UNIQUE` constraint. If a user requests a new MFA code while one is already pending, the service must delete or replace the existing row first. The insertion will fail at the database level if two rows share the same `user_id`.\n::\n\n---\n\n### `visitors` Table (External)\n\nThe `visitors` table is created and managed by the [bot-detector](\u002Fdocs\u002Fbot-detection) service, not by the IAM service. It is documented here because the `users` table references it through a foreign key.\n\n| Column | Type | Description |\n|---|---|---|\n| `visitor_id` | `CHAR(36)` | UUID generated by `DEFAULT (UUID())`. Referenced by `users.visitor_id`. `UNIQUE`. |\n| `canary_id` | `VARCHAR(64)` | **Primary key**. The fingerprint identifier set as a cookie by the bot-detector. |\n| `ip_address` | `VARCHAR(45)` | Client IP (supports IPv6 length) |\n| `user_agent` | `TEXT` | Raw User-Agent header |\n| `country`, `region`, `region_name`, `city`, `district` | `VARCHAR` | Geo-IP location data |\n| `lat`, `lon` | `VARCHAR(150)` | GPS coordinates from geo-IP lookup |\n| `timezone`, `currency` | `VARCHAR(64)` | Timezone and currency from geo-IP |\n| `isp`, `org`, `as_org` | `VARCHAR(64)` | Network information (ISP, organization, AS) |\n| `device_type`, `browser`, `browserType`, `browserVersion` | `VARCHAR(64)` | Device and browser classification |\n| `deviceVendor`, `deviceModel`, `os` | `VARCHAR(64)` | Device hardware and OS. Default `'unknown'`. |\n| `proxy`, `hosting` | `BOOLEAN` | Whether the IP is a known proxy or hosting provider |\n| `proxy_allowed`, `hosting_allowed` | `BOOLEAN` | Whether the proxy\u002Fhosting status has been manually allowed. Default `false`. |\n| `is_bot` | `BOOLEAN` | Whether the visitor is classified as a bot. Default `false`. |\n| `suspicious_activity_score` | `INT` | Cumulative suspicion score. Default `0`. Used by the IAM service's anomaly detection engine. |\n| `first_seen` | `TIMESTAMP` | When the visitor was first recorded |\n| `last_seen` | `TIMESTAMP` | Auto-updated on every interaction via `ON UPDATE CURRENT_TIMESTAMP` |\n| `request_count` | `INT` | Total number of requests from this visitor. Default `1`. |\n\n::note\nThe `canary_id` is the primary key of the `visitors` table, not `visitor_id`. The `visitor_id` is a separate UUID used as the foreign key target for `users.visitor_id`. This design allows the bot-detector to identify visitors by their fingerprint cookie (`canary_id`) while giving the IAM service a stable UUID reference (`visitor_id`) that does not change when the fingerprint rotates.\n::\n\n---\n\n## Access Token Cache\n\nAccess tokens are not stored in any database table. Instead, the service maintains an in-memory LRU cache. When an access token is generated, it is added to the cache. When a request arrives with an access token, the service checks the cache first. If the token is present and has not expired, it is valid. If it is not in the cache, the token is verified cryptographically from the JWT signature.\n\nThe cache is configured from the JWT configuration section:\n\n::field-group\n  ::field{name=\"jwt.access_tokens.maxCacheEntries\" type=\"number\"}\n  Maximum number of access tokens kept in the LRU cache. When the cache is full, the least recently used entry is evicted. Defaults to `500`.\n  ::\n\n  ::field{name=\"jwt.access_tokens.expiresInMs\" type=\"number\"}\n  Time-to-live for each cache entry in milliseconds. Entries older than this value are evicted regardless of access frequency. Defaults to 15 minutes (`900000`). Typically set to match the access token JWT expiry.\n  ::\n::\n\nThe LRU cache provides two benefits:\n\n1. **Early rejection and metadata binding.** Missing or invalid cache entries\n  fail before JWT verification, and valid cache entries provide the expected\n  `userId`, `jti`, `visitorId`, and roles used during claim validation.\n2. **Immediate revocation.** Deleting an entry from the cache makes the next\n  verification fail immediately, without waiting for JWT expiry.\n\n::warning\nThe LRU cache is per-process and not shared across instances. If you run multiple IAM service instances behind a load balancer, a token revoked on one instance remains valid in the caches of other instances until it expires or is evicted. For single-instance deployments, the cache provides strong revocation guarantees.\n::\n\n---\n\n## Hashing Utilities\n\nThe service uses two utility functions for all token hashing operations. Both enforce SHA-256 hex format and are used by refresh token, MFA code, and access token flows.\n\n### `toDigestHex`\n\nAccepts any string input and ensures it becomes a SHA-256 hex digest. If the input is already a 64-character hex string matching the SHA-256 pattern, it passes through unchanged. Otherwise, the function computes `sha256(input)` and returns the hex digest.\n\n```ts\nimport { toDigestHex } from '@riavzon\u002Fauth'\n\nconst result = await toDigestHex(rawToken)\n\u002F\u002F result.input the SHA-256 hex string\n\u002F\u002F result.wasHashed true if the input was already a valid SHA-256 hex,\n\u002F\u002F                    false if the function had to compute the hash\n```\n\nThis function uses Zod validation internally to determine whether the input matches the SHA-256 hex pattern. The idempotent design means you can safely pass either a raw token or an already-hashed value without producing a double hash.\n\n### `ensureSha256Hex`\n\nStrict validation function. Checks that the input is already a valid SHA-256 hex string (exactly 64 lowercase hex characters). If the validation fails, it throws an error. This function does not compute a hash; it only validates format.\n\n```ts\nimport { ensureSha256Hex } from '@riavzon\u002Fauth'\n\nensureSha256Hex(tokenHash) \u002F\u002F throws if not a valid SHA-256 hex string\n```\n\nUsed as a guard before database operations to ensure that only properly formatted hashes reach the `token` and `code_hash` columns.\n\n---\n\n## Entity Relationship\n\nThe five related tables form a simple hierarchy. The bot-detector's\n`visitors` table sits at the root and the IAM service owns the other four:\n\n```\nvisitors (bot-detector)\n  └── users (IAM)\n  ├── api_tokens (IAM)\n        ├── refresh_tokens (IAM)\n        │     └── mfa_codes (IAM, via token FK)\n        └── mfa_codes (IAM, via user_id FK)\n```\n\n- A **visitor** can have zero or more **users** though typically one.\n- A **user** can have zero or more **API tokens**.\n- A **user** can have zero or more **refresh tokens** one per active session\u002Fdevice.\n- A **user** can have at most one pending **MFA code** enforced by `UNIQUE` on `user_id`.\n- An **MFA code** is also linked to a specific **refresh token** the session that triggered the MFA challenge.\n\nCascade deletes flow downward: deleting a visitor is blocked, deleting a user\ncascades to their API tokens, refresh tokens, and MFA codes, and deleting a\nrefresh token cascades to any MFA code tied to that session.\n",{"title":151,"description":3276},"baSxZptKGzQPtSF5hseTO0y7te57YC9ZiW733a_SnPo",[3285,3286],{"title":147,"path":148,"stem":149,"children":-1},{"title":155,"path":156,"stem":157,"children":-1},{"id":851,"title":151,"body":3288,"description":3276,"extension":3277,"icon":3278,"meta":5184,"module":3280,"navigation":8,"path":152,"rawbody":3281,"seo":5185,"stem":153,"__hash__":3283},{"type":853,"value":3289,"toc":5164},[3290,3306,3311,3316,3318,3320,3322,3324,3370,3374,3403,3405,3407,3411,3413,3417,3437,3441,3491,3493,3495,3499,3505,3853,3857,3862,3868,3878,3880,3884,3902,3904,3908,3914,4140,4144,4149,4153,4155,4157,4207,4223,4225,4229,4235,4393,4397,4402,4406,4418,4420,4424,4428,4576,4578,4580,4626,4628,4633,4635,4645,4647,4651,4659,4927,4945,4947,4949,4951,4953,4967,4969,4985,4989,4991,4993,4995,4999,5003,5059,5061,5065,5067,5105,5111,5113,5115,5119,5124,5160,5162],[856,3291,858,3292,863,3294,867,3296,871,3298,875,3300,879,3302,884,3304,887],{},[860,3293,862],{},[860,3295,866],{},[860,3297,870],{},[860,3299,874],{},[860,3301,878],{},[881,3303,883],{"href":35},[860,3305,862],{},[856,3307,890,3308,897],{},[881,3309,896],{"href":893,"rel":3310},[895],[856,3312,900,3313,906],{},[881,3314,905],{"href":903,"rel":3315},[895],[908,3317],{},[911,3319,914],{"id":913},[916,3321,919],{"id":918},[856,3323,922],{},[924,3325,3326,3336],{},[927,3327,3328],{},[930,3329,3330,3332,3334],{},[933,3331,935],{},[933,3333,938],{},[933,3335,941],{},[943,3337,3338,3356],{},[930,3339,3340,3344,3348],{},[948,3341,3342],{},[951,3343,953],{},[948,3345,3346],{},[860,3347,958],{},[948,3349,961,3350,965,3352,969,3354,887],{},[860,3351,964],{},[860,3353,968],{},[860,3355,972],{},[930,3357,3358,3362,3366],{},[948,3359,3360],{},[951,3361,979],{},[948,3363,3364,985],{},[860,3365,984],{},[948,3367,988,3368,992],{},[860,3369,991],{},[856,3371,995,3372,999],{},[860,3373,998],{},[1001,3375,3376,3395,3399],{},[1004,3377,3378],{"name":1006,"type":1007,":required":1008},[856,3379,1011,3380,1015,3382,1015,3384,1015,3386,1015,3388,1015,3390,1031,3392,887],{},[860,3381,1014],{},[860,3383,1018],{},[860,3385,1021],{},[860,3387,1024],{},[860,3389,1027],{},[860,3391,1030],{},[881,3393,1036],{"href":1034,"rel":3394},[895],[1004,3396,3397],{"name":1039,"type":1007,":required":1008},[856,3398,1042],{},[1004,3400,3401],{"name":1045,"type":1046,":required":1008},[856,3402,1049],{},[916,3404,1053],{"id":1052},[856,3406,1056],{},[856,3408,1059,3409,1064],{},[881,3410,1063],{"href":1062},[916,3412,1068],{"id":1067},[856,3414,1071,3415,1075],{},[860,3416,1074],{},[1077,3418,3419,3421,3425,3427,3431,3433],{"level":1079},[1081,3420,953],{"id":1083},[856,3422,3423,1089],{},[860,3424,1088],{},[1081,3426,979],{"id":1092},[856,3428,3429,1098],{},[860,3430,1097],{},[1081,3432,1102],{"id":1101},[856,3434,1105,3435,1109],{},[860,3436,1108],{},[856,3438,1112,3439,1115],{},[860,3440,1074],{},[924,3442,3443,3453],{},[927,3444,3445],{},[930,3446,3447,3449,3451],{},[933,3448,1124],{},[933,3450,1127],{},[933,3452,1130],{},[943,3454,3455,3467,3479],{},[930,3456,3457,3461,3463],{},[948,3458,3459],{},[860,3460,1139],{},[948,3462,1142],{},[948,3464,3465,1147],{},[860,3466,1074],{},[930,3468,3469,3473,3475],{},[948,3470,3471],{},[860,3472,1154],{},[948,3474,1157],{},[948,3476,3477,1147],{},[860,3478,1074],{},[930,3480,3481,3485,3487],{},[948,3482,3483],{},[860,3484,1168],{},[948,3486,1171],{},[948,3488,3489,1147],{},[860,3490,1074],{},[908,3492],{},[911,3494,1181],{"id":1180},[916,3496,3497,1187],{"id":1184},[860,3498,862],{},[856,3500,1190,3501,1193,3503,1196],{},[860,3502,862],{},[860,3504,878],{},[924,3506,3507,3519],{},[927,3508,3509],{},[930,3510,3511,3513,3515,3517],{},[933,3512,1205],{},[933,3514,1208],{},[933,3516,1211],{},[933,3518,1214],{},[943,3520,3521,3537,3553,3569,3585,3601,3615,3635,3651,3669,3685,3701,3717,3733,3747,3761,3775,3789,3803,3821,3837],{},[930,3522,3523,3527,3531,3535],{},[948,3524,3525],{},[860,3526,1223],{},[948,3528,3529],{},[860,3530,1228],{},[948,3532,3533],{},[860,3534,1233],{},[948,3536,1236],{},[930,3538,3539,3543,3547,3551],{},[948,3540,3541],{},[860,3542,1243],{},[948,3544,3545],{},[860,3546,1248],{},[948,3548,3549],{},[860,3550,1253],{},[948,3552,1256],{},[930,3554,3555,3559,3563,3567],{},[948,3556,3557],{},[860,3558,1263],{},[948,3560,3561],{},[860,3562,1248],{},[948,3564,3565],{},[860,3566,1253],{},[948,3568,1274],{},[930,3570,3571,3575,3579,3583],{},[948,3572,3573],{},[860,3574,1281],{},[948,3576,3577],{},[860,3578,1286],{},[948,3580,3581],{},[860,3582,1291],{},[948,3584,1294],{},[930,3586,3587,3591,3595,3599],{},[948,3588,3589],{},[860,3590,1301],{},[948,3592,3593],{},[860,3594,1286],{},[948,3596,3597],{},[860,3598,1253],{},[948,3600,1312],{},[930,3602,3603,3607,3611,3613],{},[948,3604,3605],{},[860,3606,1319],{},[948,3608,3609],{},[860,3610,1324],{},[948,3612,1327],{},[948,3614,1330],{},[930,3616,3617,3621,3625,3627],{},[948,3618,3619],{},[860,3620,1337],{},[948,3622,3623],{},[860,3624,1342],{},[948,3626,1327],{},[948,3628,1347,3629,1015,3631,1354,3633,1358],{},[860,3630,1350],{},[860,3632,1353],{},[860,3634,1357],{},[930,3636,3637,3641,3645,3647],{},[948,3638,3639],{},[860,3640,1365],{},[948,3642,3643],{},[860,3644,1248],{},[948,3646,1327],{},[948,3648,1374,3649,1358],{},[860,3650,1357],{},[930,3652,3653,3657,3661,3665],{},[948,3654,3655],{},[860,3656,1383],{},[948,3658,3659],{},[860,3660,1388],{},[948,3662,3663],{},[860,3664,1393],{},[948,3666,1396,3667,1400],{},[860,3668,1399],{},[930,3670,3671,3675,3679,3683],{},[948,3672,3673],{},[860,3674,1407],{},[948,3676,3677],{},[860,3678,1388],{},[948,3680,3681],{},[860,3682,1416],{},[948,3684,1419],{},[930,3686,3687,3691,3695,3699],{},[948,3688,3689],{},[860,3690,1426],{},[948,3692,3693],{},[860,3694,1388],{},[948,3696,3697],{},[860,3698,1416],{},[948,3700,1437],{},[930,3702,3703,3707,3711,3715],{},[948,3704,3705],{},[860,3706,1444],{},[948,3708,3709],{},[860,3710,1388],{},[948,3712,3713],{},[860,3714,1416],{},[948,3716,1455],{},[930,3718,3719,3723,3727,3729],{},[948,3720,3721],{},[860,3722,1462],{},[948,3724,3725],{},[860,3726,1467],{},[948,3728,1327],{},[948,3730,1472,3731,1475],{},[860,3732,1357],{},[930,3734,3735,3739,3743,3745],{},[948,3736,3737],{},[860,3738,1482],{},[948,3740,3741],{},[860,3742,1248],{},[948,3744,1327],{},[948,3746,1491],{},[930,3748,3749,3753,3757,3759],{},[948,3750,3751],{},[860,3752,1498],{},[948,3754,3755],{},[860,3756,1248],{},[948,3758,1327],{},[948,3760,1507],{},[930,3762,3763,3767,3771,3773],{},[948,3764,3765],{},[860,3766,1514],{},[948,3768,3769],{},[860,3770,1324],{},[948,3772,1327],{},[948,3774,1523],{},[930,3776,3777,3781,3785,3787],{},[948,3778,3779],{},[860,3780,1530],{},[948,3782,3783],{},[860,3784,1248],{},[948,3786,1327],{},[948,3788,1539],{},[930,3790,3791,3795,3799,3801],{},[948,3792,3793],{},[860,3794,1546],{},[948,3796,3797],{},[860,3798,1248],{},[948,3800,1327],{},[948,3802,1555],{},[930,3804,3805,3809,3813,3817],{},[948,3806,3807],{},[860,3808,1562],{},[948,3810,3811],{},[860,3812,1567],{},[948,3814,3815],{},[860,3816,1253],{},[948,3818,1574,3819,1578],{},[860,3820,1577],{},[930,3822,3823,3827,3831,3835],{},[948,3824,3825],{},[860,3826,1585],{},[948,3828,3829],{},[860,3830,1590],{},[948,3832,3833],{},[860,3834,1595],{},[948,3836,1598],{},[930,3838,3839,3843,3847,3851],{},[948,3840,3841],{},[860,3842,1605],{},[948,3844,3845],{},[860,3846,1590],{},[948,3848,3849],{},[860,3850,1614],{},[948,3852,1617],{},[1081,3854,1621,3855],{"id":1620},[860,3856,1562],{},[1625,3858,3860],{"className":3859,"code":1629,"language":1630},[1628],[860,3861,1629],{"__ignoreMap":1633},[856,3863,1190,3864,1639,3866,1643],{},[860,3865,1638],{},[860,3867,1642],{},[1645,3869,3870],{},[856,3871,1190,3872,1651,3874,1654,3876,1657],{},[860,3873,1562],{},[860,3875,878],{},[860,3877,878],{},[1081,3879,1661],{"id":1660},[856,3881,1664,3882,1667],{},[860,3883,1024],{},[1001,3885,3886,3890,3894,3898],{},[1004,3887,3888],{"name":1672,"type":1046,":required":1008},[856,3889,1675],{},[1004,3891,3892],{"name":1678,"type":1679},[856,3893,1682],{},[1004,3895,3896],{"name":1685,"type":1679},[856,3897,1688],{},[1004,3899,3900],{"name":1691,"type":1679},[856,3901,1694],{},[908,3903],{},[916,3905,3906,1187],{"id":1699},[860,3907,866],{},[856,3909,1190,3910,1706,3912,887],{},[860,3911,866],{},[881,3913,167],{"href":168},[924,3915,3916,3928],{},[927,3917,3918],{},[930,3919,3920,3922,3924,3926],{},[933,3921,1205],{},[933,3923,1208],{},[933,3925,1211],{},[933,3927,1214],{},[943,3929,3930,3946,3964,3980,3996,4014,4030,4046,4062,4078,4092,4108,4124],{},[930,3931,3932,3936,3940,3944],{},[948,3933,3934],{},[860,3935,1223],{},[948,3937,3938],{},[860,3939,1228],{},[948,3941,3942],{},[860,3943,1233],{},[948,3945,1741],{},[930,3947,3948,3952,3956,3960],{},[948,3949,3950],{},[860,3951,1748],{},[948,3953,3954],{},[860,3955,1228],{},[948,3957,3958],{},[860,3959,1253],{},[948,3961,1574,3962],{},[860,3963,1761],{},[930,3965,3966,3970,3974,3978],{},[948,3967,3968],{},[860,3969,1768],{},[948,3971,3972],{},[860,3973,1773],{},[948,3975,3976],{},[860,3977,1778],{},[948,3979,1781],{},[930,3981,3982,3986,3990,3994],{},[948,3983,3984],{},[860,3985,1788],{},[948,3987,3988],{},[860,3989,1773],{},[948,3991,3992],{},[860,3993,1778],{},[948,3995,1799],{},[930,3997,3998,4002,4006,4010],{},[948,3999,4000],{},[860,4001,1806],{},[948,4003,4004],{},[860,4005,1342],{},[948,4007,4008],{},[860,4009,1253],{},[948,4011,1817,4012],{},[860,4013,1820],{},[930,4015,4016,4020,4024,4028],{},[948,4017,4018],{},[860,4019,1243],{},[948,4021,4022],{},[860,4023,1831],{},[948,4025,4026],{},[860,4027,1253],{},[948,4029,1838],{},[930,4031,4032,4036,4040,4044],{},[948,4033,4034],{},[860,4035,1585],{},[948,4037,4038],{},[860,4039,1849],{},[948,4041,4042],{},[860,4043,1854],{},[948,4045,1857],{},[930,4047,4048,4052,4056,4058],{},[948,4049,4050],{},[860,4051,1864],{},[948,4053,4054],{},[860,4055,1849],{},[948,4057,1327],{},[948,4059,1873,4060,1876],{},[860,4061,1357],{},[930,4063,4064,4068,4072,4074],{},[948,4065,4066],{},[860,4067,1883],{},[948,4069,4070],{},[860,4071,1324],{},[948,4073,1327],{},[948,4075,1892,4076,1895],{},[860,4077,1357],{},[930,4079,4080,4084,4088,4090],{},[948,4081,4082],{},[860,4083,1902],{},[948,4085,4086],{},[860,4087,1849],{},[948,4089,1327],{},[948,4091,1911],{},[930,4093,4094,4098,4102,4106],{},[948,4095,4096],{},[860,4097,1918],{},[948,4099,4100],{},[860,4101,1923],{},[948,4103,4104],{},[860,4105,1928],{},[948,4107,1931],{},[930,4109,4110,4114,4118,4122],{},[948,4111,4112],{},[860,4113,1938],{},[948,4115,4116],{},[860,4117,1228],{},[948,4119,4120],{},[860,4121,1416],{},[948,4123,1949],{},[930,4125,4126,4130,4134,4138],{},[948,4127,4128],{},[860,4129,1956],{},[948,4131,4132],{},[860,4133,1388],{},[948,4135,4136],{},[860,4137,1416],{},[948,4139,1967],{},[1081,4141,1971,4142],{"id":1970},[860,4143,1748],{},[1625,4145,4147],{"className":4146,"code":1977,"language":1630},[1628],[860,4148,1977],{"__ignoreMap":1633},[856,4150,1190,4151,1985],{},[860,4152,1984],{},[1081,4154,1989],{"id":1988},[856,4156,1992],{},[924,4158,4159,4169],{},[927,4160,4161],{},[930,4162,4163,4165,4167],{},[933,4164,2001],{},[933,4166,2004],{},[933,4168,941],{},[943,4170,4171,4183,4195],{},[930,4172,4173,4177,4181],{},[948,4174,4175],{},[860,4176,2015],{},[948,4178,4179],{},[860,4180,2020],{},[948,4182,2023],{},[930,4184,4185,4189,4193],{},[948,4186,4187],{},[860,4188,2030],{},[948,4190,4191],{},[860,4192,2035],{},[948,4194,2038],{},[930,4196,4197,4201,4205],{},[948,4198,4199],{},[860,4200,2045],{},[948,4202,4203],{},[860,4204,2050],{},[948,4206,2053],{},[1645,4208,4209],{},[856,4210,1190,4211,2060,4213,2063,4215,2067,4217,2071,4219,2074,4221,887],{},[860,4212,1768],{},[860,4214,1788],{},[860,4216,2066],{},[860,4218,2070],{},[860,4220,1902],{},[860,4222,2077],{},[908,4224],{},[916,4226,4227,1187],{"id":2082},[860,4228,870],{},[856,4230,1190,4231,2089,4233,887],{},[860,4232,870],{},[881,4234,91],{"href":92},[924,4236,4237,4249],{},[927,4238,4239],{},[930,4240,4241,4243,4245,4247],{},[933,4242,1205],{},[933,4244,1208],{},[933,4246,1211],{},[933,4248,1214],{},[943,4250,4251,4267,4285,4301,4321,4337,4355,4377],{},[930,4252,4253,4257,4261,4265],{},[948,4254,4255],{},[860,4256,1223],{},[948,4258,4259],{},[860,4260,1228],{},[948,4262,4263],{},[860,4264,1233],{},[948,4266,1741],{},[930,4268,4269,4273,4277,4281],{},[948,4270,4271],{},[860,4272,1748],{},[948,4274,4275],{},[860,4276,1228],{},[948,4278,4279],{},[860,4280,1253],{},[948,4282,1574,4283],{},[860,4284,1761],{},[930,4286,4287,4291,4295,4299],{},[948,4288,4289],{},[860,4290,2148],{},[948,4292,4293],{},[860,4294,2153],{},[948,4296,4297],{},[860,4298,1778],{},[948,4300,2160],{},[930,4302,4303,4307,4311,4315],{},[948,4304,4305],{},[860,4306,1956],{},[948,4308,4309],{},[860,4310,1388],{},[948,4312,4313],{},[860,4314,1416],{},[948,4316,2177,4317,2181,4319,2184],{},[860,4318,2180],{},[860,4320,1399],{},[930,4322,4323,4327,4331,4335],{},[948,4324,4325],{},[860,4326,1585],{},[948,4328,4329],{},[860,4330,1590],{},[948,4332,4333],{},[860,4334,1595],{},[948,4336,1857],{},[930,4338,4339,4343,4347,4351],{},[948,4340,4341],{},[860,4342,2207],{},[948,4344,4345],{},[860,4346,1590],{},[948,4348,4349],{},[860,4350,1253],{},[948,4352,2218,4353,2222],{},[860,4354,2221],{},[930,4356,4357,4361,4365,4369],{},[948,4358,4359],{},[860,4360,1938],{},[948,4362,4363],{},[860,4364,1228],{},[948,4366,4367],{},[860,4368,1416],{},[948,4370,4371,2241,4373,2244,4375,2247],{},[860,4372,1399],{},[860,4374,2180],{},[860,4376,2180],{},[930,4378,4379,4383,4387,4389],{},[948,4380,4381],{},[860,4382,2254],{},[948,4384,4385],{},[860,4386,1590],{},[948,4388,1327],{},[948,4390,2263,4391,887],{},[860,4392,2266],{},[1081,4394,1621,4395],{"id":2269},[860,4396,1748],{},[1625,4398,4400],{"className":4399,"code":2275,"language":1630},[1628],[860,4401,2275],{"__ignoreMap":1633},[856,4403,1190,4404,2282],{},[860,4405,1984],{},[1645,4407,4408],{},[856,4409,1190,4410,2289,4412,2293,4414,2297,4416,2300],{},[860,4411,2148],{},[860,4413,2292],{},[860,4415,2296],{},[881,4417,91],{"href":92},[908,4419],{},[916,4421,4422,1187],{"id":2305},[860,4423,874],{},[856,4425,1190,4426,2312],{},[860,4427,874],{},[924,4429,4430,4442],{},[927,4431,4432],{},[930,4433,4434,4436,4438,4440],{},[933,4435,1205],{},[933,4437,1208],{},[933,4439,1211],{},[933,4441,1214],{},[943,4443,4444,4460,4480,4496,4512,4528,4544,4560],{},[930,4445,4446,4450,4454,4458],{},[948,4447,4448],{},[860,4449,1223],{},[948,4451,4452],{},[860,4453,1228],{},[948,4455,4456],{},[860,4457,1233],{},[948,4459,1741],{},[930,4461,4462,4466,4470,4474],{},[948,4463,4464],{},[860,4465,1748],{},[948,4467,4468],{},[860,4469,1228],{},[948,4471,4472],{},[860,4473,1778],{},[948,4475,1574,4476,2363,4478,2367],{},[860,4477,1761],{},[860,4479,2366],{},[930,4481,4482,4486,4490,4494],{},[948,4483,4484],{},[860,4485,2148],{},[948,4487,4488],{},[860,4489,2153],{},[948,4491,4492],{},[860,4493,1778],{},[948,4495,2384],{},[930,4497,4498,4502,4506,4510],{},[948,4499,4500],{},[860,4501,2391],{},[948,4503,4504],{},[860,4505,2396],{},[948,4507,4508],{},[860,4509,1778],{},[948,4511,2403],{},[930,4513,4514,4518,4522,4526],{},[948,4515,4516],{},[860,4517,2410],{},[948,4519,4520],{},[860,4521,2415],{},[948,4523,4524],{},[860,4525,1778],{},[948,4527,2422],{},[930,4529,4530,4534,4538,4542],{},[948,4531,4532],{},[860,4533,1864],{},[948,4535,4536],{},[860,4537,1467],{},[948,4539,4540],{},[860,4541,1253],{},[948,4543,2439],{},[930,4545,4546,4550,4554,4558],{},[948,4547,4548],{},[860,4549,2446],{},[948,4551,4552],{},[860,4553,1388],{},[948,4555,4556],{},[860,4557,1416],{},[948,4559,2457],{},[930,4561,4562,4566,4570,4574],{},[948,4563,4564],{},[860,4565,1585],{},[948,4567,4568],{},[860,4569,1467],{},[948,4571,4572],{},[860,4573,1595],{},[948,4575,2474],{},[1081,4577,1989],{"id":2477},[856,4579,2480],{},[924,4581,4582,4590],{},[927,4583,4584],{},[930,4585,4586,4588],{},[933,4587,1205],{},[933,4589,941],{},[943,4591,4592,4600,4608,4618],{},[930,4593,4594,4598],{},[948,4595,4596],{},[860,4597,1748],{},[948,4599,2501],{},[930,4601,4602,4606],{},[948,4603,4604],{},[860,4605,2410],{},[948,4607,2510],{},[930,4609,4610,4614],{},[948,4611,4612],{},[860,4613,2148],{},[948,4615,2519,4616,2522],{},[860,4617,870],{},[930,4619,4620,4624],{},[948,4621,4622],{},[860,4623,2446],{},[948,4625,2531],{},[1081,4627,2535],{"id":2534},[1625,4629,4631],{"className":4630,"code":2539,"language":1630},[1628],[860,4632,2539],{"__ignoreMap":1633},[856,4634,2544],{},[2546,4636,4637],{},[856,4638,1190,4639,2552,4641,2555,4643,887],{},[860,4640,1748],{},[860,4642,2366],{},[860,4644,1748],{},[908,4646],{},[916,4648,4649,2565],{"id":2562},[860,4650,878],{},[856,4652,1190,4653,2570,4655,2573,4657,2576],{},[860,4654,878],{},[881,4656,883],{"href":35},[860,4658,862],{},[924,4660,4661,4671],{},[927,4662,4663],{},[930,4664,4665,4667,4669],{},[933,4666,1205],{},[933,4668,1208],{},[933,4670,1214],{},[943,4672,4673,4691,4705,4717,4729,4749,4763,4777,4793,4811,4829,4843,4859,4873,4887,4899,4913],{},[930,4674,4675,4679,4683],{},[948,4676,4677],{},[860,4678,1562],{},[948,4680,4681],{},[860,4682,1567],{},[948,4684,2603,4685,2607,4687,2611,4689,887],{},[860,4686,2606],{},[860,4688,2610],{},[860,4690,2366],{},[930,4692,4693,4697,4701],{},[948,4694,4695],{},[860,4696,2620],{},[948,4698,4699],{},[860,4700,2625],{},[948,4702,4703,2631],{},[951,4704,2630],{},[930,4706,4707,4711,4715],{},[948,4708,4709],{},[860,4710,2638],{},[948,4712,4713],{},[860,4714,2643],{},[948,4716,2646],{},[930,4718,4719,4723,4727],{},[948,4720,4721],{},[860,4722,2653],{},[948,4724,4725],{},[860,4726,2658],{},[948,4728,2661],{},[930,4730,4731,4743,4747],{},[948,4732,4733,1015,4735,1015,4737,1015,4739,1015,4741],{},[860,4734,1482],{},[860,4736,2670],{},[860,4738,2673],{},[860,4740,1498],{},[860,4742,1546],{},[948,4744,4745],{},[860,4746,2682],{},[948,4748,2685],{},[930,4750,4751,4757,4761],{},[948,4752,4753,1015,4755],{},[860,4754,2692],{},[860,4756,2695],{},[948,4758,4759],{},[860,4760,1831],{},[948,4762,2702],{},[930,4764,4765,4771,4775],{},[948,4766,4767,1015,4769],{},[860,4768,2709],{},[860,4770,2712],{},[948,4772,4773],{},[860,4774,2625],{},[948,4776,2719],{},[930,4778,4779,4787,4791],{},[948,4780,4781,1015,4783,1015,4785],{},[860,4782,2726],{},[860,4784,2729],{},[860,4786,2732],{},[948,4788,4789],{},[860,4790,2625],{},[948,4792,2739],{},[930,4794,4795,4805,4809],{},[948,4796,4797,1015,4799,1015,4801,1015,4803],{},[860,4798,2746],{},[860,4800,2749],{},[860,4802,2752],{},[860,4804,2755],{},[948,4806,4807],{},[860,4808,2625],{},[948,4810,2762],{},[930,4812,4813,4821,4825],{},[948,4814,4815,1015,4817,1015,4819],{},[860,4816,2769],{},[860,4818,2772],{},[860,4820,2775],{},[948,4822,4823],{},[860,4824,2625],{},[948,4826,2782,4827,887],{},[860,4828,2785],{},[930,4830,4831,4837,4841],{},[948,4832,4833,1015,4835],{},[860,4834,2792],{},[860,4836,2795],{},[948,4838,4839],{},[860,4840,1388],{},[948,4842,2802],{},[930,4844,4845,4851,4855],{},[948,4846,4847,1015,4849],{},[860,4848,2809],{},[860,4850,2812],{},[948,4852,4853],{},[860,4854,1388],{},[948,4856,2819,4857,887],{},[860,4858,2822],{},[930,4860,4861,4865,4869],{},[948,4862,4863],{},[860,4864,2829],{},[948,4866,4867],{},[860,4868,1388],{},[948,4870,2836,4871,887],{},[860,4872,2822],{},[930,4874,4875,4879,4883],{},[948,4876,4877],{},[860,4878,2845],{},[948,4880,4881],{},[860,4882,1228],{},[948,4884,2852,4885,2855],{},[860,4886,1399],{},[930,4888,4889,4893,4897],{},[948,4890,4891],{},[860,4892,2862],{},[948,4894,4895],{},[860,4896,1590],{},[948,4898,2869],{},[930,4900,4901,4905,4909],{},[948,4902,4903],{},[860,4904,2876],{},[948,4906,4907],{},[860,4908,1590],{},[948,4910,2883,4911],{},[860,4912,2886],{},[930,4914,4915,4919,4923],{},[948,4916,4917],{},[860,4918,2893],{},[948,4920,4921],{},[860,4922,1228],{},[948,4924,2900,4925,887],{},[860,4926,2180],{},[1645,4928,4929],{},[856,4930,1190,4931,2909,4933,2912,4935,2363,4937,2917,4939,2920,4941,2923,4943,2926],{},[860,4932,2620],{},[860,4934,878],{},[860,4936,1562],{},[860,4938,1562],{},[860,4940,2610],{},[860,4942,2620],{},[860,4944,1562],{},[908,4946],{},[911,4948,2932],{"id":2931},[856,4950,2935],{},[856,4952,2938],{},[1001,4954,4955,4961],{},[1004,4956,4957],{"name":2943,"type":1679},[856,4958,2946,4959,887],{},[860,4960,2949],{},[1004,4962,4963],{"name":2952,"type":1679},[856,4964,2955,4965,2959],{},[860,4966,2958],{},[856,4968,2962],{},[2964,4970,4971,4981],{},[2967,4972,4973,2972,4975,1015,4977,1015,4979,2981],{},[951,4974,2971],{},[860,4976,2975],{},[860,4978,2391],{},[860,4980,2980],{},[2967,4982,4983,2987],{},[951,4984,2986],{},[2546,4986,4987],{},[856,4988,2992],{},[908,4990],{},[911,4992,2998],{"id":2997},[856,4994,3001],{},[916,4996,4997],{"id":3004},[860,4998,3007],{},[856,5000,3010,5001,3014],{},[860,5002,3013],{},[1625,5004,5005],{"className":3017,"code":3018,"language":3019,"meta":1633,"style":1633},[860,5006,5007,5025,5029,5047,5051,5055],{"__ignoreMap":1633},[3023,5008,5009,5011,5013,5015,5017,5019,5021,5023],{"class":3025,"line":3026},[3023,5010,3030],{"class":3029},[3023,5012,3034],{"class":3033},[3023,5014,3007],{"class":3037},[3023,5016,3040],{"class":3033},[3023,5018,3043],{"class":3029},[3023,5020,3047],{"class":3046},[3023,5022,3051],{"class":3050},[3023,5024,3054],{"class":3046},[3023,5026,5027],{"class":3025,"line":3057},[3023,5028,3060],{"emptyLinePlaceholder":8},[3023,5030,5031,5033,5035,5037,5039,5041,5043,5045],{"class":3025,"line":3063},[3023,5032,3067],{"class":3066},[3023,5034,3071],{"class":3070},[3023,5036,3075],{"class":3074},[3023,5038,3078],{"class":3029},[3023,5040,3082],{"class":3081},[3023,5042,3085],{"class":3033},[3023,5044,3088],{"class":3037},[3023,5046,3091],{"class":3033},[3023,5048,5049],{"class":3025,"line":3094},[3023,5050,3098],{"class":3097},[3023,5052,5053],{"class":3025,"line":3101},[3023,5054,3104],{"class":3097},[3023,5056,5057],{"class":3025,"line":3107},[3023,5058,3110],{"class":3097},[856,5060,3113],{},[916,5062,5063],{"id":3116},[860,5064,3119],{},[856,5066,3122],{},[1625,5068,5069],{"className":3017,"code":3125,"language":3019,"meta":1633,"style":1633},[860,5070,5071,5089,5093],{"__ignoreMap":1633},[3023,5072,5073,5075,5077,5079,5081,5083,5085,5087],{"class":3025,"line":3026},[3023,5074,3030],{"class":3029},[3023,5076,3034],{"class":3033},[3023,5078,3119],{"class":3037},[3023,5080,3040],{"class":3033},[3023,5082,3043],{"class":3029},[3023,5084,3047],{"class":3046},[3023,5086,3051],{"class":3050},[3023,5088,3054],{"class":3046},[3023,5090,5091],{"class":3025,"line":3057},[3023,5092,3060],{"emptyLinePlaceholder":8},[3023,5094,5095,5097,5099,5101,5103],{"class":3025,"line":3063},[3023,5096,3119],{"class":3081},[3023,5098,3085],{"class":3033},[3023,5100,3158],{"class":3037},[3023,5102,3161],{"class":3033},[3023,5104,3164],{"class":3097},[856,5106,3167,5107,3170,5109,3173],{},[860,5108,2148],{},[860,5110,2410],{},[908,5112],{},[911,5114,3179],{"id":3178},[856,5116,3182,5117,3185],{},[860,5118,878],{},[1625,5120,5122],{"className":5121,"code":3189,"language":1630},[1628],[860,5123,3189],{"__ignoreMap":1633},[3193,5125,5126,5132,5138,5144,5154],{},[2967,5127,3197,5128,3201,5130,3204],{},[951,5129,3200],{},[951,5131,862],{},[2967,5133,3197,5134,3201,5136,887],{},[951,5135,1021],{},[951,5137,3211],{},[2967,5139,3197,5140,3201,5142,3219],{},[951,5141,1021],{},[951,5143,3218],{},[2967,5145,3197,5146,3224,5148,3228,5150,3231,5152,887],{},[951,5147,1021],{},[951,5149,3227],{},[860,5151,2366],{},[860,5153,1748],{},[2967,5155,3236,5156,3239,5158,3243],{},[951,5157,3227],{},[951,5159,3242],{},[856,5161,3246],{},[3248,5163,3250],{},{"title":1633,"searchDepth":3057,"depth":3057,"links":5165},[5166,5171,5178,5179,5183],{"id":913,"depth":3057,"text":914,"children":5167},[5168,5169,5170],{"id":918,"depth":3063,"text":919},{"id":1052,"depth":3063,"text":1053},{"id":1067,"depth":3063,"text":1068},{"id":1180,"depth":3057,"text":1181,"children":5172},[5173,5174,5175,5176,5177],{"id":1184,"depth":3063,"text":3261},{"id":1699,"depth":3063,"text":3263},{"id":2082,"depth":3063,"text":3265},{"id":2305,"depth":3063,"text":3267},{"id":2562,"depth":3063,"text":3269},{"id":2931,"depth":3057,"text":2932},{"id":2997,"depth":3057,"text":2998,"children":5180},[5181,5182],{"id":3004,"depth":3063,"text":3007},{"id":3116,"depth":3063,"text":3119},{"id":3178,"depth":3057,"text":3179},{},{"title":151,"description":3276},1780436283374]