[{"data":1,"prerenderedAt":5437},["ShallowReactive",2],{"navLinks":3,"sidebar_docs_navigation_\u002Fdocs\u002Fiam":64,"navigation":257,"navLinks_footer":837,"\u002Fdocs\u002Fiam\u002Fessentials\u002Foauth_page":850,"\u002Fdocs\u002Fiam\u002Fessentials\u002Foauth_surround":3439,"\u002Fdocs\u002Fiam\u002Fessentials\u002Foauth":3442},{"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":111,"body":852,"description":3431,"extension":3432,"icon":3433,"meta":3434,"module":3435,"navigation":8,"path":112,"rawbody":3436,"seo":3437,"stem":113,"__hash__":3438},"docs\u002Fdocs\u002Fiam\u002F01.essentials\u002F07.oauth.md",{"type":853,"value":854,"toc":3400},"minimark",[855,877,890,893,898,936,941,951,969,977,979,983,999,1004,1007,1280,1284,1295,1450,1456,1460,1566,1568,1572,1583,1668,1685,1691,1842,1857,1859,1863,2005,2007,2010,2020,2268,2286,2288,2291,2296,2300,2321,2345,2355,2357,2361,2365,2459,2462,2528,2532,2593,2595,2599,2613,2730,2734,2737,2754,2757,2759,2763,2766,2772,2775,3018,3024,3027,3113,3119,3122,3164,3166,3170,3177,3271,3273,3277,3391,3396],[856,857,858,859,863,864,867,868,871,872,876],"p",{},"The IAM service accepts OAuth social login through ",[860,861,862],"code",{},"POST \u002Fauth\u002FOAuth\u002F:providerName",". Providers are registered in the ",[860,865,866],{},"providers"," array in ",[860,869,870],{},"configuration()",". Each entry defines how the incoming OAuth profile is validated and mapped to the internal user schema. The service handles user creation for first-time OAuth users and token issuance for returning users, but it does ",[873,874,875],"strong",{},"not"," perform the OAuth authorization code exchange itself.",[878,879,880],"note",{},[856,881,882,883,889],{},"The IAM service receives the already-resolved profile data from the OAuth provider. Your client application (or a backend-for-frontend layer) is responsible for redirecting the user to the provider, exchanging the authorization code for an access token, and fetching the profile. For a full OAuth client implementation with code exchange, PKCE, and state verification, see the ",[884,885,886],"a",{"href":22},[860,887,888],{},"auth-H3Client","; module, which wraps this service and handles the complete OAuth flow.",[891,892],"hr",{},[894,895,897],"h2",{"id":896},"route","Route",[899,900,901,917],"table",{},[902,903,904],"thead",{},[905,906,907,911,914],"tr",{},[908,909,910],"th",{},"Method",[908,912,913],{},"Path",[908,915,916],{},"Body limit",[918,919,920],"tbody",{},[905,921,922,928,933],{},[923,924,925],"td",{},[860,926,927],{},"POST",[923,929,930],{},[860,931,932],{},"\u002Fauth\u002FOAuth\u002F:providerName",[923,934,935],{},"4 KB",[856,937,938],{},[873,939,940],{},"Middleware chain:",[942,943,948],"pre",{"className":944,"code":946,"language":947},[945],"language-text","validateContentType('application\u002Fjson'), express.json({ limit: '4kb' }), canary_id check, OAuthHandler\n","text",[860,949,946],{"__ignoreMap":950},"",[856,952,953,954,957,958,961,962,965,966,968],{},"The body limit is 4 KB (compared to 1 KB for ",[884,955,956],{"href":104},"login"," and ",[884,959,960],{"href":100},"signup",") to accommodate the larger profile payloads returned by some OAuth providers. The ",[860,963,964],{},"canary_id"," cookie must be present, as it is required to look up or create the visitor record that links the user to the ",[884,967,399],{"href":404}," fingerprint.",[856,970,971,972,976],{},"See ",[884,973,975],{"href":974},"\u002Fdocs\u002Fiam\u002Froutes","Routes"," for how to mount the authentication router.",[891,978],{},[894,980,982],{"id":981},"registering-a-provider","Registering a provider",[856,984,985,986,988,989,991,992,998],{},"Providers are defined in the ",[860,987,866],{}," array when calling ",[860,990,870],{},". There are two ways to define a provider: with a custom ",[884,993,997],{"href":994,"rel":995},"https:\u002F\u002Fzod.dev\u002F",[996],"nofollow","Zod"," schema, or with a field-type map.",[1000,1001,1003],"h3",{"id":1002},"option-1-custom-zod-schema","Option 1: Custom Zod schema",[856,1005,1006],{},"Use a full Zod schema when you need fine-grained validation of the provider's profile response.",[942,1008,1013],{"className":1009,"code":1010,"filename":1011,"language":1012,"meta":950,"style":950},"language-ts shiki shiki-themes light-plus light-plus dracula","import { configuration } from '@riavzon\u002Fauth'\nimport { z } from 'zod'\n\nconfiguration({\n  providers: [\n    {\n      name: 'google',\n      schema: z.object({\n        sub: z.string(),\n        email: z.string().email(),\n        name: z.string().optional(),\n        picture: z.string().url().optional(),\n        email_verified: z.boolean().optional(),\n      }),\n    },\n  ],\n  \u002F\u002F ...\n})\n","server\u002Fconfig\u002Fauth.ts","ts",[860,1014,1015,1049,1070,1076,1085,1098,1104,1123,1142,1160,1182,1203,1228,1249,1255,1261,1267,1274],{"__ignoreMap":950},[1016,1017,1020,1024,1028,1032,1035,1038,1042,1046],"span",{"class":1018,"line":1019},"line",1,[1016,1021,1023],{"class":1022},"sZ328","import",[1016,1025,1027],{"class":1026},"sDd4n"," { ",[1016,1029,1031],{"class":1030},"sjsA6","configuration",[1016,1033,1034],{"class":1026}," } ",[1016,1036,1037],{"class":1022},"from",[1016,1039,1041],{"class":1040},"sFkSl"," '",[1016,1043,1045],{"class":1044},"sFB1V","@riavzon\u002Fauth",[1016,1047,1048],{"class":1040},"'\n",[1016,1050,1052,1054,1056,1059,1061,1063,1065,1068],{"class":1018,"line":1051},2,[1016,1053,1023],{"class":1022},[1016,1055,1027],{"class":1026},[1016,1057,1058],{"class":1030},"z",[1016,1060,1034],{"class":1026},[1016,1062,1037],{"class":1022},[1016,1064,1041],{"class":1040},[1016,1066,1067],{"class":1044},"zod",[1016,1069,1048],{"class":1040},[1016,1071,1073],{"class":1018,"line":1072},3,[1016,1074,1075],{"emptyLinePlaceholder":8},"\n",[1016,1077,1079,1082],{"class":1018,"line":1078},4,[1016,1080,1031],{"class":1081},"sHOzp",[1016,1083,1084],{"class":1026},"({\n",[1016,1086,1088,1091,1095],{"class":1018,"line":1087},5,[1016,1089,1090],{"class":1030},"  providers",[1016,1092,1094],{"class":1093},"s34zl",":",[1016,1096,1097],{"class":1026}," [\n",[1016,1099,1101],{"class":1018,"line":1100},6,[1016,1102,1103],{"class":1026},"    {\n",[1016,1105,1107,1110,1112,1114,1117,1120],{"class":1018,"line":1106},7,[1016,1108,1109],{"class":1030},"      name",[1016,1111,1094],{"class":1093},[1016,1113,1041],{"class":1040},[1016,1115,1116],{"class":1044},"google",[1016,1118,1119],{"class":1040},"'",[1016,1121,1122],{"class":1026},",\n",[1016,1124,1126,1129,1131,1134,1137,1140],{"class":1018,"line":1125},8,[1016,1127,1128],{"class":1030},"      schema",[1016,1130,1094],{"class":1093},[1016,1132,1133],{"class":1030}," z",[1016,1135,1136],{"class":1026},".",[1016,1138,1139],{"class":1081},"object",[1016,1141,1084],{"class":1026},[1016,1143,1145,1148,1150,1152,1154,1157],{"class":1018,"line":1144},9,[1016,1146,1147],{"class":1030},"        sub",[1016,1149,1094],{"class":1093},[1016,1151,1133],{"class":1030},[1016,1153,1136],{"class":1026},[1016,1155,1156],{"class":1081},"string",[1016,1158,1159],{"class":1026},"(),\n",[1016,1161,1163,1166,1168,1170,1172,1174,1177,1180],{"class":1018,"line":1162},10,[1016,1164,1165],{"class":1030},"        email",[1016,1167,1094],{"class":1093},[1016,1169,1133],{"class":1030},[1016,1171,1136],{"class":1026},[1016,1173,1156],{"class":1081},[1016,1175,1176],{"class":1026},"().",[1016,1178,1179],{"class":1081},"email",[1016,1181,1159],{"class":1026},[1016,1183,1185,1188,1190,1192,1194,1196,1198,1201],{"class":1018,"line":1184},11,[1016,1186,1187],{"class":1030},"        name",[1016,1189,1094],{"class":1093},[1016,1191,1133],{"class":1030},[1016,1193,1136],{"class":1026},[1016,1195,1156],{"class":1081},[1016,1197,1176],{"class":1026},[1016,1199,1200],{"class":1081},"optional",[1016,1202,1159],{"class":1026},[1016,1204,1206,1209,1211,1213,1215,1217,1219,1222,1224,1226],{"class":1018,"line":1205},12,[1016,1207,1208],{"class":1030},"        picture",[1016,1210,1094],{"class":1093},[1016,1212,1133],{"class":1030},[1016,1214,1136],{"class":1026},[1016,1216,1156],{"class":1081},[1016,1218,1176],{"class":1026},[1016,1220,1221],{"class":1081},"url",[1016,1223,1176],{"class":1026},[1016,1225,1200],{"class":1081},[1016,1227,1159],{"class":1026},[1016,1229,1231,1234,1236,1238,1240,1243,1245,1247],{"class":1018,"line":1230},13,[1016,1232,1233],{"class":1030},"        email_verified",[1016,1235,1094],{"class":1093},[1016,1237,1133],{"class":1030},[1016,1239,1136],{"class":1026},[1016,1241,1242],{"class":1081},"boolean",[1016,1244,1176],{"class":1026},[1016,1246,1200],{"class":1081},[1016,1248,1159],{"class":1026},[1016,1250,1252],{"class":1018,"line":1251},14,[1016,1253,1254],{"class":1026},"      }),\n",[1016,1256,1258],{"class":1018,"line":1257},15,[1016,1259,1260],{"class":1026},"    },\n",[1016,1262,1264],{"class":1018,"line":1263},16,[1016,1265,1266],{"class":1026},"  ],\n",[1016,1268,1270],{"class":1018,"line":1269},17,[1016,1271,1273],{"class":1272},"sghk6","  \u002F\u002F ...\n",[1016,1275,1277],{"class":1018,"line":1276},18,[1016,1278,1279],{"class":1026},"})\n",[1000,1281,1283],{"id":1282},"option-2-field-type-map","Option 2: Field-type map",[856,1285,1286,1287,1290,1291,1294],{},"Use ",[860,1288,1289],{},"fields"," for a simpler definition when the provider returns a flat profile object with predictable types. This approach is useful for JSON-based configuration files where Zod schemas cannot be serialized. Append ",[860,1292,1293],{},"?"," to any type to mark the field optional.",[942,1296,1298],{"className":1009,"code":1297,"language":1012,"meta":950,"style":950},"configuration({\n  providers: [\n    {\n      name: 'github',\n      useStandardProfile: true,\n      fields: {\n        id: 'int',\n        email: 'email',\n        name: 'string?',\n        avatar_url: 'url?',\n        login: 'safeString?',\n      },\n    },\n  ],\n})\n",[860,1299,1300,1306,1314,1318,1333,1346,1356,1372,1386,1401,1417,1433,1438,1442,1446],{"__ignoreMap":950},[1016,1301,1302,1304],{"class":1018,"line":1019},[1016,1303,1031],{"class":1081},[1016,1305,1084],{"class":1026},[1016,1307,1308,1310,1312],{"class":1018,"line":1051},[1016,1309,1090],{"class":1030},[1016,1311,1094],{"class":1093},[1016,1313,1097],{"class":1026},[1016,1315,1316],{"class":1018,"line":1072},[1016,1317,1103],{"class":1026},[1016,1319,1320,1322,1324,1326,1329,1331],{"class":1018,"line":1078},[1016,1321,1109],{"class":1030},[1016,1323,1094],{"class":1093},[1016,1325,1041],{"class":1040},[1016,1327,1328],{"class":1044},"github",[1016,1330,1119],{"class":1040},[1016,1332,1122],{"class":1026},[1016,1334,1335,1338,1340,1344],{"class":1018,"line":1087},[1016,1336,1337],{"class":1030},"      useStandardProfile",[1016,1339,1094],{"class":1093},[1016,1341,1343],{"class":1342},"sjR7W"," true",[1016,1345,1122],{"class":1026},[1016,1347,1348,1351,1353],{"class":1018,"line":1100},[1016,1349,1350],{"class":1030},"      fields",[1016,1352,1094],{"class":1093},[1016,1354,1355],{"class":1026}," {\n",[1016,1357,1358,1361,1363,1365,1368,1370],{"class":1018,"line":1106},[1016,1359,1360],{"class":1030},"        id",[1016,1362,1094],{"class":1093},[1016,1364,1041],{"class":1040},[1016,1366,1367],{"class":1044},"int",[1016,1369,1119],{"class":1040},[1016,1371,1122],{"class":1026},[1016,1373,1374,1376,1378,1380,1382,1384],{"class":1018,"line":1125},[1016,1375,1165],{"class":1030},[1016,1377,1094],{"class":1093},[1016,1379,1041],{"class":1040},[1016,1381,1179],{"class":1044},[1016,1383,1119],{"class":1040},[1016,1385,1122],{"class":1026},[1016,1387,1388,1390,1392,1394,1397,1399],{"class":1018,"line":1144},[1016,1389,1187],{"class":1030},[1016,1391,1094],{"class":1093},[1016,1393,1041],{"class":1040},[1016,1395,1396],{"class":1044},"string?",[1016,1398,1119],{"class":1040},[1016,1400,1122],{"class":1026},[1016,1402,1403,1406,1408,1410,1413,1415],{"class":1018,"line":1162},[1016,1404,1405],{"class":1030},"        avatar_url",[1016,1407,1094],{"class":1093},[1016,1409,1041],{"class":1040},[1016,1411,1412],{"class":1044},"url?",[1016,1414,1119],{"class":1040},[1016,1416,1122],{"class":1026},[1016,1418,1419,1422,1424,1426,1429,1431],{"class":1018,"line":1184},[1016,1420,1421],{"class":1030},"        login",[1016,1423,1094],{"class":1093},[1016,1425,1041],{"class":1040},[1016,1427,1428],{"class":1044},"safeString?",[1016,1430,1119],{"class":1040},[1016,1432,1122],{"class":1026},[1016,1434,1435],{"class":1018,"line":1205},[1016,1436,1437],{"class":1026},"      },\n",[1016,1439,1440],{"class":1018,"line":1230},[1016,1441,1260],{"class":1026},[1016,1443,1444],{"class":1018,"line":1251},[1016,1445,1266],{"class":1026},[1016,1447,1448],{"class":1018,"line":1257},[1016,1449,1279],{"class":1026},[856,1451,1452,1453,1455],{},"When using ",[860,1454,1289],{},", the service builds a Zod schema from the field-type tokens at startup. The generated schema is functionally identical to a hand-written Zod schema.",[1000,1457,1459],{"id":1458},"available-field-types","Available field types",[899,1461,1462,1472],{},[902,1463,1464],{},[905,1465,1466,1469],{},[908,1467,1468],{},"Type",[908,1470,1471],{},"Description",[918,1473,1474,1488,1501,1514,1527,1540,1553],{},[905,1475,1476,1485],{},[923,1477,1478,1481,1482],{},[860,1479,1480],{},"'string'"," \u002F ",[860,1483,1484],{},"'string?'",[923,1486,1487],{},"Any string",[905,1489,1490,1498],{},[923,1491,1492,1481,1495],{},[860,1493,1494],{},"'email'",[860,1496,1497],{},"'email?'",[923,1499,1500],{},"Valid email address",[905,1502,1503,1511],{},[923,1504,1505,1481,1508],{},[860,1506,1507],{},"'url'",[860,1509,1510],{},"'url?'",[923,1512,1513],{},"Valid URL (HTTPS protocol enforced)",[905,1515,1516,1524],{},[923,1517,1518,1481,1521],{},[860,1519,1520],{},"'boolean'",[860,1522,1523],{},"'boolean?'",[923,1525,1526],{},"Boolean",[905,1528,1529,1537],{},[923,1530,1531,1481,1534],{},[860,1532,1533],{},"'number'",[860,1535,1536],{},"'number?'",[923,1538,1539],{},"Floating-point number",[905,1541,1542,1550],{},[923,1543,1544,1481,1547],{},[860,1545,1546],{},"'int'",[860,1548,1549],{},"'int?'",[923,1551,1552],{},"Integer",[905,1554,1555,1563],{},[923,1556,1557,1481,1560],{},[860,1558,1559],{},"'safeString'",[860,1561,1562],{},"'safeString?'",[923,1564,1565],{},"String with XSS sanitization applied",[891,1567],{},[894,1569,1571],{"id":1570},"standard-profile-mapping","Standard profile mapping",[856,1573,1574,1575,1578,1579,1582],{},"When ",[860,1576,1577],{},"useStandardProfile: true"," is set on a provider (or when using a custom schema that includes standard field names), the service automatically maps provider-specific field names to the internal ",[860,1580,1581],{},"StandardProfile"," interface after validation.",[899,1584,1585,1595],{},[902,1586,1587],{},[905,1588,1589,1592],{},[908,1590,1591],{},"Provider fields",[908,1593,1594],{},"Mapped to",[918,1596,1597,1614,1633,1646,1659],{},[905,1598,1599,1611],{},[923,1600,1601,1604,1605,1604,1608],{},[860,1602,1603],{},"sub",", ",[860,1606,1607],{},"id",[860,1609,1610],{},"user_id",[923,1612,1613],{},"Provider subject ID (at least one is required)",[905,1615,1616,1630],{},[923,1617,1618,1604,1621,1604,1624,1604,1627],{},[860,1619,1620],{},"picture",[860,1622,1623],{},"picture_url",[860,1625,1626],{},"avatar",[860,1628,1629],{},"avatar_url",[923,1631,1632],{},"Profile image URL",[905,1634,1635,1643],{},[923,1636,1637,1604,1640],{},[860,1638,1639],{},"family_name",[860,1641,1642],{},"last_name",[923,1644,1645],{},"Last name",[905,1647,1648,1656],{},[923,1649,1650,1604,1653],{},[860,1651,1652],{},"given_name",[860,1654,1655],{},"name",[923,1657,1658],{},"First name",[905,1660,1661,1665],{},[923,1662,1663],{},[860,1664,1179],{},[923,1666,1667],{},"Email (always required)",[856,1669,1670,1672,1673,1604,1675,1677,1678,1680,1681,1684],{},[860,1671,1179],{}," is required regardless of the mapping. The service rejects profiles that do not include a valid email address. At least one of ",[860,1674,1603],{},[860,1676,1607],{},", or ",[860,1679,1610],{}," must also be present. The schema enforces this with a Zod ",[860,1682,1683],{},".refine()"," check.",[1000,1686,1688,1690],{"id":1687},"standardprofile-interface",[860,1689,1581],{}," interface",[942,1692,1694],{"className":1009,"code":1693,"language":1012,"meta":950,"style":950},"interface StandardProfile {\n  sub?: string | number\n  id?: string | number\n  user_id?: string | number\n  email: string\n  email_verified?: boolean\n  name?: string\n  given_name?: string\n  family_name?: string\n  last_name?: string\n  avatar?: URL\n  locale?: any\n  location?: any\n}\n",[860,1695,1696,1708,1726,1739,1752,1762,1772,1781,1790,1799,1808,1818,1828,1837],{"__ignoreMap":950},[1016,1697,1698,1702,1706],{"class":1018,"line":1019},[1016,1699,1701],{"class":1700},"sl46w","interface",[1016,1703,1705],{"class":1704},"sFs1U"," StandardProfile",[1016,1707,1355],{"class":1026},[1016,1709,1710,1713,1717,1720,1723],{"class":1018,"line":1051},[1016,1711,1712],{"class":1030},"  sub",[1016,1714,1716],{"class":1715},"saOXh","?:",[1016,1718,1719],{"class":1704}," string",[1016,1721,1722],{"class":1715}," |",[1016,1724,1725],{"class":1704}," number\n",[1016,1727,1728,1731,1733,1735,1737],{"class":1018,"line":1072},[1016,1729,1730],{"class":1030},"  id",[1016,1732,1716],{"class":1715},[1016,1734,1719],{"class":1704},[1016,1736,1722],{"class":1715},[1016,1738,1725],{"class":1704},[1016,1740,1741,1744,1746,1748,1750],{"class":1018,"line":1078},[1016,1742,1743],{"class":1030},"  user_id",[1016,1745,1716],{"class":1715},[1016,1747,1719],{"class":1704},[1016,1749,1722],{"class":1715},[1016,1751,1725],{"class":1704},[1016,1753,1754,1757,1759],{"class":1018,"line":1087},[1016,1755,1756],{"class":1030},"  email",[1016,1758,1094],{"class":1715},[1016,1760,1761],{"class":1704}," string\n",[1016,1763,1764,1767,1769],{"class":1018,"line":1100},[1016,1765,1766],{"class":1030},"  email_verified",[1016,1768,1716],{"class":1715},[1016,1770,1771],{"class":1704}," boolean\n",[1016,1773,1774,1777,1779],{"class":1018,"line":1106},[1016,1775,1776],{"class":1030},"  name",[1016,1778,1716],{"class":1715},[1016,1780,1761],{"class":1704},[1016,1782,1783,1786,1788],{"class":1018,"line":1125},[1016,1784,1785],{"class":1030},"  given_name",[1016,1787,1716],{"class":1715},[1016,1789,1761],{"class":1704},[1016,1791,1792,1795,1797],{"class":1018,"line":1144},[1016,1793,1794],{"class":1030},"  family_name",[1016,1796,1716],{"class":1715},[1016,1798,1761],{"class":1704},[1016,1800,1801,1804,1806],{"class":1018,"line":1162},[1016,1802,1803],{"class":1030},"  last_name",[1016,1805,1716],{"class":1715},[1016,1807,1761],{"class":1704},[1016,1809,1810,1813,1815],{"class":1018,"line":1184},[1016,1811,1812],{"class":1030},"  avatar",[1016,1814,1716],{"class":1715},[1016,1816,1817],{"class":1704}," URL\n",[1016,1819,1820,1823,1825],{"class":1018,"line":1205},[1016,1821,1822],{"class":1030},"  locale",[1016,1824,1716],{"class":1715},[1016,1826,1827],{"class":1704}," any\n",[1016,1829,1830,1833,1835],{"class":1018,"line":1230},[1016,1831,1832],{"class":1030},"  location",[1016,1834,1716],{"class":1715},[1016,1836,1827],{"class":1704},[1016,1838,1839],{"class":1018,"line":1251},[1016,1840,1841],{"class":1026},"}\n",[856,1843,1844,1845,1847,1848,1604,1850,1604,1852,1604,1854,1856],{},"The ",[860,1846,1626],{}," field is resolved from whichever profile key is present, checking in order: ",[860,1849,1620],{},[860,1851,1623],{},[860,1853,1626],{},[860,1855,1629],{},". Only HTTPS URLs are accepted.",[891,1858],{},[894,1860,1862],{"id":1861},"the-authentication-pipeline","The authentication pipeline",[1864,1865,1867,1872,1882,1886,1895,1899,1914,1918,1935,1939,1964,1968,1974,1978,1985,1989],"steps",{"level":1866},"4",[1868,1869,1871],"h4",{"id":1870},"content-type-check","Content-Type check",[856,1873,1874,1875,1878,1879,1136],{},"The request must be ",[860,1876,1877],{},"application\u002Fjson",". Mismatches return ",[860,1880,1881],{},"403",[1868,1883,1885],{"id":1884},"provider-lookup","Provider lookup",[856,1887,1844,1888,1891,1892,1136],{},[860,1889,1890],{},":providerName"," path parameter is matched against the registered providers. If no provider matches the name exactly, the controller returns ",[860,1893,1894],{},"404",[1868,1896,1898],{"id":1897},"rate-limiting-ip","Rate limiting (IP)",[856,1900,1901,1902,1905,1906,1909,1910,1913],{},"A union limiter keyed on ",[860,1903,1904],{},"req.ip"," combines a burst guard (1 point per second, blocks 5 minutes) with a slow guard (25 points per hour, blocks 30 minutes). See ",[884,1907,147],{"href":1908},"\u002Fdocs\u002Fiam\u002Frate-limiting"," for the ",[860,1911,1912],{},"guard()"," architecture.",[1868,1915,1917],{"id":1916},"schema-validation","Schema validation",[856,1919,1920,1921,1604,1924,1677,1927,1930,1931,1934],{},"The request body is extracted from ",[860,1922,1923],{},"req.body.userInfo",[860,1925,1926],{},"req.body.user",[860,1928,1929],{},"req.body"," (in that order, to accommodate different OAuth client wrappers). The extracted profile is validated against the matched provider's Zod schema. If validation fails, the controller returns ",[860,1932,1933],{},"400"," with the Zod errors.",[1868,1936,1938],{"id":1937},"profile-mapping","Profile mapping",[856,1940,1941,1942,1945,1946,1948,1949,1951,1952,1604,1954,1677,1956,1958,1959,1961,1962,1136],{},"The validated data is passed through the provider's ",[860,1943,1944],{},"mapProfile()"," function, which normalizes the provider-specific field names into the ",[860,1947,1581],{}," shape. The ",[860,1950,1603],{}," field is resolved from ",[860,1953,1603],{},[860,1955,1607],{},[860,1957,1610],{},", whichever is present. The name is taken from ",[860,1960,1652],{}," or ",[860,1963,1655],{},[1868,1965,1967],{"id":1966},"rate-limiting-subject-id","Rate limiting (subject ID)",[856,1969,1970,1971,1973],{},"The provider subject ID (",[860,1972,1603],{},") is used as the key for a second rate limiter: 5 points per 5 minutes, blocking for 15 minutes. This prevents an attacker from hammering the OAuth endpoint with the same provider account.",[1868,1975,1977],{"id":1976},"rate-limiting-composite-key","Rate limiting (composite key)",[856,1979,1980,1981,1984],{},"A composite of ",[860,1982,1983],{},"ip + sub"," is used for a third rate limiter: 3 points per 10 minutes, blocking for 15 minutes.",[1868,1986,1988],{"id":1987},"user-lookup-or-creation","User lookup or creation",[856,1990,1991,1992,1995,1996,957,2000,2004],{},"The controller calls ",[860,1993,1994],{},"findUserByProvider(providerName, sub)"," to check if a user already exists with this provider and subject ID. The result determines the next step. See ",[884,1997,1999],{"href":1998},"#returning-users","Returning users",[884,2001,2003],{"href":2002},"#new-users","New users"," below.",[891,2006],{},[894,2008,2003],{"id":2009},"new-users",[856,2011,1574,2012,2015,2016,2019],{},[860,2013,2014],{},"findUserByProvider"," returns no match, the controller calls ",[860,2017,2018],{},"createOauthUser(canary_id, mappedProfile, providerName)",". This function:",[1864,2021,2022,2026,2053,2057,2077,2081,2088,2242,2254,2258],{"level":1866},[1868,2023,2025],{"id":2024},"look-up-the-visitor","Look up the visitor",[856,2027,2028,2029,2032,2033,2035,2036,1604,2039,1604,2042,2045,2046,2049,2050,1136],{},"Queries the ",[860,2030,2031],{},"visitors"," table using the ",[860,2034,964],{}," cookie to retrieve ",[860,2037,2038],{},"country",[860,2040,2041],{},"city",[860,2043,2044],{},"district",", and ",[860,2047,2048],{},"visitor_id",". If no visitor record exists, the function returns ",[860,2051,2052],{},"{ success: false, noCanaryCookie: true }",[1868,2054,2056],{"id":2055},"derive-the-last-name","Derive the last name",[856,2058,1844,2059,2062,2063,1604,2065,2067,2068,2070,2071,2073,2074,1136],{},[860,2060,2061],{},"deriveLastNames"," utility resolves the last name by checking, in priority order: ",[860,2064,1639],{},[860,2066,1642],{},", the portion of ",[860,2069,1655],{}," after the first word (using ",[860,2072,1652],{}," as a prefix if present). If none of these produce a value, the last name defaults to ",[860,2075,2076],{},"'No lastname'",[1868,2078,2080],{"id":2079},"insert-the-user-row","Insert the user row",[856,2082,2083,2084,2087],{},"The function inserts a row into the ",[860,2085,2086],{},"users"," table:",[899,2089,2090,2100],{},[902,2091,2092],{},[905,2093,2094,2097],{},[908,2095,2096],{},"Column",[908,2098,2099],{},"Source",[918,2101,2102,2115,2126,2135,2144,2157,2174,2185,2197,2208,2217,2225,2233],{},[905,2103,2104,2108],{},[923,2105,2106],{},[860,2107,1655],{},[923,2109,2110,1961,2112,2114],{},[860,2111,1652],{},[860,2113,1655],{}," from the profile",[905,2116,2117,2121],{},[923,2118,2119],{},[860,2120,1642],{},[923,2122,2123,2124],{},"Derived by ",[860,2125,2061],{},[905,2127,2128,2132],{},[923,2129,2130],{},[860,2131,1179],{},[923,2133,2134],{},"From the profile (required)",[905,2136,2137,2141],{},[923,2138,2139],{},[860,2140,1626],{},[923,2142,2143],{},"Resolved URL from the profile",[905,2145,2146,2151],{},[923,2147,2148],{},[860,2149,2150],{},"password_hash",[923,2152,2153,2154],{},"Literal ",[860,2155,2156],{},"'no_password'",[905,2158,2159,2164],{},[923,2160,2161],{},[860,2162,2163],{},"provider",[923,2165,2166,2167,1604,2170,2173],{},"The provider name (e.g. ",[860,2168,2169],{},"'google'",[860,2171,2172],{},"'github'",")",[905,2175,2176,2181],{},[923,2177,2178],{},[860,2179,2180],{},"provider_id",[923,2182,1970,2183,2173],{},[860,2184,1603],{},[905,2186,2187,2192],{},[923,2188,2189],{},[860,2190,2191],{},"remember_user",[923,2193,2194],{},[860,2195,2196],{},"false",[905,2198,2199,2204],{},[923,2200,2201],{},[860,2202,2203],{},"terms_and_privacy_agreement",[923,2205,2206],{},[860,2207,2196],{},[905,2209,2210,2214],{},[923,2211,2212],{},[860,2213,2038],{},[923,2215,2216],{},"From the visitor record",[905,2218,2219,2223],{},[923,2220,2221],{},[860,2222,2041],{},[923,2224,2216],{},[905,2226,2227,2231],{},[923,2228,2229],{},[860,2230,2044],{},[923,2232,2216],{},[905,2234,2235,2239],{},[923,2236,2237],{},[860,2238,2048],{},[923,2240,2241],{},"From the visitor record (UUID foreign key)",[856,2243,1844,2244,2246,2247,2250,2251,1136],{},[860,2245,1179],{}," column has a unique constraint. If a user with the same email already exists (e.g. they signed up with email\u002Fpassword previously), the database returns ",[860,2248,2249],{},"ER_DUP_ENTRY"," and the controller returns ",[860,2252,2253],{},"409 { error: 'E-mail already registered' }",[1868,2255,2257],{"id":2256},"issue-tokens","Issue tokens",[856,2259,2260,2261,957,2264,2267],{},"On success, ",[860,2262,2263],{},"generateRefreshToken",[860,2265,2266],{},"generateAccessToken"," are called to create a fresh session for the new user.",[2269,2270,2271],"warning",{},[856,2272,2273,2274,2276,2277,2279,2280,2282,2283,2285],{},"OAuth users have ",[860,2275,2150],{}," set to ",[860,2278,2156],{},". They cannot use the ",[884,2281,956],{"href":104}," route (which requires Argon2 password verification) and must always authenticate through their OAuth provider. If you want to allow OAuth users to set a password later, build a \"set password\" flow that updates the ",[860,2284,2150],{}," column.",[891,2287],{},[894,2289,1999],{"id":2290},"returning-users",[856,2292,1574,2293,2295],{},[860,2294,2014],{}," finds an existing user row matching the provider and subject ID, the function generates a new refresh token and access token for that user without creating a new row.",[1000,2297,2299],{"id":2298},"device-trust","Device trust",[856,2301,2302,2303,2306,2307,2310,2311,2313,2314,2316,2317,2320],{},"If ",[860,2304,2305],{},"trustUserDeviceOnAuth"," is ",[860,2308,2309],{},"true"," in the configuration and the ",[884,2312,399],{"href":35}," assigned a new ",[860,2315,2048],{}," for this request, the controller calls ",[860,2318,2319],{},"trustVisitor()"," to:",[2322,2323,2324,2333,2340],"ol",{},[2325,2326,2327,2328,2330,2331],"li",{},"Update the user's ",[860,2329,2048],{}," foreign key to point at the visitor row for the current ",[860,2332,964],{},[2325,2334,2335,2336,2339],{},"Call ",[860,2337,2338],{},"updateVisitors()"," from the Bot Detector to overwrite the fingerprint fields with the current request's geo and UA data",[2325,2341,2342,2343],{},"Regenerate the access token with the new ",[860,2344,2048],{},[856,2346,2347,2348,2351,2352,1136],{},"This re-baselines the fingerprint so that the ",[884,2349,2350],{"href":96},"anomaly detection"," engine compares future requests against the device the user most recently authenticated from. This is the same device-trust logic that runs during ",[884,2353,956],{"href":2354},"\u002Fdocs\u002Fiam\u002Fessentials\u002Flogin#device-trust",[891,2356],{},[894,2358,2360],{"id":2359},"response","Response",[1000,2362,2364],{"id":2363},"success-201","Success (201)",[942,2366,2369],{"className":2367,"code":2368,"language":5,"meta":950,"style":950},"language-json shiki shiki-themes light-plus light-plus dracula","{\n  \"ok\": true,\n  \"receivedAt\": \"2025-01-15T10:30:00.000Z\",\n  \"accessToken\": \"\u003Csigned JWT>\",\n  \"accessIat\": \"1705312200000\"\n}\n",[860,2370,2371,2376,2395,2416,2436,2455],{"__ignoreMap":950},[1016,2372,2373],{"class":1018,"line":1019},[1016,2374,2375],{"class":1026},"{\n",[1016,2377,2378,2382,2386,2389,2391,2393],{"class":1018,"line":1051},[1016,2379,2381],{"class":2380},"saJyd","  \"",[1016,2383,2385],{"class":2384},"s_W10","ok",[1016,2387,2388],{"class":2380},"\"",[1016,2390,1094],{"class":1715},[1016,2392,1343],{"class":1342},[1016,2394,1122],{"class":1026},[1016,2396,2397,2399,2402,2404,2406,2409,2412,2414],{"class":1018,"line":1072},[1016,2398,2381],{"class":2380},[1016,2400,2401],{"class":2384},"receivedAt",[1016,2403,2388],{"class":2380},[1016,2405,1094],{"class":1715},[1016,2407,2408],{"class":1040}," \"",[1016,2410,2411],{"class":1044},"2025-01-15T10:30:00.000Z",[1016,2413,2388],{"class":1040},[1016,2415,1122],{"class":1026},[1016,2417,2418,2420,2423,2425,2427,2429,2432,2434],{"class":1018,"line":1078},[1016,2419,2381],{"class":2380},[1016,2421,2422],{"class":2384},"accessToken",[1016,2424,2388],{"class":2380},[1016,2426,1094],{"class":1715},[1016,2428,2408],{"class":1040},[1016,2430,2431],{"class":1044},"\u003Csigned JWT>",[1016,2433,2388],{"class":1040},[1016,2435,1122],{"class":1026},[1016,2437,2438,2440,2443,2445,2447,2449,2452],{"class":1018,"line":1087},[1016,2439,2381],{"class":2380},[1016,2441,2442],{"class":2384},"accessIat",[1016,2444,2388],{"class":2380},[1016,2446,1094],{"class":1715},[1016,2448,2408],{"class":1040},[1016,2450,2451],{"class":1044},"1705312200000",[1016,2453,2454],{"class":1040},"\"\n",[1016,2456,2457],{"class":1018,"line":1100},[1016,2458,1841],{"class":1026},[856,2460,2461],{},"Two cookies are set alongside the JSON response:",[899,2463,2464,2477],{},[902,2465,2466],{},[905,2467,2468,2471,2474],{},[908,2469,2470],{},"Cookie",[908,2472,2473],{},"Value",[908,2475,2476],{},"Options",[918,2478,2479,2506],{},[905,2480,2481,2486,2492],{},[923,2482,2483],{},[860,2484,2485],{},"iat",[923,2487,2488,2491],{},[860,2489,2490],{},"Date.now()"," as string",[923,2493,2494,1604,2497,1604,2500,1604,2503],{},[860,2495,2496],{},"httpOnly",[860,2498,2499],{},"secure",[860,2501,2502],{},"sameSite: strict",[860,2504,2505],{},"path: \u002F",[905,2507,2508,2513,2516],{},[923,2509,2510],{},[860,2511,2512],{},"session",[923,2514,2515],{},"Raw refresh token (64 hex bytes)",[923,2517,2518,1604,2520,1604,2522,1604,2524,2527],{},[860,2519,2496],{},[860,2521,2499],{},[860,2523,2502],{},[860,2525,2526],{},"domain"," from config",[1000,2529,2531],{"id":2530},"error-responses","Error responses",[899,2533,2534,2544],{},[902,2535,2536],{},[905,2537,2538,2541],{},[908,2539,2540],{},"Status",[908,2542,2543],{},"Condition",[918,2545,2546,2558,2567,2583],{},[905,2547,2548,2552],{},[923,2549,2550],{},[860,2551,1933],{},[923,2553,2554,2555,2557],{},"Missing ",[860,2556,964],{}," cookie, empty body, schema validation failure, no visitor record",[905,2559,2560,2564],{},[923,2561,2562],{},[860,2563,1894],{},[923,2565,2566],{},"Provider name not found in registered providers",[905,2568,2569,2574],{},[923,2570,2571],{},[860,2572,2573],{},"409",[923,2575,2576,2577,2579,2580,2582],{},"Email already registered (duplicate ",[860,2578,1179],{}," in ",[860,2581,2086],{}," table)",[905,2584,2585,2590],{},[923,2586,2587],{},[860,2588,2589],{},"429",[923,2591,2592],{},"Rate limit exceeded on any of the three limiters",[891,2594],{},[894,2596,2598],{"id":2597},"the-oauth-request","The OAuth request",[856,2600,2601,2602,2604,2605,2607,2608,2610,2611,1136],{},"The client calls ",[860,2603,862],{}," with the profile data in the JSON body. The ",[860,2606,1890],{}," parameter must exactly match the ",[860,2609,1655],{}," registered in ",[860,2612,870],{},[942,2614,2616],{"className":1009,"code":2615,"language":1012,"meta":950,"style":950},"\u002F\u002F Client-side example (after exchanging the OAuth code for a profile)\nawait fetch('\u002Fauth\u002FOAuth\u002Fgoogle', {\n  method: 'POST',\n  credentials: 'include',\n  headers: { 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify(googleProfile),\n})\n",[860,2617,2618,2623,2644,2659,2675,2702,2726],{"__ignoreMap":950},[1016,2619,2620],{"class":1018,"line":1019},[1016,2621,2622],{"class":1272},"\u002F\u002F Client-side example (after exchanging the OAuth code for a profile)\n",[1016,2624,2625,2628,2631,2634,2636,2639,2641],{"class":1018,"line":1051},[1016,2626,2627],{"class":1022},"await",[1016,2629,2630],{"class":1081}," fetch",[1016,2632,2633],{"class":1026},"(",[1016,2635,1119],{"class":1040},[1016,2637,2638],{"class":1044},"\u002Fauth\u002FOAuth\u002Fgoogle",[1016,2640,1119],{"class":1040},[1016,2642,2643],{"class":1026},", {\n",[1016,2645,2646,2649,2651,2653,2655,2657],{"class":1018,"line":1072},[1016,2647,2648],{"class":1030},"  method",[1016,2650,1094],{"class":1093},[1016,2652,1041],{"class":1040},[1016,2654,927],{"class":1044},[1016,2656,1119],{"class":1040},[1016,2658,1122],{"class":1026},[1016,2660,2661,2664,2666,2668,2671,2673],{"class":1018,"line":1078},[1016,2662,2663],{"class":1030},"  credentials",[1016,2665,1094],{"class":1093},[1016,2667,1041],{"class":1040},[1016,2669,2670],{"class":1044},"include",[1016,2672,1119],{"class":1040},[1016,2674,1122],{"class":1026},[1016,2676,2677,2680,2682,2684,2686,2689,2691,2693,2695,2697,2699],{"class":1018,"line":1087},[1016,2678,2679],{"class":1030},"  headers",[1016,2681,1094],{"class":1093},[1016,2683,1027],{"class":1026},[1016,2685,1119],{"class":1040},[1016,2687,2688],{"class":1044},"Content-Type",[1016,2690,1119],{"class":1040},[1016,2692,1094],{"class":1093},[1016,2694,1041],{"class":1040},[1016,2696,1877],{"class":1044},[1016,2698,1119],{"class":1040},[1016,2700,2701],{"class":1026}," },\n",[1016,2703,2704,2707,2709,2713,2715,2718,2720,2723],{"class":1018,"line":1100},[1016,2705,2706],{"class":1030},"  body",[1016,2708,1094],{"class":1093},[1016,2710,2712],{"class":2711},"sPzPf"," JSON",[1016,2714,1136],{"class":1026},[1016,2716,2717],{"class":1081},"stringify",[1016,2719,2633],{"class":1026},[1016,2721,2722],{"class":1030},"googleProfile",[1016,2724,2725],{"class":1026},"),\n",[1016,2727,2728],{"class":1018,"line":1106},[1016,2729,1279],{"class":1026},[1000,2731,2733],{"id":2732},"body-extraction","Body extraction",[856,2735,2736],{},"The controller extracts the profile from the request body using a fallback chain:",[2322,2738,2739,2744,2749],{},[2325,2740,2741,2743],{},[860,2742,1923],{}," (used by some OAuth client libraries)",[2325,2745,2746,2748],{},[860,2747,1926],{}," (common in wrapper formats)",[2325,2750,2751,2753],{},[860,2752,1929],{}," (raw profile at the top level)",[856,2755,2756],{},"This flexibility allows different OAuth client implementations to send the profile in whichever wrapper format they use.",[891,2758],{},[894,2760,2762],{"id":2761},"library-exports","Library exports",[856,2764,2765],{},"When using the IAM service as a library (not the standalone service), three OAuth-related functions are exported:",[1000,2767,2769],{"id":2768},"createoauthuser",[860,2770,2771],{},"createOauthUser",[856,2773,2774],{},"Creates a new user from an OAuth profile. Call this in a custom OAuth handler when you want to control the flow.",[942,2776,2778],{"className":1009,"code":2777,"language":1012,"meta":950,"style":950},"import { createOauthUser } from '@riavzon\u002Fauth'\n\nconst result = await createOauthUser(\n  req.cookies.canary_id,\n  {\n    email: profile.email,\n    sub: profile.sub,\n    name: profile.name,\n    avatar: profile.picture,\n  },\n  'google'\n)\n\nif (result.duplicate) {\n  \u002F\u002F Email already registered\n}\n\nif (result.noCanaryCookie) {\n  \u002F\u002F No visitor record for the canary_id\n}\n\nif (result.success) {\n  \u002F\u002F result.accessToken and result.refreshToken are ready\n}\n",[860,2779,2780,2798,2802,2823,2839,2844,2860,2875,2890,2905,2910,2919,2924,2928,2947,2952,2956,2960,2975,2981,2986,2991,3007,3013],{"__ignoreMap":950},[1016,2781,2782,2784,2786,2788,2790,2792,2794,2796],{"class":1018,"line":1019},[1016,2783,1023],{"class":1022},[1016,2785,1027],{"class":1026},[1016,2787,2771],{"class":1030},[1016,2789,1034],{"class":1026},[1016,2791,1037],{"class":1022},[1016,2793,1041],{"class":1040},[1016,2795,1045],{"class":1044},[1016,2797,1048],{"class":1040},[1016,2799,2800],{"class":1018,"line":1051},[1016,2801,1075],{"emptyLinePlaceholder":8},[1016,2803,2804,2807,2811,2814,2817,2820],{"class":1018,"line":1072},[1016,2805,2806],{"class":1700},"const",[1016,2808,2810],{"class":2809},"s3JHE"," result",[1016,2812,2813],{"class":1715}," =",[1016,2815,2816],{"class":1022}," await",[1016,2818,2819],{"class":1081}," createOauthUser",[1016,2821,2822],{"class":1026},"(\n",[1016,2824,2825,2828,2830,2833,2835,2837],{"class":1018,"line":1078},[1016,2826,2827],{"class":1030},"  req",[1016,2829,1136],{"class":1026},[1016,2831,2832],{"class":1030},"cookies",[1016,2834,1136],{"class":1026},[1016,2836,964],{"class":1030},[1016,2838,1122],{"class":1026},[1016,2840,2841],{"class":1018,"line":1087},[1016,2842,2843],{"class":1026},"  {\n",[1016,2845,2846,2849,2851,2854,2856,2858],{"class":1018,"line":1100},[1016,2847,2848],{"class":1030},"    email",[1016,2850,1094],{"class":1093},[1016,2852,2853],{"class":1030}," profile",[1016,2855,1136],{"class":1026},[1016,2857,1179],{"class":1030},[1016,2859,1122],{"class":1026},[1016,2861,2862,2865,2867,2869,2871,2873],{"class":1018,"line":1106},[1016,2863,2864],{"class":1030},"    sub",[1016,2866,1094],{"class":1093},[1016,2868,2853],{"class":1030},[1016,2870,1136],{"class":1026},[1016,2872,1603],{"class":1030},[1016,2874,1122],{"class":1026},[1016,2876,2877,2880,2882,2884,2886,2888],{"class":1018,"line":1125},[1016,2878,2879],{"class":1030},"    name",[1016,2881,1094],{"class":1093},[1016,2883,2853],{"class":1030},[1016,2885,1136],{"class":1026},[1016,2887,1655],{"class":1030},[1016,2889,1122],{"class":1026},[1016,2891,2892,2895,2897,2899,2901,2903],{"class":1018,"line":1144},[1016,2893,2894],{"class":1030},"    avatar",[1016,2896,1094],{"class":1093},[1016,2898,2853],{"class":1030},[1016,2900,1136],{"class":1026},[1016,2902,1620],{"class":1030},[1016,2904,1122],{"class":1026},[1016,2906,2907],{"class":1018,"line":1162},[1016,2908,2909],{"class":1026},"  },\n",[1016,2911,2912,2915,2917],{"class":1018,"line":1184},[1016,2913,2914],{"class":1040},"  '",[1016,2916,1116],{"class":1044},[1016,2918,1048],{"class":1040},[1016,2920,2921],{"class":1018,"line":1205},[1016,2922,2923],{"class":1026},")\n",[1016,2925,2926],{"class":1018,"line":1230},[1016,2927,1075],{"emptyLinePlaceholder":8},[1016,2929,2930,2933,2936,2939,2941,2944],{"class":1018,"line":1251},[1016,2931,2932],{"class":1022},"if",[1016,2934,2935],{"class":1026}," (",[1016,2937,2938],{"class":1030},"result",[1016,2940,1136],{"class":1026},[1016,2942,2943],{"class":1030},"duplicate",[1016,2945,2946],{"class":1026},") {\n",[1016,2948,2949],{"class":1018,"line":1257},[1016,2950,2951],{"class":1272},"  \u002F\u002F Email already registered\n",[1016,2953,2954],{"class":1018,"line":1263},[1016,2955,1841],{"class":1026},[1016,2957,2958],{"class":1018,"line":1269},[1016,2959,1075],{"emptyLinePlaceholder":8},[1016,2961,2962,2964,2966,2968,2970,2973],{"class":1018,"line":1276},[1016,2963,2932],{"class":1022},[1016,2965,2935],{"class":1026},[1016,2967,2938],{"class":1030},[1016,2969,1136],{"class":1026},[1016,2971,2972],{"class":1030},"noCanaryCookie",[1016,2974,2946],{"class":1026},[1016,2976,2978],{"class":1018,"line":2977},19,[1016,2979,2980],{"class":1272},"  \u002F\u002F No visitor record for the canary_id\n",[1016,2982,2984],{"class":1018,"line":2983},20,[1016,2985,1841],{"class":1026},[1016,2987,2989],{"class":1018,"line":2988},21,[1016,2990,1075],{"emptyLinePlaceholder":8},[1016,2992,2994,2996,2998,3000,3002,3005],{"class":1018,"line":2993},22,[1016,2995,2932],{"class":1022},[1016,2997,2935],{"class":1026},[1016,2999,2938],{"class":1030},[1016,3001,1136],{"class":1026},[1016,3003,3004],{"class":1030},"success",[1016,3006,2946],{"class":1026},[1016,3008,3010],{"class":1018,"line":3009},23,[1016,3011,3012],{"class":1272},"  \u002F\u002F result.accessToken and result.refreshToken are ready\n",[1016,3014,3016],{"class":1018,"line":3015},24,[1016,3017,1841],{"class":1026},[1000,3019,3021],{"id":3020},"finduserbyoauthprovider",[860,3022,3023],{},"findUserByOauthProvider",[856,3025,3026],{},"Looks up an existing user by provider name and provider subject ID without creating a new account.",[942,3028,3030],{"className":1009,"code":3029,"language":1012,"meta":950,"style":950},"import { findUserByOauthProvider } from '@riavzon\u002Fauth'\n\nconst result = await findUserByOauthProvider('google', googleProfile.sub)\n\nif (result.user) {\n  \u002F\u002F result.id, result.visitor_id, result.accessToken, result.refreshToken\n}\n",[860,3031,3032,3050,3054,3085,3089,3104,3109],{"__ignoreMap":950},[1016,3033,3034,3036,3038,3040,3042,3044,3046,3048],{"class":1018,"line":1019},[1016,3035,1023],{"class":1022},[1016,3037,1027],{"class":1026},[1016,3039,3023],{"class":1030},[1016,3041,1034],{"class":1026},[1016,3043,1037],{"class":1022},[1016,3045,1041],{"class":1040},[1016,3047,1045],{"class":1044},[1016,3049,1048],{"class":1040},[1016,3051,3052],{"class":1018,"line":1051},[1016,3053,1075],{"emptyLinePlaceholder":8},[1016,3055,3056,3058,3060,3062,3064,3067,3069,3071,3073,3075,3077,3079,3081,3083],{"class":1018,"line":1072},[1016,3057,2806],{"class":1700},[1016,3059,2810],{"class":2809},[1016,3061,2813],{"class":1715},[1016,3063,2816],{"class":1022},[1016,3065,3066],{"class":1081}," findUserByOauthProvider",[1016,3068,2633],{"class":1026},[1016,3070,1119],{"class":1040},[1016,3072,1116],{"class":1044},[1016,3074,1119],{"class":1040},[1016,3076,1604],{"class":1026},[1016,3078,2722],{"class":1030},[1016,3080,1136],{"class":1026},[1016,3082,1603],{"class":1030},[1016,3084,2923],{"class":1026},[1016,3086,3087],{"class":1018,"line":1078},[1016,3088,1075],{"emptyLinePlaceholder":8},[1016,3090,3091,3093,3095,3097,3099,3102],{"class":1018,"line":1087},[1016,3092,2932],{"class":1022},[1016,3094,2935],{"class":1026},[1016,3096,2938],{"class":1030},[1016,3098,1136],{"class":1026},[1016,3100,3101],{"class":1030},"user",[1016,3103,2946],{"class":1026},[1016,3105,3106],{"class":1018,"line":1100},[1016,3107,3108],{"class":1272},"  \u002F\u002F result.id, result.visitor_id, result.accessToken, result.refreshToken\n",[1016,3110,3111],{"class":1018,"line":1106},[1016,3112,1841],{"class":1026},[1000,3114,3116],{"id":3115},"configureoauthproviders",[860,3117,3118],{},"configureOauthProviders",[856,3120,3121],{},"Inspects or extends the registered provider list at runtime. Returns the array of configured provider definitions.",[942,3123,3125],{"className":1009,"code":3124,"language":1012,"meta":950,"style":950},"import { configureOauthProviders } from '@riavzon\u002Fauth'\n\nconst providers = configureOauthProviders()\n",[860,3126,3127,3145,3149],{"__ignoreMap":950},[1016,3128,3129,3131,3133,3135,3137,3139,3141,3143],{"class":1018,"line":1019},[1016,3130,1023],{"class":1022},[1016,3132,1027],{"class":1026},[1016,3134,3118],{"class":1030},[1016,3136,1034],{"class":1026},[1016,3138,1037],{"class":1022},[1016,3140,1041],{"class":1040},[1016,3142,1045],{"class":1044},[1016,3144,1048],{"class":1040},[1016,3146,3147],{"class":1018,"line":1051},[1016,3148,1075],{"emptyLinePlaceholder":8},[1016,3150,3151,3153,3156,3158,3161],{"class":1018,"line":1072},[1016,3152,2806],{"class":1700},[1016,3154,3155],{"class":2809}," providers",[1016,3157,2813],{"class":1715},[1016,3159,3160],{"class":1081}," configureOauthProviders",[1016,3162,3163],{"class":1026},"()\n",[891,3165],{},[894,3167,3169],{"id":3168},"rate-limiter-reference","Rate limiter reference",[856,3171,3172,3173,3176],{},"All OAuth rate limiters are configurable under ",[860,3174,3175],{},"rate_limiters"," in the configuration object. The defaults are:",[899,3178,3179,3198],{},[902,3180,3181],{},[905,3182,3183,3186,3189,3192,3195],{},[908,3184,3185],{},"Limiter",[908,3187,3188],{},"Key",[908,3190,3191],{},"Points",[908,3193,3194],{},"Window",[908,3196,3197],{},"Block duration",[918,3199,3200,3218,3236,3254],{},[905,3201,3202,3205,3209,3212,3215],{},[923,3203,3204],{},"IP burst",[923,3206,3207],{},[860,3208,1904],{},[923,3210,3211],{},"1 \u002F 1 second",[923,3213,3214],{},"1 s",[923,3216,3217],{},"5 min",[905,3219,3220,3223,3227,3230,3233],{},[923,3221,3222],{},"IP slow",[923,3224,3225],{},[860,3226,1904],{},[923,3228,3229],{},"25 \u002F 1 hour",[923,3231,3232],{},"1 h",[923,3234,3235],{},"30 min",[905,3237,3238,3241,3246,3249,3251],{},[923,3239,3240],{},"Subject ID",[923,3242,3243,3244],{},"Provider ",[860,3245,1603],{},[923,3247,3248],{},"5 \u002F 5 minutes",[923,3250,3217],{},[923,3252,3253],{},"15 min",[905,3255,3256,3259,3263,3266,3269],{},[923,3257,3258],{},"Composite",[923,3260,3261],{},[860,3262,1983],{},[923,3264,3265],{},"3 \u002F 10 minutes",[923,3267,3268],{},"10 min",[923,3270,3253],{},[891,3272],{},[894,3274,3276],{"id":3275},"configuration-reference","Configuration reference",[899,3278,3279,3293],{},[902,3280,3281],{},[905,3282,3283,3286,3289,3291],{},[908,3284,3285],{},"Option",[908,3287,3288],{},"Location",[908,3290,1468],{},[908,3292,1471],{},[918,3294,3295,3312,3329,3349,3370],{},[905,3296,3297,3301,3304,3309],{},[923,3298,3299],{},[860,3300,866],{},[923,3302,3303],{},"Root config",[923,3305,3306],{},[860,3307,3308],{},"array",[923,3310,3311],{},"Array of provider definitions (Zod schema or field-type map)",[905,3313,3314,3318,3320,3324],{},[923,3315,3316],{},[860,3317,2305],{},[923,3319,3303],{},[923,3321,3322],{},[860,3323,1242],{},[923,3325,3326,3327,2173],{},"Whether OAuth login re-baselines the visitor fingerprint (default: ",[860,3328,2196],{},[905,3330,3331,3336,3341,3346],{},[923,3332,3333],{},[860,3334,3335],{},"jwt.refresh_tokens.refresh_ttl",[923,3337,3338],{},[860,3339,3340],{},"jwt",[923,3342,3343],{},[860,3344,3345],{},"number",[923,3347,3348],{},"Refresh token lifetime in milliseconds",[905,3350,3351,3356,3360,3364],{},[923,3352,3353],{},[860,3354,3355],{},"jwt.refresh_tokens.domain",[923,3357,3358],{},[860,3359,3340],{},[923,3361,3362],{},[860,3363,1156],{},[923,3365,3366,3367,3369],{},"Cookie domain for the ",[860,3368,2512],{}," cookie",[905,3371,3372,3377,3381,3385],{},[923,3373,3374],{},[860,3375,3376],{},"jwt.access_tokens.expiresIn",[923,3378,3379],{},[860,3380,3340],{},[923,3382,3383],{},[860,3384,1156],{},[923,3386,3387,3388,2173],{},"Access token JWT expiry (default: ",[860,3389,3390],{},"'15m'",[856,3392,971,3393,3395],{},[884,3394,237],{"href":238}," for the full schema reference.",[3397,3398,3399],"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 .sHOzp, html code.shiki .sHOzp{--shiki-light:#795E26;--shiki-default:#795E26;--shiki-dark:#50FA7B}html pre.shiki code .s34zl, html code.shiki .s34zl{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#FF79C6}html pre.shiki code .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);}html pre.shiki code .sjR7W, html code.shiki .sjR7W{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#BD93F9}html pre.shiki code .sl46w, html code.shiki .sl46w{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#FF79C6}html pre.shiki code .sFs1U, html code.shiki .sFs1U{--shiki-light:#267F99;--shiki-light-font-style:inherit;--shiki-default:#267F99;--shiki-default-font-style:inherit;--shiki-dark:#8BE9FD;--shiki-dark-font-style:italic}html pre.shiki code .saOXh, html code.shiki .saOXh{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#FF79C6}html pre.shiki code .saJyd, html code.shiki .saJyd{--shiki-light:#0451A5;--shiki-default:#0451A5;--shiki-dark:#8BE9FE}html pre.shiki code .s_W10, html code.shiki .s_W10{--shiki-light:#0451A5;--shiki-default:#0451A5;--shiki-dark:#8BE9FD}html pre.shiki code .sPzPf, html code.shiki .sPzPf{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#BD93F9}html pre.shiki code .s3JHE, html code.shiki .s3JHE{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#F8F8F2}",{"title":950,"searchDepth":1051,"depth":1051,"links":3401},[3402,3403,3408,3412,3413,3414,3417,3421,3424,3429,3430],{"id":896,"depth":1051,"text":897},{"id":981,"depth":1051,"text":982,"children":3404},[3405,3406,3407],{"id":1002,"depth":1072,"text":1003},{"id":1282,"depth":1072,"text":1283},{"id":1458,"depth":1072,"text":1459},{"id":1570,"depth":1051,"text":1571,"children":3409},[3410],{"id":1687,"depth":1072,"text":3411},"StandardProfile interface",{"id":1861,"depth":1051,"text":1862},{"id":2009,"depth":1051,"text":2003},{"id":2290,"depth":1051,"text":1999,"children":3415},[3416],{"id":2298,"depth":1072,"text":2299},{"id":2359,"depth":1051,"text":2360,"children":3418},[3419,3420],{"id":2363,"depth":1072,"text":2364},{"id":2530,"depth":1072,"text":2531},{"id":2597,"depth":1051,"text":2598,"children":3422},[3423],{"id":2732,"depth":1072,"text":2733},{"id":2761,"depth":1051,"text":2762,"children":3425},[3426,3427,3428],{"id":2768,"depth":1072,"text":2771},{"id":3020,"depth":1072,"text":3023},{"id":3115,"depth":1072,"text":3118},{"id":3168,"depth":1051,"text":3169},{"id":3275,"depth":1051,"text":3276},"How the IAM service handles OAuth social login, provider registration with schema or field-type maps, the standard profile mapping, user creation and deduplication, device trust, and the full request lifecycle.","md","i-lucide-users",{},null,"---\ntitle: OAuth\ndescription: How the IAM service handles OAuth social login, provider registration with schema or field-type maps, the standard profile mapping, user creation and deduplication, device trust, and the full request lifecycle.\nicon: i-lucide-users\n---\n\nThe IAM service accepts OAuth social login through `POST \u002Fauth\u002FOAuth\u002F:providerName`. Providers are registered in the `providers` array in `configuration()`. Each entry defines how the incoming OAuth profile is validated and mapped to the internal user schema. The service handles user creation for first-time OAuth users and token issuance for returning users, but it does **not** perform the OAuth authorization code exchange itself.\n\n::note\nThe IAM service receives the already-resolved profile data from the OAuth provider. Your client application (or a backend-for-frontend layer) is responsible for redirecting the user to the provider, exchanging the authorization code for an access token, and fetching the profile. For a full OAuth client implementation with code exchange, PKCE, and state verification, see the [`auth-H3Client`](\u002Fdocs\u002Fauth-h3client); module, which wraps this service and handles the complete OAuth flow.\n::\n\n---\n\n## Route\n\n| Method | Path | Body limit |\n|---|---|---|\n| `POST` | `\u002Fauth\u002FOAuth\u002F:providerName` | 4 KB |\n\n**Middleware chain:**\n\n```\nvalidateContentType('application\u002Fjson'), express.json({ limit: '4kb' }), canary_id check, OAuthHandler\n```\n\nThe body limit is 4 KB (compared to 1 KB for [login](\u002Fdocs\u002Fiam\u002Fessentials\u002Flogin) and [signup](\u002Fdocs\u002Fiam\u002Fessentials\u002Fsignup)) to accommodate the larger profile payloads returned by some OAuth providers. The `canary_id` cookie must be present, as it is required to look up or create the visitor record that links the user to the [Bot Detector](\u002Fdocs\u002Fbot-detection\u002Fgetting-started) fingerprint.\n\nSee [Routes](\u002Fdocs\u002Fiam\u002Froutes) for how to mount the authentication router.\n\n---\n\n## Registering a provider\n\nProviders are defined in the `providers` array when calling `configuration()`. There are two ways to define a provider: with a custom [Zod](https:\u002F\u002Fzod.dev\u002F) schema, or with a field-type map.\n\n### Option 1: Custom Zod schema\n\nUse a full Zod schema when you need fine-grained validation of the provider's profile response.\n\n```ts [server\u002Fconfig\u002Fauth.ts]\nimport { configuration } from '@riavzon\u002Fauth'\nimport { z } from 'zod'\n\nconfiguration({\n  providers: [\n    {\n      name: 'google',\n      schema: z.object({\n        sub: z.string(),\n        email: z.string().email(),\n        name: z.string().optional(),\n        picture: z.string().url().optional(),\n        email_verified: z.boolean().optional(),\n      }),\n    },\n  ],\n  \u002F\u002F ...\n})\n```\n\n### Option 2: Field-type map\n\nUse `fields` for a simpler definition when the provider returns a flat profile object with predictable types. This approach is useful for JSON-based configuration files where Zod schemas cannot be serialized. Append `?` to any type to mark the field optional.\n\n```ts\nconfiguration({\n  providers: [\n    {\n      name: 'github',\n      useStandardProfile: true,\n      fields: {\n        id: 'int',\n        email: 'email',\n        name: 'string?',\n        avatar_url: 'url?',\n        login: 'safeString?',\n      },\n    },\n  ],\n})\n```\n\nWhen using `fields`, the service builds a Zod schema from the field-type tokens at startup. The generated schema is functionally identical to a hand-written Zod schema.\n\n### Available field types\n\n| Type | Description |\n|------|-------------|\n| `'string'` \u002F `'string?'` | Any string |\n| `'email'` \u002F `'email?'` | Valid email address |\n| `'url'` \u002F `'url?'` | Valid URL (HTTPS protocol enforced) |\n| `'boolean'` \u002F `'boolean?'` | Boolean |\n| `'number'` \u002F `'number?'` | Floating-point number |\n| `'int'` \u002F `'int?'` | Integer |\n| `'safeString'` \u002F `'safeString?'` | String with XSS sanitization applied |\n\n---\n\n## Standard profile mapping\n\nWhen `useStandardProfile: true` is set on a provider (or when using a custom schema that includes standard field names), the service automatically maps provider-specific field names to the internal `StandardProfile` interface after validation.\n\n| Provider fields | Mapped to |\n|----------------|-----------|\n| `sub`, `id`, `user_id` | Provider subject ID (at least one is required) |\n| `picture`, `picture_url`, `avatar`, `avatar_url` | Profile image URL |\n| `family_name`, `last_name` | Last name |\n| `given_name`, `name` | First name |\n| `email` | Email (always required) |\n\n`email` is required regardless of the mapping. The service rejects profiles that do not include a valid email address. At least one of `sub`, `id`, or `user_id` must also be present. The schema enforces this with a Zod `.refine()` check.\n\n### `StandardProfile` interface\n\n```ts\ninterface StandardProfile {\n  sub?: string | number\n  id?: string | number\n  user_id?: string | number\n  email: string\n  email_verified?: boolean\n  name?: string\n  given_name?: string\n  family_name?: string\n  last_name?: string\n  avatar?: URL\n  locale?: any\n  location?: any\n}\n```\n\nThe `avatar` field is resolved from whichever profile key is present, checking in order: `picture`, `picture_url`, `avatar`, `avatar_url`. Only HTTPS URLs are accepted.\n\n---\n\n## The authentication pipeline\n\n::steps{level=\"4\"}\n#### Content-Type check\n\nThe request must be `application\u002Fjson`. Mismatches return `403`.\n\n#### Provider lookup\n\nThe `:providerName` path parameter is matched against the registered providers. If no provider matches the name exactly, the controller returns `404`.\n\n#### Rate limiting (IP)\n\nA union limiter keyed on `req.ip` combines a burst guard (1 point per second, blocks 5 minutes) with a slow guard (25 points per hour, blocks 30 minutes). See [Rate Limiting](\u002Fdocs\u002Fiam\u002Frate-limiting) for the `guard()` architecture.\n\n#### Schema validation\n\nThe request body is extracted from `req.body.userInfo`, `req.body.user`, or `req.body` (in that order, to accommodate different OAuth client wrappers). The extracted profile is validated against the matched provider's Zod schema. If validation fails, the controller returns `400` with the Zod errors.\n\n#### Profile mapping\n\nThe validated data is passed through the provider's `mapProfile()` function, which normalizes the provider-specific field names into the `StandardProfile` shape. The `sub` field is resolved from `sub`, `id`, or `user_id`, whichever is present. The name is taken from `given_name` or `name`.\n\n#### Rate limiting (subject ID)\n\nThe provider subject ID (`sub`) is used as the key for a second rate limiter: 5 points per 5 minutes, blocking for 15 minutes. This prevents an attacker from hammering the OAuth endpoint with the same provider account.\n\n#### Rate limiting (composite key)\n\nA composite of `ip + sub` is used for a third rate limiter: 3 points per 10 minutes, blocking for 15 minutes.\n\n#### User lookup or creation\n\nThe controller calls `findUserByProvider(providerName, sub)` to check if a user already exists with this provider and subject ID. The result determines the next step. See [Returning users](#returning-users) and [New users](#new-users) below.\n::\n\n---\n\n## New users\n\nWhen `findUserByProvider` returns no match, the controller calls `createOauthUser(canary_id, mappedProfile, providerName)`. This function:\n\n::steps{level=\"4\"}\n#### Look up the visitor\n\nQueries the `visitors` table using the `canary_id` cookie to retrieve `country`, `city`, `district`, and `visitor_id`. If no visitor record exists, the function returns `{ success: false, noCanaryCookie: true }`.\n\n#### Derive the last name\n\nThe `deriveLastNames` utility resolves the last name by checking, in priority order: `family_name`, `last_name`, the portion of `name` after the first word (using `given_name` as a prefix if present). If none of these produce a value, the last name defaults to `'No lastname'`.\n\n#### Insert the user row\n\nThe function inserts a row into the `users` table:\n\n| Column | Source |\n|---|---|\n| `name` | `given_name` or `name` from the profile |\n| `last_name` | Derived by `deriveLastNames` |\n| `email` | From the profile (required) |\n| `avatar` | Resolved URL from the profile |\n| `password_hash` | Literal `'no_password'` |\n| `provider` | The provider name (e.g. `'google'`, `'github'`) |\n| `provider_id` | The provider subject ID (`sub`) |\n| `remember_user` | `false` |\n| `terms_and_privacy_agreement` | `false` |\n| `country` | From the visitor record |\n| `city` | From the visitor record |\n| `district` | From the visitor record |\n| `visitor_id` | From the visitor record (UUID foreign key) |\n\nThe `email` column has a unique constraint. If a user with the same email already exists (e.g. they signed up with email\u002Fpassword previously), the database returns `ER_DUP_ENTRY` and the controller returns `409 { error: 'E-mail already registered' }`.\n\n#### Issue tokens\n\nOn success, `generateRefreshToken` and `generateAccessToken` are called to create a fresh session for the new user.\n::\n\n::warning\nOAuth users have `password_hash` set to `'no_password'`. They cannot use the [login](\u002Fdocs\u002Fiam\u002Fessentials\u002Flogin) route (which requires Argon2 password verification) and must always authenticate through their OAuth provider. If you want to allow OAuth users to set a password later, build a \"set password\" flow that updates the `password_hash` column.\n::\n\n---\n\n## Returning users\n\nWhen `findUserByProvider` finds an existing user row matching the provider and subject ID, the function generates a new refresh token and access token for that user without creating a new row.\n\n### Device trust\n\nIf `trustUserDeviceOnAuth` is `true` in the configuration and the [Bot Detector](\u002Fdocs\u002Fbot-detection) assigned a new `visitor_id` for this request, the controller calls `trustVisitor()` to:\n\n1. Update the user's `visitor_id` foreign key to point at the visitor row for the current `canary_id`\n2. Call `updateVisitors()` from the Bot Detector to overwrite the fingerprint fields with the current request's geo and UA data\n3. Regenerate the access token with the new `visitor_id`\n\nThis re-baselines the fingerprint so that the [anomaly detection](\u002Fdocs\u002Fiam\u002Fessentials\u002Fanomalies) engine compares future requests against the device the user most recently authenticated from. This is the same device-trust logic that runs during [login](\u002Fdocs\u002Fiam\u002Fessentials\u002Flogin#device-trust).\n\n---\n\n## Response\n\n### Success (201)\n\n```json\n{\n  \"ok\": true,\n  \"receivedAt\": \"2025-01-15T10:30:00.000Z\",\n  \"accessToken\": \"\u003Csigned JWT>\",\n  \"accessIat\": \"1705312200000\"\n}\n```\n\nTwo cookies are set alongside the JSON response:\n\n| Cookie | Value | Options |\n|---|---|---|\n| `iat` | `Date.now()` as string | `httpOnly`, `secure`, `sameSite: strict`, `path: \u002F` |\n| `session` | Raw refresh token (64 hex bytes) | `httpOnly`, `secure`, `sameSite: strict`, `domain` from config |\n\n### Error responses\n\n| Status | Condition |\n|---|---|\n| `400` | Missing `canary_id` cookie, empty body, schema validation failure, no visitor record |\n| `404` | Provider name not found in registered providers |\n| `409` | Email already registered (duplicate `email` in `users` table) |\n| `429` | Rate limit exceeded on any of the three limiters |\n\n---\n\n## The OAuth request\n\nThe client calls `POST \u002Fauth\u002FOAuth\u002F:providerName` with the profile data in the JSON body. The `:providerName` parameter must exactly match the `name` registered in `configuration()`.\n\n```ts\n\u002F\u002F Client-side example (after exchanging the OAuth code for a profile)\nawait fetch('\u002Fauth\u002FOAuth\u002Fgoogle', {\n  method: 'POST',\n  credentials: 'include',\n  headers: { 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify(googleProfile),\n})\n```\n\n### Body extraction\n\nThe controller extracts the profile from the request body using a fallback chain:\n\n1. `req.body.userInfo` (used by some OAuth client libraries)\n2. `req.body.user` (common in wrapper formats)\n3. `req.body` (raw profile at the top level)\n\nThis flexibility allows different OAuth client implementations to send the profile in whichever wrapper format they use.\n\n---\n\n## Library exports\n\nWhen using the IAM service as a library (not the standalone service), three OAuth-related functions are exported:\n\n### `createOauthUser`\n\nCreates a new user from an OAuth profile. Call this in a custom OAuth handler when you want to control the flow.\n\n```ts\nimport { createOauthUser } from '@riavzon\u002Fauth'\n\nconst result = await createOauthUser(\n  req.cookies.canary_id,\n  {\n    email: profile.email,\n    sub: profile.sub,\n    name: profile.name,\n    avatar: profile.picture,\n  },\n  'google'\n)\n\nif (result.duplicate) {\n  \u002F\u002F Email already registered\n}\n\nif (result.noCanaryCookie) {\n  \u002F\u002F No visitor record for the canary_id\n}\n\nif (result.success) {\n  \u002F\u002F result.accessToken and result.refreshToken are ready\n}\n```\n\n### `findUserByOauthProvider`\n\nLooks up an existing user by provider name and provider subject ID without creating a new account.\n\n```ts\nimport { findUserByOauthProvider } from '@riavzon\u002Fauth'\n\nconst result = await findUserByOauthProvider('google', googleProfile.sub)\n\nif (result.user) {\n  \u002F\u002F result.id, result.visitor_id, result.accessToken, result.refreshToken\n}\n```\n\n### `configureOauthProviders`\n\nInspects or extends the registered provider list at runtime. Returns the array of configured provider definitions.\n\n```ts\nimport { configureOauthProviders } from '@riavzon\u002Fauth'\n\nconst providers = configureOauthProviders()\n```\n\n---\n\n## Rate limiter reference\n\nAll OAuth rate limiters are configurable under `rate_limiters` in the configuration object. The defaults are:\n\n| Limiter | Key | Points | Window | Block duration |\n|---|---|---|---|---|\n| IP burst | `req.ip` | 1 \u002F 1 second | 1 s | 5 min |\n| IP slow | `req.ip` | 25 \u002F 1 hour | 1 h | 30 min |\n| Subject ID | Provider `sub` | 5 \u002F 5 minutes | 5 min | 15 min |\n| Composite | `ip + sub` | 3 \u002F 10 minutes | 10 min | 15 min |\n\n---\n\n## Configuration reference\n\n| Option | Location | Type | Description |\n|---|---|---|---|\n| `providers` | Root config | `array` | Array of provider definitions (Zod schema or field-type map) |\n| `trustUserDeviceOnAuth` | Root config | `boolean` | Whether OAuth login re-baselines the visitor fingerprint (default: `false`) |\n| `jwt.refresh_tokens.refresh_ttl` | `jwt` | `number` | Refresh token lifetime in milliseconds |\n| `jwt.refresh_tokens.domain` | `jwt` | `string` | Cookie domain for the `session` cookie |\n| `jwt.access_tokens.expiresIn` | `jwt` | `string` | Access token JWT expiry (default: `'15m'`) |\n\nSee [Configuration](\u002Fdocs\u002Fiam\u002Fconfiguration) for the full schema reference.\n",{"title":111,"description":3431},"kD-q5KAU9aa9Q-RYJVWNdm36K_v6mmhxF_ITdH7x0kQ",[3440,3441],{"title":107,"path":108,"stem":109,"children":-1},{"title":115,"path":116,"stem":117,"children":-1},{"id":851,"title":111,"body":3443,"description":3431,"extension":3432,"icon":3433,"meta":5435,"module":3435,"navigation":8,"path":112,"rawbody":3436,"seo":5436,"stem":113,"__hash__":3438},{"type":853,"value":3444,"toc":5405},[3445,3455,3463,3465,3467,3493,3497,3502,3512,3516,3518,3520,3529,3531,3533,3733,3735,3741,3881,3885,3887,3969,3971,3973,3979,4045,4057,4061,4185,4197,4199,4201,4283,4285,4287,4293,4485,4497,4499,4501,4505,4507,4519,4535,4541,4543,4545,4547,4625,4627,4679,4681,4731,4733,4735,4745,4843,4845,4847,4861,4863,4865,4867,4869,4873,4875,5083,5087,5089,5171,5175,5177,5215,5217,5219,5223,5297,5299,5301,5399,5403],[856,3446,858,3447,863,3449,867,3451,871,3453,876],{},[860,3448,862],{},[860,3450,866],{},[860,3452,870],{},[873,3454,875],{},[878,3456,3457],{},[856,3458,882,3459,889],{},[884,3460,3461],{"href":22},[860,3462,888],{},[891,3464],{},[894,3466,897],{"id":896},[899,3468,3469,3479],{},[902,3470,3471],{},[905,3472,3473,3475,3477],{},[908,3474,910],{},[908,3476,913],{},[908,3478,916],{},[918,3480,3481],{},[905,3482,3483,3487,3491],{},[923,3484,3485],{},[860,3486,927],{},[923,3488,3489],{},[860,3490,932],{},[923,3492,935],{},[856,3494,3495],{},[873,3496,940],{},[942,3498,3500],{"className":3499,"code":946,"language":947},[945],[860,3501,946],{"__ignoreMap":950},[856,3503,953,3504,957,3506,961,3508,965,3510,968],{},[884,3505,956],{"href":104},[884,3507,960],{"href":100},[860,3509,964],{},[884,3511,399],{"href":404},[856,3513,971,3514,976],{},[884,3515,975],{"href":974},[891,3517],{},[894,3519,982],{"id":981},[856,3521,985,3522,988,3524,991,3526,998],{},[860,3523,866],{},[860,3525,870],{},[884,3527,997],{"href":994,"rel":3528},[996],[1000,3530,1003],{"id":1002},[856,3532,1006],{},[942,3534,3535],{"className":1009,"code":1010,"filename":1011,"language":1012,"meta":950,"style":950},[860,3536,3537,3555,3573,3577,3583,3591,3595,3609,3623,3637,3655,3673,3695,3713,3717,3721,3725,3729],{"__ignoreMap":950},[1016,3538,3539,3541,3543,3545,3547,3549,3551,3553],{"class":1018,"line":1019},[1016,3540,1023],{"class":1022},[1016,3542,1027],{"class":1026},[1016,3544,1031],{"class":1030},[1016,3546,1034],{"class":1026},[1016,3548,1037],{"class":1022},[1016,3550,1041],{"class":1040},[1016,3552,1045],{"class":1044},[1016,3554,1048],{"class":1040},[1016,3556,3557,3559,3561,3563,3565,3567,3569,3571],{"class":1018,"line":1051},[1016,3558,1023],{"class":1022},[1016,3560,1027],{"class":1026},[1016,3562,1058],{"class":1030},[1016,3564,1034],{"class":1026},[1016,3566,1037],{"class":1022},[1016,3568,1041],{"class":1040},[1016,3570,1067],{"class":1044},[1016,3572,1048],{"class":1040},[1016,3574,3575],{"class":1018,"line":1072},[1016,3576,1075],{"emptyLinePlaceholder":8},[1016,3578,3579,3581],{"class":1018,"line":1078},[1016,3580,1031],{"class":1081},[1016,3582,1084],{"class":1026},[1016,3584,3585,3587,3589],{"class":1018,"line":1087},[1016,3586,1090],{"class":1030},[1016,3588,1094],{"class":1093},[1016,3590,1097],{"class":1026},[1016,3592,3593],{"class":1018,"line":1100},[1016,3594,1103],{"class":1026},[1016,3596,3597,3599,3601,3603,3605,3607],{"class":1018,"line":1106},[1016,3598,1109],{"class":1030},[1016,3600,1094],{"class":1093},[1016,3602,1041],{"class":1040},[1016,3604,1116],{"class":1044},[1016,3606,1119],{"class":1040},[1016,3608,1122],{"class":1026},[1016,3610,3611,3613,3615,3617,3619,3621],{"class":1018,"line":1125},[1016,3612,1128],{"class":1030},[1016,3614,1094],{"class":1093},[1016,3616,1133],{"class":1030},[1016,3618,1136],{"class":1026},[1016,3620,1139],{"class":1081},[1016,3622,1084],{"class":1026},[1016,3624,3625,3627,3629,3631,3633,3635],{"class":1018,"line":1144},[1016,3626,1147],{"class":1030},[1016,3628,1094],{"class":1093},[1016,3630,1133],{"class":1030},[1016,3632,1136],{"class":1026},[1016,3634,1156],{"class":1081},[1016,3636,1159],{"class":1026},[1016,3638,3639,3641,3643,3645,3647,3649,3651,3653],{"class":1018,"line":1162},[1016,3640,1165],{"class":1030},[1016,3642,1094],{"class":1093},[1016,3644,1133],{"class":1030},[1016,3646,1136],{"class":1026},[1016,3648,1156],{"class":1081},[1016,3650,1176],{"class":1026},[1016,3652,1179],{"class":1081},[1016,3654,1159],{"class":1026},[1016,3656,3657,3659,3661,3663,3665,3667,3669,3671],{"class":1018,"line":1184},[1016,3658,1187],{"class":1030},[1016,3660,1094],{"class":1093},[1016,3662,1133],{"class":1030},[1016,3664,1136],{"class":1026},[1016,3666,1156],{"class":1081},[1016,3668,1176],{"class":1026},[1016,3670,1200],{"class":1081},[1016,3672,1159],{"class":1026},[1016,3674,3675,3677,3679,3681,3683,3685,3687,3689,3691,3693],{"class":1018,"line":1205},[1016,3676,1208],{"class":1030},[1016,3678,1094],{"class":1093},[1016,3680,1133],{"class":1030},[1016,3682,1136],{"class":1026},[1016,3684,1156],{"class":1081},[1016,3686,1176],{"class":1026},[1016,3688,1221],{"class":1081},[1016,3690,1176],{"class":1026},[1016,3692,1200],{"class":1081},[1016,3694,1159],{"class":1026},[1016,3696,3697,3699,3701,3703,3705,3707,3709,3711],{"class":1018,"line":1230},[1016,3698,1233],{"class":1030},[1016,3700,1094],{"class":1093},[1016,3702,1133],{"class":1030},[1016,3704,1136],{"class":1026},[1016,3706,1242],{"class":1081},[1016,3708,1176],{"class":1026},[1016,3710,1200],{"class":1081},[1016,3712,1159],{"class":1026},[1016,3714,3715],{"class":1018,"line":1251},[1016,3716,1254],{"class":1026},[1016,3718,3719],{"class":1018,"line":1257},[1016,3720,1260],{"class":1026},[1016,3722,3723],{"class":1018,"line":1263},[1016,3724,1266],{"class":1026},[1016,3726,3727],{"class":1018,"line":1269},[1016,3728,1273],{"class":1272},[1016,3730,3731],{"class":1018,"line":1276},[1016,3732,1279],{"class":1026},[1000,3734,1283],{"id":1282},[856,3736,1286,3737,1290,3739,1294],{},[860,3738,1289],{},[860,3740,1293],{},[942,3742,3743],{"className":1009,"code":1297,"language":1012,"meta":950,"style":950},[860,3744,3745,3751,3759,3763,3777,3787,3795,3809,3823,3837,3851,3865,3869,3873,3877],{"__ignoreMap":950},[1016,3746,3747,3749],{"class":1018,"line":1019},[1016,3748,1031],{"class":1081},[1016,3750,1084],{"class":1026},[1016,3752,3753,3755,3757],{"class":1018,"line":1051},[1016,3754,1090],{"class":1030},[1016,3756,1094],{"class":1093},[1016,3758,1097],{"class":1026},[1016,3760,3761],{"class":1018,"line":1072},[1016,3762,1103],{"class":1026},[1016,3764,3765,3767,3769,3771,3773,3775],{"class":1018,"line":1078},[1016,3766,1109],{"class":1030},[1016,3768,1094],{"class":1093},[1016,3770,1041],{"class":1040},[1016,3772,1328],{"class":1044},[1016,3774,1119],{"class":1040},[1016,3776,1122],{"class":1026},[1016,3778,3779,3781,3783,3785],{"class":1018,"line":1087},[1016,3780,1337],{"class":1030},[1016,3782,1094],{"class":1093},[1016,3784,1343],{"class":1342},[1016,3786,1122],{"class":1026},[1016,3788,3789,3791,3793],{"class":1018,"line":1100},[1016,3790,1350],{"class":1030},[1016,3792,1094],{"class":1093},[1016,3794,1355],{"class":1026},[1016,3796,3797,3799,3801,3803,3805,3807],{"class":1018,"line":1106},[1016,3798,1360],{"class":1030},[1016,3800,1094],{"class":1093},[1016,3802,1041],{"class":1040},[1016,3804,1367],{"class":1044},[1016,3806,1119],{"class":1040},[1016,3808,1122],{"class":1026},[1016,3810,3811,3813,3815,3817,3819,3821],{"class":1018,"line":1125},[1016,3812,1165],{"class":1030},[1016,3814,1094],{"class":1093},[1016,3816,1041],{"class":1040},[1016,3818,1179],{"class":1044},[1016,3820,1119],{"class":1040},[1016,3822,1122],{"class":1026},[1016,3824,3825,3827,3829,3831,3833,3835],{"class":1018,"line":1144},[1016,3826,1187],{"class":1030},[1016,3828,1094],{"class":1093},[1016,3830,1041],{"class":1040},[1016,3832,1396],{"class":1044},[1016,3834,1119],{"class":1040},[1016,3836,1122],{"class":1026},[1016,3838,3839,3841,3843,3845,3847,3849],{"class":1018,"line":1162},[1016,3840,1405],{"class":1030},[1016,3842,1094],{"class":1093},[1016,3844,1041],{"class":1040},[1016,3846,1412],{"class":1044},[1016,3848,1119],{"class":1040},[1016,3850,1122],{"class":1026},[1016,3852,3853,3855,3857,3859,3861,3863],{"class":1018,"line":1184},[1016,3854,1421],{"class":1030},[1016,3856,1094],{"class":1093},[1016,3858,1041],{"class":1040},[1016,3860,1428],{"class":1044},[1016,3862,1119],{"class":1040},[1016,3864,1122],{"class":1026},[1016,3866,3867],{"class":1018,"line":1205},[1016,3868,1437],{"class":1026},[1016,3870,3871],{"class":1018,"line":1230},[1016,3872,1260],{"class":1026},[1016,3874,3875],{"class":1018,"line":1251},[1016,3876,1266],{"class":1026},[1016,3878,3879],{"class":1018,"line":1257},[1016,3880,1279],{"class":1026},[856,3882,1452,3883,1455],{},[860,3884,1289],{},[1000,3886,1459],{"id":1458},[899,3888,3889,3897],{},[902,3890,3891],{},[905,3892,3893,3895],{},[908,3894,1468],{},[908,3896,1471],{},[918,3898,3899,3909,3919,3929,3939,3949,3959],{},[905,3900,3901,3907],{},[923,3902,3903,1481,3905],{},[860,3904,1480],{},[860,3906,1484],{},[923,3908,1487],{},[905,3910,3911,3917],{},[923,3912,3913,1481,3915],{},[860,3914,1494],{},[860,3916,1497],{},[923,3918,1500],{},[905,3920,3921,3927],{},[923,3922,3923,1481,3925],{},[860,3924,1507],{},[860,3926,1510],{},[923,3928,1513],{},[905,3930,3931,3937],{},[923,3932,3933,1481,3935],{},[860,3934,1520],{},[860,3936,1523],{},[923,3938,1526],{},[905,3940,3941,3947],{},[923,3942,3943,1481,3945],{},[860,3944,1533],{},[860,3946,1536],{},[923,3948,1539],{},[905,3950,3951,3957],{},[923,3952,3953,1481,3955],{},[860,3954,1546],{},[860,3956,1549],{},[923,3958,1552],{},[905,3960,3961,3967],{},[923,3962,3963,1481,3965],{},[860,3964,1559],{},[860,3966,1562],{},[923,3968,1565],{},[891,3970],{},[894,3972,1571],{"id":1570},[856,3974,1574,3975,1578,3977,1582],{},[860,3976,1577],{},[860,3978,1581],{},[899,3980,3981,3989],{},[902,3982,3983],{},[905,3984,3985,3987],{},[908,3986,1591],{},[908,3988,1594],{},[918,3990,3991,4003,4017,4027,4037],{},[905,3992,3993,4001],{},[923,3994,3995,1604,3997,1604,3999],{},[860,3996,1603],{},[860,3998,1607],{},[860,4000,1610],{},[923,4002,1613],{},[905,4004,4005,4015],{},[923,4006,4007,1604,4009,1604,4011,1604,4013],{},[860,4008,1620],{},[860,4010,1623],{},[860,4012,1626],{},[860,4014,1629],{},[923,4016,1632],{},[905,4018,4019,4025],{},[923,4020,4021,1604,4023],{},[860,4022,1639],{},[860,4024,1642],{},[923,4026,1645],{},[905,4028,4029,4035],{},[923,4030,4031,1604,4033],{},[860,4032,1652],{},[860,4034,1655],{},[923,4036,1658],{},[905,4038,4039,4043],{},[923,4040,4041],{},[860,4042,1179],{},[923,4044,1667],{},[856,4046,4047,1672,4049,1604,4051,1677,4053,1680,4055,1684],{},[860,4048,1179],{},[860,4050,1603],{},[860,4052,1607],{},[860,4054,1610],{},[860,4056,1683],{},[1000,4058,4059,1690],{"id":1687},[860,4060,1581],{},[942,4062,4063],{"className":1009,"code":1693,"language":1012,"meta":950,"style":950},[860,4064,4065,4073,4085,4097,4109,4117,4125,4133,4141,4149,4157,4165,4173,4181],{"__ignoreMap":950},[1016,4066,4067,4069,4071],{"class":1018,"line":1019},[1016,4068,1701],{"class":1700},[1016,4070,1705],{"class":1704},[1016,4072,1355],{"class":1026},[1016,4074,4075,4077,4079,4081,4083],{"class":1018,"line":1051},[1016,4076,1712],{"class":1030},[1016,4078,1716],{"class":1715},[1016,4080,1719],{"class":1704},[1016,4082,1722],{"class":1715},[1016,4084,1725],{"class":1704},[1016,4086,4087,4089,4091,4093,4095],{"class":1018,"line":1072},[1016,4088,1730],{"class":1030},[1016,4090,1716],{"class":1715},[1016,4092,1719],{"class":1704},[1016,4094,1722],{"class":1715},[1016,4096,1725],{"class":1704},[1016,4098,4099,4101,4103,4105,4107],{"class":1018,"line":1078},[1016,4100,1743],{"class":1030},[1016,4102,1716],{"class":1715},[1016,4104,1719],{"class":1704},[1016,4106,1722],{"class":1715},[1016,4108,1725],{"class":1704},[1016,4110,4111,4113,4115],{"class":1018,"line":1087},[1016,4112,1756],{"class":1030},[1016,4114,1094],{"class":1715},[1016,4116,1761],{"class":1704},[1016,4118,4119,4121,4123],{"class":1018,"line":1100},[1016,4120,1766],{"class":1030},[1016,4122,1716],{"class":1715},[1016,4124,1771],{"class":1704},[1016,4126,4127,4129,4131],{"class":1018,"line":1106},[1016,4128,1776],{"class":1030},[1016,4130,1716],{"class":1715},[1016,4132,1761],{"class":1704},[1016,4134,4135,4137,4139],{"class":1018,"line":1125},[1016,4136,1785],{"class":1030},[1016,4138,1716],{"class":1715},[1016,4140,1761],{"class":1704},[1016,4142,4143,4145,4147],{"class":1018,"line":1144},[1016,4144,1794],{"class":1030},[1016,4146,1716],{"class":1715},[1016,4148,1761],{"class":1704},[1016,4150,4151,4153,4155],{"class":1018,"line":1162},[1016,4152,1803],{"class":1030},[1016,4154,1716],{"class":1715},[1016,4156,1761],{"class":1704},[1016,4158,4159,4161,4163],{"class":1018,"line":1184},[1016,4160,1812],{"class":1030},[1016,4162,1716],{"class":1715},[1016,4164,1817],{"class":1704},[1016,4166,4167,4169,4171],{"class":1018,"line":1205},[1016,4168,1822],{"class":1030},[1016,4170,1716],{"class":1715},[1016,4172,1827],{"class":1704},[1016,4174,4175,4177,4179],{"class":1018,"line":1230},[1016,4176,1832],{"class":1030},[1016,4178,1716],{"class":1715},[1016,4180,1827],{"class":1704},[1016,4182,4183],{"class":1018,"line":1251},[1016,4184,1841],{"class":1026},[856,4186,1844,4187,1847,4189,1604,4191,1604,4193,1604,4195,1856],{},[860,4188,1626],{},[860,4190,1620],{},[860,4192,1623],{},[860,4194,1626],{},[860,4196,1629],{},[891,4198],{},[894,4200,1862],{"id":1861},[1864,4202,4203,4205,4211,4213,4219,4221,4229,4231,4241,4243,4261,4263,4267,4269,4273,4275],{"level":1866},[1868,4204,1871],{"id":1870},[856,4206,1874,4207,1878,4209,1136],{},[860,4208,1877],{},[860,4210,1881],{},[1868,4212,1885],{"id":1884},[856,4214,1844,4215,1891,4217,1136],{},[860,4216,1890],{},[860,4218,1894],{},[1868,4220,1898],{"id":1897},[856,4222,1901,4223,1905,4225,1909,4227,1913],{},[860,4224,1904],{},[884,4226,147],{"href":1908},[860,4228,1912],{},[1868,4230,1917],{"id":1916},[856,4232,1920,4233,1604,4235,1677,4237,1930,4239,1934],{},[860,4234,1923],{},[860,4236,1926],{},[860,4238,1929],{},[860,4240,1933],{},[1868,4242,1938],{"id":1937},[856,4244,1941,4245,1945,4247,1948,4249,1951,4251,1604,4253,1677,4255,1958,4257,1961,4259,1136],{},[860,4246,1944],{},[860,4248,1581],{},[860,4250,1603],{},[860,4252,1603],{},[860,4254,1607],{},[860,4256,1610],{},[860,4258,1652],{},[860,4260,1655],{},[1868,4262,1967],{"id":1966},[856,4264,1970,4265,1973],{},[860,4266,1603],{},[1868,4268,1977],{"id":1976},[856,4270,1980,4271,1984],{},[860,4272,1983],{},[1868,4274,1988],{"id":1987},[856,4276,1991,4277,1995,4279,957,4281,2004],{},[860,4278,1994],{},[884,4280,1999],{"href":1998},[884,4282,2003],{"href":2002},[891,4284],{},[894,4286,2003],{"id":2009},[856,4288,1574,4289,2015,4291,2019],{},[860,4290,2014],{},[860,4292,2018],{},[1864,4294,4295,4297,4313,4315,4329,4331,4335,4469,4477,4479],{"level":1866},[1868,4296,2025],{"id":2024},[856,4298,2028,4299,2032,4301,2035,4303,1604,4305,1604,4307,2045,4309,2049,4311,1136],{},[860,4300,2031],{},[860,4302,964],{},[860,4304,2038],{},[860,4306,2041],{},[860,4308,2044],{},[860,4310,2048],{},[860,4312,2052],{},[1868,4314,2056],{"id":2055},[856,4316,1844,4317,2062,4319,1604,4321,2067,4323,2070,4325,2073,4327,1136],{},[860,4318,2061],{},[860,4320,1639],{},[860,4322,1642],{},[860,4324,1655],{},[860,4326,1652],{},[860,4328,2076],{},[1868,4330,2080],{"id":2079},[856,4332,2083,4333,2087],{},[860,4334,2086],{},[899,4336,4337,4345],{},[902,4338,4339],{},[905,4340,4341,4343],{},[908,4342,2096],{},[908,4344,2099],{},[918,4346,4347,4359,4369,4377,4385,4395,4407,4417,4427,4437,4445,4453,4461],{},[905,4348,4349,4353],{},[923,4350,4351],{},[860,4352,1655],{},[923,4354,4355,1961,4357,2114],{},[860,4356,1652],{},[860,4358,1655],{},[905,4360,4361,4365],{},[923,4362,4363],{},[860,4364,1642],{},[923,4366,2123,4367],{},[860,4368,2061],{},[905,4370,4371,4375],{},[923,4372,4373],{},[860,4374,1179],{},[923,4376,2134],{},[905,4378,4379,4383],{},[923,4380,4381],{},[860,4382,1626],{},[923,4384,2143],{},[905,4386,4387,4391],{},[923,4388,4389],{},[860,4390,2150],{},[923,4392,2153,4393],{},[860,4394,2156],{},[905,4396,4397,4401],{},[923,4398,4399],{},[860,4400,2163],{},[923,4402,2166,4403,1604,4405,2173],{},[860,4404,2169],{},[860,4406,2172],{},[905,4408,4409,4413],{},[923,4410,4411],{},[860,4412,2180],{},[923,4414,1970,4415,2173],{},[860,4416,1603],{},[905,4418,4419,4423],{},[923,4420,4421],{},[860,4422,2191],{},[923,4424,4425],{},[860,4426,2196],{},[905,4428,4429,4433],{},[923,4430,4431],{},[860,4432,2203],{},[923,4434,4435],{},[860,4436,2196],{},[905,4438,4439,4443],{},[923,4440,4441],{},[860,4442,2038],{},[923,4444,2216],{},[905,4446,4447,4451],{},[923,4448,4449],{},[860,4450,2041],{},[923,4452,2216],{},[905,4454,4455,4459],{},[923,4456,4457],{},[860,4458,2044],{},[923,4460,2216],{},[905,4462,4463,4467],{},[923,4464,4465],{},[860,4466,2048],{},[923,4468,2241],{},[856,4470,1844,4471,2246,4473,2250,4475,1136],{},[860,4472,1179],{},[860,4474,2249],{},[860,4476,2253],{},[1868,4478,2257],{"id":2256},[856,4480,2260,4481,957,4483,2267],{},[860,4482,2263],{},[860,4484,2266],{},[2269,4486,4487],{},[856,4488,2273,4489,2276,4491,2279,4493,2282,4495,2285],{},[860,4490,2150],{},[860,4492,2156],{},[884,4494,956],{"href":104},[860,4496,2150],{},[891,4498],{},[894,4500,1999],{"id":2290},[856,4502,1574,4503,2295],{},[860,4504,2014],{},[1000,4506,2299],{"id":2298},[856,4508,2302,4509,2306,4511,2310,4513,2313,4515,2316,4517,2320],{},[860,4510,2305],{},[860,4512,2309],{},[884,4514,399],{"href":35},[860,4516,2048],{},[860,4518,2319],{},[2322,4520,4521,4527,4531],{},[2325,4522,2327,4523,2330,4525],{},[860,4524,2048],{},[860,4526,964],{},[2325,4528,2335,4529,2339],{},[860,4530,2338],{},[2325,4532,2342,4533],{},[860,4534,2048],{},[856,4536,2347,4537,2351,4539,1136],{},[884,4538,2350],{"href":96},[884,4540,956],{"href":2354},[891,4542],{},[894,4544,2360],{"id":2359},[1000,4546,2364],{"id":2363},[942,4548,4549],{"className":2367,"code":2368,"language":5,"meta":950,"style":950},[860,4550,4551,4555,4569,4587,4605,4621],{"__ignoreMap":950},[1016,4552,4553],{"class":1018,"line":1019},[1016,4554,2375],{"class":1026},[1016,4556,4557,4559,4561,4563,4565,4567],{"class":1018,"line":1051},[1016,4558,2381],{"class":2380},[1016,4560,2385],{"class":2384},[1016,4562,2388],{"class":2380},[1016,4564,1094],{"class":1715},[1016,4566,1343],{"class":1342},[1016,4568,1122],{"class":1026},[1016,4570,4571,4573,4575,4577,4579,4581,4583,4585],{"class":1018,"line":1072},[1016,4572,2381],{"class":2380},[1016,4574,2401],{"class":2384},[1016,4576,2388],{"class":2380},[1016,4578,1094],{"class":1715},[1016,4580,2408],{"class":1040},[1016,4582,2411],{"class":1044},[1016,4584,2388],{"class":1040},[1016,4586,1122],{"class":1026},[1016,4588,4589,4591,4593,4595,4597,4599,4601,4603],{"class":1018,"line":1078},[1016,4590,2381],{"class":2380},[1016,4592,2422],{"class":2384},[1016,4594,2388],{"class":2380},[1016,4596,1094],{"class":1715},[1016,4598,2408],{"class":1040},[1016,4600,2431],{"class":1044},[1016,4602,2388],{"class":1040},[1016,4604,1122],{"class":1026},[1016,4606,4607,4609,4611,4613,4615,4617,4619],{"class":1018,"line":1087},[1016,4608,2381],{"class":2380},[1016,4610,2442],{"class":2384},[1016,4612,2388],{"class":2380},[1016,4614,1094],{"class":1715},[1016,4616,2408],{"class":1040},[1016,4618,2451],{"class":1044},[1016,4620,2454],{"class":1040},[1016,4622,4623],{"class":1018,"line":1100},[1016,4624,1841],{"class":1026},[856,4626,2461],{},[899,4628,4629,4639],{},[902,4630,4631],{},[905,4632,4633,4635,4637],{},[908,4634,2470],{},[908,4636,2473],{},[908,4638,2476],{},[918,4640,4641,4661],{},[905,4642,4643,4647,4651],{},[923,4644,4645],{},[860,4646,2485],{},[923,4648,4649,2491],{},[860,4650,2490],{},[923,4652,4653,1604,4655,1604,4657,1604,4659],{},[860,4654,2496],{},[860,4656,2499],{},[860,4658,2502],{},[860,4660,2505],{},[905,4662,4663,4667,4669],{},[923,4664,4665],{},[860,4666,2512],{},[923,4668,2515],{},[923,4670,4671,1604,4673,1604,4675,1604,4677,2527],{},[860,4672,2496],{},[860,4674,2499],{},[860,4676,2502],{},[860,4678,2526],{},[1000,4680,2531],{"id":2530},[899,4682,4683,4691],{},[902,4684,4685],{},[905,4686,4687,4689],{},[908,4688,2540],{},[908,4690,2543],{},[918,4692,4693,4703,4711,4723],{},[905,4694,4695,4699],{},[923,4696,4697],{},[860,4698,1933],{},[923,4700,2554,4701,2557],{},[860,4702,964],{},[905,4704,4705,4709],{},[923,4706,4707],{},[860,4708,1894],{},[923,4710,2566],{},[905,4712,4713,4717],{},[923,4714,4715],{},[860,4716,2573],{},[923,4718,2576,4719,2579,4721,2582],{},[860,4720,1179],{},[860,4722,2086],{},[905,4724,4725,4729],{},[923,4726,4727],{},[860,4728,2589],{},[923,4730,2592],{},[891,4732],{},[894,4734,2598],{"id":2597},[856,4736,2601,4737,2604,4739,2607,4741,2610,4743,1136],{},[860,4738,862],{},[860,4740,1890],{},[860,4742,1655],{},[860,4744,870],{},[942,4746,4747],{"className":1009,"code":2615,"language":1012,"meta":950,"style":950},[860,4748,4749,4753,4769,4783,4797,4821,4839],{"__ignoreMap":950},[1016,4750,4751],{"class":1018,"line":1019},[1016,4752,2622],{"class":1272},[1016,4754,4755,4757,4759,4761,4763,4765,4767],{"class":1018,"line":1051},[1016,4756,2627],{"class":1022},[1016,4758,2630],{"class":1081},[1016,4760,2633],{"class":1026},[1016,4762,1119],{"class":1040},[1016,4764,2638],{"class":1044},[1016,4766,1119],{"class":1040},[1016,4768,2643],{"class":1026},[1016,4770,4771,4773,4775,4777,4779,4781],{"class":1018,"line":1072},[1016,4772,2648],{"class":1030},[1016,4774,1094],{"class":1093},[1016,4776,1041],{"class":1040},[1016,4778,927],{"class":1044},[1016,4780,1119],{"class":1040},[1016,4782,1122],{"class":1026},[1016,4784,4785,4787,4789,4791,4793,4795],{"class":1018,"line":1078},[1016,4786,2663],{"class":1030},[1016,4788,1094],{"class":1093},[1016,4790,1041],{"class":1040},[1016,4792,2670],{"class":1044},[1016,4794,1119],{"class":1040},[1016,4796,1122],{"class":1026},[1016,4798,4799,4801,4803,4805,4807,4809,4811,4813,4815,4817,4819],{"class":1018,"line":1087},[1016,4800,2679],{"class":1030},[1016,4802,1094],{"class":1093},[1016,4804,1027],{"class":1026},[1016,4806,1119],{"class":1040},[1016,4808,2688],{"class":1044},[1016,4810,1119],{"class":1040},[1016,4812,1094],{"class":1093},[1016,4814,1041],{"class":1040},[1016,4816,1877],{"class":1044},[1016,4818,1119],{"class":1040},[1016,4820,2701],{"class":1026},[1016,4822,4823,4825,4827,4829,4831,4833,4835,4837],{"class":1018,"line":1100},[1016,4824,2706],{"class":1030},[1016,4826,1094],{"class":1093},[1016,4828,2712],{"class":2711},[1016,4830,1136],{"class":1026},[1016,4832,2717],{"class":1081},[1016,4834,2633],{"class":1026},[1016,4836,2722],{"class":1030},[1016,4838,2725],{"class":1026},[1016,4840,4841],{"class":1018,"line":1106},[1016,4842,1279],{"class":1026},[1000,4844,2733],{"id":2732},[856,4846,2736],{},[2322,4848,4849,4853,4857],{},[2325,4850,4851,2743],{},[860,4852,1923],{},[2325,4854,4855,2748],{},[860,4856,1926],{},[2325,4858,4859,2753],{},[860,4860,1929],{},[856,4862,2756],{},[891,4864],{},[894,4866,2762],{"id":2761},[856,4868,2765],{},[1000,4870,4871],{"id":2768},[860,4872,2771],{},[856,4874,2774],{},[942,4876,4877],{"className":1009,"code":2777,"language":1012,"meta":950,"style":950},[860,4878,4879,4897,4901,4915,4929,4933,4947,4961,4975,4989,4993,5001,5005,5009,5023,5027,5031,5035,5049,5053,5057,5061,5075,5079],{"__ignoreMap":950},[1016,4880,4881,4883,4885,4887,4889,4891,4893,4895],{"class":1018,"line":1019},[1016,4882,1023],{"class":1022},[1016,4884,1027],{"class":1026},[1016,4886,2771],{"class":1030},[1016,4888,1034],{"class":1026},[1016,4890,1037],{"class":1022},[1016,4892,1041],{"class":1040},[1016,4894,1045],{"class":1044},[1016,4896,1048],{"class":1040},[1016,4898,4899],{"class":1018,"line":1051},[1016,4900,1075],{"emptyLinePlaceholder":8},[1016,4902,4903,4905,4907,4909,4911,4913],{"class":1018,"line":1072},[1016,4904,2806],{"class":1700},[1016,4906,2810],{"class":2809},[1016,4908,2813],{"class":1715},[1016,4910,2816],{"class":1022},[1016,4912,2819],{"class":1081},[1016,4914,2822],{"class":1026},[1016,4916,4917,4919,4921,4923,4925,4927],{"class":1018,"line":1078},[1016,4918,2827],{"class":1030},[1016,4920,1136],{"class":1026},[1016,4922,2832],{"class":1030},[1016,4924,1136],{"class":1026},[1016,4926,964],{"class":1030},[1016,4928,1122],{"class":1026},[1016,4930,4931],{"class":1018,"line":1087},[1016,4932,2843],{"class":1026},[1016,4934,4935,4937,4939,4941,4943,4945],{"class":1018,"line":1100},[1016,4936,2848],{"class":1030},[1016,4938,1094],{"class":1093},[1016,4940,2853],{"class":1030},[1016,4942,1136],{"class":1026},[1016,4944,1179],{"class":1030},[1016,4946,1122],{"class":1026},[1016,4948,4949,4951,4953,4955,4957,4959],{"class":1018,"line":1106},[1016,4950,2864],{"class":1030},[1016,4952,1094],{"class":1093},[1016,4954,2853],{"class":1030},[1016,4956,1136],{"class":1026},[1016,4958,1603],{"class":1030},[1016,4960,1122],{"class":1026},[1016,4962,4963,4965,4967,4969,4971,4973],{"class":1018,"line":1125},[1016,4964,2879],{"class":1030},[1016,4966,1094],{"class":1093},[1016,4968,2853],{"class":1030},[1016,4970,1136],{"class":1026},[1016,4972,1655],{"class":1030},[1016,4974,1122],{"class":1026},[1016,4976,4977,4979,4981,4983,4985,4987],{"class":1018,"line":1144},[1016,4978,2894],{"class":1030},[1016,4980,1094],{"class":1093},[1016,4982,2853],{"class":1030},[1016,4984,1136],{"class":1026},[1016,4986,1620],{"class":1030},[1016,4988,1122],{"class":1026},[1016,4990,4991],{"class":1018,"line":1162},[1016,4992,2909],{"class":1026},[1016,4994,4995,4997,4999],{"class":1018,"line":1184},[1016,4996,2914],{"class":1040},[1016,4998,1116],{"class":1044},[1016,5000,1048],{"class":1040},[1016,5002,5003],{"class":1018,"line":1205},[1016,5004,2923],{"class":1026},[1016,5006,5007],{"class":1018,"line":1230},[1016,5008,1075],{"emptyLinePlaceholder":8},[1016,5010,5011,5013,5015,5017,5019,5021],{"class":1018,"line":1251},[1016,5012,2932],{"class":1022},[1016,5014,2935],{"class":1026},[1016,5016,2938],{"class":1030},[1016,5018,1136],{"class":1026},[1016,5020,2943],{"class":1030},[1016,5022,2946],{"class":1026},[1016,5024,5025],{"class":1018,"line":1257},[1016,5026,2951],{"class":1272},[1016,5028,5029],{"class":1018,"line":1263},[1016,5030,1841],{"class":1026},[1016,5032,5033],{"class":1018,"line":1269},[1016,5034,1075],{"emptyLinePlaceholder":8},[1016,5036,5037,5039,5041,5043,5045,5047],{"class":1018,"line":1276},[1016,5038,2932],{"class":1022},[1016,5040,2935],{"class":1026},[1016,5042,2938],{"class":1030},[1016,5044,1136],{"class":1026},[1016,5046,2972],{"class":1030},[1016,5048,2946],{"class":1026},[1016,5050,5051],{"class":1018,"line":2977},[1016,5052,2980],{"class":1272},[1016,5054,5055],{"class":1018,"line":2983},[1016,5056,1841],{"class":1026},[1016,5058,5059],{"class":1018,"line":2988},[1016,5060,1075],{"emptyLinePlaceholder":8},[1016,5062,5063,5065,5067,5069,5071,5073],{"class":1018,"line":2993},[1016,5064,2932],{"class":1022},[1016,5066,2935],{"class":1026},[1016,5068,2938],{"class":1030},[1016,5070,1136],{"class":1026},[1016,5072,3004],{"class":1030},[1016,5074,2946],{"class":1026},[1016,5076,5077],{"class":1018,"line":3009},[1016,5078,3012],{"class":1272},[1016,5080,5081],{"class":1018,"line":3015},[1016,5082,1841],{"class":1026},[1000,5084,5085],{"id":3020},[860,5086,3023],{},[856,5088,3026],{},[942,5090,5091],{"className":1009,"code":3029,"language":1012,"meta":950,"style":950},[860,5092,5093,5111,5115,5145,5149,5163,5167],{"__ignoreMap":950},[1016,5094,5095,5097,5099,5101,5103,5105,5107,5109],{"class":1018,"line":1019},[1016,5096,1023],{"class":1022},[1016,5098,1027],{"class":1026},[1016,5100,3023],{"class":1030},[1016,5102,1034],{"class":1026},[1016,5104,1037],{"class":1022},[1016,5106,1041],{"class":1040},[1016,5108,1045],{"class":1044},[1016,5110,1048],{"class":1040},[1016,5112,5113],{"class":1018,"line":1051},[1016,5114,1075],{"emptyLinePlaceholder":8},[1016,5116,5117,5119,5121,5123,5125,5127,5129,5131,5133,5135,5137,5139,5141,5143],{"class":1018,"line":1072},[1016,5118,2806],{"class":1700},[1016,5120,2810],{"class":2809},[1016,5122,2813],{"class":1715},[1016,5124,2816],{"class":1022},[1016,5126,3066],{"class":1081},[1016,5128,2633],{"class":1026},[1016,5130,1119],{"class":1040},[1016,5132,1116],{"class":1044},[1016,5134,1119],{"class":1040},[1016,5136,1604],{"class":1026},[1016,5138,2722],{"class":1030},[1016,5140,1136],{"class":1026},[1016,5142,1603],{"class":1030},[1016,5144,2923],{"class":1026},[1016,5146,5147],{"class":1018,"line":1078},[1016,5148,1075],{"emptyLinePlaceholder":8},[1016,5150,5151,5153,5155,5157,5159,5161],{"class":1018,"line":1087},[1016,5152,2932],{"class":1022},[1016,5154,2935],{"class":1026},[1016,5156,2938],{"class":1030},[1016,5158,1136],{"class":1026},[1016,5160,3101],{"class":1030},[1016,5162,2946],{"class":1026},[1016,5164,5165],{"class":1018,"line":1100},[1016,5166,3108],{"class":1272},[1016,5168,5169],{"class":1018,"line":1106},[1016,5170,1841],{"class":1026},[1000,5172,5173],{"id":3115},[860,5174,3118],{},[856,5176,3121],{},[942,5178,5179],{"className":1009,"code":3124,"language":1012,"meta":950,"style":950},[860,5180,5181,5199,5203],{"__ignoreMap":950},[1016,5182,5183,5185,5187,5189,5191,5193,5195,5197],{"class":1018,"line":1019},[1016,5184,1023],{"class":1022},[1016,5186,1027],{"class":1026},[1016,5188,3118],{"class":1030},[1016,5190,1034],{"class":1026},[1016,5192,1037],{"class":1022},[1016,5194,1041],{"class":1040},[1016,5196,1045],{"class":1044},[1016,5198,1048],{"class":1040},[1016,5200,5201],{"class":1018,"line":1051},[1016,5202,1075],{"emptyLinePlaceholder":8},[1016,5204,5205,5207,5209,5211,5213],{"class":1018,"line":1072},[1016,5206,2806],{"class":1700},[1016,5208,3155],{"class":2809},[1016,5210,2813],{"class":1715},[1016,5212,3160],{"class":1081},[1016,5214,3163],{"class":1026},[891,5216],{},[894,5218,3169],{"id":3168},[856,5220,3172,5221,3176],{},[860,5222,3175],{},[899,5224,5225,5239],{},[902,5226,5227],{},[905,5228,5229,5231,5233,5235,5237],{},[908,5230,3185],{},[908,5232,3188],{},[908,5234,3191],{},[908,5236,3194],{},[908,5238,3197],{},[918,5240,5241,5255,5269,5283],{},[905,5242,5243,5245,5249,5251,5253],{},[923,5244,3204],{},[923,5246,5247],{},[860,5248,1904],{},[923,5250,3211],{},[923,5252,3214],{},[923,5254,3217],{},[905,5256,5257,5259,5263,5265,5267],{},[923,5258,3222],{},[923,5260,5261],{},[860,5262,1904],{},[923,5264,3229],{},[923,5266,3232],{},[923,5268,3235],{},[905,5270,5271,5273,5277,5279,5281],{},[923,5272,3240],{},[923,5274,3243,5275],{},[860,5276,1603],{},[923,5278,3248],{},[923,5280,3217],{},[923,5282,3253],{},[905,5284,5285,5287,5291,5293,5295],{},[923,5286,3258],{},[923,5288,5289],{},[860,5290,1983],{},[923,5292,3265],{},[923,5294,3268],{},[923,5296,3253],{},[891,5298],{},[894,5300,3276],{"id":3275},[899,5302,5303,5315],{},[902,5304,5305],{},[905,5306,5307,5309,5311,5313],{},[908,5308,3285],{},[908,5310,3288],{},[908,5312,1468],{},[908,5314,1471],{},[918,5316,5317,5331,5347,5363,5381],{},[905,5318,5319,5323,5325,5329],{},[923,5320,5321],{},[860,5322,866],{},[923,5324,3303],{},[923,5326,5327],{},[860,5328,3308],{},[923,5330,3311],{},[905,5332,5333,5337,5339,5343],{},[923,5334,5335],{},[860,5336,2305],{},[923,5338,3303],{},[923,5340,5341],{},[860,5342,1242],{},[923,5344,3326,5345,2173],{},[860,5346,2196],{},[905,5348,5349,5353,5357,5361],{},[923,5350,5351],{},[860,5352,3335],{},[923,5354,5355],{},[860,5356,3340],{},[923,5358,5359],{},[860,5360,3345],{},[923,5362,3348],{},[905,5364,5365,5369,5373,5377],{},[923,5366,5367],{},[860,5368,3355],{},[923,5370,5371],{},[860,5372,3340],{},[923,5374,5375],{},[860,5376,1156],{},[923,5378,3366,5379,3369],{},[860,5380,2512],{},[905,5382,5383,5387,5391,5395],{},[923,5384,5385],{},[860,5386,3376],{},[923,5388,5389],{},[860,5390,3340],{},[923,5392,5393],{},[860,5394,1156],{},[923,5396,3387,5397,2173],{},[860,5398,3390],{},[856,5400,971,5401,3395],{},[884,5402,237],{"href":238},[3397,5404,3399],{},{"title":950,"searchDepth":1051,"depth":1051,"links":5406},[5407,5408,5413,5416,5417,5418,5421,5425,5428,5433,5434],{"id":896,"depth":1051,"text":897},{"id":981,"depth":1051,"text":982,"children":5409},[5410,5411,5412],{"id":1002,"depth":1072,"text":1003},{"id":1282,"depth":1072,"text":1283},{"id":1458,"depth":1072,"text":1459},{"id":1570,"depth":1051,"text":1571,"children":5414},[5415],{"id":1687,"depth":1072,"text":3411},{"id":1861,"depth":1051,"text":1862},{"id":2009,"depth":1051,"text":2003},{"id":2290,"depth":1051,"text":1999,"children":5419},[5420],{"id":2298,"depth":1072,"text":2299},{"id":2359,"depth":1051,"text":2360,"children":5422},[5423,5424],{"id":2363,"depth":1072,"text":2364},{"id":2530,"depth":1072,"text":2531},{"id":2597,"depth":1051,"text":2598,"children":5426},[5427],{"id":2732,"depth":1072,"text":2733},{"id":2761,"depth":1051,"text":2762,"children":5429},[5430,5431,5432],{"id":2768,"depth":1072,"text":2771},{"id":3020,"depth":1072,"text":3023},{"id":3115,"depth":1072,"text":3118},{"id":3168,"depth":1051,"text":3169},{"id":3275,"depth":1051,"text":3276},{},{"title":111,"description":3431},1780436281941]