[{"data":1,"prerenderedAt":5265},["ShallowReactive",2],{"navLinks":3,"sidebar_docs_navigation_\u002Fdocs\u002Fiam":64,"navigation":257,"navLinks_footer":837,"\u002Fdocs\u002Fiam\u002Fessentials\u002Fxss_page":850,"\u002Fdocs\u002Fiam\u002Fessentials\u002Fxss_surround":3335,"\u002Fdocs\u002Fiam\u002Fessentials\u002Fxss":3338},{"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":139,"body":852,"description":3327,"extension":3328,"icon":3329,"meta":3330,"module":3331,"navigation":8,"path":140,"rawbody":3332,"seo":3333,"stem":141,"__hash__":3334},"docs\u002Fdocs\u002Fiam\u002F01.essentials\u002F14.xss.md",{"type":853,"value":854,"toc":3312},"minimark",[855,879,886,889,894,903,1065,1068,1462,1464,1468,1483,1689,1694,1723,1727,1730,1783,1792,1798,1884,1886,1890,1905,2195,2199,2271,2281,2283,2288,2300,2359,2436,2439,2441,2445,2455,2602,2605,2652,2660,2662,2666,2675,3177,3179,3183,3198,3215,3217,3221,3224,3308],[856,857,858,859,863,864,867,868,875,876,878],"p",{},"The IAM service provides a layered XSS defense pipeline that runs on every user-supplied string. The pipeline consists of three components that work together: ",[860,861,862],"code",{},"sanitizeInput"," performs deep multi-pass HTML stripping and entity encoding, ",[860,865,866],{},"makeSanitizedZodString"," integrates that sanitizer into ",[869,870,874],"a",{"href":871,"rel":872},"https:\u002F\u002Fzod.dev\u002F",[873],"nofollow","Zod"," schemas so validation and sanitization happen in a single step, and ",[860,877,792],{}," orchestrates the whole flow while automatically banning the client's IP when an XSS payload is detected.",[856,880,881,882,885],{},"All three utilities are exported from ",[860,883,884],{},"@riavzon\u002Fauth"," for use in your own route handlers. The built-in authentication controllers (signup, login, MFA verification, email update, password reset, OAuth) already use the full pipeline on every field that accepts user input.",[887,888],"hr",{},[890,891,893],"h2",{"id":892},"sanitization-pipeline","Sanitization pipeline",[856,895,896,898,899,902],{},[860,897,862],{}," (exported as the default from ",[860,900,901],{},"htmlSanitizer",") is the core sanitization function. It accepts a raw string and returns a cleaned string along with a detection report indicating whether any HTML was found during processing.",[904,905,910],"pre",{"className":906,"code":907,"language":908,"meta":909,"style":909},"language-ts shiki shiki-themes light-plus light-plus dracula","import sanitizeInput from '@riavzon\u002Fauth'\n\nconst { vall, results } = sanitizeInput(userInput)\n\nif (results.htmlFound) {\n  \u002F\u002F HTML or script injection was detected and stripped\n  console.log('Detected tags:', results.tags)\n}\n\n\u002F\u002F vall is the fully sanitized string, safe for storage or rendering\n","ts","",[860,911,912,938,944,984,989,1009,1016,1048,1054,1059],{"__ignoreMap":909},[913,914,917,921,925,928,932,935],"span",{"class":915,"line":916},"line",1,[913,918,920],{"class":919},"sZ328","import",[913,922,924],{"class":923},"sjsA6"," sanitizeInput",[913,926,927],{"class":919}," from",[913,929,931],{"class":930},"sFkSl"," '",[913,933,884],{"class":934},"sFB1V",[913,936,937],{"class":930},"'\n",[913,939,941],{"class":915,"line":940},2,[913,942,943],{"emptyLinePlaceholder":8},"\n",[913,945,947,951,955,959,962,965,968,972,975,978,981],{"class":915,"line":946},3,[913,948,950],{"class":949},"sl46w","const",[913,952,954],{"class":953},"sDd4n"," { ",[913,956,958],{"class":957},"s3JHE","vall",[913,960,961],{"class":953},", ",[913,963,964],{"class":957},"results",[913,966,967],{"class":953}," } ",[913,969,971],{"class":970},"saOXh","=",[913,973,924],{"class":974},"sHOzp",[913,976,977],{"class":953},"(",[913,979,980],{"class":923},"userInput",[913,982,983],{"class":953},")\n",[913,985,987],{"class":915,"line":986},4,[913,988,943],{"emptyLinePlaceholder":8},[913,990,992,995,998,1000,1003,1006],{"class":915,"line":991},5,[913,993,994],{"class":919},"if",[913,996,997],{"class":953}," (",[913,999,964],{"class":923},[913,1001,1002],{"class":953},".",[913,1004,1005],{"class":923},"htmlFound",[913,1007,1008],{"class":953},") {\n",[913,1010,1012],{"class":915,"line":1011},6,[913,1013,1015],{"class":1014},"sghk6","  \u002F\u002F HTML or script injection was detected and stripped\n",[913,1017,1019,1022,1024,1027,1029,1032,1035,1037,1039,1041,1043,1046],{"class":915,"line":1018},7,[913,1020,1021],{"class":923},"  console",[913,1023,1002],{"class":953},[913,1025,1026],{"class":974},"log",[913,1028,977],{"class":953},[913,1030,1031],{"class":930},"'",[913,1033,1034],{"class":934},"Detected tags:",[913,1036,1031],{"class":930},[913,1038,961],{"class":953},[913,1040,964],{"class":923},[913,1042,1002],{"class":953},[913,1044,1045],{"class":923},"tags",[913,1047,983],{"class":953},[913,1049,1051],{"class":915,"line":1050},8,[913,1052,1053],{"class":953},"}\n",[913,1055,1057],{"class":915,"line":1056},9,[913,1058,943],{"emptyLinePlaceholder":8},[913,1060,1062],{"class":915,"line":1061},10,[913,1063,1064],{"class":1014},"\u002F\u002F vall is the fully sanitized string, safe for storage or rendering\n",[856,1066,1067],{},"The function performs 8 sequential stages. Each stage builds on the previous one, and an attacker must bypass all of them for a payload to survive.",[1069,1070,1072,1077,1084,1088,1112,1116,1138,1142,1161,1176,1188,1192,1199,1203,1206,1263,1276,1280,1289,1329,1345,1349,1370],"steps",{"level":1071},"4",[1073,1074,1076],"h4",{"id":1075},"length-guard","Length guard",[856,1078,1079,1080,1083],{},"Before any processing, the sanitizer rejects input longer than ",[860,1081,1082],{},"htmlSanitizer.maxAllowedInputLength"," (default 50000). Oversized input throws rather than entering the loop. This is the hard cap on CPU cost for a single call.",[1073,1085,1087],{"id":1086},"unicode-normalization","Unicode normalization",[856,1089,1090,1091,1096,1097,1100,1101,1104,1105,1108,1109,1002],{},"The input is normalized to ",[869,1092,1095],{"href":1093,"rel":1094},"https:\u002F\u002Funicode.org\u002Freports\u002Ftr15\u002F",[873],"NFKC",", which collapses visually similar characters to their canonical form Zero-width characters, soft hyphens, byte-order marks, and bidirectional override characters are stripped in the same pass. Halfwidth and\nfullwidth ASCII characters (",[860,1098,1099],{},"U+FF01"," through ",[860,1102,1103],{},"U+FF5E",") are transliterated back to standard ASCII. This defeats payloads that hide tags inside fullwidth substitutions such as ",[860,1106,1107],{},"\\uFF1C"," for ",[860,1110,1111],{},"\u003C",[1073,1113,1115],{"id":1114},"strict-uri-decode","Strict URI decode",[856,1117,1118,1121,1122,1125,1126,1129,1130,1133,1134,1137],{},[860,1119,1120],{},"decodeURIComponent"," is called once inside a ",[860,1123,1124],{},"try","\u002F",[860,1127,1128],{},"catch",". If the call throws (malformed percent-encoding like ",[860,1131,1132],{},"%ZZ","), the input is rejected immediately and returned as an empty string with ",[860,1135,1136],{},"htmlFound: true",". Legitimate input does not contain malformed URI sequences, so rejecting early keeps broken data out of the loop.",[1073,1139,1141],{"id":1140},"iterative-uri-and-entity-decoding","Iterative URI and entity decoding",[856,1143,1144,1145,1147,1148,997,1151,1156,1157,1160],{},"The function enters a decode loop that alternates between ",[860,1146,1120],{}," and ",[860,1149,1150],{},"he.decode",[869,1152,1155],{"href":1153,"rel":1154},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fhe",[873],"he"," is an HTML entity decoder). Each iteration decodes one layer of encoding. The loop continues until the output stabilizes (no change between iterations) or until the ",[860,1158,1159],{},"IrritationCount"," limit is reached.",[856,1162,1163,1164,1167,1168,1171,1172,1175],{},"This catches payloads that rely on nested encoding: ",[860,1165,1166],{},"%253Cscript%253E"," decodes to ",[860,1169,1170],{},"%3Cscript%3E"," on the first pass, then to ",[860,1173,1174],{},"\u003Cscript>"," on the second. Without the loop, a single-pass decoder would leave the inner encoding intact.",[1177,1178,1179],"warning",{},[856,1180,1181,1182,1184,1185,1187],{},"If the loop exceeds ",[860,1183,1159],{}," iterations without stabilizing, the input is rejected entirely and returned as an empty string with ",[860,1186,1136],{},". This protects against intentionally crafted inputs designed to consume CPU through deep encoding chains.",[1073,1189,1191],{"id":1190},"residual-cleanup","Residual cleanup",[856,1193,1194,1195,1198],{},"After the loop, zero-width characters are stripped again (the decoders may have reintroduced them) and any whitespace inside the bodies of surviving tag-like substrings is removed so that ",[860,1196,1197],{},"\u003Cscr\\tipt>"," cannot slip past the tag regex.",[1073,1200,1202],{"id":1201},"pattern-detection","Pattern detection",[856,1204,1205],{},"After decoding, the function tests the cleaned string against three patterns:",[1207,1208,1209,1222],"table",{},[1210,1211,1212],"thead",{},[1213,1214,1215,1219],"tr",{},[1216,1217,1218],"th",{},"Pattern",[1216,1220,1221],{},"Catches",[1223,1224,1225,1236,1253],"tbody",{},[1213,1226,1227,1233],{},[1228,1229,1230],"td",{},[860,1231,1232],{},"\u002F\u003C\\s*\\\u002F?\\s*[A-Za-z][A-Za-z0-9-]*(?:\\s+[^>]*?)?\\s*>\u002Fi",[1228,1234,1235],{},"Any HTML tag",[1213,1237,1238,1243],{},[1228,1239,1240],{},[860,1241,1242],{},"\u002Fon\\w+\\s*=\u002Fi",[1228,1244,1245,1246,961,1249,1252],{},"Inline event handlers (",[860,1247,1248],{},"onclick=",[860,1250,1251],{},"onerror=",")",[1213,1254,1255,1260],{},[1228,1256,1257],{},[860,1258,1259],{},"\u002Fjavascript\\s*:\u002Fi",[1228,1261,1262],{},"JavaScript protocol URIs",[856,1264,1265,1266,1268,1269,1272,1273,1275],{},"If any pattern matches, ",[860,1267,1005],{}," is set to ",[860,1270,1271],{},"true"," in the results. This flag is used downstream by ",[860,1274,792],{}," to trigger IP banning.",[1073,1277,1279],{"id":1278},"sanitize-html-pass","sanitize-html pass",[856,1281,1282,1283,1288],{},"The string is passed through ",[869,1284,1287],{"href":1285,"rel":1286},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fsanitize-html",[873],"sanitize-html"," with a strict configuration:",[1290,1291,1292,1299,1304,1309,1314,1319,1324],"ul",{},[1293,1294,1295,1298],"li",{},[860,1296,1297],{},"allowedTags: []",",",[1293,1300,1301,1298],{},[860,1302,1303],{},"allowedAttributes: {}",[1293,1305,1306,1298],{},[860,1307,1308],{},"allowedIframeHostnames: []",[1293,1310,1311,1298],{},[860,1312,1313],{},"allowedSchemes: []",[1293,1315,1316,1298],{},[860,1317,1318],{},"allowProtocolRelative: false",[1293,1320,1321,1298],{},[860,1322,1323],{},"nestingLimit: 10",[1293,1325,1326,1002],{},[860,1327,1328],{},"nonTextTags: ['script', 'style', 'noscript', 'iframe', 'svg']",[856,1330,1331,1332,1335,1336,1339,1340,1268,1342,1344],{},"The ",[860,1333,1334],{},"textFilter"," re-runs the tag regex on text nodes, and ",[860,1337,1338],{},"onOpenTag"," records any tag name and attribute set that the sanitizer had to strip. If the string shrinks during this pass, ",[860,1341,1005],{},[860,1343,1271],{}," even if pattern detection did not trigger.",[1073,1346,1348],{"id":1347},"entity-encoding","Entity encoding",[856,1350,1351,1352,961,1355,961,1357,961,1360,961,1363,1365,1366,1369],{},"The final output is entity-encoded: ",[860,1353,1354],{},"&",[860,1356,1111],{},[860,1358,1359],{},">",[860,1361,1362],{},"\"",[860,1364,1031],{},", backtick, and ",[860,1367,1368],{},"${"," are replaced with their entity or escaped equivalents. The backtick and template-literal escapes prevent injection into JavaScript template strings. The result is trimmed.",[1207,1371,1372,1382],{},[1210,1373,1374],{},[1213,1375,1376,1379],{},[1216,1377,1378],{},"Character",[1216,1380,1381],{},"Replacement",[1223,1383,1384,1395,1406,1417,1428,1439,1451],{},[1213,1385,1386,1390],{},[1228,1387,1388],{},[860,1389,1354],{},[1228,1391,1392],{},[860,1393,1394],{},"&amp;",[1213,1396,1397,1401],{},[1228,1398,1399],{},[860,1400,1111],{},[1228,1402,1403],{},[860,1404,1405],{},"&lt;",[1213,1407,1408,1412],{},[1228,1409,1410],{},[860,1411,1359],{},[1228,1413,1414],{},[860,1415,1416],{},"&gt;",[1213,1418,1419,1423],{},[1228,1420,1421],{},[860,1422,1362],{},[1228,1424,1425],{},[860,1426,1427],{},"&quot;",[1213,1429,1430,1434],{},[1228,1431,1432],{},[860,1433,1031],{},[1228,1435,1436],{},[860,1437,1438],{},"&#x27;",[1213,1440,1441,1446],{},[1228,1442,1443],{},[860,1444,1445],{},"`",[1228,1447,1448],{},[860,1449,1450],{},"&#x60;",[1213,1452,1453,1457],{},[1228,1454,1455],{},[860,1456,1368],{},[1228,1458,1459],{},[860,1460,1461],{},"\\${",[887,1463],{},[890,1465,1467],{"id":1466},"zod-integration","Zod integration",[856,1469,1470,1472,1473,1478,1479,1482],{},[860,1471,866],{}," creates a Zod string schema that validates length and optional regex constraints, then runs the full sanitization pipeline as a ",[869,1474,1477],{"href":1475,"rel":1476},"https:\u002F\u002Fzod.dev\u002F?id=transform",[873],"Zod transform",". The returned value is always the sanitized output, and any HTML detection is reported as a Zod issue with an ",[860,1480,1481],{},"'HTML found'"," message prefix.",[904,1484,1486],{"className":906,"code":1485,"language":908,"meta":909,"style":909},"import { makeSanitizedZodString } from '@riavzon\u002Fauth'\nimport { z } from 'zod'\n\nconst commentSchema = z.object({\n  text: makeSanitizedZodString({ min: 1, max: 1000 }),\n  name: makeSanitizedZodString({\n    min: 2,\n    max: 50,\n    pattern: \u002F^[A-Za-z\\s]+$\u002F,\n    patternMsg: 'Name must contain only letters and spaces',\n  }),\n})\n",[860,1487,1488,1507,1527,1531,1552,1589,1600,1613,1625,1661,1677,1683],{"__ignoreMap":909},[913,1489,1490,1492,1494,1496,1498,1501,1503,1505],{"class":915,"line":916},[913,1491,920],{"class":919},[913,1493,954],{"class":953},[913,1495,866],{"class":923},[913,1497,967],{"class":953},[913,1499,1500],{"class":919},"from",[913,1502,931],{"class":930},[913,1504,884],{"class":934},[913,1506,937],{"class":930},[913,1508,1509,1511,1513,1516,1518,1520,1522,1525],{"class":915,"line":940},[913,1510,920],{"class":919},[913,1512,954],{"class":953},[913,1514,1515],{"class":923},"z",[913,1517,967],{"class":953},[913,1519,1500],{"class":919},[913,1521,931],{"class":930},[913,1523,1524],{"class":934},"zod",[913,1526,937],{"class":930},[913,1528,1529],{"class":915,"line":946},[913,1530,943],{"emptyLinePlaceholder":8},[913,1532,1533,1535,1538,1541,1544,1546,1549],{"class":915,"line":986},[913,1534,950],{"class":949},[913,1536,1537],{"class":957}," commentSchema",[913,1539,1540],{"class":970}," =",[913,1542,1543],{"class":923}," z",[913,1545,1002],{"class":953},[913,1547,1548],{"class":974},"object",[913,1550,1551],{"class":953},"({\n",[913,1553,1554,1557,1561,1564,1567,1570,1572,1576,1578,1581,1583,1586],{"class":915,"line":991},[913,1555,1556],{"class":923},"  text",[913,1558,1560],{"class":1559},"s34zl",":",[913,1562,1563],{"class":974}," makeSanitizedZodString",[913,1565,1566],{"class":953},"({ ",[913,1568,1569],{"class":923},"min",[913,1571,1560],{"class":1559},[913,1573,1575],{"class":1574},"spgvN"," 1",[913,1577,961],{"class":953},[913,1579,1580],{"class":923},"max",[913,1582,1560],{"class":1559},[913,1584,1585],{"class":1574}," 1000",[913,1587,1588],{"class":953}," }),\n",[913,1590,1591,1594,1596,1598],{"class":915,"line":1011},[913,1592,1593],{"class":923},"  name",[913,1595,1560],{"class":1559},[913,1597,1563],{"class":974},[913,1599,1551],{"class":953},[913,1601,1602,1605,1607,1610],{"class":915,"line":1018},[913,1603,1604],{"class":923},"    min",[913,1606,1560],{"class":1559},[913,1608,1609],{"class":1574}," 2",[913,1611,1612],{"class":953},",\n",[913,1614,1615,1618,1620,1623],{"class":915,"line":1050},[913,1616,1617],{"class":923},"    max",[913,1619,1560],{"class":1559},[913,1621,1622],{"class":1574}," 50",[913,1624,1612],{"class":953},[913,1626,1627,1630,1632,1636,1640,1644,1648,1651,1654,1657,1659],{"class":915,"line":1056},[913,1628,1629],{"class":923},"    pattern",[913,1631,1560],{"class":1559},[913,1633,1635],{"class":1634},"sRg35"," \u002F",[913,1637,1639],{"class":1638},"st6lo","^",[913,1641,1643],{"class":1642},"sODv-","[",[913,1645,1647],{"class":1646},"s58tv","A-Za-z\\s",[913,1649,1650],{"class":1642},"]",[913,1652,1653],{"class":970},"+",[913,1655,1656],{"class":1638},"$",[913,1658,1125],{"class":1634},[913,1660,1612],{"class":953},[913,1662,1663,1666,1668,1670,1673,1675],{"class":915,"line":1061},[913,1664,1665],{"class":923},"    patternMsg",[913,1667,1560],{"class":1559},[913,1669,931],{"class":930},[913,1671,1672],{"class":934},"Name must contain only letters and spaces",[913,1674,1031],{"class":930},[913,1676,1612],{"class":953},[913,1678,1680],{"class":915,"line":1679},11,[913,1681,1682],{"class":953},"  }),\n",[913,1684,1686],{"class":915,"line":1685},12,[913,1687,1688],{"class":953},"})\n",[1690,1691,1693],"h3",{"id":1692},"parameters","Parameters",[1695,1696,1697,1704,1709,1716],"field-group",{},[1698,1699,1701],"field",{"name":1569,"type":1700,":required":1271},"number",[856,1702,1703],{},"Minimum string length. Enforced before sanitization.",[1698,1705,1706],{"name":1580,"type":1700,":required":1271},[856,1707,1708],{},"Maximum string length. Enforced before sanitization.",[1698,1710,1713],{"name":1711,"type":1712},"pattern","RegExp",[856,1714,1715],{},"Optional regex the string must match. Validated after length checks and before sanitization.",[1698,1717,1720],{"name":1718,"type":1719},"patternMsg","string",[856,1721,1722],{},"Custom error message shown when the pattern does not match.",[1690,1724,1726],{"id":1725},"how-it-works","How it works",[856,1728,1729],{},"The schema chains three operations:",[1731,1732,1733,1751,1769],"ol",{},[1293,1734,1735,1739,1740,961,1743,1746,1747,1750],{},[1736,1737,1738],"strong",{},"Length and pattern validation"," using standard Zod ",[860,1741,1742],{},".min()",[860,1744,1745],{},".max()",", and ",[860,1748,1749],{},".regex()"," validators",[1293,1752,1753,1756,1757,1760,1761,1763,1764,1766,1767],{},[1736,1754,1755],{},"HTML detection check"," via ",[860,1758,1759],{},".check()"," that calls ",[860,1762,862],{}," and pushes a custom Zod issue if ",[860,1765,1005],{}," is ",[860,1768,1271],{},[1293,1770,1771,1756,1774,1760,1777,1779,1780,1782],{},[1736,1772,1773],{},"Sanitization transform",[860,1775,1776],{},".transform()",[860,1778,862],{}," again and returns only the cleaned ",[860,1781,958],{}," string",[1784,1785,1786],"tip",{},[856,1787,1788,1789,1791],{},"Every Zod schema in the built-in authentication controllers (signup, login, MFA, email update, password reset, OAuth) uses ",[860,1790,866],{}," for all user-supplied string fields. If you add custom routes, use it for consistency.",[856,1793,1794,1795,1797],{},"The built-in schemas that use ",[860,1796,866],{}," include:",[1207,1799,1800,1810],{},[1210,1801,1802],{},[1213,1803,1804,1807],{},[1216,1805,1806],{},"Schema",[1216,1808,1809],{},"Fields",[1223,1811,1812,1827,1837,1851,1860,1873],{},[1213,1813,1814,1816],{},[1228,1815,99],{},[1228,1817,1818,961,1821,961,1824],{},[860,1819,1820],{},"name",[860,1822,1823],{},"email",[860,1825,1826],{},"password",[1213,1828,1829,1831],{},[1228,1830,103],{},[1228,1832,1833,961,1835],{},[860,1834,1823],{},[860,1836,1826],{},[1213,1838,1839,1842],{},[1228,1840,1841],{},"Email update",[1228,1843,1844,961,1846,961,1849],{},[860,1845,1823],{},[860,1847,1848],{},"newEmail",[860,1850,1826],{},[1213,1852,1853,1856],{},[1228,1854,1855],{},"MFA code",[1228,1857,1858],{},[860,1859,860],{},[1213,1861,1862,1865],{},[1228,1863,1864],{},"Password reset",[1228,1866,1867,961,1870],{},[860,1868,1869],{},"random",[860,1871,1872],{},"reason",[1213,1874,1875,1878],{},[1228,1876,1877],{},"Custom MFA",[1228,1879,1880,961,1882],{},[860,1881,1869],{},[860,1883,1872],{},[887,1885],{},[890,1887,1889],{"id":1888},"validation-with-xss-enforcement","Validation with XSS enforcement",[856,1891,1892,1894,1895,1897,1898,1900,1901,1904],{},[860,1893,792],{}," ties the full pipeline together. It parses input against a Zod schema, and when any Zod issue starts with ",[860,1896,1481],{}," (produced by ",[860,1899,866],{},"), it calls ",[860,1902,1903],{},"handleXSS"," to ban the client immediately.",[904,1906,1908],{"className":906,"code":1907,"language":908,"meta":909,"style":909},"import { validateZodSchema } from '@riavzon\u002Fauth'\n\nconst result = await validateZodSchema(commentSchema, req.body, req, log)\n\nif ('valid' in result && result.valid === false) {\n  \u002F\u002F Validation failed (could be XSS ban or normal validation error)\n  res.status(result.errors === 'XSS attempt' ? 403 : 400).json({ errors: result.errors })\n  return\n}\n\nif (!result.success) {\n  \u002F\u002F Standard Zod validation error\n  res.status(422).json(result.error.format())\n  return\n}\n\n\u002F\u002F result.data is fully sanitized and validated\nconst { text, name } = result.data\n",[860,1909,1910,1928,1932,1972,1976,2012,2017,2078,2083,2087,2091,2109,2114,2149,2154,2159,2164,2170],{"__ignoreMap":909},[913,1911,1912,1914,1916,1918,1920,1922,1924,1926],{"class":915,"line":916},[913,1913,920],{"class":919},[913,1915,954],{"class":953},[913,1917,792],{"class":923},[913,1919,967],{"class":953},[913,1921,1500],{"class":919},[913,1923,931],{"class":930},[913,1925,884],{"class":934},[913,1927,937],{"class":930},[913,1929,1930],{"class":915,"line":940},[913,1931,943],{"emptyLinePlaceholder":8},[913,1933,1934,1936,1939,1941,1944,1947,1949,1952,1954,1957,1959,1962,1964,1966,1968,1970],{"class":915,"line":946},[913,1935,950],{"class":949},[913,1937,1938],{"class":957}," result",[913,1940,1540],{"class":970},[913,1942,1943],{"class":919}," await",[913,1945,1946],{"class":974}," validateZodSchema",[913,1948,977],{"class":953},[913,1950,1951],{"class":923},"commentSchema",[913,1953,961],{"class":953},[913,1955,1956],{"class":923},"req",[913,1958,1002],{"class":953},[913,1960,1961],{"class":923},"body",[913,1963,961],{"class":953},[913,1965,1956],{"class":923},[913,1967,961],{"class":953},[913,1969,1026],{"class":923},[913,1971,983],{"class":953},[913,1973,1974],{"class":915,"line":986},[913,1975,943],{"emptyLinePlaceholder":8},[913,1977,1978,1980,1982,1984,1987,1989,1992,1994,1997,1999,2001,2003,2006,2010],{"class":915,"line":991},[913,1979,994],{"class":919},[913,1981,997],{"class":953},[913,1983,1031],{"class":930},[913,1985,1986],{"class":934},"valid",[913,1988,1031],{"class":930},[913,1990,1991],{"class":949}," in",[913,1993,1938],{"class":923},[913,1995,1996],{"class":970}," &&",[913,1998,1938],{"class":923},[913,2000,1002],{"class":953},[913,2002,1986],{"class":923},[913,2004,2005],{"class":970}," ===",[913,2007,2009],{"class":2008},"sjR7W"," false",[913,2011,1008],{"class":953},[913,2013,2014],{"class":915,"line":1011},[913,2015,2016],{"class":1014},"  \u002F\u002F Validation failed (could be XSS ban or normal validation error)\n",[913,2018,2019,2022,2024,2027,2029,2032,2034,2037,2039,2041,2044,2046,2049,2052,2055,2058,2061,2063,2065,2067,2069,2071,2073,2075],{"class":915,"line":1018},[913,2020,2021],{"class":923},"  res",[913,2023,1002],{"class":953},[913,2025,2026],{"class":974},"status",[913,2028,977],{"class":953},[913,2030,2031],{"class":923},"result",[913,2033,1002],{"class":953},[913,2035,2036],{"class":923},"errors",[913,2038,2005],{"class":970},[913,2040,931],{"class":930},[913,2042,2043],{"class":934},"XSS attempt",[913,2045,1031],{"class":930},[913,2047,2048],{"class":970}," ?",[913,2050,2051],{"class":1574}," 403",[913,2053,2054],{"class":970}," :",[913,2056,2057],{"class":1574}," 400",[913,2059,2060],{"class":953},").",[913,2062,5],{"class":974},[913,2064,1566],{"class":953},[913,2066,2036],{"class":923},[913,2068,1560],{"class":1559},[913,2070,1938],{"class":923},[913,2072,1002],{"class":953},[913,2074,2036],{"class":923},[913,2076,2077],{"class":953}," })\n",[913,2079,2080],{"class":915,"line":1050},[913,2081,2082],{"class":919},"  return\n",[913,2084,2085],{"class":915,"line":1056},[913,2086,1053],{"class":953},[913,2088,2089],{"class":915,"line":1061},[913,2090,943],{"emptyLinePlaceholder":8},[913,2092,2093,2095,2097,2100,2102,2104,2107],{"class":915,"line":1679},[913,2094,994],{"class":919},[913,2096,997],{"class":953},[913,2098,2099],{"class":970},"!",[913,2101,2031],{"class":923},[913,2103,1002],{"class":953},[913,2105,2106],{"class":923},"success",[913,2108,1008],{"class":953},[913,2110,2111],{"class":915,"line":1685},[913,2112,2113],{"class":1014},"  \u002F\u002F Standard Zod validation error\n",[913,2115,2117,2119,2121,2123,2125,2128,2130,2132,2134,2136,2138,2141,2143,2146],{"class":915,"line":2116},13,[913,2118,2021],{"class":923},[913,2120,1002],{"class":953},[913,2122,2026],{"class":974},[913,2124,977],{"class":953},[913,2126,2127],{"class":1574},"422",[913,2129,2060],{"class":953},[913,2131,5],{"class":974},[913,2133,977],{"class":953},[913,2135,2031],{"class":923},[913,2137,1002],{"class":953},[913,2139,2140],{"class":923},"error",[913,2142,1002],{"class":953},[913,2144,2145],{"class":974},"format",[913,2147,2148],{"class":953},"())\n",[913,2150,2152],{"class":915,"line":2151},14,[913,2153,2082],{"class":919},[913,2155,2157],{"class":915,"line":2156},15,[913,2158,1053],{"class":953},[913,2160,2162],{"class":915,"line":2161},16,[913,2163,943],{"emptyLinePlaceholder":8},[913,2165,2167],{"class":915,"line":2166},17,[913,2168,2169],{"class":1014},"\u002F\u002F result.data is fully sanitized and validated\n",[913,2171,2173,2175,2177,2180,2182,2184,2186,2188,2190,2192],{"class":915,"line":2172},18,[913,2174,950],{"class":949},[913,2176,954],{"class":953},[913,2178,2179],{"class":957},"text",[913,2181,961],{"class":953},[913,2183,1820],{"class":957},[913,2185,967],{"class":953},[913,2187,971],{"class":970},[913,2189,1938],{"class":923},[913,2191,1002],{"class":953},[913,2193,2194],{"class":923},"data\n",[1690,2196,2198],{"id":2197},"validation-flow","Validation flow",[1069,2200,2201,2205,2212,2216,2229,2233,2254,2261,2265],{"level":1071},[1073,2202,2204],{"id":2203},"zod-parsing","Zod parsing",[856,2206,2207,2208,2211],{},"The schema is parsed with ",[860,2209,2210],{},"safeParse()",". If parsing succeeds, the validated and transformed data is returned immediately.",[1073,2213,2215],{"id":2214},"html-issue-scan","HTML issue scan",[856,2217,2218,2219,2222,2223,2225,2226,2228],{},"If parsing fails, the function scans the Zod error issues array for any issue whose ",[860,2220,2221],{},"message"," starts with ",[860,2224,1481],{},". This marker is set by ",[860,2227,866],{}," when the sanitizer detects HTML content.",[1073,2230,2232],{"id":2231},"xss-punishment","XSS punishment",[856,2234,2235,2236,2238,2239,2241,2242,2245,2246,2249,2250,2253],{},"When an HTML issue is found, ",[860,2237,1903],{}," is called with the Express request object. The function bans the client's IP using the ",[869,2240,399],{"href":35}," service with the configured ",[860,2243,2244],{},"banScore"," (defaults to 100) and the reason ",[860,2247,2248],{},"'XSS SCRIPTING ATTEMPT'",". It also marks the visitor's ",[860,2251,2252],{},"canary_id"," as a bot and updates the banned IP record.",[856,2255,2256,2257,2260],{},"The function returns ",[860,2258,2259],{},"{ valid: false, errors: 'XSS attempt' }"," and the controller responds with HTTP 403.",[1073,2262,2264],{"id":2263},"normal-validation-errors","Normal validation errors",[856,2266,2267,2268,1002],{},"If no HTML issues are found, the function collects all Zod issues into a key-value map (field name to error message) and returns ",[860,2269,2270],{},"{ valid: false, errors: { ... } }",[2272,2273,2274],"note",{},[856,2275,2276,2277,2280],{},"The XSS ban is permanent at the ",[869,2278,399],{"href":2279},"\u002Fdocs\u002Fbot-detector"," level. The client IP is added to the banned list, the visitor is flagged as a bot, and subsequent requests from that IP receive elevated scrutiny from anomaly detection. There is no automatic expiry.",[887,2282],{},[890,2284,2286],{"id":2285},"handlexss",[860,2287,1903],{},[856,2289,2290,2292,2293,2295,2296,2299],{},[860,2291,1903],{}," is the enforcement function called when an XSS attempt is confirmed. It reads the ",[860,2294,2244],{}," from ",[860,2297,2298],{},"botDetector.settings"," in the configuration (defaulting to 100 if not set) and executes three actions:",[904,2301,2303],{"className":906,"code":2302,"language":908,"meta":909,"style":909},"import { handleXSS } from '@riavzon\u002Fauth'\n\n\u002F\u002F Called automatically by validateZodSchema — you rarely need to call this directly\nawait handleXSS(req, '\u003Cscript>alert(1)\u003C\u002Fscript>', log)\n",[860,2304,2305,2323,2327,2332],{"__ignoreMap":909},[913,2306,2307,2309,2311,2313,2315,2317,2319,2321],{"class":915,"line":916},[913,2308,920],{"class":919},[913,2310,954],{"class":953},[913,2312,1903],{"class":923},[913,2314,967],{"class":953},[913,2316,1500],{"class":919},[913,2318,931],{"class":930},[913,2320,884],{"class":934},[913,2322,937],{"class":930},[913,2324,2325],{"class":915,"line":940},[913,2326,943],{"emptyLinePlaceholder":8},[913,2328,2329],{"class":915,"line":946},[913,2330,2331],{"class":1014},"\u002F\u002F Called automatically by validateZodSchema — you rarely need to call this directly\n",[913,2333,2334,2337,2340,2342,2344,2346,2348,2351,2353,2355,2357],{"class":915,"line":986},[913,2335,2336],{"class":919},"await",[913,2338,2339],{"class":974}," handleXSS",[913,2341,977],{"class":953},[913,2343,1956],{"class":923},[913,2345,961],{"class":953},[913,2347,1031],{"class":930},[913,2349,2350],{"class":934},"\u003Cscript>alert(1)\u003C\u002Fscript>",[913,2352,1031],{"class":930},[913,2354,961],{"class":953},[913,2356,1026],{"class":923},[913,2358,983],{"class":953},[1069,2360,2361,2365,2380,2384,2390],{"level":1071},[1073,2362,2364],{"id":2363},"ip-ban","IP ban",[856,2366,2367,2370,2371,2373,2374,2376,2377,2379],{},[860,2368,2369],{},"banIp"," is called first with the client IP and the configured ",[860,2372,2244],{},". This adds the IP to the ",[869,2375,399],{"href":2279}," ban list with the reason ",[860,2378,2248],{},". This step runs before the remaining actions to ensure the IP is blocked as quickly as possible.",[1073,2381,2383],{"id":2382},"visitor-record-and-bot-flag","Visitor record and bot flag",[856,2385,2386,2387,1560],{},"Two actions run concurrently via ",[860,2388,2389],{},"Promise.all",[1207,2391,2392,2405],{},[1210,2393,2394],{},[1213,2395,2396,2399,2402],{},[1216,2397,2398],{},"Action",[1216,2400,2401],{},"Function",[1216,2403,2404],{},"Effect",[1223,2406,2407,2420],{},[1213,2408,2409,2412,2417],{},[1228,2410,2411],{},"Visitor record",[1228,2413,2414],{},[860,2415,2416],{},"updateBannedIP(canary_id, ip, ua, { score: 10, reasons: [...] })",[1228,2418,2419],{},"Updates the banned IP record with the visitor's cookie, user agent, and ban reason",[1213,2421,2422,2425,2430],{},[1228,2423,2424],{},"Bot flag",[1228,2426,2427],{},[860,2428,2429],{},"updateIsBot(true, canary_id)",[1228,2431,2432,2433,2435],{},"Marks the visitor's ",[860,2434,2252],{}," as a confirmed bot in the visitors table",[856,2437,2438],{},"The function logs a warning before and after the ban.",[887,2440],{},[890,2442,2444],{"id":2443},"timing-attack-prevention","Timing attack prevention",[856,2446,2447,2450,2451,2454],{},[860,2448,2449],{},"timeEnumeration"," (exported as ",[860,2452,2453],{},"waitSomeTime"," internally) adds a fixed delay to responses where timing differences could leak information. Authentication endpoints use it to ensure that responses for valid and invalid inputs take the same amount of time.",[904,2456,2458],{"className":906,"code":2457,"language":908,"meta":909,"style":909},"import { timeEnumeration } from '@riavzon\u002Fauth'\n\nconst start = Date.now()\n\n\u002F\u002F ... process the request (may return early if user not found)\n\nconst elapsed = Date.now() - start\nconst minimumResponseTime = 3000 \u002F\u002F 3 seconds\n\nif (elapsed \u003C minimumResponseTime) {\n  await timeEnumeration(minimumResponseTime - elapsed, log)\n}\n",[860,2459,2460,2478,2482,2502,2506,2511,2515,2539,2554,2558,2574,2598],{"__ignoreMap":909},[913,2461,2462,2464,2466,2468,2470,2472,2474,2476],{"class":915,"line":916},[913,2463,920],{"class":919},[913,2465,954],{"class":953},[913,2467,2449],{"class":923},[913,2469,967],{"class":953},[913,2471,1500],{"class":919},[913,2473,931],{"class":930},[913,2475,884],{"class":934},[913,2477,937],{"class":930},[913,2479,2480],{"class":915,"line":940},[913,2481,943],{"emptyLinePlaceholder":8},[913,2483,2484,2486,2489,2491,2494,2496,2499],{"class":915,"line":946},[913,2485,950],{"class":949},[913,2487,2488],{"class":957}," start",[913,2490,1540],{"class":970},[913,2492,2493],{"class":923}," Date",[913,2495,1002],{"class":953},[913,2497,2498],{"class":974},"now",[913,2500,2501],{"class":953},"()\n",[913,2503,2504],{"class":915,"line":986},[913,2505,943],{"emptyLinePlaceholder":8},[913,2507,2508],{"class":915,"line":991},[913,2509,2510],{"class":1014},"\u002F\u002F ... process the request (may return early if user not found)\n",[913,2512,2513],{"class":915,"line":1011},[913,2514,943],{"emptyLinePlaceholder":8},[913,2516,2517,2519,2522,2524,2526,2528,2530,2533,2536],{"class":915,"line":1018},[913,2518,950],{"class":949},[913,2520,2521],{"class":957}," elapsed",[913,2523,1540],{"class":970},[913,2525,2493],{"class":923},[913,2527,1002],{"class":953},[913,2529,2498],{"class":974},[913,2531,2532],{"class":953},"() ",[913,2534,2535],{"class":970},"-",[913,2537,2538],{"class":923}," start\n",[913,2540,2541,2543,2546,2548,2551],{"class":915,"line":1050},[913,2542,950],{"class":949},[913,2544,2545],{"class":957}," minimumResponseTime",[913,2547,1540],{"class":970},[913,2549,2550],{"class":1574}," 3000",[913,2552,2553],{"class":1014}," \u002F\u002F 3 seconds\n",[913,2555,2556],{"class":915,"line":1056},[913,2557,943],{"emptyLinePlaceholder":8},[913,2559,2560,2562,2564,2567,2570,2572],{"class":915,"line":1061},[913,2561,994],{"class":919},[913,2563,997],{"class":953},[913,2565,2566],{"class":923},"elapsed",[913,2568,2569],{"class":970}," \u003C",[913,2571,2545],{"class":923},[913,2573,1008],{"class":953},[913,2575,2576,2579,2582,2584,2587,2590,2592,2594,2596],{"class":915,"line":1679},[913,2577,2578],{"class":919},"  await",[913,2580,2581],{"class":974}," timeEnumeration",[913,2583,977],{"class":953},[913,2585,2586],{"class":923},"minimumResponseTime",[913,2588,2589],{"class":970}," -",[913,2591,2521],{"class":923},[913,2593,961],{"class":953},[913,2595,1026],{"class":923},[913,2597,983],{"class":953},[913,2599,2600],{"class":915,"line":1685},[913,2601,1053],{"class":953},[856,2603,2604],{},"The following controllers enforce a minimum 3-second response time:",[1207,2606,2607,2620],{},[1210,2608,2609],{},[1213,2610,2611,2614,2617],{},[1216,2612,2613],{},"Controller",[1216,2615,2616],{},"Route",[1216,2618,2619],{},"Why",[1223,2621,2622,2637],{},[1213,2623,2624,2629,2634],{},[1228,2625,2626],{},[860,2627,2628],{},"initPasswordReset",[1228,2630,2631],{},[860,2632,2633],{},"POST \u002Fauth\u002Fforgot-password",[1228,2635,2636],{},"Prevents enumerating which email addresses have accounts",[1213,2638,2639,2644,2649],{},[1228,2640,2641],{},[860,2642,2643],{},"initCustomMfaFlow",[1228,2645,2646],{},[860,2647,2648],{},"POST \u002Fcustom\u002Fmfa\u002F:reason",[1228,2650,2651],{},"Prevents timing analysis of custom MFA initiation",[1784,2653,2654],{},[856,2655,2656,2657,2659],{},"Always use ",[860,2658,2449],{}," on any endpoint that reveals presence or absence of a user account through its response time. A password reset endpoint that returns instantly for unknown emails and slowly for known ones leaks account existence.",[887,2661],{},[890,2663,2665],{"id":2664},"applying-xss-protection-in-custom-handlers","Applying XSS protection in custom handlers",[856,2667,2668,2669,2671,2672,2674],{},"The full pipeline works in four steps: define a schema with ",[860,2670,866],{},", validate with ",[860,2673,792],{},", check the result, and use the sanitized data.",[904,2676,2678],{"className":906,"code":2677,"language":908,"meta":909,"style":909},"import { validateZodSchema, makeSanitizedZodString } from '@riavzon\u002Fauth'\nimport { z } from 'zod'\n\nconst profileSchema = z.object({\n  displayName: makeSanitizedZodString({ min: 1, max: 100 }),\n  bio: makeSanitizedZodString({ min: 0, max: 500 }),\n})\n\nrouter.post('\u002Fprofile', async (req, res) => {\n  const log = getLogger().child({ route: '\u002Fprofile' })\n  const result = await validateZodSchema(profileSchema, req.body, req, log)\n\n  if ('valid' in result && !result.valid) {\n    if (result.errors === 'XSS attempt') {\n      return res.status(403).json({ banned: true })\n    }\n    return res.status(400).json({ errors: result.errors })\n  }\n\n  if (!result.success) {\n    return res.status(422).json(result.error.format())\n  }\n\n  \u002F\u002F result.data.displayName and result.data.bio are fully sanitized\n  await db.updateProfile(userId, result.data)\n  res.json({ ok: true })\n})\n",[860,2679,2680,2702,2720,2724,2741,2769,2798,2802,2806,2849,2883,2918,2922,2952,2975,3008,3013,3047,3052,3057,3074,3107,3112,3117,3123,3152,3172],{"__ignoreMap":909},[913,2681,2682,2684,2686,2688,2690,2692,2694,2696,2698,2700],{"class":915,"line":916},[913,2683,920],{"class":919},[913,2685,954],{"class":953},[913,2687,792],{"class":923},[913,2689,961],{"class":953},[913,2691,866],{"class":923},[913,2693,967],{"class":953},[913,2695,1500],{"class":919},[913,2697,931],{"class":930},[913,2699,884],{"class":934},[913,2701,937],{"class":930},[913,2703,2704,2706,2708,2710,2712,2714,2716,2718],{"class":915,"line":940},[913,2705,920],{"class":919},[913,2707,954],{"class":953},[913,2709,1515],{"class":923},[913,2711,967],{"class":953},[913,2713,1500],{"class":919},[913,2715,931],{"class":930},[913,2717,1524],{"class":934},[913,2719,937],{"class":930},[913,2721,2722],{"class":915,"line":946},[913,2723,943],{"emptyLinePlaceholder":8},[913,2725,2726,2728,2731,2733,2735,2737,2739],{"class":915,"line":986},[913,2727,950],{"class":949},[913,2729,2730],{"class":957}," profileSchema",[913,2732,1540],{"class":970},[913,2734,1543],{"class":923},[913,2736,1002],{"class":953},[913,2738,1548],{"class":974},[913,2740,1551],{"class":953},[913,2742,2743,2746,2748,2750,2752,2754,2756,2758,2760,2762,2764,2767],{"class":915,"line":991},[913,2744,2745],{"class":923},"  displayName",[913,2747,1560],{"class":1559},[913,2749,1563],{"class":974},[913,2751,1566],{"class":953},[913,2753,1569],{"class":923},[913,2755,1560],{"class":1559},[913,2757,1575],{"class":1574},[913,2759,961],{"class":953},[913,2761,1580],{"class":923},[913,2763,1560],{"class":1559},[913,2765,2766],{"class":1574}," 100",[913,2768,1588],{"class":953},[913,2770,2771,2774,2776,2778,2780,2782,2784,2787,2789,2791,2793,2796],{"class":915,"line":1011},[913,2772,2773],{"class":923},"  bio",[913,2775,1560],{"class":1559},[913,2777,1563],{"class":974},[913,2779,1566],{"class":953},[913,2781,1569],{"class":923},[913,2783,1560],{"class":1559},[913,2785,2786],{"class":1574}," 0",[913,2788,961],{"class":953},[913,2790,1580],{"class":923},[913,2792,1560],{"class":1559},[913,2794,2795],{"class":1574}," 500",[913,2797,1588],{"class":953},[913,2799,2800],{"class":915,"line":1018},[913,2801,1688],{"class":953},[913,2803,2804],{"class":915,"line":1050},[913,2805,943],{"emptyLinePlaceholder":8},[913,2807,2808,2811,2813,2816,2818,2820,2823,2825,2827,2830,2832,2835,2837,2840,2843,2846],{"class":915,"line":1056},[913,2809,2810],{"class":923},"router",[913,2812,1002],{"class":953},[913,2814,2815],{"class":974},"post",[913,2817,977],{"class":953},[913,2819,1031],{"class":930},[913,2821,2822],{"class":934},"\u002Fprofile",[913,2824,1031],{"class":930},[913,2826,961],{"class":953},[913,2828,2829],{"class":949},"async",[913,2831,997],{"class":953},[913,2833,1956],{"class":2834},"sygFZ",[913,2836,961],{"class":953},[913,2838,2839],{"class":2834},"res",[913,2841,2842],{"class":953},") ",[913,2844,2845],{"class":949},"=>",[913,2847,2848],{"class":953}," {\n",[913,2850,2851,2854,2857,2859,2862,2865,2868,2870,2873,2875,2877,2879,2881],{"class":915,"line":1061},[913,2852,2853],{"class":949},"  const",[913,2855,2856],{"class":957}," log",[913,2858,1540],{"class":970},[913,2860,2861],{"class":974}," getLogger",[913,2863,2864],{"class":953},"().",[913,2866,2867],{"class":974},"child",[913,2869,1566],{"class":953},[913,2871,2872],{"class":923},"route",[913,2874,1560],{"class":1559},[913,2876,931],{"class":930},[913,2878,2822],{"class":934},[913,2880,1031],{"class":930},[913,2882,2077],{"class":953},[913,2884,2885,2887,2889,2891,2893,2895,2897,2900,2902,2904,2906,2908,2910,2912,2914,2916],{"class":915,"line":1679},[913,2886,2853],{"class":949},[913,2888,1938],{"class":957},[913,2890,1540],{"class":970},[913,2892,1943],{"class":919},[913,2894,1946],{"class":974},[913,2896,977],{"class":953},[913,2898,2899],{"class":923},"profileSchema",[913,2901,961],{"class":953},[913,2903,1956],{"class":923},[913,2905,1002],{"class":953},[913,2907,1961],{"class":923},[913,2909,961],{"class":953},[913,2911,1956],{"class":923},[913,2913,961],{"class":953},[913,2915,1026],{"class":923},[913,2917,983],{"class":953},[913,2919,2920],{"class":915,"line":1685},[913,2921,943],{"emptyLinePlaceholder":8},[913,2923,2924,2927,2929,2931,2933,2935,2937,2939,2941,2944,2946,2948,2950],{"class":915,"line":2116},[913,2925,2926],{"class":919},"  if",[913,2928,997],{"class":953},[913,2930,1031],{"class":930},[913,2932,1986],{"class":934},[913,2934,1031],{"class":930},[913,2936,1991],{"class":949},[913,2938,1938],{"class":923},[913,2940,1996],{"class":970},[913,2942,2943],{"class":970}," !",[913,2945,2031],{"class":923},[913,2947,1002],{"class":953},[913,2949,1986],{"class":923},[913,2951,1008],{"class":953},[913,2953,2954,2957,2959,2961,2963,2965,2967,2969,2971,2973],{"class":915,"line":2151},[913,2955,2956],{"class":919},"    if",[913,2958,997],{"class":953},[913,2960,2031],{"class":923},[913,2962,1002],{"class":953},[913,2964,2036],{"class":923},[913,2966,2005],{"class":970},[913,2968,931],{"class":930},[913,2970,2043],{"class":934},[913,2972,1031],{"class":930},[913,2974,1008],{"class":953},[913,2976,2977,2980,2983,2985,2987,2989,2992,2994,2996,2998,3001,3003,3006],{"class":915,"line":2156},[913,2978,2979],{"class":919},"      return",[913,2981,2982],{"class":923}," res",[913,2984,1002],{"class":953},[913,2986,2026],{"class":974},[913,2988,977],{"class":953},[913,2990,2991],{"class":1574},"403",[913,2993,2060],{"class":953},[913,2995,5],{"class":974},[913,2997,1566],{"class":953},[913,2999,3000],{"class":923},"banned",[913,3002,1560],{"class":1559},[913,3004,3005],{"class":2008}," true",[913,3007,2077],{"class":953},[913,3009,3010],{"class":915,"line":2161},[913,3011,3012],{"class":953},"    }\n",[913,3014,3015,3018,3020,3022,3024,3026,3029,3031,3033,3035,3037,3039,3041,3043,3045],{"class":915,"line":2166},[913,3016,3017],{"class":919},"    return",[913,3019,2982],{"class":923},[913,3021,1002],{"class":953},[913,3023,2026],{"class":974},[913,3025,977],{"class":953},[913,3027,3028],{"class":1574},"400",[913,3030,2060],{"class":953},[913,3032,5],{"class":974},[913,3034,1566],{"class":953},[913,3036,2036],{"class":923},[913,3038,1560],{"class":1559},[913,3040,1938],{"class":923},[913,3042,1002],{"class":953},[913,3044,2036],{"class":923},[913,3046,2077],{"class":953},[913,3048,3049],{"class":915,"line":2172},[913,3050,3051],{"class":953},"  }\n",[913,3053,3055],{"class":915,"line":3054},19,[913,3056,943],{"emptyLinePlaceholder":8},[913,3058,3060,3062,3064,3066,3068,3070,3072],{"class":915,"line":3059},20,[913,3061,2926],{"class":919},[913,3063,997],{"class":953},[913,3065,2099],{"class":970},[913,3067,2031],{"class":923},[913,3069,1002],{"class":953},[913,3071,2106],{"class":923},[913,3073,1008],{"class":953},[913,3075,3077,3079,3081,3083,3085,3087,3089,3091,3093,3095,3097,3099,3101,3103,3105],{"class":915,"line":3076},21,[913,3078,3017],{"class":919},[913,3080,2982],{"class":923},[913,3082,1002],{"class":953},[913,3084,2026],{"class":974},[913,3086,977],{"class":953},[913,3088,2127],{"class":1574},[913,3090,2060],{"class":953},[913,3092,5],{"class":974},[913,3094,977],{"class":953},[913,3096,2031],{"class":923},[913,3098,1002],{"class":953},[913,3100,2140],{"class":923},[913,3102,1002],{"class":953},[913,3104,2145],{"class":974},[913,3106,2148],{"class":953},[913,3108,3110],{"class":915,"line":3109},22,[913,3111,3051],{"class":953},[913,3113,3115],{"class":915,"line":3114},23,[913,3116,943],{"emptyLinePlaceholder":8},[913,3118,3120],{"class":915,"line":3119},24,[913,3121,3122],{"class":1014},"  \u002F\u002F result.data.displayName and result.data.bio are fully sanitized\n",[913,3124,3126,3128,3131,3133,3136,3138,3141,3143,3145,3147,3150],{"class":915,"line":3125},25,[913,3127,2578],{"class":919},[913,3129,3130],{"class":923}," db",[913,3132,1002],{"class":953},[913,3134,3135],{"class":974},"updateProfile",[913,3137,977],{"class":953},[913,3139,3140],{"class":923},"userId",[913,3142,961],{"class":953},[913,3144,2031],{"class":923},[913,3146,1002],{"class":953},[913,3148,3149],{"class":923},"data",[913,3151,983],{"class":953},[913,3153,3155,3157,3159,3161,3163,3166,3168,3170],{"class":915,"line":3154},26,[913,3156,2021],{"class":923},[913,3158,1002],{"class":953},[913,3160,5],{"class":974},[913,3162,1566],{"class":953},[913,3164,3165],{"class":923},"ok",[913,3167,1560],{"class":1559},[913,3169,3005],{"class":2008},[913,3171,2077],{"class":953},[913,3173,3175],{"class":915,"line":3174},27,[913,3176,1688],{"class":953},[887,3178],{},[890,3180,3182],{"id":3181},"configuration-reference","Configuration reference",[1695,3184,3185,3192],{},[1698,3186,3189],{"name":3187,"type":1700,"default":3188},"htmlSanitizer.IrritationCount","50",[856,3190,3191],{},"Maximum number of URI-decode and entity-decode iterations. Higher values catch deeper encoding chains but increase CPU cost per request. The input is rejected entirely if this limit is reached without the output stabilizing.",[1698,3193,3195],{"name":1082,"type":1700,"default":3194},"50000",[856,3196,3197],{},"Maximum input string length in characters. Inputs exceeding this limit are rejected before any processing begins. Prevents memory exhaustion from oversized payloads.",[3199,3200,3201],"caution",{},[856,3202,3203,3204,3206,3207,3210,3211,3214],{},"Setting ",[860,3205,1159],{}," to a very high value on a public endpoint creates a CPU exhaustion vector. Pair it with ",[860,3208,3209],{},"maxAllowedInputLength"," and a request body size limit (e.g. ",[860,3212,3213],{},"express.json({ limit: '2kb' })",") to bound worst-case processing time.",[887,3216],{},[890,3218,3220],{"id":3219},"summary","Summary",[856,3222,3223],{},"The XSS protection pipeline integrates with several other IAM subsystems:",[1207,3225,3226,3236],{},[1210,3227,3228],{},[1213,3229,3230,3233],{},[1216,3231,3232],{},"System",[1216,3234,3235],{},"Integration point",[1223,3237,3238,3251,3271,3282,3299],{},[1213,3239,3240,3244],{},[1228,3241,3242],{},[869,3243,95],{"href":96},[1228,3245,3246,3247,3250],{},"Banned IPs from XSS attempts raise the ",[860,3248,3249],{},"suspicious_activity_score",", which triggers MFA challenges or hard blocks when the score exceeds 25% of the ban threshold",[1213,3252,3253,3257],{},[1228,3254,3255],{},[869,3256,399],{"href":2279},[1228,3258,3259,3261,3262,961,3264,1746,3267,3270],{},[860,3260,1903],{}," calls ",[860,3263,2369],{},[860,3265,3266],{},"updateBannedIP",[860,3268,3269],{},"updateIsBot"," to record the threat in the bot detection database",[1213,3272,3273,3277],{},[1228,3274,3275],{},[869,3276,127],{"href":128},[1228,3278,1331,3279,3281],{},[860,3280,2252],{}," cookie ties the XSS ban to a specific device, so the ban persists even if the client's IP changes",[1213,3283,3284,3288],{},[1228,3285,3286],{},[869,3287,99],{"href":100},[1228,3289,3290,3291,961,3293,1746,3295,1100,3297],{},"New account creation validates ",[860,3292,1820],{},[860,3294,1823],{},[860,3296,1826],{},[860,3298,866],{},[1213,3300,3301,3305],{},[1228,3302,3303],{},[869,3304,123],{"href":124},[1228,3306,3307],{},"OTP code submission validates the code field through the same pipeline",[3309,3310,3311],"style",{},"html pre.shiki code .sZ328, html code.shiki .sZ328{--shiki-light:#AF00DB;--shiki-default:#AF00DB;--shiki-dark:#FF79C6}html pre.shiki code .sjsA6, html code.shiki .sjsA6{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#F8F8F2}html pre.shiki code .sFkSl, html code.shiki .sFkSl{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#E9F284}html pre.shiki code .sFB1V, html code.shiki .sFB1V{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#F1FA8C}html pre.shiki code .sl46w, html code.shiki .sl46w{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#FF79C6}html pre.shiki code .sDd4n, html code.shiki .sDd4n{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#F8F8F2}html pre.shiki code .s3JHE, html code.shiki .s3JHE{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#F8F8F2}html pre.shiki code .saOXh, html code.shiki .saOXh{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#FF79C6}html pre.shiki code .sHOzp, html code.shiki .sHOzp{--shiki-light:#795E26;--shiki-default:#795E26;--shiki-dark:#50FA7B}html pre.shiki code .sghk6, html code.shiki .sghk6{--shiki-light:#008000;--shiki-default:#008000;--shiki-dark:#6272A4}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s34zl, html code.shiki .s34zl{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#FF79C6}html pre.shiki code .spgvN, html code.shiki .spgvN{--shiki-light:#098658;--shiki-default:#098658;--shiki-dark:#BD93F9}html pre.shiki code .sRg35, html code.shiki .sRg35{--shiki-light:#811F3F;--shiki-default:#811F3F;--shiki-dark:#FF5555}html pre.shiki code .st6lo, html code.shiki .st6lo{--shiki-light:#EE0000;--shiki-default:#EE0000;--shiki-dark:#FF79C6}html pre.shiki code .sODv-, html code.shiki .sODv-{--shiki-light:#D16969;--shiki-default:#D16969;--shiki-dark:#8BE9FD}html pre.shiki code .s58tv, html code.shiki .s58tv{--shiki-light:#811F3F;--shiki-default:#811F3F;--shiki-dark:#BD93F9}html pre.shiki code .sjR7W, html code.shiki .sjR7W{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#BD93F9}html pre.shiki code .sygFZ, html code.shiki .sygFZ{--shiki-light:#001080;--shiki-light-font-style:inherit;--shiki-default:#001080;--shiki-default-font-style:inherit;--shiki-dark:#FFB86C;--shiki-dark-font-style:italic}",{"title":909,"searchDepth":940,"depth":940,"links":3313},[3314,3315,3319,3322,3323,3324,3325,3326],{"id":892,"depth":940,"text":893},{"id":1466,"depth":940,"text":1467,"children":3316},[3317,3318],{"id":1692,"depth":946,"text":1693},{"id":1725,"depth":946,"text":1726},{"id":1888,"depth":940,"text":1889,"children":3320},[3321],{"id":2197,"depth":946,"text":2198},{"id":2285,"depth":940,"text":1903},{"id":2443,"depth":940,"text":2444},{"id":2664,"depth":940,"text":2665},{"id":3181,"depth":940,"text":3182},{"id":3219,"depth":940,"text":3220},"The multi-pass HTML sanitization pipeline, Zod integration, automatic IP banning on XSS detection, timing-attack prevention, and how to apply the full defense chain in custom handlers.","md","i-lucide-shield-x",{},null,"---\ntitle: XSS Protection\ndescription: The multi-pass HTML sanitization pipeline, Zod integration, automatic IP banning on XSS detection, timing-attack prevention, and how to apply the full defense chain in custom handlers.\nicon: i-lucide-shield-x\n---\n\nThe IAM service provides a layered XSS defense pipeline that runs on every user-supplied string. The pipeline consists of three components that work together: `sanitizeInput` performs deep multi-pass HTML stripping and entity encoding, `makeSanitizedZodString` integrates that sanitizer into [Zod](https:\u002F\u002Fzod.dev\u002F) schemas so validation and sanitization happen in a single step, and `validateZodSchema` orchestrates the whole flow while automatically banning the client's IP when an XSS payload is detected.\n\nAll three utilities are exported from `@riavzon\u002Fauth` for use in your own route handlers. The built-in authentication controllers (signup, login, MFA verification, email update, password reset, OAuth) already use the full pipeline on every field that accepts user input.\n\n---\n\n## Sanitization pipeline\n\n`sanitizeInput` (exported as the default from `htmlSanitizer`) is the core sanitization function. It accepts a raw string and returns a cleaned string along with a detection report indicating whether any HTML was found during processing.\n\n```ts\nimport sanitizeInput from '@riavzon\u002Fauth'\n\nconst { vall, results } = sanitizeInput(userInput)\n\nif (results.htmlFound) {\n  \u002F\u002F HTML or script injection was detected and stripped\n  console.log('Detected tags:', results.tags)\n}\n\n\u002F\u002F vall is the fully sanitized string, safe for storage or rendering\n```\n\nThe function performs 8 sequential stages. Each stage builds on the previous one, and an attacker must bypass all of them for a payload to survive.\n\n::steps{level=\"4\"}\n\n#### Length guard\n\nBefore any processing, the sanitizer rejects input longer than `htmlSanitizer.maxAllowedInputLength` (default 50000). Oversized input throws rather than entering the loop. This is the hard cap on CPU cost for a single call.\n\n#### Unicode normalization\n\nThe input is normalized to [NFKC](https:\u002F\u002Funicode.org\u002Freports\u002Ftr15\u002F), which collapses visually similar characters to their canonical form Zero-width characters, soft hyphens, byte-order marks, and bidirectional override characters are stripped in the same pass. Halfwidth and\nfullwidth ASCII characters (`U+FF01` through `U+FF5E`) are transliterated back to standard ASCII. This defeats payloads that hide tags inside fullwidth substitutions such as `\\uFF1C` for `\u003C`.\n\n#### Strict URI decode\n\n`decodeURIComponent` is called once inside a `try`\u002F`catch`. If the call throws (malformed percent-encoding like `%ZZ`), the input is rejected immediately and returned as an empty string with `htmlFound: true`. Legitimate input does not contain malformed URI sequences, so rejecting early keeps broken data out of the loop.\n\n#### Iterative URI and entity decoding\n\nThe function enters a decode loop that alternates between `decodeURIComponent` and `he.decode` ([he](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fhe) is an HTML entity decoder). Each iteration decodes one layer of encoding. The loop continues until the output stabilizes (no change between iterations) or until the `IrritationCount` limit is reached.\n\nThis catches payloads that rely on nested encoding: `%253Cscript%253E` decodes to `%3Cscript%3E` on the first pass, then to `\u003Cscript>` on the second. Without the loop, a single-pass decoder would leave the inner encoding intact.\n\n::warning\nIf the loop exceeds `IrritationCount` iterations without stabilizing, the input is rejected entirely and returned as an empty string with `htmlFound: true`. This protects against intentionally crafted inputs designed to consume CPU through deep encoding chains.\n::\n\n#### Residual cleanup\n\nAfter the loop, zero-width characters are stripped again (the decoders may have reintroduced them) and any whitespace inside the bodies of surviving tag-like substrings is removed so that `\u003Cscr\\tipt>` cannot slip past the tag regex.\n\n#### Pattern detection\n\nAfter decoding, the function tests the cleaned string against three patterns:\n\n| Pattern | Catches |\n|---|---|\n| `\u002F\u003C\\s*\\\u002F?\\s*[A-Za-z][A-Za-z0-9-]*(?:\\s+[^>]*?)?\\s*>\u002Fi` | Any HTML tag |\n| `\u002Fon\\w+\\s*=\u002Fi` | Inline event handlers (`onclick=`, `onerror=`) |\n| `\u002Fjavascript\\s*:\u002Fi` | JavaScript protocol URIs |\n\nIf any pattern matches, `htmlFound` is set to `true` in the results. This flag is used downstream by `validateZodSchema` to trigger IP banning.\n\n#### sanitize-html pass\n\nThe string is passed through [sanitize-html](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fsanitize-html) with a strict configuration:\n\n- `allowedTags: []`,\n- `allowedAttributes: {}`,\n- `allowedIframeHostnames: []`,\n- `allowedSchemes: []`,\n- `allowProtocolRelative: false`, \n- `nestingLimit: 10`,\n- `nonTextTags: ['script', 'style', 'noscript', 'iframe', 'svg']`.\n\nThe `textFilter` re-runs the tag regex on text nodes, and `onOpenTag` records any tag name and attribute set that the sanitizer had to strip. If the string shrinks during this pass, `htmlFound` is set to `true` even if pattern detection did not trigger.\n\n#### Entity encoding\n\nThe final output is entity-encoded: `&`, `\u003C`, `>`, `\"`, `'`, backtick, and `${` are replaced with their entity or escaped equivalents. The backtick and template-literal escapes prevent injection into JavaScript template strings. The result is trimmed.\n\n| Character | Replacement |\n|---|---|\n| `&` | `&amp;` |\n| `\u003C` | `&lt;` |\n| `>` | `&gt;` |\n| `\"` | `&quot;` |\n| `'` | `&#x27;` |\n| `` ` `` | `&#x60;` |\n| `${` | `\\${` |\n\n::\n\n---\n\n## Zod integration\n\n`makeSanitizedZodString` creates a Zod string schema that validates length and optional regex constraints, then runs the full sanitization pipeline as a [Zod transform](https:\u002F\u002Fzod.dev\u002F?id=transform). The returned value is always the sanitized output, and any HTML detection is reported as a Zod issue with an `'HTML found'` message prefix.\n\n```ts\nimport { makeSanitizedZodString } from '@riavzon\u002Fauth'\nimport { z } from 'zod'\n\nconst commentSchema = z.object({\n  text: makeSanitizedZodString({ min: 1, max: 1000 }),\n  name: makeSanitizedZodString({\n    min: 2,\n    max: 50,\n    pattern: \u002F^[A-Za-z\\s]+$\u002F,\n    patternMsg: 'Name must contain only letters and spaces',\n  }),\n})\n```\n\n### Parameters\n\n::field-group\n::field{name=\"min\" type=\"number\" required}\nMinimum string length. Enforced before sanitization.\n::\n\n::field{name=\"max\" type=\"number\" required}\nMaximum string length. Enforced before sanitization.\n::\n\n::field{name=\"pattern\" type=\"RegExp\"}\nOptional regex the string must match. Validated after length checks and before sanitization.\n::\n\n::field{name=\"patternMsg\" type=\"string\"}\nCustom error message shown when the pattern does not match.\n::\n::\n\n### How it works\n\nThe schema chains three operations:\n\n1. **Length and pattern validation** using standard Zod `.min()`, `.max()`, and `.regex()` validators\n2. **HTML detection check** via `.check()` that calls `sanitizeInput` and pushes a custom Zod issue if `htmlFound` is `true`\n3. **Sanitization transform** via `.transform()` that calls `sanitizeInput` again and returns only the cleaned `vall` string\n\n::tip\nEvery Zod schema in the built-in authentication controllers (signup, login, MFA, email update, password reset, OAuth) uses `makeSanitizedZodString` for all user-supplied string fields. If you add custom routes, use it for consistency.\n::\n\nThe built-in schemas that use `makeSanitizedZodString` include:\n\n| Schema | Fields |\n|---|---|\n| Signup | `name`, `email`, `password` |\n| Login | `email`, `password` |\n| Email update | `email`, `newEmail`, `password` |\n| MFA code | `code` |\n| Password reset | `random`, `reason` |\n| Custom MFA | `random`, `reason` |\n\n---\n\n## Validation with XSS enforcement\n\n`validateZodSchema` ties the full pipeline together. It parses input against a Zod schema, and when any Zod issue starts with `'HTML found'` (produced by `makeSanitizedZodString`), it calls `handleXSS` to ban the client immediately.\n\n```ts\nimport { validateZodSchema } from '@riavzon\u002Fauth'\n\nconst result = await validateZodSchema(commentSchema, req.body, req, log)\n\nif ('valid' in result && result.valid === false) {\n  \u002F\u002F Validation failed (could be XSS ban or normal validation error)\n  res.status(result.errors === 'XSS attempt' ? 403 : 400).json({ errors: result.errors })\n  return\n}\n\nif (!result.success) {\n  \u002F\u002F Standard Zod validation error\n  res.status(422).json(result.error.format())\n  return\n}\n\n\u002F\u002F result.data is fully sanitized and validated\nconst { text, name } = result.data\n```\n\n### Validation flow\n\n::steps{level=\"4\"}\n#### Zod parsing\n\nThe schema is parsed with `safeParse()`. If parsing succeeds, the validated and transformed data is returned immediately.\n\n#### HTML issue scan\n\nIf parsing fails, the function scans the Zod error issues array for any issue whose `message` starts with `'HTML found'`. This marker is set by `makeSanitizedZodString` when the sanitizer detects HTML content.\n\n#### XSS punishment\n\nWhen an HTML issue is found, `handleXSS` is called with the Express request object. The function bans the client's IP using the [Bot Detector](\u002Fdocs\u002Fbot-detection) service with the configured `banScore` (defaults to 100) and the reason `'XSS SCRIPTING ATTEMPT'`. It also marks the visitor's `canary_id` as a bot and updates the banned IP record.\n\nThe function returns `{ valid: false, errors: 'XSS attempt' }` and the controller responds with HTTP 403.\n\n#### Normal validation errors\n\nIf no HTML issues are found, the function collects all Zod issues into a key-value map (field name to error message) and returns `{ valid: false, errors: { ... } }`.\n::\n\n::note\nThe XSS ban is permanent at the [Bot Detector](\u002Fdocs\u002Fbot-detector) level. The client IP is added to the banned list, the visitor is flagged as a bot, and subsequent requests from that IP receive elevated scrutiny from anomaly detection. There is no automatic expiry.\n::\n\n---\n\n## `handleXSS`\n\n`handleXSS` is the enforcement function called when an XSS attempt is confirmed. It reads the `banScore` from `botDetector.settings` in the configuration (defaulting to 100 if not set) and executes three actions:\n\n```ts\nimport { handleXSS } from '@riavzon\u002Fauth'\n\n\u002F\u002F Called automatically by validateZodSchema — you rarely need to call this directly\nawait handleXSS(req, '\u003Cscript>alert(1)\u003C\u002Fscript>', log)\n```\n\n::steps{level=\"4\"}\n#### IP ban\n\n`banIp` is called first with the client IP and the configured `banScore`. This adds the IP to the [Bot Detector](\u002Fdocs\u002Fbot-detector) ban list with the reason `'XSS SCRIPTING ATTEMPT'`. This step runs before the remaining actions to ensure the IP is blocked as quickly as possible.\n\n#### Visitor record and bot flag\n\nTwo actions run concurrently via `Promise.all`:\n\n| Action | Function | Effect |\n|---|---|---|\n| Visitor record | `updateBannedIP(canary_id, ip, ua, { score: 10, reasons: [...] })` | Updates the banned IP record with the visitor's cookie, user agent, and ban reason |\n| Bot flag | `updateIsBot(true, canary_id)` | Marks the visitor's `canary_id` as a confirmed bot in the visitors table |\n::\n\nThe function logs a warning before and after the ban.\n\n---\n\n## Timing attack prevention\n\n`timeEnumeration` (exported as `waitSomeTime` internally) adds a fixed delay to responses where timing differences could leak information. Authentication endpoints use it to ensure that responses for valid and invalid inputs take the same amount of time.\n\n```ts\nimport { timeEnumeration } from '@riavzon\u002Fauth'\n\nconst start = Date.now()\n\n\u002F\u002F ... process the request (may return early if user not found)\n\nconst elapsed = Date.now() - start\nconst minimumResponseTime = 3000 \u002F\u002F 3 seconds\n\nif (elapsed \u003C minimumResponseTime) {\n  await timeEnumeration(minimumResponseTime - elapsed, log)\n}\n```\n\nThe following controllers enforce a minimum 3-second response time:\n\n| Controller | Route | Why |\n|---|---|---|\n| `initPasswordReset` | `POST \u002Fauth\u002Fforgot-password` | Prevents enumerating which email addresses have accounts |\n| `initCustomMfaFlow` | `POST \u002Fcustom\u002Fmfa\u002F:reason` | Prevents timing analysis of custom MFA initiation |\n\n::tip\nAlways use `timeEnumeration` on any endpoint that reveals presence or absence of a user account through its response time. A password reset endpoint that returns instantly for unknown emails and slowly for known ones leaks account existence.\n::\n\n---\n\n## Applying XSS protection in custom handlers\n\nThe full pipeline works in four steps: define a schema with `makeSanitizedZodString`, validate with `validateZodSchema`, check the result, and use the sanitized data.\n\n```ts\nimport { validateZodSchema, makeSanitizedZodString } from '@riavzon\u002Fauth'\nimport { z } from 'zod'\n\nconst profileSchema = z.object({\n  displayName: makeSanitizedZodString({ min: 1, max: 100 }),\n  bio: makeSanitizedZodString({ min: 0, max: 500 }),\n})\n\nrouter.post('\u002Fprofile', async (req, res) => {\n  const log = getLogger().child({ route: '\u002Fprofile' })\n  const result = await validateZodSchema(profileSchema, req.body, req, log)\n\n  if ('valid' in result && !result.valid) {\n    if (result.errors === 'XSS attempt') {\n      return res.status(403).json({ banned: true })\n    }\n    return res.status(400).json({ errors: result.errors })\n  }\n\n  if (!result.success) {\n    return res.status(422).json(result.error.format())\n  }\n\n  \u002F\u002F result.data.displayName and result.data.bio are fully sanitized\n  await db.updateProfile(userId, result.data)\n  res.json({ ok: true })\n})\n```\n\n---\n\n## Configuration reference\n\n::field-group\n::field{name=\"htmlSanitizer.IrritationCount\" type=\"number\" default=\"50\"}\nMaximum number of URI-decode and entity-decode iterations. Higher values catch deeper encoding chains but increase CPU cost per request. The input is rejected entirely if this limit is reached without the output stabilizing.\n::\n\n::field{name=\"htmlSanitizer.maxAllowedInputLength\" type=\"number\" default=\"50000\"}\nMaximum input string length in characters. Inputs exceeding this limit are rejected before any processing begins. Prevents memory exhaustion from oversized payloads.\n::\n::\n\n::caution\nSetting `IrritationCount` to a very high value on a public endpoint creates a CPU exhaustion vector. Pair it with `maxAllowedInputLength` and a request body size limit (e.g. `express.json({ limit: '2kb' })`) to bound worst-case processing time.\n::\n\n---\n\n## Summary\n\nThe XSS protection pipeline integrates with several other IAM subsystems:\n\n| System | Integration point |\n|---|---|\n| [Anomaly Detection](\u002Fdocs\u002Fiam\u002Fessentials\u002Fanomalies) | Banned IPs from XSS attempts raise the `suspicious_activity_score`, which triggers MFA challenges or hard blocks when the score exceeds 25% of the ban threshold |\n| [Bot Detector](\u002Fdocs\u002Fbot-detector) | `handleXSS` calls `banIp`, `updateBannedIP`, and `updateIsBot` to record the threat in the bot detection database |\n| [Fingerprinting](\u002Fdocs\u002Fiam\u002Fessentials\u002Ffingerprinting) | The `canary_id` cookie ties the XSS ban to a specific device, so the ban persists even if the client's IP changes |\n| [Signup](\u002Fdocs\u002Fiam\u002Fessentials\u002Fsignup) | New account creation validates `name`, `email`, and `password` through `makeSanitizedZodString` |\n| [MFA](\u002Fdocs\u002Fiam\u002Fessentials\u002Fmfa) | OTP code submission validates the code field through the same pipeline |\n",{"title":139,"description":3327},"Y8bJ4QxGE3Tur8nEK8YBN2ir3A0qOP94c64aOHE0Q4Q",[3336,3337],{"title":135,"path":136,"stem":137,"children":-1},{"title":143,"path":144,"stem":145,"children":-1},{"id":851,"title":139,"body":3339,"description":3327,"extension":3328,"icon":3329,"meta":5263,"module":3331,"navigation":8,"path":140,"rawbody":3332,"seo":5264,"stem":141,"__hash__":3334},{"type":853,"value":3340,"toc":5248},[3341,3352,3356,3358,3360,3366,3472,3474,3743,3745,3747,3756,3918,3920,3938,3940,3942,3976,3982,3986,4060,4062,4064,4074,4322,4324,4366,4372,4374,4378,4386,4440,4496,4498,4500,4502,4508,4636,4638,4676,4682,4684,4686,4692,5144,5146,5148,5158,5168,5170,5172,5174,5246],[856,3342,858,3343,863,3345,867,3347,875,3350,878],{},[860,3344,862],{},[860,3346,866],{},[869,3348,874],{"href":871,"rel":3349},[873],[860,3351,792],{},[856,3353,881,3354,885],{},[860,3355,884],{},[887,3357],{},[890,3359,893],{"id":892},[856,3361,3362,898,3364,902],{},[860,3363,862],{},[860,3365,901],{},[904,3367,3368],{"className":906,"code":907,"language":908,"meta":909,"style":909},[860,3369,3370,3384,3388,3412,3416,3430,3434,3460,3464,3468],{"__ignoreMap":909},[913,3371,3372,3374,3376,3378,3380,3382],{"class":915,"line":916},[913,3373,920],{"class":919},[913,3375,924],{"class":923},[913,3377,927],{"class":919},[913,3379,931],{"class":930},[913,3381,884],{"class":934},[913,3383,937],{"class":930},[913,3385,3386],{"class":915,"line":940},[913,3387,943],{"emptyLinePlaceholder":8},[913,3389,3390,3392,3394,3396,3398,3400,3402,3404,3406,3408,3410],{"class":915,"line":946},[913,3391,950],{"class":949},[913,3393,954],{"class":953},[913,3395,958],{"class":957},[913,3397,961],{"class":953},[913,3399,964],{"class":957},[913,3401,967],{"class":953},[913,3403,971],{"class":970},[913,3405,924],{"class":974},[913,3407,977],{"class":953},[913,3409,980],{"class":923},[913,3411,983],{"class":953},[913,3413,3414],{"class":915,"line":986},[913,3415,943],{"emptyLinePlaceholder":8},[913,3417,3418,3420,3422,3424,3426,3428],{"class":915,"line":991},[913,3419,994],{"class":919},[913,3421,997],{"class":953},[913,3423,964],{"class":923},[913,3425,1002],{"class":953},[913,3427,1005],{"class":923},[913,3429,1008],{"class":953},[913,3431,3432],{"class":915,"line":1011},[913,3433,1015],{"class":1014},[913,3435,3436,3438,3440,3442,3444,3446,3448,3450,3452,3454,3456,3458],{"class":915,"line":1018},[913,3437,1021],{"class":923},[913,3439,1002],{"class":953},[913,3441,1026],{"class":974},[913,3443,977],{"class":953},[913,3445,1031],{"class":930},[913,3447,1034],{"class":934},[913,3449,1031],{"class":930},[913,3451,961],{"class":953},[913,3453,964],{"class":923},[913,3455,1002],{"class":953},[913,3457,1045],{"class":923},[913,3459,983],{"class":953},[913,3461,3462],{"class":915,"line":1050},[913,3463,1053],{"class":953},[913,3465,3466],{"class":915,"line":1056},[913,3467,943],{"emptyLinePlaceholder":8},[913,3469,3470],{"class":915,"line":1061},[913,3471,1064],{"class":1014},[856,3473,1067],{},[1069,3475,3476,3478,3482,3484,3497,3499,3511,3513,3524,3532,3540,3542,3546,3548,3550,3590,3598,3600,3605,3635,3645,3647,3661],{"level":1071},[1073,3477,1076],{"id":1075},[856,3479,1079,3480,1083],{},[860,3481,1082],{},[1073,3483,1087],{"id":1086},[856,3485,1090,3486,1096,3489,1100,3491,1104,3493,1108,3495,1002],{},[869,3487,1095],{"href":1093,"rel":3488},[873],[860,3490,1099],{},[860,3492,1103],{},[860,3494,1107],{},[860,3496,1111],{},[1073,3498,1115],{"id":1114},[856,3500,3501,1121,3503,1125,3505,1129,3507,1133,3509,1137],{},[860,3502,1120],{},[860,3504,1124],{},[860,3506,1128],{},[860,3508,1132],{},[860,3510,1136],{},[1073,3512,1141],{"id":1140},[856,3514,1144,3515,1147,3517,997,3519,1156,3522,1160],{},[860,3516,1120],{},[860,3518,1150],{},[869,3520,1155],{"href":1153,"rel":3521},[873],[860,3523,1159],{},[856,3525,1163,3526,1167,3528,1171,3530,1175],{},[860,3527,1166],{},[860,3529,1170],{},[860,3531,1174],{},[1177,3533,3534],{},[856,3535,1181,3536,1184,3538,1187],{},[860,3537,1159],{},[860,3539,1136],{},[1073,3541,1191],{"id":1190},[856,3543,1194,3544,1198],{},[860,3545,1197],{},[1073,3547,1202],{"id":1201},[856,3549,1205],{},[1207,3551,3552,3560],{},[1210,3553,3554],{},[1213,3555,3556,3558],{},[1216,3557,1218],{},[1216,3559,1221],{},[1223,3561,3562,3570,3582],{},[1213,3563,3564,3568],{},[1228,3565,3566],{},[860,3567,1232],{},[1228,3569,1235],{},[1213,3571,3572,3576],{},[1228,3573,3574],{},[860,3575,1242],{},[1228,3577,1245,3578,961,3580,1252],{},[860,3579,1248],{},[860,3581,1251],{},[1213,3583,3584,3588],{},[1228,3585,3586],{},[860,3587,1259],{},[1228,3589,1262],{},[856,3591,1265,3592,1268,3594,1272,3596,1275],{},[860,3593,1005],{},[860,3595,1271],{},[860,3597,792],{},[1073,3599,1279],{"id":1278},[856,3601,1282,3602,1288],{},[869,3603,1287],{"href":1285,"rel":3604},[873],[1290,3606,3607,3611,3615,3619,3623,3627,3631],{},[1293,3608,3609,1298],{},[860,3610,1297],{},[1293,3612,3613,1298],{},[860,3614,1303],{},[1293,3616,3617,1298],{},[860,3618,1308],{},[1293,3620,3621,1298],{},[860,3622,1313],{},[1293,3624,3625,1298],{},[860,3626,1318],{},[1293,3628,3629,1298],{},[860,3630,1323],{},[1293,3632,3633,1002],{},[860,3634,1328],{},[856,3636,1331,3637,1335,3639,1339,3641,1268,3643,1344],{},[860,3638,1334],{},[860,3640,1338],{},[860,3642,1005],{},[860,3644,1271],{},[1073,3646,1348],{"id":1347},[856,3648,1351,3649,961,3651,961,3653,961,3655,961,3657,1365,3659,1369],{},[860,3650,1354],{},[860,3652,1111],{},[860,3654,1359],{},[860,3656,1362],{},[860,3658,1031],{},[860,3660,1368],{},[1207,3662,3663,3671],{},[1210,3664,3665],{},[1213,3666,3667,3669],{},[1216,3668,1378],{},[1216,3670,1381],{},[1223,3672,3673,3683,3693,3703,3713,3723,3733],{},[1213,3674,3675,3679],{},[1228,3676,3677],{},[860,3678,1354],{},[1228,3680,3681],{},[860,3682,1394],{},[1213,3684,3685,3689],{},[1228,3686,3687],{},[860,3688,1111],{},[1228,3690,3691],{},[860,3692,1405],{},[1213,3694,3695,3699],{},[1228,3696,3697],{},[860,3698,1359],{},[1228,3700,3701],{},[860,3702,1416],{},[1213,3704,3705,3709],{},[1228,3706,3707],{},[860,3708,1362],{},[1228,3710,3711],{},[860,3712,1427],{},[1213,3714,3715,3719],{},[1228,3716,3717],{},[860,3718,1031],{},[1228,3720,3721],{},[860,3722,1438],{},[1213,3724,3725,3729],{},[1228,3726,3727],{},[860,3728,1445],{},[1228,3730,3731],{},[860,3732,1450],{},[1213,3734,3735,3739],{},[1228,3736,3737],{},[860,3738,1368],{},[1228,3740,3741],{},[860,3742,1461],{},[887,3744],{},[890,3746,1467],{"id":1466},[856,3748,3749,1472,3751,1478,3754,1482],{},[860,3750,866],{},[869,3752,1477],{"href":1475,"rel":3753},[873],[860,3755,1481],{},[904,3757,3758],{"className":906,"code":1485,"language":908,"meta":909,"style":909},[860,3759,3760,3778,3796,3800,3816,3842,3852,3862,3872,3896,3910,3914],{"__ignoreMap":909},[913,3761,3762,3764,3766,3768,3770,3772,3774,3776],{"class":915,"line":916},[913,3763,920],{"class":919},[913,3765,954],{"class":953},[913,3767,866],{"class":923},[913,3769,967],{"class":953},[913,3771,1500],{"class":919},[913,3773,931],{"class":930},[913,3775,884],{"class":934},[913,3777,937],{"class":930},[913,3779,3780,3782,3784,3786,3788,3790,3792,3794],{"class":915,"line":940},[913,3781,920],{"class":919},[913,3783,954],{"class":953},[913,3785,1515],{"class":923},[913,3787,967],{"class":953},[913,3789,1500],{"class":919},[913,3791,931],{"class":930},[913,3793,1524],{"class":934},[913,3795,937],{"class":930},[913,3797,3798],{"class":915,"line":946},[913,3799,943],{"emptyLinePlaceholder":8},[913,3801,3802,3804,3806,3808,3810,3812,3814],{"class":915,"line":986},[913,3803,950],{"class":949},[913,3805,1537],{"class":957},[913,3807,1540],{"class":970},[913,3809,1543],{"class":923},[913,3811,1002],{"class":953},[913,3813,1548],{"class":974},[913,3815,1551],{"class":953},[913,3817,3818,3820,3822,3824,3826,3828,3830,3832,3834,3836,3838,3840],{"class":915,"line":991},[913,3819,1556],{"class":923},[913,3821,1560],{"class":1559},[913,3823,1563],{"class":974},[913,3825,1566],{"class":953},[913,3827,1569],{"class":923},[913,3829,1560],{"class":1559},[913,3831,1575],{"class":1574},[913,3833,961],{"class":953},[913,3835,1580],{"class":923},[913,3837,1560],{"class":1559},[913,3839,1585],{"class":1574},[913,3841,1588],{"class":953},[913,3843,3844,3846,3848,3850],{"class":915,"line":1011},[913,3845,1593],{"class":923},[913,3847,1560],{"class":1559},[913,3849,1563],{"class":974},[913,3851,1551],{"class":953},[913,3853,3854,3856,3858,3860],{"class":915,"line":1018},[913,3855,1604],{"class":923},[913,3857,1560],{"class":1559},[913,3859,1609],{"class":1574},[913,3861,1612],{"class":953},[913,3863,3864,3866,3868,3870],{"class":915,"line":1050},[913,3865,1617],{"class":923},[913,3867,1560],{"class":1559},[913,3869,1622],{"class":1574},[913,3871,1612],{"class":953},[913,3873,3874,3876,3878,3880,3882,3884,3886,3888,3890,3892,3894],{"class":915,"line":1056},[913,3875,1629],{"class":923},[913,3877,1560],{"class":1559},[913,3879,1635],{"class":1634},[913,3881,1639],{"class":1638},[913,3883,1643],{"class":1642},[913,3885,1647],{"class":1646},[913,3887,1650],{"class":1642},[913,3889,1653],{"class":970},[913,3891,1656],{"class":1638},[913,3893,1125],{"class":1634},[913,3895,1612],{"class":953},[913,3897,3898,3900,3902,3904,3906,3908],{"class":915,"line":1061},[913,3899,1665],{"class":923},[913,3901,1560],{"class":1559},[913,3903,931],{"class":930},[913,3905,1672],{"class":934},[913,3907,1031],{"class":930},[913,3909,1612],{"class":953},[913,3911,3912],{"class":915,"line":1679},[913,3913,1682],{"class":953},[913,3915,3916],{"class":915,"line":1685},[913,3917,1688],{"class":953},[1690,3919,1693],{"id":1692},[1695,3921,3922,3926,3930,3934],{},[1698,3923,3924],{"name":1569,"type":1700,":required":1271},[856,3925,1703],{},[1698,3927,3928],{"name":1580,"type":1700,":required":1271},[856,3929,1708],{},[1698,3931,3932],{"name":1711,"type":1712},[856,3933,1715],{},[1698,3935,3936],{"name":1718,"type":1719},[856,3937,1722],{},[1690,3939,1726],{"id":1725},[856,3941,1729],{},[1731,3943,3944,3954,3966],{},[1293,3945,3946,1739,3948,961,3950,1746,3952,1750],{},[1736,3947,1738],{},[860,3949,1742],{},[860,3951,1745],{},[860,3953,1749],{},[1293,3955,3956,1756,3958,1760,3960,1763,3962,1766,3964],{},[1736,3957,1755],{},[860,3959,1759],{},[860,3961,862],{},[860,3963,1005],{},[860,3965,1271],{},[1293,3967,3968,1756,3970,1760,3972,1779,3974,1782],{},[1736,3969,1773],{},[860,3971,1776],{},[860,3973,862],{},[860,3975,958],{},[1784,3977,3978],{},[856,3979,1788,3980,1791],{},[860,3981,866],{},[856,3983,1794,3984,1797],{},[860,3985,866],{},[1207,3987,3988,3996],{},[1210,3989,3990],{},[1213,3991,3992,3994],{},[1216,3993,1806],{},[1216,3995,1809],{},[1223,3997,3998,4010,4020,4032,4040,4050],{},[1213,3999,4000,4002],{},[1228,4001,99],{},[1228,4003,4004,961,4006,961,4008],{},[860,4005,1820],{},[860,4007,1823],{},[860,4009,1826],{},[1213,4011,4012,4014],{},[1228,4013,103],{},[1228,4015,4016,961,4018],{},[860,4017,1823],{},[860,4019,1826],{},[1213,4021,4022,4024],{},[1228,4023,1841],{},[1228,4025,4026,961,4028,961,4030],{},[860,4027,1823],{},[860,4029,1848],{},[860,4031,1826],{},[1213,4033,4034,4036],{},[1228,4035,1855],{},[1228,4037,4038],{},[860,4039,860],{},[1213,4041,4042,4044],{},[1228,4043,1864],{},[1228,4045,4046,961,4048],{},[860,4047,1869],{},[860,4049,1872],{},[1213,4051,4052,4054],{},[1228,4053,1877],{},[1228,4055,4056,961,4058],{},[860,4057,1869],{},[860,4059,1872],{},[887,4061],{},[890,4063,1889],{"id":1888},[856,4065,4066,1894,4068,1897,4070,1900,4072,1904],{},[860,4067,792],{},[860,4069,1481],{},[860,4071,866],{},[860,4073,1903],{},[904,4075,4076],{"className":906,"code":1907,"language":908,"meta":909,"style":909},[860,4077,4078,4096,4100,4134,4138,4168,4172,4222,4226,4230,4234,4250,4254,4284,4288,4292,4296,4300],{"__ignoreMap":909},[913,4079,4080,4082,4084,4086,4088,4090,4092,4094],{"class":915,"line":916},[913,4081,920],{"class":919},[913,4083,954],{"class":953},[913,4085,792],{"class":923},[913,4087,967],{"class":953},[913,4089,1500],{"class":919},[913,4091,931],{"class":930},[913,4093,884],{"class":934},[913,4095,937],{"class":930},[913,4097,4098],{"class":915,"line":940},[913,4099,943],{"emptyLinePlaceholder":8},[913,4101,4102,4104,4106,4108,4110,4112,4114,4116,4118,4120,4122,4124,4126,4128,4130,4132],{"class":915,"line":946},[913,4103,950],{"class":949},[913,4105,1938],{"class":957},[913,4107,1540],{"class":970},[913,4109,1943],{"class":919},[913,4111,1946],{"class":974},[913,4113,977],{"class":953},[913,4115,1951],{"class":923},[913,4117,961],{"class":953},[913,4119,1956],{"class":923},[913,4121,1002],{"class":953},[913,4123,1961],{"class":923},[913,4125,961],{"class":953},[913,4127,1956],{"class":923},[913,4129,961],{"class":953},[913,4131,1026],{"class":923},[913,4133,983],{"class":953},[913,4135,4136],{"class":915,"line":986},[913,4137,943],{"emptyLinePlaceholder":8},[913,4139,4140,4142,4144,4146,4148,4150,4152,4154,4156,4158,4160,4162,4164,4166],{"class":915,"line":991},[913,4141,994],{"class":919},[913,4143,997],{"class":953},[913,4145,1031],{"class":930},[913,4147,1986],{"class":934},[913,4149,1031],{"class":930},[913,4151,1991],{"class":949},[913,4153,1938],{"class":923},[913,4155,1996],{"class":970},[913,4157,1938],{"class":923},[913,4159,1002],{"class":953},[913,4161,1986],{"class":923},[913,4163,2005],{"class":970},[913,4165,2009],{"class":2008},[913,4167,1008],{"class":953},[913,4169,4170],{"class":915,"line":1011},[913,4171,2016],{"class":1014},[913,4173,4174,4176,4178,4180,4182,4184,4186,4188,4190,4192,4194,4196,4198,4200,4202,4204,4206,4208,4210,4212,4214,4216,4218,4220],{"class":915,"line":1018},[913,4175,2021],{"class":923},[913,4177,1002],{"class":953},[913,4179,2026],{"class":974},[913,4181,977],{"class":953},[913,4183,2031],{"class":923},[913,4185,1002],{"class":953},[913,4187,2036],{"class":923},[913,4189,2005],{"class":970},[913,4191,931],{"class":930},[913,4193,2043],{"class":934},[913,4195,1031],{"class":930},[913,4197,2048],{"class":970},[913,4199,2051],{"class":1574},[913,4201,2054],{"class":970},[913,4203,2057],{"class":1574},[913,4205,2060],{"class":953},[913,4207,5],{"class":974},[913,4209,1566],{"class":953},[913,4211,2036],{"class":923},[913,4213,1560],{"class":1559},[913,4215,1938],{"class":923},[913,4217,1002],{"class":953},[913,4219,2036],{"class":923},[913,4221,2077],{"class":953},[913,4223,4224],{"class":915,"line":1050},[913,4225,2082],{"class":919},[913,4227,4228],{"class":915,"line":1056},[913,4229,1053],{"class":953},[913,4231,4232],{"class":915,"line":1061},[913,4233,943],{"emptyLinePlaceholder":8},[913,4235,4236,4238,4240,4242,4244,4246,4248],{"class":915,"line":1679},[913,4237,994],{"class":919},[913,4239,997],{"class":953},[913,4241,2099],{"class":970},[913,4243,2031],{"class":923},[913,4245,1002],{"class":953},[913,4247,2106],{"class":923},[913,4249,1008],{"class":953},[913,4251,4252],{"class":915,"line":1685},[913,4253,2113],{"class":1014},[913,4255,4256,4258,4260,4262,4264,4266,4268,4270,4272,4274,4276,4278,4280,4282],{"class":915,"line":2116},[913,4257,2021],{"class":923},[913,4259,1002],{"class":953},[913,4261,2026],{"class":974},[913,4263,977],{"class":953},[913,4265,2127],{"class":1574},[913,4267,2060],{"class":953},[913,4269,5],{"class":974},[913,4271,977],{"class":953},[913,4273,2031],{"class":923},[913,4275,1002],{"class":953},[913,4277,2140],{"class":923},[913,4279,1002],{"class":953},[913,4281,2145],{"class":974},[913,4283,2148],{"class":953},[913,4285,4286],{"class":915,"line":2151},[913,4287,2082],{"class":919},[913,4289,4290],{"class":915,"line":2156},[913,4291,1053],{"class":953},[913,4293,4294],{"class":915,"line":2161},[913,4295,943],{"emptyLinePlaceholder":8},[913,4297,4298],{"class":915,"line":2166},[913,4299,2169],{"class":1014},[913,4301,4302,4304,4306,4308,4310,4312,4314,4316,4318,4320],{"class":915,"line":2172},[913,4303,950],{"class":949},[913,4305,954],{"class":953},[913,4307,2179],{"class":957},[913,4309,961],{"class":953},[913,4311,1820],{"class":957},[913,4313,967],{"class":953},[913,4315,971],{"class":970},[913,4317,1938],{"class":923},[913,4319,1002],{"class":953},[913,4321,2194],{"class":923},[1690,4323,2198],{"id":2197},[1069,4325,4326,4328,4332,4334,4342,4344,4356,4360,4362],{"level":1071},[1073,4327,2204],{"id":2203},[856,4329,2207,4330,2211],{},[860,4331,2210],{},[1073,4333,2215],{"id":2214},[856,4335,2218,4336,2222,4338,2225,4340,2228],{},[860,4337,2221],{},[860,4339,1481],{},[860,4341,866],{},[1073,4343,2232],{"id":2231},[856,4345,2235,4346,2238,4348,2241,4350,2245,4352,2249,4354,2253],{},[860,4347,1903],{},[869,4349,399],{"href":35},[860,4351,2244],{},[860,4353,2248],{},[860,4355,2252],{},[856,4357,2256,4358,2260],{},[860,4359,2259],{},[1073,4361,2264],{"id":2263},[856,4363,2267,4364,1002],{},[860,4365,2270],{},[2272,4367,4368],{},[856,4369,2276,4370,2280],{},[869,4371,399],{"href":2279},[887,4373],{},[890,4375,4376],{"id":2285},[860,4377,1903],{},[856,4379,4380,2292,4382,2295,4384,2299],{},[860,4381,1903],{},[860,4383,2244],{},[860,4385,2298],{},[904,4387,4388],{"className":906,"code":2302,"language":908,"meta":909,"style":909},[860,4389,4390,4408,4412,4416],{"__ignoreMap":909},[913,4391,4392,4394,4396,4398,4400,4402,4404,4406],{"class":915,"line":916},[913,4393,920],{"class":919},[913,4395,954],{"class":953},[913,4397,1903],{"class":923},[913,4399,967],{"class":953},[913,4401,1500],{"class":919},[913,4403,931],{"class":930},[913,4405,884],{"class":934},[913,4407,937],{"class":930},[913,4409,4410],{"class":915,"line":940},[913,4411,943],{"emptyLinePlaceholder":8},[913,4413,4414],{"class":915,"line":946},[913,4415,2331],{"class":1014},[913,4417,4418,4420,4422,4424,4426,4428,4430,4432,4434,4436,4438],{"class":915,"line":986},[913,4419,2336],{"class":919},[913,4421,2339],{"class":974},[913,4423,977],{"class":953},[913,4425,1956],{"class":923},[913,4427,961],{"class":953},[913,4429,1031],{"class":930},[913,4431,2350],{"class":934},[913,4433,1031],{"class":930},[913,4435,961],{"class":953},[913,4437,1026],{"class":923},[913,4439,983],{"class":953},[1069,4441,4442,4444,4454,4456,4460],{"level":1071},[1073,4443,2364],{"id":2363},[856,4445,4446,2370,4448,2373,4450,2376,4452,2379],{},[860,4447,2369],{},[860,4449,2244],{},[869,4451,399],{"href":2279},[860,4453,2248],{},[1073,4455,2383],{"id":2382},[856,4457,2386,4458,1560],{},[860,4459,2389],{},[1207,4461,4462,4472],{},[1210,4463,4464],{},[1213,4465,4466,4468,4470],{},[1216,4467,2398],{},[1216,4469,2401],{},[1216,4471,2404],{},[1223,4473,4474,4484],{},[1213,4475,4476,4478,4482],{},[1228,4477,2411],{},[1228,4479,4480],{},[860,4481,2416],{},[1228,4483,2419],{},[1213,4485,4486,4488,4492],{},[1228,4487,2424],{},[1228,4489,4490],{},[860,4491,2429],{},[1228,4493,2432,4494,2435],{},[860,4495,2252],{},[856,4497,2438],{},[887,4499],{},[890,4501,2444],{"id":2443},[856,4503,4504,2450,4506,2454],{},[860,4505,2449],{},[860,4507,2453],{},[904,4509,4510],{"className":906,"code":2457,"language":908,"meta":909,"style":909},[860,4511,4512,4530,4534,4550,4554,4558,4562,4582,4594,4598,4612,4632],{"__ignoreMap":909},[913,4513,4514,4516,4518,4520,4522,4524,4526,4528],{"class":915,"line":916},[913,4515,920],{"class":919},[913,4517,954],{"class":953},[913,4519,2449],{"class":923},[913,4521,967],{"class":953},[913,4523,1500],{"class":919},[913,4525,931],{"class":930},[913,4527,884],{"class":934},[913,4529,937],{"class":930},[913,4531,4532],{"class":915,"line":940},[913,4533,943],{"emptyLinePlaceholder":8},[913,4535,4536,4538,4540,4542,4544,4546,4548],{"class":915,"line":946},[913,4537,950],{"class":949},[913,4539,2488],{"class":957},[913,4541,1540],{"class":970},[913,4543,2493],{"class":923},[913,4545,1002],{"class":953},[913,4547,2498],{"class":974},[913,4549,2501],{"class":953},[913,4551,4552],{"class":915,"line":986},[913,4553,943],{"emptyLinePlaceholder":8},[913,4555,4556],{"class":915,"line":991},[913,4557,2510],{"class":1014},[913,4559,4560],{"class":915,"line":1011},[913,4561,943],{"emptyLinePlaceholder":8},[913,4563,4564,4566,4568,4570,4572,4574,4576,4578,4580],{"class":915,"line":1018},[913,4565,950],{"class":949},[913,4567,2521],{"class":957},[913,4569,1540],{"class":970},[913,4571,2493],{"class":923},[913,4573,1002],{"class":953},[913,4575,2498],{"class":974},[913,4577,2532],{"class":953},[913,4579,2535],{"class":970},[913,4581,2538],{"class":923},[913,4583,4584,4586,4588,4590,4592],{"class":915,"line":1050},[913,4585,950],{"class":949},[913,4587,2545],{"class":957},[913,4589,1540],{"class":970},[913,4591,2550],{"class":1574},[913,4593,2553],{"class":1014},[913,4595,4596],{"class":915,"line":1056},[913,4597,943],{"emptyLinePlaceholder":8},[913,4599,4600,4602,4604,4606,4608,4610],{"class":915,"line":1061},[913,4601,994],{"class":919},[913,4603,997],{"class":953},[913,4605,2566],{"class":923},[913,4607,2569],{"class":970},[913,4609,2545],{"class":923},[913,4611,1008],{"class":953},[913,4613,4614,4616,4618,4620,4622,4624,4626,4628,4630],{"class":915,"line":1679},[913,4615,2578],{"class":919},[913,4617,2581],{"class":974},[913,4619,977],{"class":953},[913,4621,2586],{"class":923},[913,4623,2589],{"class":970},[913,4625,2521],{"class":923},[913,4627,961],{"class":953},[913,4629,1026],{"class":923},[913,4631,983],{"class":953},[913,4633,4634],{"class":915,"line":1685},[913,4635,1053],{"class":953},[856,4637,2604],{},[1207,4639,4640,4650],{},[1210,4641,4642],{},[1213,4643,4644,4646,4648],{},[1216,4645,2613],{},[1216,4647,2616],{},[1216,4649,2619],{},[1223,4651,4652,4664],{},[1213,4653,4654,4658,4662],{},[1228,4655,4656],{},[860,4657,2628],{},[1228,4659,4660],{},[860,4661,2633],{},[1228,4663,2636],{},[1213,4665,4666,4670,4674],{},[1228,4667,4668],{},[860,4669,2643],{},[1228,4671,4672],{},[860,4673,2648],{},[1228,4675,2651],{},[1784,4677,4678],{},[856,4679,2656,4680,2659],{},[860,4681,2449],{},[887,4683],{},[890,4685,2665],{"id":2664},[856,4687,2668,4688,2671,4690,2674],{},[860,4689,866],{},[860,4691,792],{},[904,4693,4694],{"className":906,"code":2677,"language":908,"meta":909,"style":909},[860,4695,4696,4718,4736,4740,4756,4782,4808,4812,4816,4850,4878,4912,4916,4944,4966,4994,4998,5030,5034,5038,5054,5086,5090,5094,5098,5122,5140],{"__ignoreMap":909},[913,4697,4698,4700,4702,4704,4706,4708,4710,4712,4714,4716],{"class":915,"line":916},[913,4699,920],{"class":919},[913,4701,954],{"class":953},[913,4703,792],{"class":923},[913,4705,961],{"class":953},[913,4707,866],{"class":923},[913,4709,967],{"class":953},[913,4711,1500],{"class":919},[913,4713,931],{"class":930},[913,4715,884],{"class":934},[913,4717,937],{"class":930},[913,4719,4720,4722,4724,4726,4728,4730,4732,4734],{"class":915,"line":940},[913,4721,920],{"class":919},[913,4723,954],{"class":953},[913,4725,1515],{"class":923},[913,4727,967],{"class":953},[913,4729,1500],{"class":919},[913,4731,931],{"class":930},[913,4733,1524],{"class":934},[913,4735,937],{"class":930},[913,4737,4738],{"class":915,"line":946},[913,4739,943],{"emptyLinePlaceholder":8},[913,4741,4742,4744,4746,4748,4750,4752,4754],{"class":915,"line":986},[913,4743,950],{"class":949},[913,4745,2730],{"class":957},[913,4747,1540],{"class":970},[913,4749,1543],{"class":923},[913,4751,1002],{"class":953},[913,4753,1548],{"class":974},[913,4755,1551],{"class":953},[913,4757,4758,4760,4762,4764,4766,4768,4770,4772,4774,4776,4778,4780],{"class":915,"line":991},[913,4759,2745],{"class":923},[913,4761,1560],{"class":1559},[913,4763,1563],{"class":974},[913,4765,1566],{"class":953},[913,4767,1569],{"class":923},[913,4769,1560],{"class":1559},[913,4771,1575],{"class":1574},[913,4773,961],{"class":953},[913,4775,1580],{"class":923},[913,4777,1560],{"class":1559},[913,4779,2766],{"class":1574},[913,4781,1588],{"class":953},[913,4783,4784,4786,4788,4790,4792,4794,4796,4798,4800,4802,4804,4806],{"class":915,"line":1011},[913,4785,2773],{"class":923},[913,4787,1560],{"class":1559},[913,4789,1563],{"class":974},[913,4791,1566],{"class":953},[913,4793,1569],{"class":923},[913,4795,1560],{"class":1559},[913,4797,2786],{"class":1574},[913,4799,961],{"class":953},[913,4801,1580],{"class":923},[913,4803,1560],{"class":1559},[913,4805,2795],{"class":1574},[913,4807,1588],{"class":953},[913,4809,4810],{"class":915,"line":1018},[913,4811,1688],{"class":953},[913,4813,4814],{"class":915,"line":1050},[913,4815,943],{"emptyLinePlaceholder":8},[913,4817,4818,4820,4822,4824,4826,4828,4830,4832,4834,4836,4838,4840,4842,4844,4846,4848],{"class":915,"line":1056},[913,4819,2810],{"class":923},[913,4821,1002],{"class":953},[913,4823,2815],{"class":974},[913,4825,977],{"class":953},[913,4827,1031],{"class":930},[913,4829,2822],{"class":934},[913,4831,1031],{"class":930},[913,4833,961],{"class":953},[913,4835,2829],{"class":949},[913,4837,997],{"class":953},[913,4839,1956],{"class":2834},[913,4841,961],{"class":953},[913,4843,2839],{"class":2834},[913,4845,2842],{"class":953},[913,4847,2845],{"class":949},[913,4849,2848],{"class":953},[913,4851,4852,4854,4856,4858,4860,4862,4864,4866,4868,4870,4872,4874,4876],{"class":915,"line":1061},[913,4853,2853],{"class":949},[913,4855,2856],{"class":957},[913,4857,1540],{"class":970},[913,4859,2861],{"class":974},[913,4861,2864],{"class":953},[913,4863,2867],{"class":974},[913,4865,1566],{"class":953},[913,4867,2872],{"class":923},[913,4869,1560],{"class":1559},[913,4871,931],{"class":930},[913,4873,2822],{"class":934},[913,4875,1031],{"class":930},[913,4877,2077],{"class":953},[913,4879,4880,4882,4884,4886,4888,4890,4892,4894,4896,4898,4900,4902,4904,4906,4908,4910],{"class":915,"line":1679},[913,4881,2853],{"class":949},[913,4883,1938],{"class":957},[913,4885,1540],{"class":970},[913,4887,1943],{"class":919},[913,4889,1946],{"class":974},[913,4891,977],{"class":953},[913,4893,2899],{"class":923},[913,4895,961],{"class":953},[913,4897,1956],{"class":923},[913,4899,1002],{"class":953},[913,4901,1961],{"class":923},[913,4903,961],{"class":953},[913,4905,1956],{"class":923},[913,4907,961],{"class":953},[913,4909,1026],{"class":923},[913,4911,983],{"class":953},[913,4913,4914],{"class":915,"line":1685},[913,4915,943],{"emptyLinePlaceholder":8},[913,4917,4918,4920,4922,4924,4926,4928,4930,4932,4934,4936,4938,4940,4942],{"class":915,"line":2116},[913,4919,2926],{"class":919},[913,4921,997],{"class":953},[913,4923,1031],{"class":930},[913,4925,1986],{"class":934},[913,4927,1031],{"class":930},[913,4929,1991],{"class":949},[913,4931,1938],{"class":923},[913,4933,1996],{"class":970},[913,4935,2943],{"class":970},[913,4937,2031],{"class":923},[913,4939,1002],{"class":953},[913,4941,1986],{"class":923},[913,4943,1008],{"class":953},[913,4945,4946,4948,4950,4952,4954,4956,4958,4960,4962,4964],{"class":915,"line":2151},[913,4947,2956],{"class":919},[913,4949,997],{"class":953},[913,4951,2031],{"class":923},[913,4953,1002],{"class":953},[913,4955,2036],{"class":923},[913,4957,2005],{"class":970},[913,4959,931],{"class":930},[913,4961,2043],{"class":934},[913,4963,1031],{"class":930},[913,4965,1008],{"class":953},[913,4967,4968,4970,4972,4974,4976,4978,4980,4982,4984,4986,4988,4990,4992],{"class":915,"line":2156},[913,4969,2979],{"class":919},[913,4971,2982],{"class":923},[913,4973,1002],{"class":953},[913,4975,2026],{"class":974},[913,4977,977],{"class":953},[913,4979,2991],{"class":1574},[913,4981,2060],{"class":953},[913,4983,5],{"class":974},[913,4985,1566],{"class":953},[913,4987,3000],{"class":923},[913,4989,1560],{"class":1559},[913,4991,3005],{"class":2008},[913,4993,2077],{"class":953},[913,4995,4996],{"class":915,"line":2161},[913,4997,3012],{"class":953},[913,4999,5000,5002,5004,5006,5008,5010,5012,5014,5016,5018,5020,5022,5024,5026,5028],{"class":915,"line":2166},[913,5001,3017],{"class":919},[913,5003,2982],{"class":923},[913,5005,1002],{"class":953},[913,5007,2026],{"class":974},[913,5009,977],{"class":953},[913,5011,3028],{"class":1574},[913,5013,2060],{"class":953},[913,5015,5],{"class":974},[913,5017,1566],{"class":953},[913,5019,2036],{"class":923},[913,5021,1560],{"class":1559},[913,5023,1938],{"class":923},[913,5025,1002],{"class":953},[913,5027,2036],{"class":923},[913,5029,2077],{"class":953},[913,5031,5032],{"class":915,"line":2172},[913,5033,3051],{"class":953},[913,5035,5036],{"class":915,"line":3054},[913,5037,943],{"emptyLinePlaceholder":8},[913,5039,5040,5042,5044,5046,5048,5050,5052],{"class":915,"line":3059},[913,5041,2926],{"class":919},[913,5043,997],{"class":953},[913,5045,2099],{"class":970},[913,5047,2031],{"class":923},[913,5049,1002],{"class":953},[913,5051,2106],{"class":923},[913,5053,1008],{"class":953},[913,5055,5056,5058,5060,5062,5064,5066,5068,5070,5072,5074,5076,5078,5080,5082,5084],{"class":915,"line":3076},[913,5057,3017],{"class":919},[913,5059,2982],{"class":923},[913,5061,1002],{"class":953},[913,5063,2026],{"class":974},[913,5065,977],{"class":953},[913,5067,2127],{"class":1574},[913,5069,2060],{"class":953},[913,5071,5],{"class":974},[913,5073,977],{"class":953},[913,5075,2031],{"class":923},[913,5077,1002],{"class":953},[913,5079,2140],{"class":923},[913,5081,1002],{"class":953},[913,5083,2145],{"class":974},[913,5085,2148],{"class":953},[913,5087,5088],{"class":915,"line":3109},[913,5089,3051],{"class":953},[913,5091,5092],{"class":915,"line":3114},[913,5093,943],{"emptyLinePlaceholder":8},[913,5095,5096],{"class":915,"line":3119},[913,5097,3122],{"class":1014},[913,5099,5100,5102,5104,5106,5108,5110,5112,5114,5116,5118,5120],{"class":915,"line":3125},[913,5101,2578],{"class":919},[913,5103,3130],{"class":923},[913,5105,1002],{"class":953},[913,5107,3135],{"class":974},[913,5109,977],{"class":953},[913,5111,3140],{"class":923},[913,5113,961],{"class":953},[913,5115,2031],{"class":923},[913,5117,1002],{"class":953},[913,5119,3149],{"class":923},[913,5121,983],{"class":953},[913,5123,5124,5126,5128,5130,5132,5134,5136,5138],{"class":915,"line":3154},[913,5125,2021],{"class":923},[913,5127,1002],{"class":953},[913,5129,5],{"class":974},[913,5131,1566],{"class":953},[913,5133,3165],{"class":923},[913,5135,1560],{"class":1559},[913,5137,3005],{"class":2008},[913,5139,2077],{"class":953},[913,5141,5142],{"class":915,"line":3174},[913,5143,1688],{"class":953},[887,5145],{},[890,5147,3182],{"id":3181},[1695,5149,5150,5154],{},[1698,5151,5152],{"name":3187,"type":1700,"default":3188},[856,5153,3191],{},[1698,5155,5156],{"name":1082,"type":1700,"default":3194},[856,5157,3197],{},[3199,5159,5160],{},[856,5161,3203,5162,3206,5164,3210,5166,3214],{},[860,5163,1159],{},[860,5165,3209],{},[860,5167,3213],{},[887,5169],{},[890,5171,3220],{"id":3219},[856,5173,3223],{},[1207,5175,5176,5184],{},[1210,5177,5178],{},[1213,5179,5180,5182],{},[1216,5181,3232],{},[1216,5183,3235],{},[1223,5185,5186,5196,5212,5222,5238],{},[1213,5187,5188,5192],{},[1228,5189,5190],{},[869,5191,95],{"href":96},[1228,5193,3246,5194,3250],{},[860,5195,3249],{},[1213,5197,5198,5202],{},[1228,5199,5200],{},[869,5201,399],{"href":2279},[1228,5203,5204,3261,5206,961,5208,1746,5210,3270],{},[860,5205,1903],{},[860,5207,2369],{},[860,5209,3266],{},[860,5211,3269],{},[1213,5213,5214,5218],{},[1228,5215,5216],{},[869,5217,127],{"href":128},[1228,5219,1331,5220,3281],{},[860,5221,2252],{},[1213,5223,5224,5228],{},[1228,5225,5226],{},[869,5227,99],{"href":100},[1228,5229,3290,5230,961,5232,1746,5234,1100,5236],{},[860,5231,1820],{},[860,5233,1823],{},[860,5235,1826],{},[860,5237,866],{},[1213,5239,5240,5244],{},[1228,5241,5242],{},[869,5243,123],{"href":124},[1228,5245,3307],{},[3309,5247,3311],{},{"title":909,"searchDepth":940,"depth":940,"links":5249},[5250,5251,5255,5258,5259,5260,5261,5262],{"id":892,"depth":940,"text":893},{"id":1466,"depth":940,"text":1467,"children":5252},[5253,5254],{"id":1692,"depth":946,"text":1693},{"id":1725,"depth":946,"text":1726},{"id":1888,"depth":940,"text":1889,"children":5256},[5257],{"id":2197,"depth":946,"text":2198},{"id":2285,"depth":940,"text":1903},{"id":2443,"depth":940,"text":2444},{"id":2664,"depth":940,"text":2665},{"id":3181,"depth":940,"text":3182},{"id":3219,"depth":940,"text":3220},{},{"title":139,"description":3327},1780436283108]