[{"data":1,"prerenderedAt":5981},["ShallowReactive",2],{"navLinks":3,"sidebar_docs_navigation_\u002Fdocs\u002Fiam":64,"navigation":257,"navLinks_footer":837,"\u002Fdocs\u002Fiam\u002Fgetting-started_page":850,"\u002Fdocs\u002Fiam\u002Fgetting-started_surround":3709,"\u002Fdocs\u002Fiam\u002Fgetting-started":3712},{"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":14,"body":852,"description":3702,"extension":3703,"icon":15,"meta":3704,"module":3705,"navigation":8,"path":74,"rawbody":3706,"seo":3707,"stem":75,"__hash__":3708},"docs\u002Fdocs\u002Fiam\u002F00.getting-started.md",{"type":853,"value":854,"toc":3689},"minimark",[855,863,868,871,874,904,907,920,923,946,957,960,964,977,982,1000,1009,1016,1262,1996,2000,2003,2096,2098,2102,2105,2167,2181,2254,2256,2260,3430,3432,3439,3445,3516,3522,3606,3611,3613,3617,3620,3685],[856,857,858,862],"p",{},[859,860,861],"code",{},"@riavzon\u002Fauth"," runs as a standalone Express 5 service backed by MySQL. You can use it as a library in your own application, or run the production-ready Docker image that ships with secrets encrypted at rest.",[864,865,867],"h2",{"id":866},"requirements","Requirements",[856,869,870],{},"Depending on how you plan to use the service, your environment needs to meet the following:",[856,872,873],{},"Docker with encryption:",[875,876,877,884,895],"ul",{},[878,879,880],"li",{},[881,882,883],"strong",{},"Node.js 20 or later",[878,885,886],{},[887,888,892],"a",{"href":889,"rel":890},"https:\u002F\u002Fgithub.com\u002FFiloSottile\u002Fage",[891],"nofollow",[881,893,894],{},"age",[878,896,897],{},[887,898,901],{"href":899,"rel":900},"https:\u002F\u002Fdocs.docker.com",[891],[881,902,903],{},"Docker",[856,905,906],{},"Docker without encryption:",[875,908,909,913],{},[878,910,911],{},[881,912,883],{},[878,914,915],{},[887,916,918],{"href":899,"rel":917},[891],[881,919,903],{},[856,921,922],{},"Local\u002FLibrary:",[875,924,925,929,934],{},[878,926,927],{},[881,928,883],{},[878,930,931],{},[881,932,933],{},"MySQL 8+",[878,935,936,945],{},[887,937,940],{"href":938,"rel":939},"https:\u002F\u002Fgithub.com\u002Fipinfo\u002Fmmdbctl",[891],[881,941,942],{},[859,943,944],{},"mmdbctl"," binary for MMDB compilation (installed automatically during build)",[947,948,951],"callout",{"color":949,"icon":950},"info","i-lucide-container",[856,952,953,954,956],{},"The recommended deployment path is the hardened Docker image. It handles all dependencies, database initialization, ",[859,955,944],{}," installations, and data-source compilation automatically.",[958,959],"hr",{},[864,961,963],{"id":962},"docker-deployment","Docker deployment",[856,965,966,967,969,970,972,973,976],{},"The IAM service ships as a public Docker image. The image uses a multi-stage build: it installs all required binaries (",[859,968,894],{},", ",[859,971,944],{},"), dependencies, compiles all Shield Base and Bot Detector data sources, bundles the service, then produces a minimal image with ",[859,974,975],{},"read_only"," filesystem support.",[978,979,981],"h3",{"id":980},"secrets-at-rest","Secrets at rest",[856,983,984,985,988,989,992,993,995,996,999],{},"The Docker image uses ",[887,986,894],{"href":889,"rel":987},[891]," to encrypt and decrypt your configuration file (",[859,990,991],{},"config.json",").\nEncrypt your config locally with ",[859,994,894],{},", and the image decrypts it at startup using the ",[859,997,998],{},"decrypt.sh"," entrypoint script. The service deletes the decrypted file automatically after loading it.",[856,1001,1002,1003,1008],{},"You can provide the age key and encrypted config as ",[887,1004,1007],{"href":1005,"rel":1006},"https:\u002F\u002Fdocs.docker.com\u002Fcompose\u002Fhow-tos\u002Fuse-secrets\u002F",[891],"Docker secrets",".",[856,1010,1011,1012,1015],{},"If you don't want to deal with encryption, mount your config file directly at ",[859,1013,1014],{},"\u002Frun\u002Fapp\u002Fconfig.json",":",[1017,1018,1024],"pre",{"className":1019,"code":1020,"filename":1021,"language":1022,"meta":1023,"style":1023},"language-yaml shiki shiki-themes light-plus light-plus dracula","  auth:\n    image: sergio68\u002Fauth\n    read_only: true  \n    restart: unless-stopped\n    cap_drop: [\"ALL\"]\n    user: 10001:10001\n    volumes: \n      - .\u002Fauth-logs\u002Fserver:\u002Fapp\u002Fauth-logs:rw\n      - .\u002Fauth-logs\u002Fserver\u002Fbot-detector:\u002Fapp\u002Fbot-detector-logs:rw\n      - .\u002Fconfig.json:\u002Frun\u002Fapp\u002Fconfig.json\n      - bot-detector-data:\u002Fapp\u002Fnode_modules\u002F@riavzon\u002Fbot-detector\u002Fdist\u002F_data-sources:rw\n      - email-data:\u002Fapp\u002Fdist\u002Femail-db:rw\n    tmpfs:\n      - \u002Frun\u002Fapp:rw,noexec,nosuid,nodev,uid=10001,gid=10001,size=1m\n    pids_limit: 200\n    ports:\n      - \"10000:10000\"\n    security_opt:\n      - \"no-new-privileges:true\"\n    depends_on:\n      mysql:\n        condition: service_healthy\n\n","docker-compose.yml","yaml","",[859,1025,1026,1039,1051,1067,1078,1102,1113,1124,1133,1141,1149,1157,1165,1173,1181,1193,1201,1215,1223,1235,1243,1251],{"__ignoreMap":1023},[1027,1028,1031,1035],"span",{"class":1029,"line":1030},"line",1,[1027,1032,1034],{"class":1033},"sXrRR","  auth",[1027,1036,1038],{"class":1037},"saOXh",":\n",[1027,1040,1042,1045,1047],{"class":1029,"line":1041},2,[1027,1043,1044],{"class":1033},"    image",[1027,1046,1015],{"class":1037},[1027,1048,1050],{"class":1049},"sKKzR"," sergio68\u002Fauth\n",[1027,1052,1054,1057,1059,1063],{"class":1029,"line":1053},3,[1027,1055,1056],{"class":1033},"    read_only",[1027,1058,1015],{"class":1037},[1027,1060,1062],{"class":1061},"sjR7W"," true",[1027,1064,1066],{"class":1065},"sDd4n","  \n",[1027,1068,1070,1073,1075],{"class":1029,"line":1069},4,[1027,1071,1072],{"class":1033},"    restart",[1027,1074,1015],{"class":1037},[1027,1076,1077],{"class":1049}," unless-stopped\n",[1027,1079,1081,1084,1086,1089,1093,1097,1099],{"class":1029,"line":1080},5,[1027,1082,1083],{"class":1033},"    cap_drop",[1027,1085,1015],{"class":1037},[1027,1087,1088],{"class":1065}," [",[1027,1090,1092],{"class":1091},"sFkSl","\"",[1027,1094,1096],{"class":1095},"sFB1V","ALL",[1027,1098,1092],{"class":1091},[1027,1100,1101],{"class":1065},"]\n",[1027,1103,1105,1108,1110],{"class":1029,"line":1104},6,[1027,1106,1107],{"class":1033},"    user",[1027,1109,1015],{"class":1037},[1027,1111,1112],{"class":1049}," 10001:10001\n",[1027,1114,1116,1119,1121],{"class":1029,"line":1115},7,[1027,1117,1118],{"class":1033},"    volumes",[1027,1120,1015],{"class":1037},[1027,1122,1123],{"class":1065}," \n",[1027,1125,1127,1130],{"class":1029,"line":1126},8,[1027,1128,1129],{"class":1037},"      -",[1027,1131,1132],{"class":1049}," .\u002Fauth-logs\u002Fserver:\u002Fapp\u002Fauth-logs:rw\n",[1027,1134,1136,1138],{"class":1029,"line":1135},9,[1027,1137,1129],{"class":1037},[1027,1139,1140],{"class":1049}," .\u002Fauth-logs\u002Fserver\u002Fbot-detector:\u002Fapp\u002Fbot-detector-logs:rw\n",[1027,1142,1144,1146],{"class":1029,"line":1143},10,[1027,1145,1129],{"class":1037},[1027,1147,1148],{"class":1049}," .\u002Fconfig.json:\u002Frun\u002Fapp\u002Fconfig.json\n",[1027,1150,1152,1154],{"class":1029,"line":1151},11,[1027,1153,1129],{"class":1037},[1027,1155,1156],{"class":1049}," bot-detector-data:\u002Fapp\u002Fnode_modules\u002F@riavzon\u002Fbot-detector\u002Fdist\u002F_data-sources:rw\n",[1027,1158,1160,1162],{"class":1029,"line":1159},12,[1027,1161,1129],{"class":1037},[1027,1163,1164],{"class":1049}," email-data:\u002Fapp\u002Fdist\u002Femail-db:rw\n",[1027,1166,1168,1171],{"class":1029,"line":1167},13,[1027,1169,1170],{"class":1033},"    tmpfs",[1027,1172,1038],{"class":1037},[1027,1174,1176,1178],{"class":1029,"line":1175},14,[1027,1177,1129],{"class":1037},[1027,1179,1180],{"class":1049}," \u002Frun\u002Fapp:rw,noexec,nosuid,nodev,uid=10001,gid=10001,size=1m\n",[1027,1182,1184,1187,1189],{"class":1029,"line":1183},15,[1027,1185,1186],{"class":1033},"    pids_limit",[1027,1188,1015],{"class":1037},[1027,1190,1192],{"class":1191},"spgvN"," 200\n",[1027,1194,1196,1199],{"class":1029,"line":1195},16,[1027,1197,1198],{"class":1033},"    ports",[1027,1200,1038],{"class":1037},[1027,1202,1204,1206,1209,1212],{"class":1029,"line":1203},17,[1027,1205,1129],{"class":1037},[1027,1207,1208],{"class":1091}," \"",[1027,1210,1211],{"class":1095},"10000:10000",[1027,1213,1214],{"class":1091},"\"\n",[1027,1216,1218,1221],{"class":1029,"line":1217},18,[1027,1219,1220],{"class":1033},"    security_opt",[1027,1222,1038],{"class":1037},[1027,1224,1226,1228,1230,1233],{"class":1029,"line":1225},19,[1027,1227,1129],{"class":1037},[1027,1229,1208],{"class":1091},[1027,1231,1232],{"class":1095},"no-new-privileges:true",[1027,1234,1214],{"class":1091},[1027,1236,1238,1241],{"class":1029,"line":1237},20,[1027,1239,1240],{"class":1033},"    depends_on",[1027,1242,1038],{"class":1037},[1027,1244,1246,1249],{"class":1029,"line":1245},21,[1027,1247,1248],{"class":1033},"      mysql",[1027,1250,1038],{"class":1037},[1027,1252,1254,1257,1259],{"class":1029,"line":1253},22,[1027,1255,1256],{"class":1033},"        condition",[1027,1258,1015],{"class":1037},[1027,1260,1261],{"class":1049}," service_healthy\n",[1263,1264,1266,1271,1307,1310,1324,1333,1337,1347,1386,1392,1404,1410,1936,1939,1973,1977],"steps",{"level":1265},"4",[1267,1268,1270],"h4",{"id":1269},"generate-an-age-key-pair","Generate an age key pair",[1017,1272,1277],{"className":1273,"code":1274,"filename":1275,"language":1276,"meta":1023,"style":1023},"language-bash shiki shiki-themes light-plus light-plus dracula","age-keygen -o age_key && age-keygen -y age_key > public_key\n","Terminal","bash",[859,1278,1279],{"__ignoreMap":1023},[1027,1280,1281,1285,1288,1291,1294,1296,1299,1301,1304],{"class":1029,"line":1030},[1027,1282,1284],{"class":1283},"sHOzp","age-keygen",[1027,1286,1287],{"class":1061}," -o",[1027,1289,1290],{"class":1095}," age_key",[1027,1292,1293],{"class":1065}," && ",[1027,1295,1284],{"class":1283},[1027,1297,1298],{"class":1061}," -y",[1027,1300,1290],{"class":1095},[1027,1302,1303],{"class":1037}," >",[1027,1305,1306],{"class":1095}," public_key\n",[856,1308,1309],{},"This will generate 2 files:",[875,1311,1312,1318],{},[878,1313,1314,1317],{},[859,1315,1316],{},"age_key"," is the private key. Store it securely.",[878,1319,1320,1323],{},[859,1321,1322],{},"public_key"," is the public key.",[1325,1326,1327],"warning",{},[856,1328,1329,1330,1332],{},"Never commit ",[859,1331,1316],{}," to version control",[1267,1334,1336],{"id":1335},"encrypt-your-configuration","Encrypt your configuration",[856,1338,1339,1340,1342,1343,1346],{},"Create your ",[859,1341,991],{}," with the full ",[887,1344,1345],{"href":238},"configuration"," object, then encrypt it:",[1017,1348,1350],{"className":1273,"code":1349,"filename":1275,"language":1276,"meta":1023,"style":1023},"age -a -e -r \"$(cat public_key)\" -o config.json.age config.json\n",[859,1351,1352],{"__ignoreMap":1023},[1027,1353,1354,1356,1359,1362,1365,1367,1370,1373,1376,1378,1380,1383],{"class":1029,"line":1030},[1027,1355,894],{"class":1283},[1027,1357,1358],{"class":1061}," -a",[1027,1360,1361],{"class":1061}," -e",[1027,1363,1364],{"class":1061}," -r",[1027,1366,1208],{"class":1091},[1027,1368,1369],{"class":1095},"$(",[1027,1371,1372],{"class":1283},"cat",[1027,1374,1375],{"class":1095}," public_key)",[1027,1377,1092],{"class":1091},[1027,1379,1287],{"class":1061},[1027,1381,1382],{"class":1095}," config.json.age",[1027,1384,1385],{"class":1095}," config.json\n",[856,1387,1388,1391],{},[859,1389,1390],{},"config.json.age"," is your encrypted config. Only the matching private key can decrypt this file.",[1393,1394,1395],"tip",{},[856,1396,1397,1398,1400,1401,1403],{},"In production, consider deleting ",[859,1399,991],{}," from the local host and storing ",[859,1402,1316],{}," in an appropriate secret manager.",[1267,1405,1407,1408],{"id":1406},"create-a-docker-composeyml","Create a ",[859,1409,1021],{},[1017,1411,1413],{"className":1019,"code":1412,"filename":1021,"language":1022,"meta":1023,"style":1023},"services:\n  mysql: \n    restart: unless-stopped\n    environment:\n      MYSQL_ROOT_PASSWORD: secure_password\n      MYSQL_DATABASE: auth_db\n      MYSQL_USER: auth_user\n      MYSQL_PASSWORD: secure_password\n    cap_drop: [\"ALL\"]\n    user: \"999:999\"\n    security_opt: \n      - \"no-new-privileges:true\"\n    volumes:\n      - sql_db:\u002Fvar\u002Flib\u002Fmysql\n    healthcheck:\n      test: [\"CMD-SHELL\", \"bash -lc 'exec 3\u003C>\u002Fdev\u002Ftcp\u002F127.0.0.1\u002F3306'\"]\n      interval: 10s\n      timeout: 8s \n      retries: 5\n      start_period: 7m\n    tmpfs:\n      - \u002Fvar\u002Flib\u002Fmysql:rw,noexec,nosuid,nodev,size=512m  \n\n  auth:\n    image: sergio68\u002Fauth\n    read_only: true  \n    restart: unless-stopped\n    cap_drop: [\"ALL\"]\n    user: 10001:10001\n    volumes: \n      - .\u002Fauth-logs\u002Fserver:\u002Fapp\u002Fauth-logs:rw\n      - .\u002Fauth-logs\u002Fserver\u002Fbot-detector:\u002Fapp\u002Fbot-detector-logs:rw\n      - bot-detector-data:\u002Fapp\u002Fnode_modules\u002F@riavzon\u002Fbot-detector\u002Fdist\u002F_data-sources:rw\n      - email-data:\u002Fapp\u002Fdist\u002Femail-db:rw\n    tmpfs:\n      - \u002Frun\u002Fapp:rw,noexec,nosuid,nodev,uid=10001,gid=10001,size=1m\n    pids_limit: 200\n    ports:\n      - \"10000:10000\"\n    secrets:\n      - age_key\n      - encrypted_config\n    security_opt:\n      - \"no-new-privileges:true\"\n    depends_on:\n      mysql:\n        condition: service_healthy\n\nvolumes:\n  sql_db:  \n  bot-detector-data:\n  email-data:\n\nsecrets:\n  age_key:\n    file: .\u002Fage_key\n  encrypted_config:\n    file: .\u002Fconfig.json.age\n",[859,1414,1415,1422,1431,1439,1446,1456,1466,1476,1485,1501,1514,1522,1532,1538,1545,1552,1579,1589,1601,1611,1621,1627,1636,1642,1649,1658,1669,1678,1695,1704,1713,1720,1727,1734,1741,1748,1755,1764,1771,1782,1790,1798,1806,1813,1824,1831,1838,1847,1852,1860,1870,1878,1886,1891,1899,1907,1918,1926],{"__ignoreMap":1023},[1027,1416,1417,1420],{"class":1029,"line":1030},[1027,1418,1419],{"class":1033},"services",[1027,1421,1038],{"class":1037},[1027,1423,1424,1427,1429],{"class":1029,"line":1041},[1027,1425,1426],{"class":1033},"  mysql",[1027,1428,1015],{"class":1037},[1027,1430,1123],{"class":1065},[1027,1432,1433,1435,1437],{"class":1029,"line":1053},[1027,1434,1072],{"class":1033},[1027,1436,1015],{"class":1037},[1027,1438,1077],{"class":1049},[1027,1440,1441,1444],{"class":1029,"line":1069},[1027,1442,1443],{"class":1033},"    environment",[1027,1445,1038],{"class":1037},[1027,1447,1448,1451,1453],{"class":1029,"line":1080},[1027,1449,1450],{"class":1033},"      MYSQL_ROOT_PASSWORD",[1027,1452,1015],{"class":1037},[1027,1454,1455],{"class":1049}," secure_password\n",[1027,1457,1458,1461,1463],{"class":1029,"line":1104},[1027,1459,1460],{"class":1033},"      MYSQL_DATABASE",[1027,1462,1015],{"class":1037},[1027,1464,1465],{"class":1049}," auth_db\n",[1027,1467,1468,1471,1473],{"class":1029,"line":1115},[1027,1469,1470],{"class":1033},"      MYSQL_USER",[1027,1472,1015],{"class":1037},[1027,1474,1475],{"class":1049}," auth_user\n",[1027,1477,1478,1481,1483],{"class":1029,"line":1126},[1027,1479,1480],{"class":1033},"      MYSQL_PASSWORD",[1027,1482,1015],{"class":1037},[1027,1484,1455],{"class":1049},[1027,1486,1487,1489,1491,1493,1495,1497,1499],{"class":1029,"line":1135},[1027,1488,1083],{"class":1033},[1027,1490,1015],{"class":1037},[1027,1492,1088],{"class":1065},[1027,1494,1092],{"class":1091},[1027,1496,1096],{"class":1095},[1027,1498,1092],{"class":1091},[1027,1500,1101],{"class":1065},[1027,1502,1503,1505,1507,1509,1512],{"class":1029,"line":1143},[1027,1504,1107],{"class":1033},[1027,1506,1015],{"class":1037},[1027,1508,1208],{"class":1091},[1027,1510,1511],{"class":1095},"999:999",[1027,1513,1214],{"class":1091},[1027,1515,1516,1518,1520],{"class":1029,"line":1151},[1027,1517,1220],{"class":1033},[1027,1519,1015],{"class":1037},[1027,1521,1123],{"class":1065},[1027,1523,1524,1526,1528,1530],{"class":1029,"line":1159},[1027,1525,1129],{"class":1037},[1027,1527,1208],{"class":1091},[1027,1529,1232],{"class":1095},[1027,1531,1214],{"class":1091},[1027,1533,1534,1536],{"class":1029,"line":1167},[1027,1535,1118],{"class":1033},[1027,1537,1038],{"class":1037},[1027,1539,1540,1542],{"class":1029,"line":1175},[1027,1541,1129],{"class":1037},[1027,1543,1544],{"class":1049}," sql_db:\u002Fvar\u002Flib\u002Fmysql\n",[1027,1546,1547,1550],{"class":1029,"line":1183},[1027,1548,1549],{"class":1033},"    healthcheck",[1027,1551,1038],{"class":1037},[1027,1553,1554,1557,1559,1561,1563,1566,1568,1570,1572,1575,1577],{"class":1029,"line":1195},[1027,1555,1556],{"class":1033},"      test",[1027,1558,1015],{"class":1037},[1027,1560,1088],{"class":1065},[1027,1562,1092],{"class":1091},[1027,1564,1565],{"class":1095},"CMD-SHELL",[1027,1567,1092],{"class":1091},[1027,1569,969],{"class":1065},[1027,1571,1092],{"class":1091},[1027,1573,1574],{"class":1095},"bash -lc 'exec 3\u003C>\u002Fdev\u002Ftcp\u002F127.0.0.1\u002F3306'",[1027,1576,1092],{"class":1091},[1027,1578,1101],{"class":1065},[1027,1580,1581,1584,1586],{"class":1029,"line":1203},[1027,1582,1583],{"class":1033},"      interval",[1027,1585,1015],{"class":1037},[1027,1587,1588],{"class":1049}," 10s\n",[1027,1590,1591,1594,1596,1599],{"class":1029,"line":1217},[1027,1592,1593],{"class":1033},"      timeout",[1027,1595,1015],{"class":1037},[1027,1597,1598],{"class":1049}," 8s",[1027,1600,1123],{"class":1065},[1027,1602,1603,1606,1608],{"class":1029,"line":1225},[1027,1604,1605],{"class":1033},"      retries",[1027,1607,1015],{"class":1037},[1027,1609,1610],{"class":1191}," 5\n",[1027,1612,1613,1616,1618],{"class":1029,"line":1237},[1027,1614,1615],{"class":1033},"      start_period",[1027,1617,1015],{"class":1037},[1027,1619,1620],{"class":1049}," 7m\n",[1027,1622,1623,1625],{"class":1029,"line":1245},[1027,1624,1170],{"class":1033},[1027,1626,1038],{"class":1037},[1027,1628,1629,1631,1634],{"class":1029,"line":1253},[1027,1630,1129],{"class":1037},[1027,1632,1633],{"class":1049}," \u002Fvar\u002Flib\u002Fmysql:rw,noexec,nosuid,nodev,size=512m",[1027,1635,1066],{"class":1065},[1027,1637,1639],{"class":1029,"line":1638},23,[1027,1640,1641],{"emptyLinePlaceholder":8},"\n",[1027,1643,1645,1647],{"class":1029,"line":1644},24,[1027,1646,1034],{"class":1033},[1027,1648,1038],{"class":1037},[1027,1650,1652,1654,1656],{"class":1029,"line":1651},25,[1027,1653,1044],{"class":1033},[1027,1655,1015],{"class":1037},[1027,1657,1050],{"class":1049},[1027,1659,1661,1663,1665,1667],{"class":1029,"line":1660},26,[1027,1662,1056],{"class":1033},[1027,1664,1015],{"class":1037},[1027,1666,1062],{"class":1061},[1027,1668,1066],{"class":1065},[1027,1670,1672,1674,1676],{"class":1029,"line":1671},27,[1027,1673,1072],{"class":1033},[1027,1675,1015],{"class":1037},[1027,1677,1077],{"class":1049},[1027,1679,1681,1683,1685,1687,1689,1691,1693],{"class":1029,"line":1680},28,[1027,1682,1083],{"class":1033},[1027,1684,1015],{"class":1037},[1027,1686,1088],{"class":1065},[1027,1688,1092],{"class":1091},[1027,1690,1096],{"class":1095},[1027,1692,1092],{"class":1091},[1027,1694,1101],{"class":1065},[1027,1696,1698,1700,1702],{"class":1029,"line":1697},29,[1027,1699,1107],{"class":1033},[1027,1701,1015],{"class":1037},[1027,1703,1112],{"class":1049},[1027,1705,1707,1709,1711],{"class":1029,"line":1706},30,[1027,1708,1118],{"class":1033},[1027,1710,1015],{"class":1037},[1027,1712,1123],{"class":1065},[1027,1714,1716,1718],{"class":1029,"line":1715},31,[1027,1717,1129],{"class":1037},[1027,1719,1132],{"class":1049},[1027,1721,1723,1725],{"class":1029,"line":1722},32,[1027,1724,1129],{"class":1037},[1027,1726,1140],{"class":1049},[1027,1728,1730,1732],{"class":1029,"line":1729},33,[1027,1731,1129],{"class":1037},[1027,1733,1156],{"class":1049},[1027,1735,1737,1739],{"class":1029,"line":1736},34,[1027,1738,1129],{"class":1037},[1027,1740,1164],{"class":1049},[1027,1742,1744,1746],{"class":1029,"line":1743},35,[1027,1745,1170],{"class":1033},[1027,1747,1038],{"class":1037},[1027,1749,1751,1753],{"class":1029,"line":1750},36,[1027,1752,1129],{"class":1037},[1027,1754,1180],{"class":1049},[1027,1756,1758,1760,1762],{"class":1029,"line":1757},37,[1027,1759,1186],{"class":1033},[1027,1761,1015],{"class":1037},[1027,1763,1192],{"class":1191},[1027,1765,1767,1769],{"class":1029,"line":1766},38,[1027,1768,1198],{"class":1033},[1027,1770,1038],{"class":1037},[1027,1772,1774,1776,1778,1780],{"class":1029,"line":1773},39,[1027,1775,1129],{"class":1037},[1027,1777,1208],{"class":1091},[1027,1779,1211],{"class":1095},[1027,1781,1214],{"class":1091},[1027,1783,1785,1788],{"class":1029,"line":1784},40,[1027,1786,1787],{"class":1033},"    secrets",[1027,1789,1038],{"class":1037},[1027,1791,1793,1795],{"class":1029,"line":1792},41,[1027,1794,1129],{"class":1037},[1027,1796,1797],{"class":1049}," age_key\n",[1027,1799,1801,1803],{"class":1029,"line":1800},42,[1027,1802,1129],{"class":1037},[1027,1804,1805],{"class":1049}," encrypted_config\n",[1027,1807,1809,1811],{"class":1029,"line":1808},43,[1027,1810,1220],{"class":1033},[1027,1812,1038],{"class":1037},[1027,1814,1816,1818,1820,1822],{"class":1029,"line":1815},44,[1027,1817,1129],{"class":1037},[1027,1819,1208],{"class":1091},[1027,1821,1232],{"class":1095},[1027,1823,1214],{"class":1091},[1027,1825,1827,1829],{"class":1029,"line":1826},45,[1027,1828,1240],{"class":1033},[1027,1830,1038],{"class":1037},[1027,1832,1834,1836],{"class":1029,"line":1833},46,[1027,1835,1248],{"class":1033},[1027,1837,1038],{"class":1037},[1027,1839,1841,1843,1845],{"class":1029,"line":1840},47,[1027,1842,1256],{"class":1033},[1027,1844,1015],{"class":1037},[1027,1846,1261],{"class":1049},[1027,1848,1850],{"class":1029,"line":1849},48,[1027,1851,1641],{"emptyLinePlaceholder":8},[1027,1853,1855,1858],{"class":1029,"line":1854},49,[1027,1856,1857],{"class":1033},"volumes",[1027,1859,1038],{"class":1037},[1027,1861,1863,1866,1868],{"class":1029,"line":1862},50,[1027,1864,1865],{"class":1033},"  sql_db",[1027,1867,1015],{"class":1037},[1027,1869,1066],{"class":1065},[1027,1871,1873,1876],{"class":1029,"line":1872},51,[1027,1874,1875],{"class":1033},"  bot-detector-data",[1027,1877,1038],{"class":1037},[1027,1879,1881,1884],{"class":1029,"line":1880},52,[1027,1882,1883],{"class":1033},"  email-data",[1027,1885,1038],{"class":1037},[1027,1887,1889],{"class":1029,"line":1888},53,[1027,1890,1641],{"emptyLinePlaceholder":8},[1027,1892,1894,1897],{"class":1029,"line":1893},54,[1027,1895,1896],{"class":1033},"secrets",[1027,1898,1038],{"class":1037},[1027,1900,1902,1905],{"class":1029,"line":1901},55,[1027,1903,1904],{"class":1033},"  age_key",[1027,1906,1038],{"class":1037},[1027,1908,1910,1913,1915],{"class":1029,"line":1909},56,[1027,1911,1912],{"class":1033},"    file",[1027,1914,1015],{"class":1037},[1027,1916,1917],{"class":1049}," .\u002Fage_key\n",[1027,1919,1921,1924],{"class":1029,"line":1920},57,[1027,1922,1923],{"class":1033},"  encrypted_config",[1027,1925,1038],{"class":1037},[1027,1927,1929,1931,1933],{"class":1029,"line":1928},58,[1027,1930,1912],{"class":1033},[1027,1932,1015],{"class":1037},[1027,1934,1935],{"class":1049}," .\u002Fconfig.json.age\n",[856,1937,1938],{},"The volumes that are required are:",[875,1940,1941,1947,1957,1967],{},[878,1942,1943,1946],{},[859,1944,1945],{},".\u002Fauth-logs\u002Fserver"," for the auth logs, can be any local path.",[878,1948,1949,1952,1953,1956],{},[859,1950,1951],{},".\u002Fauth-logs\u002Fserver\u002Fbot-detector"," for the ",[859,1954,1955],{},"bot-detector"," logs, can be any local path.",[878,1958,1959,1962,1963,1966],{},[859,1960,1961],{},"bot-detector-data"," for keeping the data sources fresh, and compiling ",[859,1964,1965],{},"bot-detector generate"," data sources. Can be any name.",[878,1968,1969,1972],{},[859,1970,1971],{},"email-data"," for the disposable email list data. Can be any name.",[1267,1974,1976],{"id":1975},"start-the-service","Start the service",[1017,1978,1980],{"className":1273,"code":1979,"filename":1275,"language":1276,"meta":1023,"style":1023},"docker compose up -d\n",[859,1981,1982],{"__ignoreMap":1023},[1027,1983,1984,1987,1990,1993],{"class":1029,"line":1030},[1027,1985,1986],{"class":1283},"docker",[1027,1988,1989],{"class":1095}," compose",[1027,1991,1992],{"class":1095}," up",[1027,1994,1995],{"class":1061}," -d\n",[978,1997,1999],{"id":1998},"image-security-hardening","Image security hardening",[856,2001,2002],{},"The production image enforces the following:",[2004,2005,2006,2019],"table",{},[2007,2008,2009],"thead",{},[2010,2011,2012,2016],"tr",{},[2013,2014,2015],"th",{},"Control",[2013,2017,2018],{},"Value",[2020,2021,2022,2034,2044,2056,2067,2077,2085],"tbody",{},[2010,2023,2024,2028],{},[2025,2026,2027],"td",{},"Non-root user",[2025,2029,2030,2033],{},[859,2031,2032],{},"appuser"," (UID 10001)",[2010,2035,2036,2039],{},[2025,2037,2038],{},"Filesystem",[2025,2040,2041],{},[859,2042,2043],{},"read_only: true",[2010,2045,2046,2049],{},[2025,2047,2048],{},"Capabilities",[2025,2050,2051,2052,2055],{},"All dropped (",[859,2053,2054],{},"cap_drop: [\"ALL\"]",")",[2010,2057,2058,2061],{},[2025,2059,2060],{},"Privilege escalation",[2025,2062,2063,2064,2055],{},"Blocked (",[859,2065,2066],{},"no-new-privileges: true",[2010,2068,2069,2072],{},[2025,2070,2071],{},"PID limit",[2025,2073,2074],{},[859,2075,2076],{},"200",[2010,2078,2079,2082],{},[2025,2080,2081],{},"Config lifetime",[2025,2083,2084],{},"Decrypted into tmpfs, deleted after load",[2010,2086,2087,2090],{},[2025,2088,2089],{},"Healthcheck",[2025,2091,2092,2095],{},[859,2093,2094],{},"GET \u002Fhealth"," every 30s",[958,2097],{},[864,2099,2101],{"id":2100},"library-installation","Library installation",[856,2103,2104],{},"If you prefer to integrate the IAM module into your own Express application rather than running the standalone service, install it as a dependency.",[2106,2107,2108,2124,2138,2153],"code-group",{},[1017,2109,2112],{"className":1273,"code":2110,"filename":2111,"language":1276,"meta":1023,"style":1023},"pnpm add @riavzon\u002Fauth\n","pnpm",[859,2113,2114],{"__ignoreMap":1023},[1027,2115,2116,2118,2121],{"class":1029,"line":1030},[1027,2117,2111],{"class":1283},[1027,2119,2120],{"class":1095}," add",[1027,2122,2123],{"class":1095}," @riavzon\u002Fauth\n",[1017,2125,2128],{"className":1273,"code":2126,"filename":2127,"language":1276,"meta":1023,"style":1023},"yarn add @riavzon\u002Fauth\n","yarn",[859,2129,2130],{"__ignoreMap":1023},[1027,2131,2132,2134,2136],{"class":1029,"line":1030},[1027,2133,2127],{"class":1283},[1027,2135,2120],{"class":1095},[1027,2137,2123],{"class":1095},[1017,2139,2142],{"className":1273,"code":2140,"filename":2141,"language":1276,"meta":1023,"style":1023},"npm install @riavzon\u002Fauth\n","npm",[859,2143,2144],{"__ignoreMap":1023},[1027,2145,2146,2148,2151],{"class":1029,"line":1030},[1027,2147,2141],{"class":1283},[1027,2149,2150],{"class":1095}," install",[1027,2152,2123],{"class":1095},[1017,2154,2157],{"className":1273,"code":2155,"filename":2156,"language":1276,"meta":1023,"style":1023},"bun add @riavzon\u002Fauth\n","bun",[859,2158,2159],{"__ignoreMap":1023},[1027,2160,2161,2163,2165],{"class":1029,"line":1030},[1027,2162,2156],{"class":1283},[1027,2164,2120],{"class":1095},[1027,2166,2123],{"class":1095},[856,2168,2169,2170,969,2173,2176,2177,2180],{},"The module also requires ",[859,2171,2172],{},"express",[859,2174,2175],{},"cookie-parser",", and ",[859,2178,2179],{},"mysql2"," as peer dependencies:",[2106,2182,2183,2203,2220,2237],{},[1017,2184,2186],{"className":1273,"code":2185,"filename":2111,"language":1276,"meta":1023,"style":1023},"pnpm add express cookie-parser mysql2\n",[859,2187,2188],{"__ignoreMap":1023},[1027,2189,2190,2192,2194,2197,2200],{"class":1029,"line":1030},[1027,2191,2111],{"class":1283},[1027,2193,2120],{"class":1095},[1027,2195,2196],{"class":1095}," express",[1027,2198,2199],{"class":1095}," cookie-parser",[1027,2201,2202],{"class":1095}," mysql2\n",[1017,2204,2206],{"className":1273,"code":2205,"filename":2127,"language":1276,"meta":1023,"style":1023},"yarn add express cookie-parser mysql2\n",[859,2207,2208],{"__ignoreMap":1023},[1027,2209,2210,2212,2214,2216,2218],{"class":1029,"line":1030},[1027,2211,2127],{"class":1283},[1027,2213,2120],{"class":1095},[1027,2215,2196],{"class":1095},[1027,2217,2199],{"class":1095},[1027,2219,2202],{"class":1095},[1017,2221,2223],{"className":1273,"code":2222,"filename":2141,"language":1276,"meta":1023,"style":1023},"npm install express cookie-parser mysql2\n",[859,2224,2225],{"__ignoreMap":1023},[1027,2226,2227,2229,2231,2233,2235],{"class":1029,"line":1030},[1027,2228,2141],{"class":1283},[1027,2230,2150],{"class":1095},[1027,2232,2196],{"class":1095},[1027,2234,2199],{"class":1095},[1027,2236,2202],{"class":1095},[1017,2238,2240],{"className":1273,"code":2239,"filename":2156,"language":1276,"meta":1023,"style":1023},"bun add express cookie-parser mysql2\n",[859,2241,2242],{"__ignoreMap":1023},[1027,2243,2244,2246,2248,2250,2252],{"class":1029,"line":1030},[1027,2245,2156],{"class":1283},[1027,2247,2120],{"class":1095},[1027,2249,2196],{"class":1095},[1027,2251,2199],{"class":1095},[1027,2253,2202],{"class":1095},[958,2255],{},[978,2257,2259],{"id":2258},"quick-start-library-mode","Quick start (library mode)",[1263,2261,2262,2266,2293,2921,2925,3190,3194,3200,3292,3303,3307,3316,3328,3338,3341,3370,3373,3411,3423],{"level":1265},[1267,2263,2265],{"id":2264},"configure-the-service","Configure the service",[856,2267,2268,2269,2272,2273,969,2276,969,2279,969,2282,2176,2285,2288,2289,2292],{},"Call ",[859,2270,2271],{},"configuration()"," once at startup. The only required fields are ",[859,2274,2275],{},"store",[859,2277,2278],{},"password",[859,2280,2281],{},"jwt",[859,2283,2284],{},"email",[859,2286,2287],{},"magic_links",". See the full ",[887,2290,2291],{"href":238},"Configuration reference"," for every option.",[1017,2294,2299],{"className":2295,"code":2296,"filename":2297,"language":2298,"meta":1023,"style":1023},"language-ts shiki shiki-themes light-plus light-plus dracula","export const config = {\n  store: {\n    main: { \n      host: 'localhost',\n      user: 'root',\n      password: 'secret',\n      database: 'auth' \n    },\n    rate_limiters_pool: {\n      store: { \n        host: 'localhost',\n        user: 'root',\n        password: 'secret',\n        database: 'auth_limiters' \n      },\n      dbName: 'auth_limiters',\n    },\n  },\n  password: { \n    pepper: process.env.PEPPER! \n  },\n  botDetector: { \n    enableBotDetector: true \n  },\n  htmlSanitizer: { \n    IrritationCount: 50, \n    maxAllowedInputLength: 50000 \n  },\n  magic_links: {\n    jwt_secret_key: process.env.MAGIC_SECRET!,\n    domain: 'https:\u002F\u002Fexample.com',\n    notificationEmail: {\n      privacyPolicyLink: 'https:\u002F\u002Fexample.com\u002Fprivacy',\n      contactPageLink: 'https:\u002F\u002Fexample.com\u002Fcontact',\n      changePasswordPageLink: 'https:\u002F\u002Fexample.com\u002Fsettings\u002Fpassword',\n      loginPageLink: 'https:\u002F\u002Fexample.com\u002Flogin',\n    },\n  },\n  jwt: {\n    jwt_secret_key: process.env.JWT_SECRET!,\n    access_tokens: {},\n    refresh_tokens: {\n      refresh_ttl: 604800000,\n      domain: 'example.com',\n      MAX_SESSION_LIFE: 2592000000,\n      maxAllowedSessionsPerUser: 5,\n      byPassAnomaliesFor: 300000,\n    },\n  },\n  email: { resend_key: process.env.RESEND_KEY!, email: 'no-reply@example.com' },\n}\n","config.ts","ts",[859,2300,2301,2321,2332,2342,2361,2377,2393,2409,2414,2423,2432,2447,2462,2477,2493,2498,2513,2517,2522,2531,2557,2561,2570,2581,2585,2594,2607,2619,2623,2632,2654,2670,2679,2695,2711,2727,2743,2747,2751,2760,2781,2791,2800,2812,2828,2840,2852,2864,2868,2872,2916],{"__ignoreMap":1023},[1027,2302,2303,2307,2311,2315,2318],{"class":1029,"line":1030},[1027,2304,2306],{"class":2305},"sZ328","export",[1027,2308,2310],{"class":2309},"sl46w"," const",[1027,2312,2314],{"class":2313},"s3JHE"," config",[1027,2316,2317],{"class":1037}," =",[1027,2319,2320],{"class":1065}," {\n",[1027,2322,2323,2327,2330],{"class":1029,"line":1041},[1027,2324,2326],{"class":2325},"sjsA6","  store",[1027,2328,1015],{"class":2329},"s34zl",[1027,2331,2320],{"class":1065},[1027,2333,2334,2337,2339],{"class":1029,"line":1053},[1027,2335,2336],{"class":2325},"    main",[1027,2338,1015],{"class":2329},[1027,2340,2341],{"class":1065}," { \n",[1027,2343,2344,2347,2349,2352,2355,2358],{"class":1029,"line":1069},[1027,2345,2346],{"class":2325},"      host",[1027,2348,1015],{"class":2329},[1027,2350,2351],{"class":1091}," '",[1027,2353,2354],{"class":1095},"localhost",[1027,2356,2357],{"class":1091},"'",[1027,2359,2360],{"class":1065},",\n",[1027,2362,2363,2366,2368,2370,2373,2375],{"class":1029,"line":1080},[1027,2364,2365],{"class":2325},"      user",[1027,2367,1015],{"class":2329},[1027,2369,2351],{"class":1091},[1027,2371,2372],{"class":1095},"root",[1027,2374,2357],{"class":1091},[1027,2376,2360],{"class":1065},[1027,2378,2379,2382,2384,2386,2389,2391],{"class":1029,"line":1104},[1027,2380,2381],{"class":2325},"      password",[1027,2383,1015],{"class":2329},[1027,2385,2351],{"class":1091},[1027,2387,2388],{"class":1095},"secret",[1027,2390,2357],{"class":1091},[1027,2392,2360],{"class":1065},[1027,2394,2395,2398,2400,2402,2405,2407],{"class":1029,"line":1115},[1027,2396,2397],{"class":2325},"      database",[1027,2399,1015],{"class":2329},[1027,2401,2351],{"class":1091},[1027,2403,2404],{"class":1095},"auth",[1027,2406,2357],{"class":1091},[1027,2408,1123],{"class":1065},[1027,2410,2411],{"class":1029,"line":1126},[1027,2412,2413],{"class":1065},"    },\n",[1027,2415,2416,2419,2421],{"class":1029,"line":1135},[1027,2417,2418],{"class":2325},"    rate_limiters_pool",[1027,2420,1015],{"class":2329},[1027,2422,2320],{"class":1065},[1027,2424,2425,2428,2430],{"class":1029,"line":1143},[1027,2426,2427],{"class":2325},"      store",[1027,2429,1015],{"class":2329},[1027,2431,2341],{"class":1065},[1027,2433,2434,2437,2439,2441,2443,2445],{"class":1029,"line":1151},[1027,2435,2436],{"class":2325},"        host",[1027,2438,1015],{"class":2329},[1027,2440,2351],{"class":1091},[1027,2442,2354],{"class":1095},[1027,2444,2357],{"class":1091},[1027,2446,2360],{"class":1065},[1027,2448,2449,2452,2454,2456,2458,2460],{"class":1029,"line":1159},[1027,2450,2451],{"class":2325},"        user",[1027,2453,1015],{"class":2329},[1027,2455,2351],{"class":1091},[1027,2457,2372],{"class":1095},[1027,2459,2357],{"class":1091},[1027,2461,2360],{"class":1065},[1027,2463,2464,2467,2469,2471,2473,2475],{"class":1029,"line":1167},[1027,2465,2466],{"class":2325},"        password",[1027,2468,1015],{"class":2329},[1027,2470,2351],{"class":1091},[1027,2472,2388],{"class":1095},[1027,2474,2357],{"class":1091},[1027,2476,2360],{"class":1065},[1027,2478,2479,2482,2484,2486,2489,2491],{"class":1029,"line":1175},[1027,2480,2481],{"class":2325},"        database",[1027,2483,1015],{"class":2329},[1027,2485,2351],{"class":1091},[1027,2487,2488],{"class":1095},"auth_limiters",[1027,2490,2357],{"class":1091},[1027,2492,1123],{"class":1065},[1027,2494,2495],{"class":1029,"line":1183},[1027,2496,2497],{"class":1065},"      },\n",[1027,2499,2500,2503,2505,2507,2509,2511],{"class":1029,"line":1195},[1027,2501,2502],{"class":2325},"      dbName",[1027,2504,1015],{"class":2329},[1027,2506,2351],{"class":1091},[1027,2508,2488],{"class":1095},[1027,2510,2357],{"class":1091},[1027,2512,2360],{"class":1065},[1027,2514,2515],{"class":1029,"line":1203},[1027,2516,2413],{"class":1065},[1027,2518,2519],{"class":1029,"line":1217},[1027,2520,2521],{"class":1065},"  },\n",[1027,2523,2524,2527,2529],{"class":1029,"line":1225},[1027,2525,2526],{"class":2325},"  password",[1027,2528,1015],{"class":2329},[1027,2530,2341],{"class":1065},[1027,2532,2533,2536,2538,2541,2543,2546,2548,2552,2555],{"class":1029,"line":1237},[1027,2534,2535],{"class":2325},"    pepper",[1027,2537,1015],{"class":2329},[1027,2539,2540],{"class":2325}," process",[1027,2542,1008],{"class":1065},[1027,2544,2545],{"class":2325},"env",[1027,2547,1008],{"class":1065},[1027,2549,2551],{"class":2550},"sPzPf","PEPPER",[1027,2553,2554],{"class":1037},"!",[1027,2556,1123],{"class":1065},[1027,2558,2559],{"class":1029,"line":1245},[1027,2560,2521],{"class":1065},[1027,2562,2563,2566,2568],{"class":1029,"line":1253},[1027,2564,2565],{"class":2325},"  botDetector",[1027,2567,1015],{"class":2329},[1027,2569,2341],{"class":1065},[1027,2571,2572,2575,2577,2579],{"class":1029,"line":1638},[1027,2573,2574],{"class":2325},"    enableBotDetector",[1027,2576,1015],{"class":2329},[1027,2578,1062],{"class":1061},[1027,2580,1123],{"class":1065},[1027,2582,2583],{"class":1029,"line":1644},[1027,2584,2521],{"class":1065},[1027,2586,2587,2590,2592],{"class":1029,"line":1651},[1027,2588,2589],{"class":2325},"  htmlSanitizer",[1027,2591,1015],{"class":2329},[1027,2593,2341],{"class":1065},[1027,2595,2596,2599,2601,2604],{"class":1029,"line":1660},[1027,2597,2598],{"class":2325},"    IrritationCount",[1027,2600,1015],{"class":2329},[1027,2602,2603],{"class":1191}," 50",[1027,2605,2606],{"class":1065},", \n",[1027,2608,2609,2612,2614,2617],{"class":1029,"line":1671},[1027,2610,2611],{"class":2325},"    maxAllowedInputLength",[1027,2613,1015],{"class":2329},[1027,2615,2616],{"class":1191}," 50000",[1027,2618,1123],{"class":1065},[1027,2620,2621],{"class":1029,"line":1680},[1027,2622,2521],{"class":1065},[1027,2624,2625,2628,2630],{"class":1029,"line":1697},[1027,2626,2627],{"class":2325},"  magic_links",[1027,2629,1015],{"class":2329},[1027,2631,2320],{"class":1065},[1027,2633,2634,2637,2639,2641,2643,2645,2647,2650,2652],{"class":1029,"line":1706},[1027,2635,2636],{"class":2325},"    jwt_secret_key",[1027,2638,1015],{"class":2329},[1027,2640,2540],{"class":2325},[1027,2642,1008],{"class":1065},[1027,2644,2545],{"class":2325},[1027,2646,1008],{"class":1065},[1027,2648,2649],{"class":2550},"MAGIC_SECRET",[1027,2651,2554],{"class":1037},[1027,2653,2360],{"class":1065},[1027,2655,2656,2659,2661,2663,2666,2668],{"class":1029,"line":1715},[1027,2657,2658],{"class":2325},"    domain",[1027,2660,1015],{"class":2329},[1027,2662,2351],{"class":1091},[1027,2664,2665],{"class":1095},"https:\u002F\u002Fexample.com",[1027,2667,2357],{"class":1091},[1027,2669,2360],{"class":1065},[1027,2671,2672,2675,2677],{"class":1029,"line":1722},[1027,2673,2674],{"class":2325},"    notificationEmail",[1027,2676,1015],{"class":2329},[1027,2678,2320],{"class":1065},[1027,2680,2681,2684,2686,2688,2691,2693],{"class":1029,"line":1729},[1027,2682,2683],{"class":2325},"      privacyPolicyLink",[1027,2685,1015],{"class":2329},[1027,2687,2351],{"class":1091},[1027,2689,2690],{"class":1095},"https:\u002F\u002Fexample.com\u002Fprivacy",[1027,2692,2357],{"class":1091},[1027,2694,2360],{"class":1065},[1027,2696,2697,2700,2702,2704,2707,2709],{"class":1029,"line":1736},[1027,2698,2699],{"class":2325},"      contactPageLink",[1027,2701,1015],{"class":2329},[1027,2703,2351],{"class":1091},[1027,2705,2706],{"class":1095},"https:\u002F\u002Fexample.com\u002Fcontact",[1027,2708,2357],{"class":1091},[1027,2710,2360],{"class":1065},[1027,2712,2713,2716,2718,2720,2723,2725],{"class":1029,"line":1743},[1027,2714,2715],{"class":2325},"      changePasswordPageLink",[1027,2717,1015],{"class":2329},[1027,2719,2351],{"class":1091},[1027,2721,2722],{"class":1095},"https:\u002F\u002Fexample.com\u002Fsettings\u002Fpassword",[1027,2724,2357],{"class":1091},[1027,2726,2360],{"class":1065},[1027,2728,2729,2732,2734,2736,2739,2741],{"class":1029,"line":1750},[1027,2730,2731],{"class":2325},"      loginPageLink",[1027,2733,1015],{"class":2329},[1027,2735,2351],{"class":1091},[1027,2737,2738],{"class":1095},"https:\u002F\u002Fexample.com\u002Flogin",[1027,2740,2357],{"class":1091},[1027,2742,2360],{"class":1065},[1027,2744,2745],{"class":1029,"line":1757},[1027,2746,2413],{"class":1065},[1027,2748,2749],{"class":1029,"line":1766},[1027,2750,2521],{"class":1065},[1027,2752,2753,2756,2758],{"class":1029,"line":1773},[1027,2754,2755],{"class":2325},"  jwt",[1027,2757,1015],{"class":2329},[1027,2759,2320],{"class":1065},[1027,2761,2762,2764,2766,2768,2770,2772,2774,2777,2779],{"class":1029,"line":1784},[1027,2763,2636],{"class":2325},[1027,2765,1015],{"class":2329},[1027,2767,2540],{"class":2325},[1027,2769,1008],{"class":1065},[1027,2771,2545],{"class":2325},[1027,2773,1008],{"class":1065},[1027,2775,2776],{"class":2550},"JWT_SECRET",[1027,2778,2554],{"class":1037},[1027,2780,2360],{"class":1065},[1027,2782,2783,2786,2788],{"class":1029,"line":1792},[1027,2784,2785],{"class":2325},"    access_tokens",[1027,2787,1015],{"class":2329},[1027,2789,2790],{"class":1065}," {},\n",[1027,2792,2793,2796,2798],{"class":1029,"line":1800},[1027,2794,2795],{"class":2325},"    refresh_tokens",[1027,2797,1015],{"class":2329},[1027,2799,2320],{"class":1065},[1027,2801,2802,2805,2807,2810],{"class":1029,"line":1808},[1027,2803,2804],{"class":2325},"      refresh_ttl",[1027,2806,1015],{"class":2329},[1027,2808,2809],{"class":1191}," 604800000",[1027,2811,2360],{"class":1065},[1027,2813,2814,2817,2819,2821,2824,2826],{"class":1029,"line":1815},[1027,2815,2816],{"class":2325},"      domain",[1027,2818,1015],{"class":2329},[1027,2820,2351],{"class":1091},[1027,2822,2823],{"class":1095},"example.com",[1027,2825,2357],{"class":1091},[1027,2827,2360],{"class":1065},[1027,2829,2830,2833,2835,2838],{"class":1029,"line":1826},[1027,2831,2832],{"class":2325},"      MAX_SESSION_LIFE",[1027,2834,1015],{"class":2329},[1027,2836,2837],{"class":1191}," 2592000000",[1027,2839,2360],{"class":1065},[1027,2841,2842,2845,2847,2850],{"class":1029,"line":1833},[1027,2843,2844],{"class":2325},"      maxAllowedSessionsPerUser",[1027,2846,1015],{"class":2329},[1027,2848,2849],{"class":1191}," 5",[1027,2851,2360],{"class":1065},[1027,2853,2854,2857,2859,2862],{"class":1029,"line":1840},[1027,2855,2856],{"class":2325},"      byPassAnomaliesFor",[1027,2858,1015],{"class":2329},[1027,2860,2861],{"class":1191}," 300000",[1027,2863,2360],{"class":1065},[1027,2865,2866],{"class":1029,"line":1849},[1027,2867,2413],{"class":1065},[1027,2869,2870],{"class":1029,"line":1854},[1027,2871,2521],{"class":1065},[1027,2873,2874,2877,2879,2882,2885,2887,2889,2891,2893,2895,2898,2900,2902,2904,2906,2908,2911,2913],{"class":1029,"line":1862},[1027,2875,2876],{"class":2325},"  email",[1027,2878,1015],{"class":2329},[1027,2880,2881],{"class":1065}," { ",[1027,2883,2884],{"class":2325},"resend_key",[1027,2886,1015],{"class":2329},[1027,2888,2540],{"class":2325},[1027,2890,1008],{"class":1065},[1027,2892,2545],{"class":2325},[1027,2894,1008],{"class":1065},[1027,2896,2897],{"class":2550},"RESEND_KEY",[1027,2899,2554],{"class":1037},[1027,2901,969],{"class":1065},[1027,2903,2284],{"class":2325},[1027,2905,1015],{"class":2329},[1027,2907,2351],{"class":1091},[1027,2909,2910],{"class":1095},"no-reply@example.com",[1027,2912,2357],{"class":1091},[1027,2914,2915],{"class":1065}," },\n",[1027,2917,2918],{"class":1029,"line":1872},[1027,2919,2920],{"class":1065},"}\n",[1267,2922,2924],{"id":2923},"mount-the-routes","Mount the routes",[1017,2926,2929],{"className":2295,"code":2927,"filename":2928,"language":2298,"meta":1023,"style":1023},"import express from 'express'\nimport cookieParser from 'cookie-parser'\nimport {\n  authenticationRoutes,\n  magicLinks,\n  tokenRotationRoutes,\n  bffAccessRoute,\n} from '@riavzon\u002Fauth'\nimport { configuration } from '@riavzon\u002Fauth'\nimport { config } from '.\u002Fconfig.js';\n\nconst app = express()\napp.use(cookieParser())\n\nawait configuration(config)\napp.use(authenticationRoutes)\napp.use(tokenRotationRoutes)\napp.use(magicLinks)\napp.use(bffAccessRoute)\n\napp.listen(10000)\n","server.ts",[859,2930,2931,2948,2963,2969,2976,2983,2990,2997,3011,3030,3053,3057,3072,3091,3095,3110,3125,3140,3155,3170,3174],{"__ignoreMap":1023},[1027,2932,2933,2936,2938,2941,2943,2945],{"class":1029,"line":1030},[1027,2934,2935],{"class":2305},"import",[1027,2937,2196],{"class":2325},[1027,2939,2940],{"class":2305}," from",[1027,2942,2351],{"class":1091},[1027,2944,2172],{"class":1095},[1027,2946,2947],{"class":1091},"'\n",[1027,2949,2950,2952,2955,2957,2959,2961],{"class":1029,"line":1041},[1027,2951,2935],{"class":2305},[1027,2953,2954],{"class":2325}," cookieParser",[1027,2956,2940],{"class":2305},[1027,2958,2351],{"class":1091},[1027,2960,2175],{"class":1095},[1027,2962,2947],{"class":1091},[1027,2964,2965,2967],{"class":1029,"line":1053},[1027,2966,2935],{"class":2305},[1027,2968,2320],{"class":1065},[1027,2970,2971,2974],{"class":1029,"line":1069},[1027,2972,2973],{"class":2325},"  authenticationRoutes",[1027,2975,2360],{"class":1065},[1027,2977,2978,2981],{"class":1029,"line":1080},[1027,2979,2980],{"class":2325},"  magicLinks",[1027,2982,2360],{"class":1065},[1027,2984,2985,2988],{"class":1029,"line":1104},[1027,2986,2987],{"class":2325},"  tokenRotationRoutes",[1027,2989,2360],{"class":1065},[1027,2991,2992,2995],{"class":1029,"line":1115},[1027,2993,2994],{"class":2325},"  bffAccessRoute",[1027,2996,2360],{"class":1065},[1027,2998,2999,3002,3005,3007,3009],{"class":1029,"line":1126},[1027,3000,3001],{"class":1065},"} ",[1027,3003,3004],{"class":2305},"from",[1027,3006,2351],{"class":1091},[1027,3008,861],{"class":1095},[1027,3010,2947],{"class":1091},[1027,3012,3013,3015,3017,3019,3022,3024,3026,3028],{"class":1029,"line":1135},[1027,3014,2935],{"class":2305},[1027,3016,2881],{"class":1065},[1027,3018,1345],{"class":2325},[1027,3020,3021],{"class":1065}," } ",[1027,3023,3004],{"class":2305},[1027,3025,2351],{"class":1091},[1027,3027,861],{"class":1095},[1027,3029,2947],{"class":1091},[1027,3031,3032,3034,3036,3039,3041,3043,3045,3048,3050],{"class":1029,"line":1143},[1027,3033,2935],{"class":2305},[1027,3035,2881],{"class":1065},[1027,3037,3038],{"class":2325},"config",[1027,3040,3021],{"class":1065},[1027,3042,3004],{"class":2305},[1027,3044,2351],{"class":1091},[1027,3046,3047],{"class":1095},".\u002Fconfig.js",[1027,3049,2357],{"class":1091},[1027,3051,3052],{"class":1065},";\n",[1027,3054,3055],{"class":1029,"line":1151},[1027,3056,1641],{"emptyLinePlaceholder":8},[1027,3058,3059,3062,3065,3067,3069],{"class":1029,"line":1159},[1027,3060,3061],{"class":2309},"const",[1027,3063,3064],{"class":2313}," app",[1027,3066,2317],{"class":1037},[1027,3068,2196],{"class":1283},[1027,3070,3071],{"class":1065},"()\n",[1027,3073,3074,3077,3079,3082,3085,3088],{"class":1029,"line":1167},[1027,3075,3076],{"class":2325},"app",[1027,3078,1008],{"class":1065},[1027,3080,3081],{"class":1283},"use",[1027,3083,3084],{"class":1065},"(",[1027,3086,3087],{"class":1283},"cookieParser",[1027,3089,3090],{"class":1065},"())\n",[1027,3092,3093],{"class":1029,"line":1175},[1027,3094,1641],{"emptyLinePlaceholder":8},[1027,3096,3097,3100,3103,3105,3107],{"class":1029,"line":1183},[1027,3098,3099],{"class":2305},"await",[1027,3101,3102],{"class":1283}," configuration",[1027,3104,3084],{"class":1065},[1027,3106,3038],{"class":2325},[1027,3108,3109],{"class":1065},")\n",[1027,3111,3112,3114,3116,3118,3120,3123],{"class":1029,"line":1195},[1027,3113,3076],{"class":2325},[1027,3115,1008],{"class":1065},[1027,3117,3081],{"class":1283},[1027,3119,3084],{"class":1065},[1027,3121,3122],{"class":2325},"authenticationRoutes",[1027,3124,3109],{"class":1065},[1027,3126,3127,3129,3131,3133,3135,3138],{"class":1029,"line":1203},[1027,3128,3076],{"class":2325},[1027,3130,1008],{"class":1065},[1027,3132,3081],{"class":1283},[1027,3134,3084],{"class":1065},[1027,3136,3137],{"class":2325},"tokenRotationRoutes",[1027,3139,3109],{"class":1065},[1027,3141,3142,3144,3146,3148,3150,3153],{"class":1029,"line":1217},[1027,3143,3076],{"class":2325},[1027,3145,1008],{"class":1065},[1027,3147,3081],{"class":1283},[1027,3149,3084],{"class":1065},[1027,3151,3152],{"class":2325},"magicLinks",[1027,3154,3109],{"class":1065},[1027,3156,3157,3159,3161,3163,3165,3168],{"class":1029,"line":1225},[1027,3158,3076],{"class":2325},[1027,3160,1008],{"class":1065},[1027,3162,3081],{"class":1283},[1027,3164,3084],{"class":1065},[1027,3166,3167],{"class":2325},"bffAccessRoute",[1027,3169,3109],{"class":1065},[1027,3171,3172],{"class":1029,"line":1237},[1027,3173,1641],{"emptyLinePlaceholder":8},[1027,3175,3176,3178,3180,3183,3185,3188],{"class":1029,"line":1245},[1027,3177,3076],{"class":2325},[1027,3179,1008],{"class":1065},[1027,3181,3182],{"class":1283},"listen",[1027,3184,3084],{"class":1065},[1027,3186,3187],{"class":1191},"10000",[1027,3189,3109],{"class":1065},[1267,3191,3193],{"id":3192},"compile-the-bot-detector-data-sources","Compile the Bot Detector data sources",[856,3195,3196,3197,3199],{},"The auth service depends on ",[887,3198,399],{"href":35}," for IP analysis, threat scoring, and bot detection. Download and compile all required data sources before starting the service:",[2106,3201,3202,3227,3248,3270],{},[1017,3203,3205],{"className":1273,"code":3204,"filename":2111,"language":1276,"meta":1023,"style":1023},"pnpm bot-detector init --contact=\"you@example.com\"\n",[859,3206,3207],{"__ignoreMap":1023},[1027,3208,3209,3211,3214,3217,3220,3222,3225],{"class":1029,"line":1030},[1027,3210,2111],{"class":1283},[1027,3212,3213],{"class":1095}," bot-detector",[1027,3215,3216],{"class":1095}," init",[1027,3218,3219],{"class":1061}," --contact=",[1027,3221,1092],{"class":1091},[1027,3223,3224],{"class":1095},"you@example.com",[1027,3226,1214],{"class":1091},[1017,3228,3230],{"className":1273,"code":3229,"filename":2127,"language":1276,"meta":1023,"style":1023},"yarn bot-detector init --contact=\"you@example.com\"\n",[859,3231,3232],{"__ignoreMap":1023},[1027,3233,3234,3236,3238,3240,3242,3244,3246],{"class":1029,"line":1030},[1027,3235,2127],{"class":1283},[1027,3237,3213],{"class":1095},[1027,3239,3216],{"class":1095},[1027,3241,3219],{"class":1061},[1027,3243,1092],{"class":1091},[1027,3245,3224],{"class":1095},[1027,3247,1214],{"class":1091},[1017,3249,3251],{"className":1273,"code":3250,"filename":2141,"language":1276,"meta":1023,"style":1023},"npx bot-detector init --contact=\"you@example.com\"\n",[859,3252,3253],{"__ignoreMap":1023},[1027,3254,3255,3258,3260,3262,3264,3266,3268],{"class":1029,"line":1030},[1027,3256,3257],{"class":1283},"npx",[1027,3259,3213],{"class":1095},[1027,3261,3216],{"class":1095},[1027,3263,3219],{"class":1061},[1027,3265,1092],{"class":1091},[1027,3267,3224],{"class":1095},[1027,3269,1214],{"class":1091},[1017,3271,3273],{"className":1273,"code":3272,"filename":2156,"language":1276,"meta":1023,"style":1023},"bunx bot-detector init --contact=\"you@example.com\"\n",[859,3274,3275],{"__ignoreMap":1023},[1027,3276,3277,3280,3282,3284,3286,3288,3290],{"class":1029,"line":1030},[1027,3278,3279],{"class":1283},"bunx",[1027,3281,3213],{"class":1095},[1027,3283,3216],{"class":1095},[1027,3285,3219],{"class":1061},[1027,3287,1092],{"class":1091},[1027,3289,3224],{"class":1095},[1027,3291,1214],{"class":1091},[856,3293,3294,3295,3298,3299,3302],{},"The ",[859,3296,3297],{},"--contact"," flag provides a User-Agent string for BGP data downloads. This step compiles MMDB and LMDB databases for geolocation, ASN, proxy detection, threat lists, and more. See the ",[887,3300,3301],{"href":35},"Bot Detector documentation"," for the full list of data sources.",[1267,3304,3306],{"id":3305},"create-the-database-tables","Create the database tables",[856,3308,3309,3310,3312,3313,3315],{},"Run the ",[859,3311,2404],{}," CLI to compile the disposable email database and create the required database tables. Pass the path to your ",[859,3314,991],{}," as an argument:",[1017,3317,3319],{"className":1273,"code":3318,"filename":1275,"language":1276,"meta":1023,"style":1023},"auth .\u002Fconfig.json\n",[859,3320,3321],{"__ignoreMap":1023},[1027,3322,3323,3325],{"class":1029,"line":1030},[1027,3324,2404],{"class":1283},[1027,3326,3327],{"class":1095}," .\u002Fconfig.json\n",[856,3329,3330,3331,3334,3335,1008],{},"The CLI accepts the config path as a positional argument, or reads it from the ",[859,3332,3333],{},"CONFIG_PATH"," environment variable. If neither is provided, it defaults to ",[859,3336,3337],{},".\u002Fconfig.json",[856,3339,3340],{},"This command runs three tasks sequentially:",[3342,3343,3344,3354,3367],"ol",{},[878,3345,3346,3347,3350,3351,1008],{},"Downloads and compiles the ",[887,3348,3349],{"href":611},"disposable email domain blocklist"," into an LMDB database at ",[859,3352,3353],{},"dist\u002Femail-db\u002Fdisposable-emails.mdb",[878,3355,3356,3357,969,3360,969,3363,3366],{},"Creates all required auth MySQL tables (",[859,3358,3359],{},"users",[859,3361,3362],{},"refresh_tokens",[859,3364,3365],{},"mfa_codes",", etc.).",[878,3368,3369],{},"Creates the Bot Detector tables used for IP analysis and threat scoring.",[856,3371,3372],{},"You can also call it in your code:",[1017,3374,3377],{"className":2295,"code":3375,"filename":3376,"language":2298,"meta":1023,"style":1023},"import { initAuthData } from '@riavzon\u002Fauth'\nawait initAuthData(config)\n","main.ts",[859,3378,3379,3398],{"__ignoreMap":1023},[1027,3380,3381,3383,3385,3388,3390,3392,3394,3396],{"class":1029,"line":1030},[1027,3382,2935],{"class":2305},[1027,3384,2881],{"class":1065},[1027,3386,3387],{"class":2325},"initAuthData",[1027,3389,3021],{"class":1065},[1027,3391,3004],{"class":2305},[1027,3393,2351],{"class":1091},[1027,3395,861],{"class":1095},[1027,3397,2947],{"class":1091},[1027,3399,3400,3402,3405,3407,3409],{"class":1029,"line":1041},[1027,3401,3099],{"class":2305},[1027,3403,3404],{"class":1283}," initAuthData",[1027,3406,3084],{"class":1065},[1027,3408,3038],{"class":2325},[1027,3410,3109],{"class":1065},[947,3412,3414],{"color":949,"icon":3413},"i-lucide-info",[856,3415,3294,3416,3418,3419,3422],{},[859,3417,2404],{}," binary is available after installing the package. If running locally without a global install, use ",[859,3420,3421],{},"npx @riavzon\u002Fauth .\u002Fconfig.json"," instead.",[1325,3424,3425],{},[856,3426,2268,3427,3429],{},[859,3428,2271],{}," before mounting any routes or using any exported function. The entire module reads the resolved config at runtime; calling an export before configuration throws immediately.",[958,3431],{},[978,3433,3435,3436],{"id":3434},"using-bootstrapapp","Using ",[859,3437,3438],{},"bootstrapApp",[856,3440,3441,3442,3444],{},"For the fastest path, the module exports ",[859,3443,3438],{},", which wires up the\nfull middleware chain (Helmet, IP validation, the public API verification\nroute, HMAC, cookie parser, Bot Detector, the authenticated routers, and error\nhandling) in the correct order and returns a ready-to-use Express app:",[1017,3446,3448],{"className":2295,"code":3447,"filename":2928,"language":2298,"meta":1023,"style":1023},"import { bootstrapApp } from '@riavzon\u002Fauth\u002Fservice'\n\nconst app = await bootstrapApp(config)\napp.listen(10000, '0.0.0.0')\n",[859,3449,3450,3469,3473,3493],{"__ignoreMap":1023},[1027,3451,3452,3454,3456,3458,3460,3462,3464,3467],{"class":1029,"line":1030},[1027,3453,2935],{"class":2305},[1027,3455,2881],{"class":1065},[1027,3457,3438],{"class":2325},[1027,3459,3021],{"class":1065},[1027,3461,3004],{"class":2305},[1027,3463,2351],{"class":1091},[1027,3465,3466],{"class":1095},"@riavzon\u002Fauth\u002Fservice",[1027,3468,2947],{"class":1091},[1027,3470,3471],{"class":1029,"line":1041},[1027,3472,1641],{"emptyLinePlaceholder":8},[1027,3474,3475,3477,3479,3481,3484,3487,3489,3491],{"class":1029,"line":1053},[1027,3476,3061],{"class":2309},[1027,3478,3064],{"class":2313},[1027,3480,2317],{"class":1037},[1027,3482,3483],{"class":2305}," await",[1027,3485,3486],{"class":1283}," bootstrapApp",[1027,3488,3084],{"class":1065},[1027,3490,3038],{"class":2325},[1027,3492,3109],{"class":1065},[1027,3494,3495,3497,3499,3501,3503,3505,3507,3509,3512,3514],{"class":1029,"line":1069},[1027,3496,3076],{"class":2325},[1027,3498,1008],{"class":1065},[1027,3500,3182],{"class":1283},[1027,3502,3084],{"class":1065},[1027,3504,3187],{"class":1191},[1027,3506,969],{"class":1065},[1027,3508,2357],{"class":1091},[1027,3510,3511],{"class":1095},"0.0.0.0",[1027,3513,2357],{"class":1091},[1027,3515,3109],{"class":1065},[856,3517,3518,3519,3521],{},"The middleware chain ",[859,3520,3438],{}," applies:",[3342,3523,3524,3529,3532,3535,3538,3544,3547,3550,3553,3560,3563,3568,3572,3579,3582,3585,3588,3591,3594,3597,3600,3603],{},[878,3525,3526,3527,2055],{},"Health check endpoint (",[859,3528,2094],{},[878,3530,3531],{},"Bot Detector configuration and table creation",[878,3533,3534],{},"Auth table creation",[878,3536,3537],{},"HTTP logger (Pino)",[878,3539,3540,3541],{},"Disable ",[859,3542,3543],{},"x-powered-by",[878,3545,3546],{},"Helmet security headers",[878,3548,3549],{},"Service headers",[878,3551,3552],{},"IP validation",[878,3554,3555,3556,3559],{},"HMAC authentication (when ",[859,3557,3558],{},"service.Hmac"," is configured)",[878,3561,3562],{},"Public API token verification route",[878,3564,3565],{},[859,3566,3567],{},"express.json()",[878,3569,3570],{},[859,3571,2175],{},[878,3573,3574,3575,3578],{},"Bot Detector ",[859,3576,3577],{},"ApiResponse"," middleware",[878,3580,3581],{},"Authentication routes",[878,3583,3584],{},"Token rotation routes",[878,3586,3587],{},"Magic link routes",[878,3589,3590],{},"BFF access route",[878,3592,3593],{},"API token management routes",[878,3595,3596],{},"Operational config route",[878,3598,3599],{},"Bot Detector warm-up",[878,3601,3602],{},"404 handler",[878,3604,3605],{},"Global error handler",[1393,3607,3608],{},[856,3609,3610],{},"In library mode, you do not have to register any particular route. You can use the exported methods directly to compose your own flows.",[958,3612],{},[864,3614,3616],{"id":3615},"environment-variables","Environment variables",[856,3618,3619],{},"The standalone service reads the configuration from a JSON file. Override the path with:",[2004,3621,3622,3635],{},[2007,3623,3624],{},[2010,3625,3626,3629,3632],{},[2013,3627,3628],{},"Variable",[2013,3630,3631],{},"Default",[2013,3633,3634],{},"Description",[2020,3636,3637,3650,3669],{},[2010,3638,3639,3643,3647],{},[2025,3640,3641],{},[859,3642,3333],{},[2025,3644,3645],{},[859,3646,1014],{},[2025,3648,3649],{},"Path to the JSON configuration file",[2010,3651,3652,3657,3662],{},[2025,3653,3654],{},[859,3655,3656],{},"SKIP_CONFIG_UNLINK",[2025,3658,3659],{},[859,3660,3661],{},"false",[2025,3663,3664,3665,3668],{},"Set to ",[859,3666,3667],{},"true"," to keep the config file in the container after loading",[2010,3670,3671,3676,3679],{},[2025,3672,3673],{},[859,3674,3675],{},"NODE_ENV",[2025,3677,3678],{},"-",[2025,3680,3664,3681,3684],{},[859,3682,3683],{},"production"," in the Docker image",[3686,3687,3688],"style",{},"html pre.shiki code .sHOzp, html code.shiki .sHOzp{--shiki-light:#795E26;--shiki-default:#795E26;--shiki-dark:#50FA7B}html pre.shiki code .sjR7W, html code.shiki .sjR7W{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#BD93F9}html pre.shiki code .sFB1V, html code.shiki .sFB1V{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#F1FA8C}html pre.shiki code .sDd4n, html code.shiki .sDd4n{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#F8F8F2}html pre.shiki code .saOXh, html code.shiki .saOXh{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#FF79C6}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 .sFkSl, html code.shiki .sFkSl{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#E9F284}html pre.shiki code .sZ328, html code.shiki .sZ328{--shiki-light:#AF00DB;--shiki-default:#AF00DB;--shiki-dark:#FF79C6}html pre.shiki code .sl46w, html code.shiki .sl46w{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#FF79C6}html pre.shiki code .s3JHE, html code.shiki .s3JHE{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#F8F8F2}html pre.shiki code .sjsA6, html code.shiki .sjsA6{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#F8F8F2}html pre.shiki code .s34zl, html code.shiki .s34zl{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#FF79C6}html pre.shiki code .sPzPf, html code.shiki .sPzPf{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#BD93F9}html pre.shiki code .spgvN, html code.shiki .spgvN{--shiki-light:#098658;--shiki-default:#098658;--shiki-dark:#BD93F9}html pre.shiki code .sXrRR, html code.shiki .sXrRR{--shiki-light:#800000;--shiki-default:#800000;--shiki-dark:#8BE9FD}html pre.shiki code .sKKzR, html code.shiki .sKKzR{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#F1FA8C}",{"title":1023,"searchDepth":1041,"depth":1041,"links":3690},[3691,3692,3696,3701],{"id":866,"depth":1041,"text":867},{"id":962,"depth":1041,"text":963,"children":3693},[3694,3695],{"id":980,"depth":1053,"text":981},{"id":1998,"depth":1053,"text":1999},{"id":2100,"depth":1041,"text":2101,"children":3697},[3698,3699],{"id":2258,"depth":1053,"text":2259},{"id":3434,"depth":1053,"text":3700},"Using bootstrapApp",{"id":3615,"depth":1041,"text":3616},"Prerequisites, installation, Docker deployment, and first run of the IAM service.","md",{},null,"---\ntitle: Getting Started\ndescription: Prerequisites, installation, Docker deployment, and first run of the IAM service.\nicon: i-lucide-rocket\n---\n\n`@riavzon\u002Fauth` runs as a standalone Express 5 service backed by MySQL. You can use it as a library in your own application, or run the production-ready Docker image that ships with secrets encrypted at rest.\n\n## Requirements\n\nDepending on how you plan to use the service, your environment needs to meet the following:\n\nDocker with encryption:\n  - **Node.js 20 or later**\n  - [**age**](https:\u002F\u002Fgithub.com\u002FFiloSottile\u002Fage)\n  - [**Docker**](https:\u002F\u002Fdocs.docker.com)\n\nDocker without encryption:\n  - **Node.js 20 or later**\n  - [**Docker**](https:\u002F\u002Fdocs.docker.com)\n\nLocal\u002FLibrary:\n- **Node.js 20 or later**\n- **MySQL 8+**\n- [**`mmdbctl`**](https:\u002F\u002Fgithub.com\u002Fipinfo\u002Fmmdbctl) binary for MMDB compilation (installed automatically during build)\n\n::callout{icon=\"i-lucide-container\" color=\"info\"}\nThe recommended deployment path is the hardened Docker image. It handles all dependencies, database initialization, `mmdbctl` installations, and data-source compilation automatically.\n::\n\n---\n\n## Docker deployment\n\nThe IAM service ships as a public Docker image. The image uses a multi-stage build: it installs all required binaries (`age`, `mmdbctl`), dependencies, compiles all Shield Base and Bot Detector data sources, bundles the service, then produces a minimal image with `read_only` filesystem support.\n\n### Secrets at rest\n\nThe Docker image uses [age](https:\u002F\u002Fgithub.com\u002FFiloSottile\u002Fage) to encrypt and decrypt your configuration file (`config.json`).\nEncrypt your config locally with `age`, and the image decrypts it at startup using the `decrypt.sh` entrypoint script. The service deletes the decrypted file automatically after loading it.\n\nYou can provide the age key and encrypted config as [Docker secrets](https:\u002F\u002Fdocs.docker.com\u002Fcompose\u002Fhow-tos\u002Fuse-secrets\u002F).\n\nIf you don't want to deal with encryption, mount your config file directly at `\u002Frun\u002Fapp\u002Fconfig.json`:\n\n```yaml [docker-compose.yml]\n  auth:\n    image: sergio68\u002Fauth\n    read_only: true  \n    restart: unless-stopped\n    cap_drop: [\"ALL\"]\n    user: 10001:10001\n    volumes: \n      - .\u002Fauth-logs\u002Fserver:\u002Fapp\u002Fauth-logs:rw\n      - .\u002Fauth-logs\u002Fserver\u002Fbot-detector:\u002Fapp\u002Fbot-detector-logs:rw\n      - .\u002Fconfig.json:\u002Frun\u002Fapp\u002Fconfig.json\n      - bot-detector-data:\u002Fapp\u002Fnode_modules\u002F@riavzon\u002Fbot-detector\u002Fdist\u002F_data-sources:rw\n      - email-data:\u002Fapp\u002Fdist\u002Femail-db:rw\n    tmpfs:\n      - \u002Frun\u002Fapp:rw,noexec,nosuid,nodev,uid=10001,gid=10001,size=1m\n    pids_limit: 200\n    ports:\n      - \"10000:10000\"\n    security_opt:\n      - \"no-new-privileges:true\"\n    depends_on:\n      mysql:\n        condition: service_healthy\n\n```\n\n::steps{level=\"4\"}\n\n#### Generate an age key pair\n\n```bash [Terminal]\nage-keygen -o age_key && age-keygen -y age_key > public_key\n```\nThis will generate 2 files:\n\n- `age_key` is the private key. Store it securely.\n- `public_key` is the public key.\n\n::warning\n  Never commit `age_key` to version control\n::\n\n#### Encrypt your configuration\n\nCreate your `config.json` with the full [configuration](\u002Fdocs\u002Fiam\u002Fconfiguration) object, then encrypt it:\n\n```bash [Terminal]\nage -a -e -r \"$(cat public_key)\" -o config.json.age config.json\n```\n\n`config.json.age` is your encrypted config. Only the matching private key can decrypt this file.\n\n::tip\n  In production, consider deleting `config.json` from the local host and storing `age_key` in an appropriate secret manager.\n::\n\n#### Create a `docker-compose.yml`\n\n```yaml [docker-compose.yml]\nservices:\n  mysql: \n    restart: unless-stopped\n    environment:\n      MYSQL_ROOT_PASSWORD: secure_password\n      MYSQL_DATABASE: auth_db\n      MYSQL_USER: auth_user\n      MYSQL_PASSWORD: secure_password\n    cap_drop: [\"ALL\"]\n    user: \"999:999\"\n    security_opt: \n      - \"no-new-privileges:true\"\n    volumes:\n      - sql_db:\u002Fvar\u002Flib\u002Fmysql\n    healthcheck:\n      test: [\"CMD-SHELL\", \"bash -lc 'exec 3\u003C>\u002Fdev\u002Ftcp\u002F127.0.0.1\u002F3306'\"]\n      interval: 10s\n      timeout: 8s \n      retries: 5\n      start_period: 7m\n    tmpfs:\n      - \u002Fvar\u002Flib\u002Fmysql:rw,noexec,nosuid,nodev,size=512m  \n\n  auth:\n    image: sergio68\u002Fauth\n    read_only: true  \n    restart: unless-stopped\n    cap_drop: [\"ALL\"]\n    user: 10001:10001\n    volumes: \n      - .\u002Fauth-logs\u002Fserver:\u002Fapp\u002Fauth-logs:rw\n      - .\u002Fauth-logs\u002Fserver\u002Fbot-detector:\u002Fapp\u002Fbot-detector-logs:rw\n      - bot-detector-data:\u002Fapp\u002Fnode_modules\u002F@riavzon\u002Fbot-detector\u002Fdist\u002F_data-sources:rw\n      - email-data:\u002Fapp\u002Fdist\u002Femail-db:rw\n    tmpfs:\n      - \u002Frun\u002Fapp:rw,noexec,nosuid,nodev,uid=10001,gid=10001,size=1m\n    pids_limit: 200\n    ports:\n      - \"10000:10000\"\n    secrets:\n      - age_key\n      - encrypted_config\n    security_opt:\n      - \"no-new-privileges:true\"\n    depends_on:\n      mysql:\n        condition: service_healthy\n\nvolumes:\n  sql_db:  \n  bot-detector-data:\n  email-data:\n\nsecrets:\n  age_key:\n    file: .\u002Fage_key\n  encrypted_config:\n    file: .\u002Fconfig.json.age\n```\nThe volumes that are required are: \n- `.\u002Fauth-logs\u002Fserver` for the auth logs, can be any local path.\n- `.\u002Fauth-logs\u002Fserver\u002Fbot-detector` for the `bot-detector` logs, can be any local path.\n- `bot-detector-data` for keeping the data sources fresh, and compiling `bot-detector generate` data sources. Can be any name.\n- `email-data` for the disposable email list data. Can be any name.\n\n#### Start the service\n\n```bash [Terminal]\ndocker compose up -d\n```\n\n::\n\n### Image security hardening\n\nThe production image enforces the following:\n\n| Control | Value |\n|---------|-------|\n| Non-root user | `appuser` (UID 10001) |\n| Filesystem | `read_only: true` |\n| Capabilities | All dropped (`cap_drop: [\"ALL\"]`) |\n| Privilege escalation | Blocked (`no-new-privileges: true`) |\n| PID limit | `200` |\n| Config lifetime | Decrypted into tmpfs, deleted after load |\n| Healthcheck | `GET \u002Fhealth` every 30s |\n\n\n---\n\n## Library installation\n\nIf you prefer to integrate the IAM module into your own Express application rather than running the standalone service, install it as a dependency.\n\n::code-group\n\n```bash [pnpm]\npnpm add @riavzon\u002Fauth\n```\n\n```bash [yarn]\nyarn add @riavzon\u002Fauth\n```\n\n```bash [npm]\nnpm install @riavzon\u002Fauth\n```\n\n```bash [bun]\nbun add @riavzon\u002Fauth\n```\n\n::\n\nThe module also requires `express`, `cookie-parser`, and `mysql2` as peer dependencies:\n\n::code-group\n\n```bash [pnpm]\npnpm add express cookie-parser mysql2\n```\n\n```bash [yarn]\nyarn add express cookie-parser mysql2\n```\n\n```bash [npm]\nnpm install express cookie-parser mysql2\n```\n\n```bash [bun]\nbun add express cookie-parser mysql2\n```\n\n::\n\n---\n\n### Quick start (library mode)\n\n::steps{level=\"4\"}\n\n#### Configure the service\n\nCall `configuration()` once at startup. The only required fields are `store`, `password`, `jwt`, `email`, and `magic_links`. See the full [Configuration reference](\u002Fdocs\u002Fiam\u002Fconfiguration) for every option.\n\n```ts [config.ts]\nexport const config = {\n  store: {\n    main: { \n      host: 'localhost',\n      user: 'root',\n      password: 'secret',\n      database: 'auth' \n    },\n    rate_limiters_pool: {\n      store: { \n        host: 'localhost',\n        user: 'root',\n        password: 'secret',\n        database: 'auth_limiters' \n      },\n      dbName: 'auth_limiters',\n    },\n  },\n  password: { \n    pepper: process.env.PEPPER! \n  },\n  botDetector: { \n    enableBotDetector: true \n  },\n  htmlSanitizer: { \n    IrritationCount: 50, \n    maxAllowedInputLength: 50000 \n  },\n  magic_links: {\n    jwt_secret_key: process.env.MAGIC_SECRET!,\n    domain: 'https:\u002F\u002Fexample.com',\n    notificationEmail: {\n      privacyPolicyLink: 'https:\u002F\u002Fexample.com\u002Fprivacy',\n      contactPageLink: 'https:\u002F\u002Fexample.com\u002Fcontact',\n      changePasswordPageLink: 'https:\u002F\u002Fexample.com\u002Fsettings\u002Fpassword',\n      loginPageLink: 'https:\u002F\u002Fexample.com\u002Flogin',\n    },\n  },\n  jwt: {\n    jwt_secret_key: process.env.JWT_SECRET!,\n    access_tokens: {},\n    refresh_tokens: {\n      refresh_ttl: 604800000,\n      domain: 'example.com',\n      MAX_SESSION_LIFE: 2592000000,\n      maxAllowedSessionsPerUser: 5,\n      byPassAnomaliesFor: 300000,\n    },\n  },\n  email: { resend_key: process.env.RESEND_KEY!, email: 'no-reply@example.com' },\n}\n```\n\n#### Mount the routes\n```ts [server.ts]\nimport express from 'express'\nimport cookieParser from 'cookie-parser'\nimport {\n  authenticationRoutes,\n  magicLinks,\n  tokenRotationRoutes,\n  bffAccessRoute,\n} from '@riavzon\u002Fauth'\nimport { configuration } from '@riavzon\u002Fauth'\nimport { config } from '.\u002Fconfig.js';\n\nconst app = express()\napp.use(cookieParser())\n\nawait configuration(config)\napp.use(authenticationRoutes)\napp.use(tokenRotationRoutes)\napp.use(magicLinks)\napp.use(bffAccessRoute)\n\napp.listen(10000)\n```\n\n#### Compile the Bot Detector data sources\n\nThe auth service depends on [Bot Detector](\u002Fdocs\u002Fbot-detection) for IP analysis, threat scoring, and bot detection. Download and compile all required data sources before starting the service:\n\n::code-group\n\n```bash [pnpm]\npnpm bot-detector init --contact=\"you@example.com\"\n```\n\n```bash [yarn]\nyarn bot-detector init --contact=\"you@example.com\"\n```\n\n```bash [npm]\nnpx bot-detector init --contact=\"you@example.com\"\n```\n\n```bash [bun]\nbunx bot-detector init --contact=\"you@example.com\"\n```\n\n::\n\nThe `--contact` flag provides a User-Agent string for BGP data downloads. This step compiles MMDB and LMDB databases for geolocation, ASN, proxy detection, threat lists, and more. See the [Bot Detector documentation](\u002Fdocs\u002Fbot-detection) for the full list of data sources.\n\n#### Create the database tables\n\nRun the `auth` CLI to compile the disposable email database and create the required database tables. Pass the path to your `config.json` as an argument:\n\n```bash [Terminal]\nauth .\u002Fconfig.json\n```\n\nThe CLI accepts the config path as a positional argument, or reads it from the `CONFIG_PATH` environment variable. If neither is provided, it defaults to `.\u002Fconfig.json`.\n\nThis command runs three tasks sequentially:\n\n1. Downloads and compiles the [disposable email domain blocklist](\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Femail) into an LMDB database at `dist\u002Femail-db\u002Fdisposable-emails.mdb`.\n2. Creates all required auth MySQL tables (`users`, `refresh_tokens`, `mfa_codes`, etc.).\n3. Creates the Bot Detector tables used for IP analysis and threat scoring.\n\nYou can also call it in your code: \n\n```ts [main.ts]\nimport { initAuthData } from '@riavzon\u002Fauth'\nawait initAuthData(config)\n```\n\n::callout{icon=\"i-lucide-info\" color=\"info\"}\nThe `auth` binary is available after installing the package. If running locally without a global install, use `npx @riavzon\u002Fauth .\u002Fconfig.json` instead.\n::\n\n::warning\nCall `configuration()` before mounting any routes or using any exported function. The entire module reads the resolved config at runtime; calling an export before configuration throws immediately.\n::\n\n::\n\n---\n\n### Using `bootstrapApp`\n\nFor the fastest path, the module exports `bootstrapApp`, which wires up the\nfull middleware chain (Helmet, IP validation, the public API verification\nroute, HMAC, cookie parser, Bot Detector, the authenticated routers, and error\nhandling) in the correct order and returns a ready-to-use Express app:\n\n```ts [server.ts]\nimport { bootstrapApp } from '@riavzon\u002Fauth\u002Fservice'\n\nconst app = await bootstrapApp(config)\napp.listen(10000, '0.0.0.0')\n```\n\nThe middleware chain `bootstrapApp` applies:\n\n1. Health check endpoint (`GET \u002Fhealth`)\n2. Bot Detector configuration and table creation\n3. Auth table creation\n4. HTTP logger (Pino)\n5. Disable `x-powered-by`\n6. Helmet security headers\n7. Service headers\n8. IP validation\n9. HMAC authentication (when `service.Hmac` is configured)\n10. Public API token verification route\n11. `express.json()`\n12. `cookie-parser`\n13. Bot Detector `ApiResponse` middleware\n14. Authentication routes\n15. Token rotation routes\n16. Magic link routes\n17. BFF access route\n18. API token management routes\n19. Operational config route\n20. Bot Detector warm-up\n21. 404 handler\n22. Global error handler\n\n::tip\nIn library mode, you do not have to register any particular route. You can use the exported methods directly to compose your own flows.\n::\n---\n\n## Environment variables\n\nThe standalone service reads the configuration from a JSON file. Override the path with:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `CONFIG_PATH` | `\u002Frun\u002Fapp\u002Fconfig.json` | Path to the JSON configuration file |\n| `SKIP_CONFIG_UNLINK` | `false` | Set to `true` to keep the config file in the container after loading |\n| `NODE_ENV` | - | Set to `production` in the Docker image |",{"title":14,"description":3702},"oYq5ZXEzJKNdfg8YYd8fnFKiIkS2GZ6sxkG08h4Y9n4",[3710,3711],{"title":27,"path":29,"stem":70,"children":-1},{"title":77,"path":78,"stem":79,"children":-1},{"id":851,"title":14,"body":3713,"description":3702,"extension":3703,"icon":15,"meta":5979,"module":3705,"navigation":8,"path":74,"rawbody":3706,"seo":5980,"stem":75,"__hash__":3708},{"type":853,"value":3714,"toc":5967},[3715,3719,3721,3723,3725,3745,3747,3760,3762,3781,3787,3789,3791,3799,3801,3812,3817,3821,3991,4581,4583,4585,4651,4653,4655,4657,4707,4715,4781,4783,4785,5765,5767,5771,5775,5841,5845,5903,5907,5909,5911,5913,5965],[856,3716,3717,862],{},[859,3718,861],{},[864,3720,867],{"id":866},[856,3722,870],{},[856,3724,873],{},[875,3726,3727,3731,3738],{},[878,3728,3729],{},[881,3730,883],{},[878,3732,3733],{},[887,3734,3736],{"href":889,"rel":3735},[891],[881,3737,894],{},[878,3739,3740],{},[887,3741,3743],{"href":899,"rel":3742},[891],[881,3744,903],{},[856,3746,906],{},[875,3748,3749,3753],{},[878,3750,3751],{},[881,3752,883],{},[878,3754,3755],{},[887,3756,3758],{"href":899,"rel":3757},[891],[881,3759,903],{},[856,3761,922],{},[875,3763,3764,3768,3772],{},[878,3765,3766],{},[881,3767,883],{},[878,3769,3770],{},[881,3771,933],{},[878,3773,3774,945],{},[887,3775,3777],{"href":938,"rel":3776},[891],[881,3778,3779],{},[859,3780,944],{},[947,3782,3783],{"color":949,"icon":950},[856,3784,953,3785,956],{},[859,3786,944],{},[958,3788],{},[864,3790,963],{"id":962},[856,3792,966,3793,969,3795,972,3797,976],{},[859,3794,894],{},[859,3796,944],{},[859,3798,975],{},[978,3800,981],{"id":980},[856,3802,984,3803,988,3806,992,3808,995,3810,999],{},[887,3804,894],{"href":889,"rel":3805},[891],[859,3807,991],{},[859,3809,894],{},[859,3811,998],{},[856,3813,1002,3814,1008],{},[887,3815,1007],{"href":1005,"rel":3816},[891],[856,3818,1011,3819,1015],{},[859,3820,1014],{},[1017,3822,3823],{"className":1019,"code":1020,"filename":1021,"language":1022,"meta":1023,"style":1023},[859,3824,3825,3831,3839,3849,3857,3873,3881,3889,3895,3901,3907,3913,3919,3925,3931,3939,3945,3955,3961,3971,3977,3983],{"__ignoreMap":1023},[1027,3826,3827,3829],{"class":1029,"line":1030},[1027,3828,1034],{"class":1033},[1027,3830,1038],{"class":1037},[1027,3832,3833,3835,3837],{"class":1029,"line":1041},[1027,3834,1044],{"class":1033},[1027,3836,1015],{"class":1037},[1027,3838,1050],{"class":1049},[1027,3840,3841,3843,3845,3847],{"class":1029,"line":1053},[1027,3842,1056],{"class":1033},[1027,3844,1015],{"class":1037},[1027,3846,1062],{"class":1061},[1027,3848,1066],{"class":1065},[1027,3850,3851,3853,3855],{"class":1029,"line":1069},[1027,3852,1072],{"class":1033},[1027,3854,1015],{"class":1037},[1027,3856,1077],{"class":1049},[1027,3858,3859,3861,3863,3865,3867,3869,3871],{"class":1029,"line":1080},[1027,3860,1083],{"class":1033},[1027,3862,1015],{"class":1037},[1027,3864,1088],{"class":1065},[1027,3866,1092],{"class":1091},[1027,3868,1096],{"class":1095},[1027,3870,1092],{"class":1091},[1027,3872,1101],{"class":1065},[1027,3874,3875,3877,3879],{"class":1029,"line":1104},[1027,3876,1107],{"class":1033},[1027,3878,1015],{"class":1037},[1027,3880,1112],{"class":1049},[1027,3882,3883,3885,3887],{"class":1029,"line":1115},[1027,3884,1118],{"class":1033},[1027,3886,1015],{"class":1037},[1027,3888,1123],{"class":1065},[1027,3890,3891,3893],{"class":1029,"line":1126},[1027,3892,1129],{"class":1037},[1027,3894,1132],{"class":1049},[1027,3896,3897,3899],{"class":1029,"line":1135},[1027,3898,1129],{"class":1037},[1027,3900,1140],{"class":1049},[1027,3902,3903,3905],{"class":1029,"line":1143},[1027,3904,1129],{"class":1037},[1027,3906,1148],{"class":1049},[1027,3908,3909,3911],{"class":1029,"line":1151},[1027,3910,1129],{"class":1037},[1027,3912,1156],{"class":1049},[1027,3914,3915,3917],{"class":1029,"line":1159},[1027,3916,1129],{"class":1037},[1027,3918,1164],{"class":1049},[1027,3920,3921,3923],{"class":1029,"line":1167},[1027,3922,1170],{"class":1033},[1027,3924,1038],{"class":1037},[1027,3926,3927,3929],{"class":1029,"line":1175},[1027,3928,1129],{"class":1037},[1027,3930,1180],{"class":1049},[1027,3932,3933,3935,3937],{"class":1029,"line":1183},[1027,3934,1186],{"class":1033},[1027,3936,1015],{"class":1037},[1027,3938,1192],{"class":1191},[1027,3940,3941,3943],{"class":1029,"line":1195},[1027,3942,1198],{"class":1033},[1027,3944,1038],{"class":1037},[1027,3946,3947,3949,3951,3953],{"class":1029,"line":1203},[1027,3948,1129],{"class":1037},[1027,3950,1208],{"class":1091},[1027,3952,1211],{"class":1095},[1027,3954,1214],{"class":1091},[1027,3956,3957,3959],{"class":1029,"line":1217},[1027,3958,1220],{"class":1033},[1027,3960,1038],{"class":1037},[1027,3962,3963,3965,3967,3969],{"class":1029,"line":1225},[1027,3964,1129],{"class":1037},[1027,3966,1208],{"class":1091},[1027,3968,1232],{"class":1095},[1027,3970,1214],{"class":1091},[1027,3972,3973,3975],{"class":1029,"line":1237},[1027,3974,1240],{"class":1033},[1027,3976,1038],{"class":1037},[1027,3978,3979,3981],{"class":1029,"line":1245},[1027,3980,1248],{"class":1033},[1027,3982,1038],{"class":1037},[1027,3984,3985,3987,3989],{"class":1029,"line":1253},[1027,3986,1256],{"class":1033},[1027,3988,1015],{"class":1037},[1027,3990,1261],{"class":1049},[1263,3992,3993,3995,4019,4021,4031,4037,4039,4045,4075,4079,4087,4091,4541,4543,4565,4567],{"level":1265},[1267,3994,1270],{"id":1269},[1017,3996,3997],{"className":1273,"code":1274,"filename":1275,"language":1276,"meta":1023,"style":1023},[859,3998,3999],{"__ignoreMap":1023},[1027,4000,4001,4003,4005,4007,4009,4011,4013,4015,4017],{"class":1029,"line":1030},[1027,4002,1284],{"class":1283},[1027,4004,1287],{"class":1061},[1027,4006,1290],{"class":1095},[1027,4008,1293],{"class":1065},[1027,4010,1284],{"class":1283},[1027,4012,1298],{"class":1061},[1027,4014,1290],{"class":1095},[1027,4016,1303],{"class":1037},[1027,4018,1306],{"class":1095},[856,4020,1309],{},[875,4022,4023,4027],{},[878,4024,4025,1317],{},[859,4026,1316],{},[878,4028,4029,1323],{},[859,4030,1322],{},[1325,4032,4033],{},[856,4034,1329,4035,1332],{},[859,4036,1316],{},[1267,4038,1336],{"id":1335},[856,4040,1339,4041,1342,4043,1346],{},[859,4042,991],{},[887,4044,1345],{"href":238},[1017,4046,4047],{"className":1273,"code":1349,"filename":1275,"language":1276,"meta":1023,"style":1023},[859,4048,4049],{"__ignoreMap":1023},[1027,4050,4051,4053,4055,4057,4059,4061,4063,4065,4067,4069,4071,4073],{"class":1029,"line":1030},[1027,4052,894],{"class":1283},[1027,4054,1358],{"class":1061},[1027,4056,1361],{"class":1061},[1027,4058,1364],{"class":1061},[1027,4060,1208],{"class":1091},[1027,4062,1369],{"class":1095},[1027,4064,1372],{"class":1283},[1027,4066,1375],{"class":1095},[1027,4068,1092],{"class":1091},[1027,4070,1287],{"class":1061},[1027,4072,1382],{"class":1095},[1027,4074,1385],{"class":1095},[856,4076,4077,1391],{},[859,4078,1390],{},[1393,4080,4081],{},[856,4082,1397,4083,1400,4085,1403],{},[859,4084,991],{},[859,4086,1316],{},[1267,4088,1407,4089],{"id":1406},[859,4090,1021],{},[1017,4092,4093],{"className":1019,"code":1412,"filename":1021,"language":1022,"meta":1023,"style":1023},[859,4094,4095,4101,4109,4117,4123,4131,4139,4147,4155,4171,4183,4191,4201,4207,4213,4219,4243,4251,4261,4269,4277,4283,4291,4295,4301,4309,4319,4327,4343,4351,4359,4365,4371,4377,4383,4389,4395,4403,4409,4419,4425,4431,4437,4443,4453,4459,4465,4473,4477,4483,4491,4497,4503,4507,4513,4519,4527,4533],{"__ignoreMap":1023},[1027,4096,4097,4099],{"class":1029,"line":1030},[1027,4098,1419],{"class":1033},[1027,4100,1038],{"class":1037},[1027,4102,4103,4105,4107],{"class":1029,"line":1041},[1027,4104,1426],{"class":1033},[1027,4106,1015],{"class":1037},[1027,4108,1123],{"class":1065},[1027,4110,4111,4113,4115],{"class":1029,"line":1053},[1027,4112,1072],{"class":1033},[1027,4114,1015],{"class":1037},[1027,4116,1077],{"class":1049},[1027,4118,4119,4121],{"class":1029,"line":1069},[1027,4120,1443],{"class":1033},[1027,4122,1038],{"class":1037},[1027,4124,4125,4127,4129],{"class":1029,"line":1080},[1027,4126,1450],{"class":1033},[1027,4128,1015],{"class":1037},[1027,4130,1455],{"class":1049},[1027,4132,4133,4135,4137],{"class":1029,"line":1104},[1027,4134,1460],{"class":1033},[1027,4136,1015],{"class":1037},[1027,4138,1465],{"class":1049},[1027,4140,4141,4143,4145],{"class":1029,"line":1115},[1027,4142,1470],{"class":1033},[1027,4144,1015],{"class":1037},[1027,4146,1475],{"class":1049},[1027,4148,4149,4151,4153],{"class":1029,"line":1126},[1027,4150,1480],{"class":1033},[1027,4152,1015],{"class":1037},[1027,4154,1455],{"class":1049},[1027,4156,4157,4159,4161,4163,4165,4167,4169],{"class":1029,"line":1135},[1027,4158,1083],{"class":1033},[1027,4160,1015],{"class":1037},[1027,4162,1088],{"class":1065},[1027,4164,1092],{"class":1091},[1027,4166,1096],{"class":1095},[1027,4168,1092],{"class":1091},[1027,4170,1101],{"class":1065},[1027,4172,4173,4175,4177,4179,4181],{"class":1029,"line":1143},[1027,4174,1107],{"class":1033},[1027,4176,1015],{"class":1037},[1027,4178,1208],{"class":1091},[1027,4180,1511],{"class":1095},[1027,4182,1214],{"class":1091},[1027,4184,4185,4187,4189],{"class":1029,"line":1151},[1027,4186,1220],{"class":1033},[1027,4188,1015],{"class":1037},[1027,4190,1123],{"class":1065},[1027,4192,4193,4195,4197,4199],{"class":1029,"line":1159},[1027,4194,1129],{"class":1037},[1027,4196,1208],{"class":1091},[1027,4198,1232],{"class":1095},[1027,4200,1214],{"class":1091},[1027,4202,4203,4205],{"class":1029,"line":1167},[1027,4204,1118],{"class":1033},[1027,4206,1038],{"class":1037},[1027,4208,4209,4211],{"class":1029,"line":1175},[1027,4210,1129],{"class":1037},[1027,4212,1544],{"class":1049},[1027,4214,4215,4217],{"class":1029,"line":1183},[1027,4216,1549],{"class":1033},[1027,4218,1038],{"class":1037},[1027,4220,4221,4223,4225,4227,4229,4231,4233,4235,4237,4239,4241],{"class":1029,"line":1195},[1027,4222,1556],{"class":1033},[1027,4224,1015],{"class":1037},[1027,4226,1088],{"class":1065},[1027,4228,1092],{"class":1091},[1027,4230,1565],{"class":1095},[1027,4232,1092],{"class":1091},[1027,4234,969],{"class":1065},[1027,4236,1092],{"class":1091},[1027,4238,1574],{"class":1095},[1027,4240,1092],{"class":1091},[1027,4242,1101],{"class":1065},[1027,4244,4245,4247,4249],{"class":1029,"line":1203},[1027,4246,1583],{"class":1033},[1027,4248,1015],{"class":1037},[1027,4250,1588],{"class":1049},[1027,4252,4253,4255,4257,4259],{"class":1029,"line":1217},[1027,4254,1593],{"class":1033},[1027,4256,1015],{"class":1037},[1027,4258,1598],{"class":1049},[1027,4260,1123],{"class":1065},[1027,4262,4263,4265,4267],{"class":1029,"line":1225},[1027,4264,1605],{"class":1033},[1027,4266,1015],{"class":1037},[1027,4268,1610],{"class":1191},[1027,4270,4271,4273,4275],{"class":1029,"line":1237},[1027,4272,1615],{"class":1033},[1027,4274,1015],{"class":1037},[1027,4276,1620],{"class":1049},[1027,4278,4279,4281],{"class":1029,"line":1245},[1027,4280,1170],{"class":1033},[1027,4282,1038],{"class":1037},[1027,4284,4285,4287,4289],{"class":1029,"line":1253},[1027,4286,1129],{"class":1037},[1027,4288,1633],{"class":1049},[1027,4290,1066],{"class":1065},[1027,4292,4293],{"class":1029,"line":1638},[1027,4294,1641],{"emptyLinePlaceholder":8},[1027,4296,4297,4299],{"class":1029,"line":1644},[1027,4298,1034],{"class":1033},[1027,4300,1038],{"class":1037},[1027,4302,4303,4305,4307],{"class":1029,"line":1651},[1027,4304,1044],{"class":1033},[1027,4306,1015],{"class":1037},[1027,4308,1050],{"class":1049},[1027,4310,4311,4313,4315,4317],{"class":1029,"line":1660},[1027,4312,1056],{"class":1033},[1027,4314,1015],{"class":1037},[1027,4316,1062],{"class":1061},[1027,4318,1066],{"class":1065},[1027,4320,4321,4323,4325],{"class":1029,"line":1671},[1027,4322,1072],{"class":1033},[1027,4324,1015],{"class":1037},[1027,4326,1077],{"class":1049},[1027,4328,4329,4331,4333,4335,4337,4339,4341],{"class":1029,"line":1680},[1027,4330,1083],{"class":1033},[1027,4332,1015],{"class":1037},[1027,4334,1088],{"class":1065},[1027,4336,1092],{"class":1091},[1027,4338,1096],{"class":1095},[1027,4340,1092],{"class":1091},[1027,4342,1101],{"class":1065},[1027,4344,4345,4347,4349],{"class":1029,"line":1697},[1027,4346,1107],{"class":1033},[1027,4348,1015],{"class":1037},[1027,4350,1112],{"class":1049},[1027,4352,4353,4355,4357],{"class":1029,"line":1706},[1027,4354,1118],{"class":1033},[1027,4356,1015],{"class":1037},[1027,4358,1123],{"class":1065},[1027,4360,4361,4363],{"class":1029,"line":1715},[1027,4362,1129],{"class":1037},[1027,4364,1132],{"class":1049},[1027,4366,4367,4369],{"class":1029,"line":1722},[1027,4368,1129],{"class":1037},[1027,4370,1140],{"class":1049},[1027,4372,4373,4375],{"class":1029,"line":1729},[1027,4374,1129],{"class":1037},[1027,4376,1156],{"class":1049},[1027,4378,4379,4381],{"class":1029,"line":1736},[1027,4380,1129],{"class":1037},[1027,4382,1164],{"class":1049},[1027,4384,4385,4387],{"class":1029,"line":1743},[1027,4386,1170],{"class":1033},[1027,4388,1038],{"class":1037},[1027,4390,4391,4393],{"class":1029,"line":1750},[1027,4392,1129],{"class":1037},[1027,4394,1180],{"class":1049},[1027,4396,4397,4399,4401],{"class":1029,"line":1757},[1027,4398,1186],{"class":1033},[1027,4400,1015],{"class":1037},[1027,4402,1192],{"class":1191},[1027,4404,4405,4407],{"class":1029,"line":1766},[1027,4406,1198],{"class":1033},[1027,4408,1038],{"class":1037},[1027,4410,4411,4413,4415,4417],{"class":1029,"line":1773},[1027,4412,1129],{"class":1037},[1027,4414,1208],{"class":1091},[1027,4416,1211],{"class":1095},[1027,4418,1214],{"class":1091},[1027,4420,4421,4423],{"class":1029,"line":1784},[1027,4422,1787],{"class":1033},[1027,4424,1038],{"class":1037},[1027,4426,4427,4429],{"class":1029,"line":1792},[1027,4428,1129],{"class":1037},[1027,4430,1797],{"class":1049},[1027,4432,4433,4435],{"class":1029,"line":1800},[1027,4434,1129],{"class":1037},[1027,4436,1805],{"class":1049},[1027,4438,4439,4441],{"class":1029,"line":1808},[1027,4440,1220],{"class":1033},[1027,4442,1038],{"class":1037},[1027,4444,4445,4447,4449,4451],{"class":1029,"line":1815},[1027,4446,1129],{"class":1037},[1027,4448,1208],{"class":1091},[1027,4450,1232],{"class":1095},[1027,4452,1214],{"class":1091},[1027,4454,4455,4457],{"class":1029,"line":1826},[1027,4456,1240],{"class":1033},[1027,4458,1038],{"class":1037},[1027,4460,4461,4463],{"class":1029,"line":1833},[1027,4462,1248],{"class":1033},[1027,4464,1038],{"class":1037},[1027,4466,4467,4469,4471],{"class":1029,"line":1840},[1027,4468,1256],{"class":1033},[1027,4470,1015],{"class":1037},[1027,4472,1261],{"class":1049},[1027,4474,4475],{"class":1029,"line":1849},[1027,4476,1641],{"emptyLinePlaceholder":8},[1027,4478,4479,4481],{"class":1029,"line":1854},[1027,4480,1857],{"class":1033},[1027,4482,1038],{"class":1037},[1027,4484,4485,4487,4489],{"class":1029,"line":1862},[1027,4486,1865],{"class":1033},[1027,4488,1015],{"class":1037},[1027,4490,1066],{"class":1065},[1027,4492,4493,4495],{"class":1029,"line":1872},[1027,4494,1875],{"class":1033},[1027,4496,1038],{"class":1037},[1027,4498,4499,4501],{"class":1029,"line":1880},[1027,4500,1883],{"class":1033},[1027,4502,1038],{"class":1037},[1027,4504,4505],{"class":1029,"line":1888},[1027,4506,1641],{"emptyLinePlaceholder":8},[1027,4508,4509,4511],{"class":1029,"line":1893},[1027,4510,1896],{"class":1033},[1027,4512,1038],{"class":1037},[1027,4514,4515,4517],{"class":1029,"line":1901},[1027,4516,1904],{"class":1033},[1027,4518,1038],{"class":1037},[1027,4520,4521,4523,4525],{"class":1029,"line":1909},[1027,4522,1912],{"class":1033},[1027,4524,1015],{"class":1037},[1027,4526,1917],{"class":1049},[1027,4528,4529,4531],{"class":1029,"line":1920},[1027,4530,1923],{"class":1033},[1027,4532,1038],{"class":1037},[1027,4534,4535,4537,4539],{"class":1029,"line":1928},[1027,4536,1912],{"class":1033},[1027,4538,1015],{"class":1037},[1027,4540,1935],{"class":1049},[856,4542,1938],{},[875,4544,4545,4549,4555,4561],{},[878,4546,4547,1946],{},[859,4548,1945],{},[878,4550,4551,1952,4553,1956],{},[859,4552,1951],{},[859,4554,1955],{},[878,4556,4557,1962,4559,1966],{},[859,4558,1961],{},[859,4560,1965],{},[878,4562,4563,1972],{},[859,4564,1971],{},[1267,4566,1976],{"id":1975},[1017,4568,4569],{"className":1273,"code":1979,"filename":1275,"language":1276,"meta":1023,"style":1023},[859,4570,4571],{"__ignoreMap":1023},[1027,4572,4573,4575,4577,4579],{"class":1029,"line":1030},[1027,4574,1986],{"class":1283},[1027,4576,1989],{"class":1095},[1027,4578,1992],{"class":1095},[1027,4580,1995],{"class":1061},[978,4582,1999],{"id":1998},[856,4584,2002],{},[2004,4586,4587,4595],{},[2007,4588,4589],{},[2010,4590,4591,4593],{},[2013,4592,2015],{},[2013,4594,2018],{},[2020,4596,4597,4605,4613,4621,4629,4637,4643],{},[2010,4598,4599,4601],{},[2025,4600,2027],{},[2025,4602,4603,2033],{},[859,4604,2032],{},[2010,4606,4607,4609],{},[2025,4608,2038],{},[2025,4610,4611],{},[859,4612,2043],{},[2010,4614,4615,4617],{},[2025,4616,2048],{},[2025,4618,2051,4619,2055],{},[859,4620,2054],{},[2010,4622,4623,4625],{},[2025,4624,2060],{},[2025,4626,2063,4627,2055],{},[859,4628,2066],{},[2010,4630,4631,4633],{},[2025,4632,2071],{},[2025,4634,4635],{},[859,4636,2076],{},[2010,4638,4639,4641],{},[2025,4640,2081],{},[2025,4642,2084],{},[2010,4644,4645,4647],{},[2025,4646,2089],{},[2025,4648,4649,2095],{},[859,4650,2094],{},[958,4652],{},[864,4654,2101],{"id":2100},[856,4656,2104],{},[2106,4658,4659,4671,4683,4695],{},[1017,4660,4661],{"className":1273,"code":2110,"filename":2111,"language":1276,"meta":1023,"style":1023},[859,4662,4663],{"__ignoreMap":1023},[1027,4664,4665,4667,4669],{"class":1029,"line":1030},[1027,4666,2111],{"class":1283},[1027,4668,2120],{"class":1095},[1027,4670,2123],{"class":1095},[1017,4672,4673],{"className":1273,"code":2126,"filename":2127,"language":1276,"meta":1023,"style":1023},[859,4674,4675],{"__ignoreMap":1023},[1027,4676,4677,4679,4681],{"class":1029,"line":1030},[1027,4678,2127],{"class":1283},[1027,4680,2120],{"class":1095},[1027,4682,2123],{"class":1095},[1017,4684,4685],{"className":1273,"code":2140,"filename":2141,"language":1276,"meta":1023,"style":1023},[859,4686,4687],{"__ignoreMap":1023},[1027,4688,4689,4691,4693],{"class":1029,"line":1030},[1027,4690,2141],{"class":1283},[1027,4692,2150],{"class":1095},[1027,4694,2123],{"class":1095},[1017,4696,4697],{"className":1273,"code":2155,"filename":2156,"language":1276,"meta":1023,"style":1023},[859,4698,4699],{"__ignoreMap":1023},[1027,4700,4701,4703,4705],{"class":1029,"line":1030},[1027,4702,2156],{"class":1283},[1027,4704,2120],{"class":1095},[1027,4706,2123],{"class":1095},[856,4708,2169,4709,969,4711,2176,4713,2180],{},[859,4710,2172],{},[859,4712,2175],{},[859,4714,2179],{},[2106,4716,4717,4733,4749,4765],{},[1017,4718,4719],{"className":1273,"code":2185,"filename":2111,"language":1276,"meta":1023,"style":1023},[859,4720,4721],{"__ignoreMap":1023},[1027,4722,4723,4725,4727,4729,4731],{"class":1029,"line":1030},[1027,4724,2111],{"class":1283},[1027,4726,2120],{"class":1095},[1027,4728,2196],{"class":1095},[1027,4730,2199],{"class":1095},[1027,4732,2202],{"class":1095},[1017,4734,4735],{"className":1273,"code":2205,"filename":2127,"language":1276,"meta":1023,"style":1023},[859,4736,4737],{"__ignoreMap":1023},[1027,4738,4739,4741,4743,4745,4747],{"class":1029,"line":1030},[1027,4740,2127],{"class":1283},[1027,4742,2120],{"class":1095},[1027,4744,2196],{"class":1095},[1027,4746,2199],{"class":1095},[1027,4748,2202],{"class":1095},[1017,4750,4751],{"className":1273,"code":2222,"filename":2141,"language":1276,"meta":1023,"style":1023},[859,4752,4753],{"__ignoreMap":1023},[1027,4754,4755,4757,4759,4761,4763],{"class":1029,"line":1030},[1027,4756,2141],{"class":1283},[1027,4758,2150],{"class":1095},[1027,4760,2196],{"class":1095},[1027,4762,2199],{"class":1095},[1027,4764,2202],{"class":1095},[1017,4766,4767],{"className":1273,"code":2239,"filename":2156,"language":1276,"meta":1023,"style":1023},[859,4768,4769],{"__ignoreMap":1023},[1027,4770,4771,4773,4775,4777,4779],{"class":1029,"line":1030},[1027,4772,2156],{"class":1283},[1027,4774,2120],{"class":1095},[1027,4776,2196],{"class":1095},[1027,4778,2199],{"class":1095},[1027,4780,2202],{"class":1095},[958,4782],{},[978,4784,2259],{"id":2258},[1263,4786,4787,4789,4805,5343,5345,5577,5579,5583,5665,5671,5673,5679,5689,5695,5697,5715,5717,5751,5759],{"level":1265},[1267,4788,2265],{"id":2264},[856,4790,2268,4791,2272,4793,969,4795,969,4797,969,4799,2176,4801,2288,4803,2292],{},[859,4792,2271],{},[859,4794,2275],{},[859,4796,2278],{},[859,4798,2281],{},[859,4800,2284],{},[859,4802,2287],{},[887,4804,2291],{"href":238},[1017,4806,4807],{"className":2295,"code":2296,"filename":2297,"language":2298,"meta":1023,"style":1023},[859,4808,4809,4821,4829,4837,4851,4865,4879,4893,4897,4905,4913,4927,4941,4955,4969,4973,4987,4991,4995,5003,5023,5027,5035,5045,5049,5057,5067,5077,5081,5089,5109,5123,5131,5145,5159,5173,5187,5191,5195,5203,5223,5231,5239,5249,5263,5273,5283,5293,5297,5301,5339],{"__ignoreMap":1023},[1027,4810,4811,4813,4815,4817,4819],{"class":1029,"line":1030},[1027,4812,2306],{"class":2305},[1027,4814,2310],{"class":2309},[1027,4816,2314],{"class":2313},[1027,4818,2317],{"class":1037},[1027,4820,2320],{"class":1065},[1027,4822,4823,4825,4827],{"class":1029,"line":1041},[1027,4824,2326],{"class":2325},[1027,4826,1015],{"class":2329},[1027,4828,2320],{"class":1065},[1027,4830,4831,4833,4835],{"class":1029,"line":1053},[1027,4832,2336],{"class":2325},[1027,4834,1015],{"class":2329},[1027,4836,2341],{"class":1065},[1027,4838,4839,4841,4843,4845,4847,4849],{"class":1029,"line":1069},[1027,4840,2346],{"class":2325},[1027,4842,1015],{"class":2329},[1027,4844,2351],{"class":1091},[1027,4846,2354],{"class":1095},[1027,4848,2357],{"class":1091},[1027,4850,2360],{"class":1065},[1027,4852,4853,4855,4857,4859,4861,4863],{"class":1029,"line":1080},[1027,4854,2365],{"class":2325},[1027,4856,1015],{"class":2329},[1027,4858,2351],{"class":1091},[1027,4860,2372],{"class":1095},[1027,4862,2357],{"class":1091},[1027,4864,2360],{"class":1065},[1027,4866,4867,4869,4871,4873,4875,4877],{"class":1029,"line":1104},[1027,4868,2381],{"class":2325},[1027,4870,1015],{"class":2329},[1027,4872,2351],{"class":1091},[1027,4874,2388],{"class":1095},[1027,4876,2357],{"class":1091},[1027,4878,2360],{"class":1065},[1027,4880,4881,4883,4885,4887,4889,4891],{"class":1029,"line":1115},[1027,4882,2397],{"class":2325},[1027,4884,1015],{"class":2329},[1027,4886,2351],{"class":1091},[1027,4888,2404],{"class":1095},[1027,4890,2357],{"class":1091},[1027,4892,1123],{"class":1065},[1027,4894,4895],{"class":1029,"line":1126},[1027,4896,2413],{"class":1065},[1027,4898,4899,4901,4903],{"class":1029,"line":1135},[1027,4900,2418],{"class":2325},[1027,4902,1015],{"class":2329},[1027,4904,2320],{"class":1065},[1027,4906,4907,4909,4911],{"class":1029,"line":1143},[1027,4908,2427],{"class":2325},[1027,4910,1015],{"class":2329},[1027,4912,2341],{"class":1065},[1027,4914,4915,4917,4919,4921,4923,4925],{"class":1029,"line":1151},[1027,4916,2436],{"class":2325},[1027,4918,1015],{"class":2329},[1027,4920,2351],{"class":1091},[1027,4922,2354],{"class":1095},[1027,4924,2357],{"class":1091},[1027,4926,2360],{"class":1065},[1027,4928,4929,4931,4933,4935,4937,4939],{"class":1029,"line":1159},[1027,4930,2451],{"class":2325},[1027,4932,1015],{"class":2329},[1027,4934,2351],{"class":1091},[1027,4936,2372],{"class":1095},[1027,4938,2357],{"class":1091},[1027,4940,2360],{"class":1065},[1027,4942,4943,4945,4947,4949,4951,4953],{"class":1029,"line":1167},[1027,4944,2466],{"class":2325},[1027,4946,1015],{"class":2329},[1027,4948,2351],{"class":1091},[1027,4950,2388],{"class":1095},[1027,4952,2357],{"class":1091},[1027,4954,2360],{"class":1065},[1027,4956,4957,4959,4961,4963,4965,4967],{"class":1029,"line":1175},[1027,4958,2481],{"class":2325},[1027,4960,1015],{"class":2329},[1027,4962,2351],{"class":1091},[1027,4964,2488],{"class":1095},[1027,4966,2357],{"class":1091},[1027,4968,1123],{"class":1065},[1027,4970,4971],{"class":1029,"line":1183},[1027,4972,2497],{"class":1065},[1027,4974,4975,4977,4979,4981,4983,4985],{"class":1029,"line":1195},[1027,4976,2502],{"class":2325},[1027,4978,1015],{"class":2329},[1027,4980,2351],{"class":1091},[1027,4982,2488],{"class":1095},[1027,4984,2357],{"class":1091},[1027,4986,2360],{"class":1065},[1027,4988,4989],{"class":1029,"line":1203},[1027,4990,2413],{"class":1065},[1027,4992,4993],{"class":1029,"line":1217},[1027,4994,2521],{"class":1065},[1027,4996,4997,4999,5001],{"class":1029,"line":1225},[1027,4998,2526],{"class":2325},[1027,5000,1015],{"class":2329},[1027,5002,2341],{"class":1065},[1027,5004,5005,5007,5009,5011,5013,5015,5017,5019,5021],{"class":1029,"line":1237},[1027,5006,2535],{"class":2325},[1027,5008,1015],{"class":2329},[1027,5010,2540],{"class":2325},[1027,5012,1008],{"class":1065},[1027,5014,2545],{"class":2325},[1027,5016,1008],{"class":1065},[1027,5018,2551],{"class":2550},[1027,5020,2554],{"class":1037},[1027,5022,1123],{"class":1065},[1027,5024,5025],{"class":1029,"line":1245},[1027,5026,2521],{"class":1065},[1027,5028,5029,5031,5033],{"class":1029,"line":1253},[1027,5030,2565],{"class":2325},[1027,5032,1015],{"class":2329},[1027,5034,2341],{"class":1065},[1027,5036,5037,5039,5041,5043],{"class":1029,"line":1638},[1027,5038,2574],{"class":2325},[1027,5040,1015],{"class":2329},[1027,5042,1062],{"class":1061},[1027,5044,1123],{"class":1065},[1027,5046,5047],{"class":1029,"line":1644},[1027,5048,2521],{"class":1065},[1027,5050,5051,5053,5055],{"class":1029,"line":1651},[1027,5052,2589],{"class":2325},[1027,5054,1015],{"class":2329},[1027,5056,2341],{"class":1065},[1027,5058,5059,5061,5063,5065],{"class":1029,"line":1660},[1027,5060,2598],{"class":2325},[1027,5062,1015],{"class":2329},[1027,5064,2603],{"class":1191},[1027,5066,2606],{"class":1065},[1027,5068,5069,5071,5073,5075],{"class":1029,"line":1671},[1027,5070,2611],{"class":2325},[1027,5072,1015],{"class":2329},[1027,5074,2616],{"class":1191},[1027,5076,1123],{"class":1065},[1027,5078,5079],{"class":1029,"line":1680},[1027,5080,2521],{"class":1065},[1027,5082,5083,5085,5087],{"class":1029,"line":1697},[1027,5084,2627],{"class":2325},[1027,5086,1015],{"class":2329},[1027,5088,2320],{"class":1065},[1027,5090,5091,5093,5095,5097,5099,5101,5103,5105,5107],{"class":1029,"line":1706},[1027,5092,2636],{"class":2325},[1027,5094,1015],{"class":2329},[1027,5096,2540],{"class":2325},[1027,5098,1008],{"class":1065},[1027,5100,2545],{"class":2325},[1027,5102,1008],{"class":1065},[1027,5104,2649],{"class":2550},[1027,5106,2554],{"class":1037},[1027,5108,2360],{"class":1065},[1027,5110,5111,5113,5115,5117,5119,5121],{"class":1029,"line":1715},[1027,5112,2658],{"class":2325},[1027,5114,1015],{"class":2329},[1027,5116,2351],{"class":1091},[1027,5118,2665],{"class":1095},[1027,5120,2357],{"class":1091},[1027,5122,2360],{"class":1065},[1027,5124,5125,5127,5129],{"class":1029,"line":1722},[1027,5126,2674],{"class":2325},[1027,5128,1015],{"class":2329},[1027,5130,2320],{"class":1065},[1027,5132,5133,5135,5137,5139,5141,5143],{"class":1029,"line":1729},[1027,5134,2683],{"class":2325},[1027,5136,1015],{"class":2329},[1027,5138,2351],{"class":1091},[1027,5140,2690],{"class":1095},[1027,5142,2357],{"class":1091},[1027,5144,2360],{"class":1065},[1027,5146,5147,5149,5151,5153,5155,5157],{"class":1029,"line":1736},[1027,5148,2699],{"class":2325},[1027,5150,1015],{"class":2329},[1027,5152,2351],{"class":1091},[1027,5154,2706],{"class":1095},[1027,5156,2357],{"class":1091},[1027,5158,2360],{"class":1065},[1027,5160,5161,5163,5165,5167,5169,5171],{"class":1029,"line":1743},[1027,5162,2715],{"class":2325},[1027,5164,1015],{"class":2329},[1027,5166,2351],{"class":1091},[1027,5168,2722],{"class":1095},[1027,5170,2357],{"class":1091},[1027,5172,2360],{"class":1065},[1027,5174,5175,5177,5179,5181,5183,5185],{"class":1029,"line":1750},[1027,5176,2731],{"class":2325},[1027,5178,1015],{"class":2329},[1027,5180,2351],{"class":1091},[1027,5182,2738],{"class":1095},[1027,5184,2357],{"class":1091},[1027,5186,2360],{"class":1065},[1027,5188,5189],{"class":1029,"line":1757},[1027,5190,2413],{"class":1065},[1027,5192,5193],{"class":1029,"line":1766},[1027,5194,2521],{"class":1065},[1027,5196,5197,5199,5201],{"class":1029,"line":1773},[1027,5198,2755],{"class":2325},[1027,5200,1015],{"class":2329},[1027,5202,2320],{"class":1065},[1027,5204,5205,5207,5209,5211,5213,5215,5217,5219,5221],{"class":1029,"line":1784},[1027,5206,2636],{"class":2325},[1027,5208,1015],{"class":2329},[1027,5210,2540],{"class":2325},[1027,5212,1008],{"class":1065},[1027,5214,2545],{"class":2325},[1027,5216,1008],{"class":1065},[1027,5218,2776],{"class":2550},[1027,5220,2554],{"class":1037},[1027,5222,2360],{"class":1065},[1027,5224,5225,5227,5229],{"class":1029,"line":1792},[1027,5226,2785],{"class":2325},[1027,5228,1015],{"class":2329},[1027,5230,2790],{"class":1065},[1027,5232,5233,5235,5237],{"class":1029,"line":1800},[1027,5234,2795],{"class":2325},[1027,5236,1015],{"class":2329},[1027,5238,2320],{"class":1065},[1027,5240,5241,5243,5245,5247],{"class":1029,"line":1808},[1027,5242,2804],{"class":2325},[1027,5244,1015],{"class":2329},[1027,5246,2809],{"class":1191},[1027,5248,2360],{"class":1065},[1027,5250,5251,5253,5255,5257,5259,5261],{"class":1029,"line":1815},[1027,5252,2816],{"class":2325},[1027,5254,1015],{"class":2329},[1027,5256,2351],{"class":1091},[1027,5258,2823],{"class":1095},[1027,5260,2357],{"class":1091},[1027,5262,2360],{"class":1065},[1027,5264,5265,5267,5269,5271],{"class":1029,"line":1826},[1027,5266,2832],{"class":2325},[1027,5268,1015],{"class":2329},[1027,5270,2837],{"class":1191},[1027,5272,2360],{"class":1065},[1027,5274,5275,5277,5279,5281],{"class":1029,"line":1833},[1027,5276,2844],{"class":2325},[1027,5278,1015],{"class":2329},[1027,5280,2849],{"class":1191},[1027,5282,2360],{"class":1065},[1027,5284,5285,5287,5289,5291],{"class":1029,"line":1840},[1027,5286,2856],{"class":2325},[1027,5288,1015],{"class":2329},[1027,5290,2861],{"class":1191},[1027,5292,2360],{"class":1065},[1027,5294,5295],{"class":1029,"line":1849},[1027,5296,2413],{"class":1065},[1027,5298,5299],{"class":1029,"line":1854},[1027,5300,2521],{"class":1065},[1027,5302,5303,5305,5307,5309,5311,5313,5315,5317,5319,5321,5323,5325,5327,5329,5331,5333,5335,5337],{"class":1029,"line":1862},[1027,5304,2876],{"class":2325},[1027,5306,1015],{"class":2329},[1027,5308,2881],{"class":1065},[1027,5310,2884],{"class":2325},[1027,5312,1015],{"class":2329},[1027,5314,2540],{"class":2325},[1027,5316,1008],{"class":1065},[1027,5318,2545],{"class":2325},[1027,5320,1008],{"class":1065},[1027,5322,2897],{"class":2550},[1027,5324,2554],{"class":1037},[1027,5326,969],{"class":1065},[1027,5328,2284],{"class":2325},[1027,5330,1015],{"class":2329},[1027,5332,2351],{"class":1091},[1027,5334,2910],{"class":1095},[1027,5336,2357],{"class":1091},[1027,5338,2915],{"class":1065},[1027,5340,5341],{"class":1029,"line":1872},[1027,5342,2920],{"class":1065},[1267,5344,2924],{"id":2923},[1017,5346,5347],{"className":2295,"code":2927,"filename":2928,"language":2298,"meta":1023,"style":1023},[859,5348,5349,5363,5377,5383,5389,5395,5401,5407,5419,5437,5457,5461,5473,5487,5491,5503,5517,5531,5545,5559,5563],{"__ignoreMap":1023},[1027,5350,5351,5353,5355,5357,5359,5361],{"class":1029,"line":1030},[1027,5352,2935],{"class":2305},[1027,5354,2196],{"class":2325},[1027,5356,2940],{"class":2305},[1027,5358,2351],{"class":1091},[1027,5360,2172],{"class":1095},[1027,5362,2947],{"class":1091},[1027,5364,5365,5367,5369,5371,5373,5375],{"class":1029,"line":1041},[1027,5366,2935],{"class":2305},[1027,5368,2954],{"class":2325},[1027,5370,2940],{"class":2305},[1027,5372,2351],{"class":1091},[1027,5374,2175],{"class":1095},[1027,5376,2947],{"class":1091},[1027,5378,5379,5381],{"class":1029,"line":1053},[1027,5380,2935],{"class":2305},[1027,5382,2320],{"class":1065},[1027,5384,5385,5387],{"class":1029,"line":1069},[1027,5386,2973],{"class":2325},[1027,5388,2360],{"class":1065},[1027,5390,5391,5393],{"class":1029,"line":1080},[1027,5392,2980],{"class":2325},[1027,5394,2360],{"class":1065},[1027,5396,5397,5399],{"class":1029,"line":1104},[1027,5398,2987],{"class":2325},[1027,5400,2360],{"class":1065},[1027,5402,5403,5405],{"class":1029,"line":1115},[1027,5404,2994],{"class":2325},[1027,5406,2360],{"class":1065},[1027,5408,5409,5411,5413,5415,5417],{"class":1029,"line":1126},[1027,5410,3001],{"class":1065},[1027,5412,3004],{"class":2305},[1027,5414,2351],{"class":1091},[1027,5416,861],{"class":1095},[1027,5418,2947],{"class":1091},[1027,5420,5421,5423,5425,5427,5429,5431,5433,5435],{"class":1029,"line":1135},[1027,5422,2935],{"class":2305},[1027,5424,2881],{"class":1065},[1027,5426,1345],{"class":2325},[1027,5428,3021],{"class":1065},[1027,5430,3004],{"class":2305},[1027,5432,2351],{"class":1091},[1027,5434,861],{"class":1095},[1027,5436,2947],{"class":1091},[1027,5438,5439,5441,5443,5445,5447,5449,5451,5453,5455],{"class":1029,"line":1143},[1027,5440,2935],{"class":2305},[1027,5442,2881],{"class":1065},[1027,5444,3038],{"class":2325},[1027,5446,3021],{"class":1065},[1027,5448,3004],{"class":2305},[1027,5450,2351],{"class":1091},[1027,5452,3047],{"class":1095},[1027,5454,2357],{"class":1091},[1027,5456,3052],{"class":1065},[1027,5458,5459],{"class":1029,"line":1151},[1027,5460,1641],{"emptyLinePlaceholder":8},[1027,5462,5463,5465,5467,5469,5471],{"class":1029,"line":1159},[1027,5464,3061],{"class":2309},[1027,5466,3064],{"class":2313},[1027,5468,2317],{"class":1037},[1027,5470,2196],{"class":1283},[1027,5472,3071],{"class":1065},[1027,5474,5475,5477,5479,5481,5483,5485],{"class":1029,"line":1167},[1027,5476,3076],{"class":2325},[1027,5478,1008],{"class":1065},[1027,5480,3081],{"class":1283},[1027,5482,3084],{"class":1065},[1027,5484,3087],{"class":1283},[1027,5486,3090],{"class":1065},[1027,5488,5489],{"class":1029,"line":1175},[1027,5490,1641],{"emptyLinePlaceholder":8},[1027,5492,5493,5495,5497,5499,5501],{"class":1029,"line":1183},[1027,5494,3099],{"class":2305},[1027,5496,3102],{"class":1283},[1027,5498,3084],{"class":1065},[1027,5500,3038],{"class":2325},[1027,5502,3109],{"class":1065},[1027,5504,5505,5507,5509,5511,5513,5515],{"class":1029,"line":1195},[1027,5506,3076],{"class":2325},[1027,5508,1008],{"class":1065},[1027,5510,3081],{"class":1283},[1027,5512,3084],{"class":1065},[1027,5514,3122],{"class":2325},[1027,5516,3109],{"class":1065},[1027,5518,5519,5521,5523,5525,5527,5529],{"class":1029,"line":1203},[1027,5520,3076],{"class":2325},[1027,5522,1008],{"class":1065},[1027,5524,3081],{"class":1283},[1027,5526,3084],{"class":1065},[1027,5528,3137],{"class":2325},[1027,5530,3109],{"class":1065},[1027,5532,5533,5535,5537,5539,5541,5543],{"class":1029,"line":1217},[1027,5534,3076],{"class":2325},[1027,5536,1008],{"class":1065},[1027,5538,3081],{"class":1283},[1027,5540,3084],{"class":1065},[1027,5542,3152],{"class":2325},[1027,5544,3109],{"class":1065},[1027,5546,5547,5549,5551,5553,5555,5557],{"class":1029,"line":1225},[1027,5548,3076],{"class":2325},[1027,5550,1008],{"class":1065},[1027,5552,3081],{"class":1283},[1027,5554,3084],{"class":1065},[1027,5556,3167],{"class":2325},[1027,5558,3109],{"class":1065},[1027,5560,5561],{"class":1029,"line":1237},[1027,5562,1641],{"emptyLinePlaceholder":8},[1027,5564,5565,5567,5569,5571,5573,5575],{"class":1029,"line":1245},[1027,5566,3076],{"class":2325},[1027,5568,1008],{"class":1065},[1027,5570,3182],{"class":1283},[1027,5572,3084],{"class":1065},[1027,5574,3187],{"class":1191},[1027,5576,3109],{"class":1065},[1267,5578,3193],{"id":3192},[856,5580,3196,5581,3199],{},[887,5582,399],{"href":35},[2106,5584,5585,5605,5625,5645],{},[1017,5586,5587],{"className":1273,"code":3204,"filename":2111,"language":1276,"meta":1023,"style":1023},[859,5588,5589],{"__ignoreMap":1023},[1027,5590,5591,5593,5595,5597,5599,5601,5603],{"class":1029,"line":1030},[1027,5592,2111],{"class":1283},[1027,5594,3213],{"class":1095},[1027,5596,3216],{"class":1095},[1027,5598,3219],{"class":1061},[1027,5600,1092],{"class":1091},[1027,5602,3224],{"class":1095},[1027,5604,1214],{"class":1091},[1017,5606,5607],{"className":1273,"code":3229,"filename":2127,"language":1276,"meta":1023,"style":1023},[859,5608,5609],{"__ignoreMap":1023},[1027,5610,5611,5613,5615,5617,5619,5621,5623],{"class":1029,"line":1030},[1027,5612,2127],{"class":1283},[1027,5614,3213],{"class":1095},[1027,5616,3216],{"class":1095},[1027,5618,3219],{"class":1061},[1027,5620,1092],{"class":1091},[1027,5622,3224],{"class":1095},[1027,5624,1214],{"class":1091},[1017,5626,5627],{"className":1273,"code":3250,"filename":2141,"language":1276,"meta":1023,"style":1023},[859,5628,5629],{"__ignoreMap":1023},[1027,5630,5631,5633,5635,5637,5639,5641,5643],{"class":1029,"line":1030},[1027,5632,3257],{"class":1283},[1027,5634,3213],{"class":1095},[1027,5636,3216],{"class":1095},[1027,5638,3219],{"class":1061},[1027,5640,1092],{"class":1091},[1027,5642,3224],{"class":1095},[1027,5644,1214],{"class":1091},[1017,5646,5647],{"className":1273,"code":3272,"filename":2156,"language":1276,"meta":1023,"style":1023},[859,5648,5649],{"__ignoreMap":1023},[1027,5650,5651,5653,5655,5657,5659,5661,5663],{"class":1029,"line":1030},[1027,5652,3279],{"class":1283},[1027,5654,3213],{"class":1095},[1027,5656,3216],{"class":1095},[1027,5658,3219],{"class":1061},[1027,5660,1092],{"class":1091},[1027,5662,3224],{"class":1095},[1027,5664,1214],{"class":1091},[856,5666,3294,5667,3298,5669,3302],{},[859,5668,3297],{},[887,5670,3301],{"href":35},[1267,5672,3306],{"id":3305},[856,5674,3309,5675,3312,5677,3315],{},[859,5676,2404],{},[859,5678,991],{},[1017,5680,5681],{"className":1273,"code":3318,"filename":1275,"language":1276,"meta":1023,"style":1023},[859,5682,5683],{"__ignoreMap":1023},[1027,5684,5685,5687],{"class":1029,"line":1030},[1027,5686,2404],{"class":1283},[1027,5688,3327],{"class":1095},[856,5690,3330,5691,3334,5693,1008],{},[859,5692,3333],{},[859,5694,3337],{},[856,5696,3340],{},[3342,5698,5699,5705,5713],{},[878,5700,3346,5701,3350,5703,1008],{},[887,5702,3349],{"href":611},[859,5704,3353],{},[878,5706,3356,5707,969,5709,969,5711,3366],{},[859,5708,3359],{},[859,5710,3362],{},[859,5712,3365],{},[878,5714,3369],{},[856,5716,3372],{},[1017,5718,5719],{"className":2295,"code":3375,"filename":3376,"language":2298,"meta":1023,"style":1023},[859,5720,5721,5739],{"__ignoreMap":1023},[1027,5722,5723,5725,5727,5729,5731,5733,5735,5737],{"class":1029,"line":1030},[1027,5724,2935],{"class":2305},[1027,5726,2881],{"class":1065},[1027,5728,3387],{"class":2325},[1027,5730,3021],{"class":1065},[1027,5732,3004],{"class":2305},[1027,5734,2351],{"class":1091},[1027,5736,861],{"class":1095},[1027,5738,2947],{"class":1091},[1027,5740,5741,5743,5745,5747,5749],{"class":1029,"line":1041},[1027,5742,3099],{"class":2305},[1027,5744,3404],{"class":1283},[1027,5746,3084],{"class":1065},[1027,5748,3038],{"class":2325},[1027,5750,3109],{"class":1065},[947,5752,5753],{"color":949,"icon":3413},[856,5754,3294,5755,3418,5757,3422],{},[859,5756,2404],{},[859,5758,3421],{},[1325,5760,5761],{},[856,5762,2268,5763,3429],{},[859,5764,2271],{},[958,5766],{},[978,5768,3435,5769],{"id":3434},[859,5770,3438],{},[856,5772,3441,5773,3444],{},[859,5774,3438],{},[1017,5776,5777],{"className":2295,"code":3447,"filename":2928,"language":2298,"meta":1023,"style":1023},[859,5778,5779,5797,5801,5819],{"__ignoreMap":1023},[1027,5780,5781,5783,5785,5787,5789,5791,5793,5795],{"class":1029,"line":1030},[1027,5782,2935],{"class":2305},[1027,5784,2881],{"class":1065},[1027,5786,3438],{"class":2325},[1027,5788,3021],{"class":1065},[1027,5790,3004],{"class":2305},[1027,5792,2351],{"class":1091},[1027,5794,3466],{"class":1095},[1027,5796,2947],{"class":1091},[1027,5798,5799],{"class":1029,"line":1041},[1027,5800,1641],{"emptyLinePlaceholder":8},[1027,5802,5803,5805,5807,5809,5811,5813,5815,5817],{"class":1029,"line":1053},[1027,5804,3061],{"class":2309},[1027,5806,3064],{"class":2313},[1027,5808,2317],{"class":1037},[1027,5810,3483],{"class":2305},[1027,5812,3486],{"class":1283},[1027,5814,3084],{"class":1065},[1027,5816,3038],{"class":2325},[1027,5818,3109],{"class":1065},[1027,5820,5821,5823,5825,5827,5829,5831,5833,5835,5837,5839],{"class":1029,"line":1069},[1027,5822,3076],{"class":2325},[1027,5824,1008],{"class":1065},[1027,5826,3182],{"class":1283},[1027,5828,3084],{"class":1065},[1027,5830,3187],{"class":1191},[1027,5832,969],{"class":1065},[1027,5834,2357],{"class":1091},[1027,5836,3511],{"class":1095},[1027,5838,2357],{"class":1091},[1027,5840,3109],{"class":1065},[856,5842,3518,5843,3521],{},[859,5844,3438],{},[3342,5846,5847,5851,5853,5855,5857,5861,5863,5865,5867,5871,5873,5877,5881,5885,5887,5889,5891,5893,5895,5897,5899,5901],{},[878,5848,3526,5849,2055],{},[859,5850,2094],{},[878,5852,3531],{},[878,5854,3534],{},[878,5856,3537],{},[878,5858,3540,5859],{},[859,5860,3543],{},[878,5862,3546],{},[878,5864,3549],{},[878,5866,3552],{},[878,5868,3555,5869,3559],{},[859,5870,3558],{},[878,5872,3562],{},[878,5874,5875],{},[859,5876,3567],{},[878,5878,5879],{},[859,5880,2175],{},[878,5882,3574,5883,3578],{},[859,5884,3577],{},[878,5886,3581],{},[878,5888,3584],{},[878,5890,3587],{},[878,5892,3590],{},[878,5894,3593],{},[878,5896,3596],{},[878,5898,3599],{},[878,5900,3602],{},[878,5902,3605],{},[1393,5904,5905],{},[856,5906,3610],{},[958,5908],{},[864,5910,3616],{"id":3615},[856,5912,3619],{},[2004,5914,5915,5925],{},[2007,5916,5917],{},[2010,5918,5919,5921,5923],{},[2013,5920,3628],{},[2013,5922,3631],{},[2013,5924,3634],{},[2020,5926,5927,5939,5953],{},[2010,5928,5929,5933,5937],{},[2025,5930,5931],{},[859,5932,3333],{},[2025,5934,5935],{},[859,5936,1014],{},[2025,5938,3649],{},[2010,5940,5941,5945,5949],{},[2025,5942,5943],{},[859,5944,3656],{},[2025,5946,5947],{},[859,5948,3661],{},[2025,5950,3664,5951,3668],{},[859,5952,3667],{},[2010,5954,5955,5959,5961],{},[2025,5956,5957],{},[859,5958,3675],{},[2025,5960,3678],{},[2025,5962,3664,5963,3684],{},[859,5964,3683],{},[3686,5966,3688],{},{"title":1023,"searchDepth":1041,"depth":1041,"links":5968},[5969,5970,5974,5978],{"id":866,"depth":1041,"text":867},{"id":962,"depth":1041,"text":963,"children":5971},[5972,5973],{"id":980,"depth":1053,"text":981},{"id":1998,"depth":1053,"text":1999},{"id":2100,"depth":1041,"text":2101,"children":5975},[5976,5977],{"id":2258,"depth":1053,"text":2259},{"id":3434,"depth":1053,"text":3700},{"id":3615,"depth":1041,"text":3616},{},{"title":14,"description":3702},1780436278737]