[{"data":1,"prerenderedAt":4387},["ShallowReactive",2],{"navLinks":3,"sidebar_docs_navigation_\u002Fdocs\u002Fiam":64,"navigation":257,"navLinks_footer":837,"\u002Fdocs\u002Fiam\u002Fessentials\u002Femails_page":850,"\u002Fdocs\u002Fiam\u002Fessentials\u002Femails_surround":2872,"\u002Fdocs\u002Fiam\u002Fessentials\u002Femails":2875},{"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":119,"body":852,"description":2864,"extension":2865,"icon":2866,"meta":2867,"module":2868,"navigation":8,"path":120,"rawbody":2869,"seo":2870,"stem":121,"__hash__":2871},"docs\u002Fdocs\u002Fiam\u002F01.essentials\u002F09.emails.md",{"type":853,"value":854,"toc":2835},"minimark",[855,878,890,903,906,911,916,1058,1061,1125,1127,1131,1136,1142,1153,1229,1238,1242,1247,1258,1319,1327,1329,1333,1348,1352,1456,1460,1548,1550,1554,1567,1573,1591,1716,1736,1741,1753,1814,1830,1835,1843,1997,2006,2008,2012,2022,2026,2086,2093,2097,2153,2159,2163,2209,2215,2219,2228,2361,2377,2379,2383,2395,2517,2528,2541,2551,2553,2557,2568,2680,2699,2713,2715,2719,2723,2729,2751,2755,2760,2791,2795,2800,2831],[856,857,858,859,866,867,871,872,877],"p",{},"The IAM service sends transactional emails through the ",[860,861,865],"a",{"href":862,"rel":863},"https:\u002F\u002Fresend.com\u002F",[864],"nofollow","Resend"," SDK. Every outbound email passes through a single function, ",[868,869,870],"code",{},"sendSystemEmail",", which resolves an ",[860,873,876],{"href":874,"rel":875},"https:\u002F\u002Fejs.co\u002F",[864],"EJS"," template by name, renders it with the provided data, and hands the resulting HTML to Resend for delivery.",[856,879,880,881,885,886,889],{},"Two categories of email ship out of the box: ",[882,883,884],"strong",{},"OTP emails"," (used by adaptive MFA, custom MFA, and email update flows) and ",[882,887,888],{},"notification emails"," (used by password reset confirmations, email change alerts, and any custom notification you define). Both categories use responsive HTML templates tested across major email clients.",[856,891,892,893,897,898,902],{},"Before any email is sent, the service can optionally validate the recipient address in two layers: a ",[860,894,896],{"href":895},"#disposable-email-detection","disposable-email check"," against an LMDB database and a ",[860,899,901],{"href":900},"#mx-record-validation","DNS MX lookup"," to confirm the domain accepts mail.",[904,905],"hr",{},[907,908,910],"h2",{"id":909},"delivery-pipeline","Delivery pipeline",[856,912,913,915],{},[868,914,870],{}," is the single entry point for all outbound email. It accepts a recipient (or array of recipients), a subject line, a data object for template interpolation, and a template path relative to the emails directory.",[917,918,923],"pre",{"className":919,"code":920,"language":921,"meta":922,"style":922},"language-ts shiki shiki-themes light-plus light-plus dracula","import { sendSystemEmail } from '@riavzon\u002Fauth'\n\nawait sendSystemEmail(\n  'user@example.com',\n  'Welcome to Our Service',\n  { name: 'Alice', loginUrl: 'https:\u002F\u002Fexample.com\u002Flogin' },\n  'welcome'\n)\n","ts","",[868,924,925,958,964,977,992,1004,1042,1052],{"__ignoreMap":922},[926,927,930,934,938,941,944,947,951,955],"span",{"class":928,"line":929},"line",1,[926,931,933],{"class":932},"sZ328","import",[926,935,937],{"class":936},"sDd4n"," { ",[926,939,870],{"class":940},"sjsA6",[926,942,943],{"class":936}," } ",[926,945,946],{"class":932},"from",[926,948,950],{"class":949},"sFkSl"," '",[926,952,954],{"class":953},"sFB1V","@riavzon\u002Fauth",[926,956,957],{"class":949},"'\n",[926,959,961],{"class":928,"line":960},2,[926,962,963],{"emptyLinePlaceholder":8},"\n",[926,965,967,970,974],{"class":928,"line":966},3,[926,968,969],{"class":932},"await",[926,971,973],{"class":972},"sHOzp"," sendSystemEmail",[926,975,976],{"class":936},"(\n",[926,978,980,983,986,989],{"class":928,"line":979},4,[926,981,982],{"class":949},"  '",[926,984,985],{"class":953},"user@example.com",[926,987,988],{"class":949},"'",[926,990,991],{"class":936},",\n",[926,993,995,997,1000,1002],{"class":928,"line":994},5,[926,996,982],{"class":949},[926,998,999],{"class":953},"Welcome to Our Service",[926,1001,988],{"class":949},[926,1003,991],{"class":936},[926,1005,1007,1010,1013,1017,1019,1022,1024,1027,1030,1032,1034,1037,1039],{"class":928,"line":1006},6,[926,1008,1009],{"class":936},"  { ",[926,1011,1012],{"class":940},"name",[926,1014,1016],{"class":1015},"s34zl",":",[926,1018,950],{"class":949},[926,1020,1021],{"class":953},"Alice",[926,1023,988],{"class":949},[926,1025,1026],{"class":936},", ",[926,1028,1029],{"class":940},"loginUrl",[926,1031,1016],{"class":1015},[926,1033,950],{"class":949},[926,1035,1036],{"class":953},"https:\u002F\u002Fexample.com\u002Flogin",[926,1038,988],{"class":949},[926,1040,1041],{"class":936}," },\n",[926,1043,1045,1047,1050],{"class":928,"line":1044},7,[926,1046,982],{"class":949},[926,1048,1049],{"class":953},"welcome",[926,1051,957],{"class":949},[926,1053,1055],{"class":928,"line":1054},8,[926,1056,1057],{"class":936},")\n",[856,1059,1060],{},"Internally the function performs three steps:",[1062,1063,1065,1070,1091,1095,1110,1114],"steps",{"level":1064},"4",[1066,1067,1069],"h4",{"id":1068},"template-resolution","Template resolution",[856,1071,1072,1073,1076,1077,1026,1080,1083,1084,1087,1088,1090],{},"The function appends ",[868,1074,1075],{},".ejs"," to the template name and searches three directories in order: ",[868,1078,1079],{},"emails\u002F",[868,1081,1082],{},"dist\u002Femails\u002F",", and ",[868,1085,1086],{},"src\u002FjwtAuth\u002Femails\u002F",". The first match wins. This search order lets you place custom templates in the top-level ",[868,1089,1079],{}," directory without modifying the source tree.",[1066,1092,1094],{"id":1093},"ejs-rendering","EJS rendering",[856,1096,1097,1098,1101,1102,1105,1106,1109],{},"The data object is spread into the template as local variables. Templates use standard EJS syntax: ",[868,1099,1100],{},"\u003C%= variable %>"," for escaped output and ",[868,1103,1104],{},"\u003C%- variable %>"," for raw HTML (used by the notification template's ",[868,1107,1108],{},"message"," field).",[1066,1111,1113],{"id":1112},"resend-delivery","Resend delivery",[856,1115,1116,1117,1120,1121,1124],{},"The rendered HTML is sent via ",[868,1118,1119],{},"resend.emails.send()"," using the API key and sender address from the ",[868,1122,1123],{},"email"," configuration block. The function logs the Resend response and throws on render failures, but logs and returns silently on Resend API errors to avoid crashing the caller.",[904,1126],{},[907,1128,1130],{"id":1129},"built-in-templates","Built-in templates",[1132,1133,1135],"h3",{"id":1134},"otp-template","OTP template",[856,1137,1138,1139],{},"Path: ",[868,1140,1141],{},"OTP\u002Findex.ejs",[856,1143,1144,1145,1148,1149,1152],{},"The OTP template is used by ",[868,1146,1147],{},"sendTempMfaLink"," (adaptive MFA) and ",[868,1150,1151],{},"generateCustomMfaFlow"," (custom MFA and email update). It renders a responsive email with five sections:",[1154,1155,1156,1169],"table",{},[1157,1158,1159],"thead",{},[1160,1161,1162,1166],"tr",{},[1163,1164,1165],"th",{},"Section",[1163,1167,1168],{},"Content",[1170,1171,1172,1185,1193,1213,1221],"tbody",{},[1160,1173,1174,1178],{},[1175,1176,1177],"td",{},"Banner",[1175,1179,1180,1181,1184],{},"A configurable image at the top of the email (",[868,1182,1183],{},"banner_image",")",[1160,1186,1187,1190],{},[1175,1188,1189],{},"Code display",[1175,1191,1192],{},"The 7-digit OTP code shown in a bordered button that also links to the magic link URL",[1160,1194,1195,1198],{},[1175,1196,1197],{},"Metadata row",[1175,1199,1200,1201,1204,1205,1208,1209,1212],{},"Three columns showing ",[882,1202,1203],{},"Device"," (browser + OS), ",[882,1206,1207],{},"Location"," (IP-based), and ",[882,1210,1211],{},"Date"," (server timestamp) with configurable icons",[1160,1214,1215,1218],{},[1175,1216,1217],{},"Security warning",[1175,1219,1220],{},"A message warning the user to reset their password if they did not request the code, with a link to the configured reset-password page",[1160,1222,1223,1226],{},[1175,1224,1225],{},"CTA button",[1175,1227,1228],{},"A \"Verify Here\" button linking to the magic link URL",[856,1230,1231,1232,1237],{},"The template uses the ",[860,1233,1236],{"href":1234,"rel":1235},"https:\u002F\u002Ffonts.google.com\u002Fspecimen\u002FMontserrat",[864],"Montserrat"," font family and is built with table-based layout for maximum email client compatibility, including Outlook (MSO conditional comments).",[1132,1239,1241],{"id":1240},"notification-template","Notification template",[856,1243,1138,1244],{},[868,1245,1246],{},"nottifications\u002Findex.ejs",[856,1248,1249,1250,1253,1254,1257],{},"The notification template is used by ",[868,1251,1252],{},"resetPasswordEmail"," (password reset confirmation) and ",[868,1255,1256],{},"sendEmailNotification"," (generic notifications such as the email-change alert). It renders a simpler layout:",[1154,1259,1260,1268],{},[1157,1261,1262],{},[1160,1263,1264,1266],{},[1163,1265,1165],{},[1163,1267,1168],{},[1170,1269,1270,1281,1289,1304,1311],{},[1160,1271,1272,1275],{},[1175,1273,1274],{},"Header image",[1175,1276,1277,1278,1184],{},"A configurable banner (",[868,1279,1280],{},"main_image",[1160,1282,1283,1286],{},[1175,1284,1285],{},"Title and action",[1175,1287,1288],{},"Bold title with a subtitle instruction line",[1160,1290,1291,1294],{},[1175,1292,1293],{},"Body",[1175,1295,1296,1297,1299,1300,1303],{},"A letter-style block: \"Dear {username}\", followed by the ",[868,1298,1108],{}," field (supports raw HTML via ",[868,1301,1302],{},"\u003C%-","), a security warning, and a signature with the website name",[1160,1305,1306,1308],{},[1175,1307,1225],{},[1175,1309,1310],{},"A configurable button label and link",[1160,1312,1313,1316],{},[1175,1314,1315],{},"Footer",[1175,1317,1318],{},"Privacy policy and contact page links",[856,1320,1231,1321,1326],{},[860,1322,1325],{"href":1323,"rel":1324},"https:\u002F\u002Ffonts.google.com\u002Fspecimen\u002FRaleway",[864],"Raleway"," font family.",[904,1328],{},[907,1330,1332],{"id":1331},"template-variables","Template variables",[856,1334,1335,1336,1339,1340,1343,1344,1347],{},"Each template type expects a specific data shape. The service defines two TypeScript interfaces, ",[868,1337,1338],{},"OTPEmails"," and ",[868,1341,1342],{},"NotificationEmails",", unified under the ",[868,1345,1346],{},"EmailData"," type.",[1132,1349,1351],{"id":1350},"otp-variables","OTP variables",[1353,1354,1355,1364,1370,1384,1396,1408,1417,1427,1432,1438,1444,1450],"field-group",{},[1356,1357,1361],"field",{"name":1358,"type":1359,":required":1360},"link","string","true",[856,1362,1363],{},"The full magic link URL the button points to.",[1356,1365,1367],{"name":868,"type":1366,":required":1360},"string | number",[856,1368,1369],{},"The 7-digit OTP code displayed in the email body.",[1356,1371,1373],{"name":1372,"type":1359},"device",[856,1374,1375,1376,1379,1380,1383],{},"OS string shown in the Device column (e.g. ",[868,1377,1378],{},"'macOS'","). Falls back to ",[868,1381,1382],{},"'Unknown Device'",".",[1356,1385,1387],{"name":1386,"type":1359},"browser",[856,1388,1389,1390,1379,1393,1383],{},"Browser name shown in the Device column (e.g. ",[868,1391,1392],{},"'Chrome 125'",[868,1394,1395],{},"'Unknown Browser'",[1356,1397,1399],{"name":1398,"type":1359},"location",[856,1400,1401,1402,1379,1405,1383],{},"IP-based location string shown in the Location column (e.g. ",[868,1403,1404],{},"'Berlin, DE'",[868,1406,1407],{},"'Unknown Location'",[1356,1409,1411],{"name":1410,"type":1359},"date",[856,1412,1413,1414,1383],{},"Formatted timestamp shown in the Date column. Generated server-side via ",[868,1415,1416],{},"new Date().toLocaleString()",[1356,1418,1420],{"name":1419,"type":1359},"cta",[856,1421,1422,1423,1426],{},"Button label text. Default ",[868,1424,1425],{},"'Verify Here'"," for MFA emails.",[1356,1428,1429],{"name":1183,"type":1359},[856,1430,1431],{},"URL to the banner image displayed at the top of the email.",[1356,1433,1435],{"name":1434,"type":1359},"device_image",[856,1436,1437],{},"URL to the icon displayed above the Device column.",[1356,1439,1441],{"name":1440,"type":1359},"location_image",[856,1442,1443],{},"URL to the icon displayed above the Location column.",[1356,1445,1447],{"name":1446,"type":1359},"date_image",[856,1448,1449],{},"URL to the icon displayed above the Date column.",[1356,1451,1453],{"name":1452,"type":1359},"link_to_reset_password",[856,1454,1455],{},"URL to the password reset page, shown in the security warning section.",[1132,1457,1459],{"id":1458},"notification-variables","Notification variables",[1353,1461,1462,1468,1478,1484,1490,1508,1519,1525,1531,1537,1543],{},[1356,1463,1465],{"name":1464,"type":1359,":required":1360},"title",[856,1466,1467],{},"The big header text at the top of the email body.",[1356,1469,1471],{"name":1470,"type":1359,":required":1360},"action",[856,1472,1473,1474,1477],{},"Sub-header instruction line below the title (e.g. ",[868,1475,1476],{},"'Please reset your password'",").",[1356,1479,1481],{"name":1480,"type":1359,":required":1360},"subject",[856,1482,1483],{},"The email subject line. Also rendered inside the body as a \"Subject:\" heading.",[1356,1485,1487],{"name":1486,"type":1359,":required":1360},"username",[856,1488,1489],{},"The recipient's display name, used in the \"Dear {username}\" greeting.",[1356,1491,1492],{"name":1108,"type":1359,":required":1360},[856,1493,1494,1495,1497,1498,1026,1501,1083,1504,1507],{},"The main body text. Supports raw HTML (rendered with ",[868,1496,1302],{},"). Use ",[868,1499,1500],{},"\u003Cb>",[868,1502,1503],{},"\u003Cbr\u002F>",[868,1505,1506],{},"\u003Ca>"," tags for formatting.",[1356,1509,1510],{"name":1419,"type":1359,":required":1360},[856,1511,1512,1513,1026,1516,1477],{},"Button label text (e.g. ",[868,1514,1515],{},"'Change Password'",[868,1517,1518],{},"'Contact Support'",[1356,1520,1522],{"name":1521,"type":1359,":required":1360},"cta_link",[856,1523,1524],{},"URL the CTA button points to.",[1356,1526,1528],{"name":1527,"type":1359,":required":1360},"websiteName",[856,1529,1530],{},"Your website name, shown in the email signature.",[1356,1532,1534],{"name":1533,"type":1359,":required":1360},"privacy_link",[856,1535,1536],{},"URL to your privacy policy page, linked in the footer.",[1356,1538,1540],{"name":1539,"type":1359,":required":1360},"contact_link",[856,1541,1542],{},"URL to your contact page, linked in the footer.",[1356,1544,1545],{"name":1280,"type":1359,":required":1360},[856,1546,1547],{},"URL to the header banner image.",[904,1549],{},[907,1551,1553],{"id":1552},"helper-functions","Helper functions",[856,1555,1556,1557,1559,1560,1339,1563,1566],{},"Three helper functions wrap ",[868,1558,870],{}," with pre-configured templates and data shapes. Each one reads configuration values from ",[868,1561,1562],{},"magic_links.emailImages",[868,1564,1565],{},"magic_links.notificationEmail",", so the caller only needs to provide the dynamic fields.",[1132,1568,1570],{"id":1569},"mfaemail",[868,1571,1572],{},"mfaEmail",[856,1574,1575,1576,1579,1580,1339,1582,1584,1585,1587,1588,1590],{},"Sends an OTP email using the ",[868,1577,1578],{},"OTP\u002Findex"," template. Called internally by ",[868,1581,1147],{},[868,1583,1151],{},". This is an internal helper and is not exported from ",[868,1586,954],{},". Use ",[868,1589,870],{}," for custom email delivery.",[917,1592,1594],{"className":919,"code":1593,"language":921,"meta":922,"style":922},"\u002F\u002F internal — called by sendTempMfaLink and generateCustomMfaFlow\nawait mfaEmail(\n  1234567,                               \u002F\u002F 7-digit OTP code\n  'user@example.com',                    \u002F\u002F recipient\n  'https:\u002F\u002Fexample.com\u002Fauth\u002Fbounce?...', \u002F\u002F full magic link URL\n  {\n    device: 'Chrome on macOS',\n    browser: 'Chrome 125',\n    location: 'Berlin, DE',\n  }\n)\n",[868,1595,1596,1602,1611,1623,1637,1651,1656,1672,1688,1705,1711],{"__ignoreMap":922},[926,1597,1598],{"class":928,"line":929},[926,1599,1601],{"class":1600},"sghk6","\u002F\u002F internal — called by sendTempMfaLink and generateCustomMfaFlow\n",[926,1603,1604,1606,1609],{"class":928,"line":960},[926,1605,969],{"class":932},[926,1607,1608],{"class":972}," mfaEmail",[926,1610,976],{"class":936},[926,1612,1613,1617,1620],{"class":928,"line":966},[926,1614,1616],{"class":1615},"spgvN","  1234567",[926,1618,1619],{"class":936},",                               ",[926,1621,1622],{"class":1600},"\u002F\u002F 7-digit OTP code\n",[926,1624,1625,1627,1629,1631,1634],{"class":928,"line":979},[926,1626,982],{"class":949},[926,1628,985],{"class":953},[926,1630,988],{"class":949},[926,1632,1633],{"class":936},",                    ",[926,1635,1636],{"class":1600},"\u002F\u002F recipient\n",[926,1638,1639,1641,1644,1646,1648],{"class":928,"line":994},[926,1640,982],{"class":949},[926,1642,1643],{"class":953},"https:\u002F\u002Fexample.com\u002Fauth\u002Fbounce?...",[926,1645,988],{"class":949},[926,1647,1026],{"class":936},[926,1649,1650],{"class":1600},"\u002F\u002F full magic link URL\n",[926,1652,1653],{"class":928,"line":1006},[926,1654,1655],{"class":936},"  {\n",[926,1657,1658,1661,1663,1665,1668,1670],{"class":928,"line":1044},[926,1659,1660],{"class":940},"    device",[926,1662,1016],{"class":1015},[926,1664,950],{"class":949},[926,1666,1667],{"class":953},"Chrome on macOS",[926,1669,988],{"class":949},[926,1671,991],{"class":936},[926,1673,1674,1677,1679,1681,1684,1686],{"class":928,"line":1054},[926,1675,1676],{"class":940},"    browser",[926,1678,1016],{"class":1015},[926,1680,950],{"class":949},[926,1682,1683],{"class":953},"Chrome 125",[926,1685,988],{"class":949},[926,1687,991],{"class":936},[926,1689,1691,1694,1696,1698,1701,1703],{"class":928,"line":1690},9,[926,1692,1693],{"class":940},"    location",[926,1695,1016],{"class":1015},[926,1697,950],{"class":949},[926,1699,1700],{"class":953},"Berlin, DE",[926,1702,988],{"class":949},[926,1704,991],{"class":936},[926,1706,1708],{"class":928,"line":1707},10,[926,1709,1710],{"class":936},"  }\n",[926,1712,1714],{"class":928,"line":1713},11,[926,1715,1057],{"class":936},[856,1717,1718,1719,1722,1723,1726,1727,1729,1730,1732,1733,1383],{},"The function reads ",[868,1720,1721],{},"emailImages.otp"," for the four image URLs and ",[868,1724,1725],{},"linkToResetPasswordPage"," for the security warning link. The ",[868,1728,1410],{}," field is generated automatically from ",[868,1731,1416],{},". The email subject is formatted as ",[868,1734,1735],{},"Security Code - {code}",[1132,1737,1739],{"id":1738},"resetpasswordemail",[868,1740,1252],{},[856,1742,1743,1744,1579,1747,1750,1751,1383],{},"Sends a notification email using the ",[868,1745,1746],{},"nottifications\u002Findex",[868,1748,1749],{},"sendTempPasswordResetLink"," when a user requests a password reset. This is an internal helper and is not exported from ",[868,1752,954],{},[917,1754,1756],{"className":919,"code":1755,"language":921,"meta":922,"style":922},"\u002F\u002F internal — called by sendTempPasswordResetLink\nawait resetPasswordEmail(\n  'Alice',                               \u002F\u002F user's display name\n  'alice@example.com',                   \u002F\u002F recipient\n  'https:\u002F\u002Fexample.com\u002Fauth\u002Fbounce?...'  \u002F\u002F password reset URL\n)\n",[868,1757,1758,1763,1772,1785,1799,1810],{"__ignoreMap":922},[926,1759,1760],{"class":928,"line":929},[926,1761,1762],{"class":1600},"\u002F\u002F internal — called by sendTempPasswordResetLink\n",[926,1764,1765,1767,1770],{"class":928,"line":960},[926,1766,969],{"class":932},[926,1768,1769],{"class":972}," resetPasswordEmail",[926,1771,976],{"class":936},[926,1773,1774,1776,1778,1780,1782],{"class":928,"line":966},[926,1775,982],{"class":949},[926,1777,1021],{"class":953},[926,1779,988],{"class":949},[926,1781,1619],{"class":936},[926,1783,1784],{"class":1600},"\u002F\u002F user's display name\n",[926,1786,1787,1789,1792,1794,1797],{"class":928,"line":979},[926,1788,982],{"class":949},[926,1790,1791],{"class":953},"alice@example.com",[926,1793,988],{"class":949},[926,1795,1796],{"class":936},",                   ",[926,1798,1636],{"class":1600},[926,1800,1801,1803,1805,1807],{"class":928,"line":994},[926,1802,982],{"class":949},[926,1804,1643],{"class":953},[926,1806,988],{"class":949},[926,1808,1809],{"class":1600},"  \u002F\u002F password reset URL\n",[926,1811,1812],{"class":928,"line":1006},[926,1813,1057],{"class":936},[856,1815,1718,1816,1819,1820,1823,1824,1826,1827,1383],{},[868,1817,1818],{},"emailImages.notificationBanner"," for the header image and ",[868,1821,1822],{},"notificationEmail.*"," for the website name, privacy link, contact link, and change-password page link. The CTA button label is ",[868,1825,1515],{}," and the subject is ",[868,1828,1829],{},"'Password Reset Request'",[1132,1831,1833],{"id":1832},"sendemailnotification",[868,1834,1256],{},[856,1836,1837,1838,1587,1840,1842],{},"Sends a customizable notification email. Called by the email update controller to alert the user that their email address has changed. This is an internal helper and is not exported from ",[868,1839,954],{},[868,1841,870],{}," for custom notifications.",[917,1844,1846],{"className":919,"code":1845,"language":921,"meta":922,"style":922},"\u002F\u002F internal — called by updateEmailController and verifyPasswordReset\nawait sendEmailNotification(\n  'alice@example.com',\n  'Alice',\n  {\n    title: 'Your Email Has Changed',\n    action: 'Notice of Change',\n    subject: 'Security Alert: Email Address Updated',\n    message:\n      'Your email has been updated to \u003Cb>new@example.com\u003C\u002Fb>.\u003Cbr\u002F>If you did not authorize this, contact support.',\n    cta: 'Contact Support',\n    cta_link: 'https:\u002F\u002Fexample.com\u002Fcontact',\n  }\n)\n",[868,1847,1848,1853,1862,1872,1882,1886,1902,1918,1934,1942,1954,1970,1987,1992],{"__ignoreMap":922},[926,1849,1850],{"class":928,"line":929},[926,1851,1852],{"class":1600},"\u002F\u002F internal — called by updateEmailController and verifyPasswordReset\n",[926,1854,1855,1857,1860],{"class":928,"line":960},[926,1856,969],{"class":932},[926,1858,1859],{"class":972}," sendEmailNotification",[926,1861,976],{"class":936},[926,1863,1864,1866,1868,1870],{"class":928,"line":966},[926,1865,982],{"class":949},[926,1867,1791],{"class":953},[926,1869,988],{"class":949},[926,1871,991],{"class":936},[926,1873,1874,1876,1878,1880],{"class":928,"line":979},[926,1875,982],{"class":949},[926,1877,1021],{"class":953},[926,1879,988],{"class":949},[926,1881,991],{"class":936},[926,1883,1884],{"class":928,"line":994},[926,1885,1655],{"class":936},[926,1887,1888,1891,1893,1895,1898,1900],{"class":928,"line":1006},[926,1889,1890],{"class":940},"    title",[926,1892,1016],{"class":1015},[926,1894,950],{"class":949},[926,1896,1897],{"class":953},"Your Email Has Changed",[926,1899,988],{"class":949},[926,1901,991],{"class":936},[926,1903,1904,1907,1909,1911,1914,1916],{"class":928,"line":1044},[926,1905,1906],{"class":940},"    action",[926,1908,1016],{"class":1015},[926,1910,950],{"class":949},[926,1912,1913],{"class":953},"Notice of Change",[926,1915,988],{"class":949},[926,1917,991],{"class":936},[926,1919,1920,1923,1925,1927,1930,1932],{"class":928,"line":1054},[926,1921,1922],{"class":940},"    subject",[926,1924,1016],{"class":1015},[926,1926,950],{"class":949},[926,1928,1929],{"class":953},"Security Alert: Email Address Updated",[926,1931,988],{"class":949},[926,1933,991],{"class":936},[926,1935,1936,1939],{"class":928,"line":1690},[926,1937,1938],{"class":940},"    message",[926,1940,1941],{"class":1015},":\n",[926,1943,1944,1947,1950,1952],{"class":928,"line":1707},[926,1945,1946],{"class":949},"      '",[926,1948,1949],{"class":953},"Your email has been updated to \u003Cb>new@example.com\u003C\u002Fb>.\u003Cbr\u002F>If you did not authorize this, contact support.",[926,1951,988],{"class":949},[926,1953,991],{"class":936},[926,1955,1956,1959,1961,1963,1966,1968],{"class":928,"line":1713},[926,1957,1958],{"class":940},"    cta",[926,1960,1016],{"class":1015},[926,1962,950],{"class":949},[926,1964,1965],{"class":953},"Contact Support",[926,1967,988],{"class":949},[926,1969,991],{"class":936},[926,1971,1973,1976,1978,1980,1983,1985],{"class":928,"line":1972},12,[926,1974,1975],{"class":940},"    cta_link",[926,1977,1016],{"class":1015},[926,1979,950],{"class":949},[926,1981,1982],{"class":953},"https:\u002F\u002Fexample.com\u002Fcontact",[926,1984,988],{"class":949},[926,1986,991],{"class":936},[926,1988,1990],{"class":928,"line":1989},13,[926,1991,1710],{"class":936},[926,1993,1995],{"class":928,"line":1994},14,[926,1996,1057],{"class":936},[856,1998,1999,2000,1339,2003,2005],{},"The function merges the provided fields with defaults pulled from ",[868,2001,2002],{},"notificationEmail",[868,2004,1818],{},". Any field you omit falls back to the password-reset defaults (title, action, subject, message, CTA).",[904,2007],{},[907,2009,2011],{"id":2010},"custom-templates","Custom templates",[856,2013,2014,2015,2018,2019,2021],{},"The template manager lets you register, list, and remove custom ",[860,2016,876],{"href":874,"rel":2017},[864]," templates at runtime. Custom templates are written as ",[868,2020,1075],{}," files and stored alongside the built-in templates.",[1132,2023,2025],{"id":2024},"creating-a-template","Creating a template",[917,2027,2029],{"className":919,"code":2028,"language":921,"meta":922,"style":922},"import { makeEmailTemplate } from '@riavzon\u002Fauth'\n\nawait makeEmailTemplate(\n  '\u003Ch1>Welcome, \u003C%= name %>!\u003C\u002Fh1>\u003Cp>\u003Ca href=\"\u003C%= loginUrl %>\">Sign in\u003C\u002Fa>\u003C\u002Fp>',\n  'welcome'\n)\n",[868,2030,2031,2050,2054,2063,2074,2082],{"__ignoreMap":922},[926,2032,2033,2035,2037,2040,2042,2044,2046,2048],{"class":928,"line":929},[926,2034,933],{"class":932},[926,2036,937],{"class":936},[926,2038,2039],{"class":940},"makeEmailTemplate",[926,2041,943],{"class":936},[926,2043,946],{"class":932},[926,2045,950],{"class":949},[926,2047,954],{"class":953},[926,2049,957],{"class":949},[926,2051,2052],{"class":928,"line":960},[926,2053,963],{"emptyLinePlaceholder":8},[926,2055,2056,2058,2061],{"class":928,"line":966},[926,2057,969],{"class":932},[926,2059,2060],{"class":972}," makeEmailTemplate",[926,2062,976],{"class":936},[926,2064,2065,2067,2070,2072],{"class":928,"line":979},[926,2066,982],{"class":949},[926,2068,2069],{"class":953},"\u003Ch1>Welcome, \u003C%= name %>!\u003C\u002Fh1>\u003Cp>\u003Ca href=\"\u003C%= loginUrl %>\">Sign in\u003C\u002Fa>\u003C\u002Fp>",[926,2071,988],{"class":949},[926,2073,991],{"class":936},[926,2075,2076,2078,2080],{"class":928,"line":994},[926,2077,982],{"class":949},[926,2079,1049],{"class":953},[926,2081,957],{"class":949},[926,2083,2084],{"class":928,"line":1006},[926,2085,1057],{"class":936},[856,2087,2088,2089,2092],{},"The function writes a ",[868,2090,2091],{},"welcome.ejs"," file to the emails directory. If a template with the same name already exists, it throws an error to prevent accidental overwrites.",[1132,2094,2096],{"id":2095},"listing-templates","Listing templates",[917,2098,2100],{"className":919,"code":2099,"language":921,"meta":922,"style":922},"import { listTemplates } from '@riavzon\u002Fauth'\n\nconst templates = await listTemplates()\n\u002F\u002F ['OTP\u002Findex.ejs', 'nottifications\u002Findex.ejs', 'welcome.ejs']\n",[868,2101,2102,2121,2125,2148],{"__ignoreMap":922},[926,2103,2104,2106,2108,2111,2113,2115,2117,2119],{"class":928,"line":929},[926,2105,933],{"class":932},[926,2107,937],{"class":936},[926,2109,2110],{"class":940},"listTemplates",[926,2112,943],{"class":936},[926,2114,946],{"class":932},[926,2116,950],{"class":949},[926,2118,954],{"class":953},[926,2120,957],{"class":949},[926,2122,2123],{"class":928,"line":960},[926,2124,963],{"emptyLinePlaceholder":8},[926,2126,2127,2131,2135,2139,2142,2145],{"class":928,"line":966},[926,2128,2130],{"class":2129},"sl46w","const",[926,2132,2134],{"class":2133},"s3JHE"," templates",[926,2136,2138],{"class":2137},"saOXh"," =",[926,2140,2141],{"class":932}," await",[926,2143,2144],{"class":972}," listTemplates",[926,2146,2147],{"class":936},"()\n",[926,2149,2150],{"class":928,"line":979},[926,2151,2152],{"class":1600},"\u002F\u002F ['OTP\u002Findex.ejs', 'nottifications\u002Findex.ejs', 'welcome.ejs']\n",[856,2154,2155,2156,2158],{},"Returns all ",[868,2157,1075],{}," files found recursively in the emails directory, including subdirectories.",[1132,2160,2162],{"id":2161},"deleting-a-template","Deleting a template",[917,2164,2166],{"className":919,"code":2165,"language":921,"meta":922,"style":922},"import { deleteTemplate } from '@riavzon\u002Fauth'\n\nawait deleteTemplate('welcome')\n",[868,2167,2168,2187,2191],{"__ignoreMap":922},[926,2169,2170,2172,2174,2177,2179,2181,2183,2185],{"class":928,"line":929},[926,2171,933],{"class":932},[926,2173,937],{"class":936},[926,2175,2176],{"class":940},"deleteTemplate",[926,2178,943],{"class":936},[926,2180,946],{"class":932},[926,2182,950],{"class":949},[926,2184,954],{"class":953},[926,2186,957],{"class":949},[926,2188,2189],{"class":928,"line":960},[926,2190,963],{"emptyLinePlaceholder":8},[926,2192,2193,2195,2198,2201,2203,2205,2207],{"class":928,"line":966},[926,2194,969],{"class":932},[926,2196,2197],{"class":972}," deleteTemplate",[926,2199,2200],{"class":936},"(",[926,2202,988],{"class":949},[926,2204,1049],{"class":953},[926,2206,988],{"class":949},[926,2208,1057],{"class":936},[856,2210,2211,2212,2214],{},"Removes the ",[868,2213,2091],{}," file from the emails directory. Throws if the file does not exist.",[1132,2216,2218],{"id":2217},"using-a-custom-template","Using a custom template",[856,2220,2221,2222,2224,2225,2227],{},"Pass the template name (without ",[868,2223,1075],{},") to ",[868,2226,870],{},". For templates inside subdirectories, include the path relative to the emails root:",[917,2229,2231],{"className":919,"code":2230,"language":921,"meta":922,"style":922},"await sendSystemEmail(\n  'user@example.com',\n  'Welcome!',\n  { name: 'Alice', loginUrl: 'https:\u002F\u002Fexample.com\u002Flogin' },\n  'welcome'              \u002F\u002F resolves to welcome.ejs\n)\n\nawait sendSystemEmail(\n  'user@example.com',\n  'Your Invoice',\n  invoiceData,\n  'billing\u002Finvoice'      \u002F\u002F resolves to billing\u002Finvoice.ejs\n)\n",[868,2232,2233,2241,2251,2262,2290,2301,2305,2309,2317,2327,2338,2345,2357],{"__ignoreMap":922},[926,2234,2235,2237,2239],{"class":928,"line":929},[926,2236,969],{"class":932},[926,2238,973],{"class":972},[926,2240,976],{"class":936},[926,2242,2243,2245,2247,2249],{"class":928,"line":960},[926,2244,982],{"class":949},[926,2246,985],{"class":953},[926,2248,988],{"class":949},[926,2250,991],{"class":936},[926,2252,2253,2255,2258,2260],{"class":928,"line":966},[926,2254,982],{"class":949},[926,2256,2257],{"class":953},"Welcome!",[926,2259,988],{"class":949},[926,2261,991],{"class":936},[926,2263,2264,2266,2268,2270,2272,2274,2276,2278,2280,2282,2284,2286,2288],{"class":928,"line":979},[926,2265,1009],{"class":936},[926,2267,1012],{"class":940},[926,2269,1016],{"class":1015},[926,2271,950],{"class":949},[926,2273,1021],{"class":953},[926,2275,988],{"class":949},[926,2277,1026],{"class":936},[926,2279,1029],{"class":940},[926,2281,1016],{"class":1015},[926,2283,950],{"class":949},[926,2285,1036],{"class":953},[926,2287,988],{"class":949},[926,2289,1041],{"class":936},[926,2291,2292,2294,2296,2298],{"class":928,"line":994},[926,2293,982],{"class":949},[926,2295,1049],{"class":953},[926,2297,988],{"class":949},[926,2299,2300],{"class":1600},"              \u002F\u002F resolves to welcome.ejs\n",[926,2302,2303],{"class":928,"line":1006},[926,2304,1057],{"class":936},[926,2306,2307],{"class":928,"line":1044},[926,2308,963],{"emptyLinePlaceholder":8},[926,2310,2311,2313,2315],{"class":928,"line":1054},[926,2312,969],{"class":932},[926,2314,973],{"class":972},[926,2316,976],{"class":936},[926,2318,2319,2321,2323,2325],{"class":928,"line":1690},[926,2320,982],{"class":949},[926,2322,985],{"class":953},[926,2324,988],{"class":949},[926,2326,991],{"class":936},[926,2328,2329,2331,2334,2336],{"class":928,"line":1707},[926,2330,982],{"class":949},[926,2332,2333],{"class":953},"Your Invoice",[926,2335,988],{"class":949},[926,2337,991],{"class":936},[926,2339,2340,2343],{"class":928,"line":1713},[926,2341,2342],{"class":940},"  invoiceData",[926,2344,991],{"class":936},[926,2346,2347,2349,2352,2354],{"class":928,"line":1972},[926,2348,982],{"class":949},[926,2350,2351],{"class":953},"billing\u002Finvoice",[926,2353,988],{"class":949},[926,2355,2356],{"class":1600},"      \u002F\u002F resolves to billing\u002Finvoice.ejs\n",[926,2358,2359],{"class":928,"line":1989},[926,2360,1057],{"class":936},[2362,2363,2364],"tip",{},[856,2365,2366,2367,1026,2369,1083,2371,2373,2374,2376],{},"The template resolver searches ",[868,2368,1079],{},[868,2370,1082],{},[868,2372,1086],{}," in order. Place custom templates in ",[868,2375,1079],{}," at the project root so they are found first and survive rebuilds.",[904,2378],{},[907,2380,2382],{"id":2381},"disposable-email-detection","Disposable email detection",[856,2384,2385,2388,2389,2394],{},[868,2386,2387],{},"isDisposable"," checks whether an email address belongs to a known disposable-email provider. The function extracts the domain, lowercases it, and looks it up in a pre-loaded ",[860,2390,2393],{"href":2391,"rel":2392},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FLightning_Memory-Mapped_Database",[864],"LMDB"," map. If the domain exists in the map, the address is considered disposable.",[917,2396,2398],{"className":919,"code":2397,"language":921,"meta":922,"style":922},"import { isDisposable } from '@riavzon\u002Fauth'\n\nconst blocked = await isDisposable('user@mailnull.com', log)\n\nif (blocked) {\n  res.status(400).json({ error: 'Disposable email addresses are not accepted.' })\n  return\n}\n",[868,2399,2400,2418,2422,2452,2456,2470,2507,2512],{"__ignoreMap":922},[926,2401,2402,2404,2406,2408,2410,2412,2414,2416],{"class":928,"line":929},[926,2403,933],{"class":932},[926,2405,937],{"class":936},[926,2407,2387],{"class":940},[926,2409,943],{"class":936},[926,2411,946],{"class":932},[926,2413,950],{"class":949},[926,2415,954],{"class":953},[926,2417,957],{"class":949},[926,2419,2420],{"class":928,"line":960},[926,2421,963],{"emptyLinePlaceholder":8},[926,2423,2424,2426,2429,2431,2433,2436,2438,2440,2443,2445,2447,2450],{"class":928,"line":966},[926,2425,2130],{"class":2129},[926,2427,2428],{"class":2133}," blocked",[926,2430,2138],{"class":2137},[926,2432,2141],{"class":932},[926,2434,2435],{"class":972}," isDisposable",[926,2437,2200],{"class":936},[926,2439,988],{"class":949},[926,2441,2442],{"class":953},"user@mailnull.com",[926,2444,988],{"class":949},[926,2446,1026],{"class":936},[926,2448,2449],{"class":940},"log",[926,2451,1057],{"class":936},[926,2453,2454],{"class":928,"line":979},[926,2455,963],{"emptyLinePlaceholder":8},[926,2457,2458,2461,2464,2467],{"class":928,"line":994},[926,2459,2460],{"class":932},"if",[926,2462,2463],{"class":936}," (",[926,2465,2466],{"class":940},"blocked",[926,2468,2469],{"class":936},") {\n",[926,2471,2472,2475,2477,2480,2482,2485,2487,2489,2492,2495,2497,2499,2502,2504],{"class":928,"line":1006},[926,2473,2474],{"class":940},"  res",[926,2476,1383],{"class":936},[926,2478,2479],{"class":972},"status",[926,2481,2200],{"class":936},[926,2483,2484],{"class":1615},"400",[926,2486,1477],{"class":936},[926,2488,5],{"class":972},[926,2490,2491],{"class":936},"({ ",[926,2493,2494],{"class":940},"error",[926,2496,1016],{"class":1015},[926,2498,950],{"class":949},[926,2500,2501],{"class":953},"Disposable email addresses are not accepted.",[926,2503,988],{"class":949},[926,2505,2506],{"class":936}," })\n",[926,2508,2509],{"class":928,"line":1044},[926,2510,2511],{"class":932},"  return\n",[926,2513,2514],{"class":928,"line":1054},[926,2515,2516],{"class":936},"}\n",[856,2518,2519,2520,2523,2524,2527],{},"The disposable-email list is loaded once at startup from a local database file managed by the ",[860,2521,2522],{"href":611},"Shield Base CLI",". The list is compiled from multiple open-source sources and updated by running the CLI with the ",[868,2525,2526],{},"--email"," flag.",[2529,2530,2531],"warning",{},[856,2532,2533,2534,2536,2537,2540],{},"The LMDB database must be present on disk before the IAM service starts. If the file is missing, ",[868,2535,2387],{}," returns ",[868,2538,2539],{},"false"," for all lookups (fails open).",[856,2542,2543,2544,2547,2548,2550],{},"The ",[860,2545,2546],{"href":100},"signup controller"," calls ",[868,2549,2387],{}," automatically before creating a new user account. You can also call it from any custom route that accepts an email address.",[904,2552],{},[907,2554,2556],{"id":2555},"mx-record-validation","MX record validation",[856,2558,2559,2562,2563,2567],{},[868,2560,2561],{},"isValidDomain"," verifies that the email domain has valid mail exchange records by performing a ",[860,2564,901],{"href":2565,"rel":2566},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMX_record",[864],". Results are cached in an LRU cache with a 24-hour TTL to avoid repeated DNS queries for the same domain.",[917,2569,2571],{"className":919,"code":2570,"language":921,"meta":922,"style":922},"import { isValidDomain } from '@riavzon\u002Fauth'\n\nconst hasMx = await isValidDomain('user@example.com', log)\n\nif (!hasMx) {\n  res.status(400).json({ error: 'Email domain does not accept mail.' })\n  return\n}\n",[868,2572,2573,2591,2595,2623,2627,2641,2672,2676],{"__ignoreMap":922},[926,2574,2575,2577,2579,2581,2583,2585,2587,2589],{"class":928,"line":929},[926,2576,933],{"class":932},[926,2578,937],{"class":936},[926,2580,2561],{"class":940},[926,2582,943],{"class":936},[926,2584,946],{"class":932},[926,2586,950],{"class":949},[926,2588,954],{"class":953},[926,2590,957],{"class":949},[926,2592,2593],{"class":928,"line":960},[926,2594,963],{"emptyLinePlaceholder":8},[926,2596,2597,2599,2602,2604,2606,2609,2611,2613,2615,2617,2619,2621],{"class":928,"line":966},[926,2598,2130],{"class":2129},[926,2600,2601],{"class":2133}," hasMx",[926,2603,2138],{"class":2137},[926,2605,2141],{"class":932},[926,2607,2608],{"class":972}," isValidDomain",[926,2610,2200],{"class":936},[926,2612,988],{"class":949},[926,2614,985],{"class":953},[926,2616,988],{"class":949},[926,2618,1026],{"class":936},[926,2620,2449],{"class":940},[926,2622,1057],{"class":936},[926,2624,2625],{"class":928,"line":979},[926,2626,963],{"emptyLinePlaceholder":8},[926,2628,2629,2631,2633,2636,2639],{"class":928,"line":994},[926,2630,2460],{"class":932},[926,2632,2463],{"class":936},[926,2634,2635],{"class":2137},"!",[926,2637,2638],{"class":940},"hasMx",[926,2640,2469],{"class":936},[926,2642,2643,2645,2647,2649,2651,2653,2655,2657,2659,2661,2663,2665,2668,2670],{"class":928,"line":1006},[926,2644,2474],{"class":940},[926,2646,1383],{"class":936},[926,2648,2479],{"class":972},[926,2650,2200],{"class":936},[926,2652,2484],{"class":1615},[926,2654,1477],{"class":936},[926,2656,5],{"class":972},[926,2658,2491],{"class":936},[926,2660,2494],{"class":940},[926,2662,1016],{"class":1015},[926,2664,950],{"class":949},[926,2666,2667],{"class":953},"Email domain does not accept mail.",[926,2669,988],{"class":949},[926,2671,2506],{"class":936},[926,2673,2674],{"class":928,"line":1044},[926,2675,2511],{"class":932},[926,2677,2678],{"class":928,"line":1054},[926,2679,2516],{"class":936},[856,2681,2682,2683,2686,2687,2690,2691,2694,2695,2698],{},"The function handles internationalized domain names by converting them to ASCII with ",[868,2684,2685],{},"domainToASCII"," before the lookup. If a transient DNS failure occurs (anything other than ",[868,2688,2689],{},"ENODATA"," or ",[868,2692,2693],{},"ENOTFOUND","), the domain is ",[882,2696,2697],{},"allowed through"," to avoid blocking legitimate users during DNS outages.",[2362,2700,2701],{},[856,2702,2703,2704,2706,2707,2709,2710,2712],{},"Use ",[868,2705,2561],{}," alongside ",[868,2708,2387],{}," for a two-layer email validation pipeline. The ",[860,2711,2546],{"href":100}," runs both checks in sequence before creating any user record.",[904,2714],{},[907,2716,2718],{"id":2717},"configuration-reference","Configuration reference",[1132,2720,2722],{"id":2721},"resend-credentials","Resend credentials",[856,2724,2725,2726,2728],{},"All outbound email uses the credentials in the ",[868,2727,1123],{}," configuration block.",[1353,2730,2731,2741],{},[1356,2732,2734],{"name":2733,"type":1359,":required":1360},"email.resend_key",[856,2735,2736,2737,2740],{},"Your ",[860,2738,865],{"href":862,"rel":2739},[864]," API key. Used to authenticate all outbound email requests.",[1356,2742,2744],{"name":2743,"type":1359,":required":1360},"email.email",[856,2745,2746,2747,2750],{},"The sender address for all outbound emails (e.g. ",[868,2748,2749],{},"'no-reply@example.com'","). Must be a verified sender in your Resend account.",[1132,2752,2754],{"id":2753},"email-images","Email images",[856,2756,2757,2758,1383],{},"Image URLs used by the built-in templates. Configured under ",[868,2759,1562],{},[1353,2761,2762,2768,2774,2780,2786],{},[1356,2763,2765],{"name":2764,"type":1359},"emailImages.otp.bannerImage",[856,2766,2767],{},"URL to the banner image displayed at the top of OTP emails.",[1356,2769,2771],{"name":2770,"type":1359},"emailImages.otp.device_image",[856,2772,2773],{},"URL to the icon displayed above the Device metadata column in OTP emails.",[1356,2775,2777],{"name":2776,"type":1359},"emailImages.otp.location_image",[856,2778,2779],{},"URL to the icon displayed above the Location metadata column in OTP emails.",[1356,2781,2783],{"name":2782,"type":1359},"emailImages.otp.date_image",[856,2784,2785],{},"URL to the icon displayed above the Date metadata column in OTP emails.",[1356,2787,2788],{"name":1818,"type":1359},[856,2789,2790],{},"URL to the header banner image used by notification emails (password reset, email change alerts).",[1132,2792,2794],{"id":2793},"notification-email","Notification email",[856,2796,2797,2798,1383],{},"Text values used by notification templates. Configured under ",[868,2799,1565],{},[1353,2801,2802,2807,2813,2819,2825],{},[1356,2803,2805],{"name":2804,"type":1359},"notificationEmail.websiteName",[856,2806,1530],{},[1356,2808,2810],{"name":2809,"type":1359},"notificationEmail.privacyPolicyLink",[856,2811,2812],{},"URL to your privacy policy page, linked in the email footer.",[1356,2814,2816],{"name":2815,"type":1359},"notificationEmail.contactPageLink",[856,2817,2818],{},"URL to your contact page, linked in the email footer.",[1356,2820,2822],{"name":2821,"type":1359},"notificationEmail.changePasswordPageLink",[856,2823,2824],{},"URL to your change-password page, used as the CTA link in password reset notifications.",[1356,2826,2828],{"name":2827,"type":1359},"notificationEmail.loginPageLink",[856,2829,2830],{},"URL to your login page, linked in notification emails.",[2832,2833,2834],"style",{},"html pre.shiki code .sZ328, html code.shiki .sZ328{--shiki-light:#AF00DB;--shiki-default:#AF00DB;--shiki-dark:#FF79C6}html pre.shiki code .sDd4n, html code.shiki .sDd4n{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#F8F8F2}html pre.shiki code .sjsA6, html code.shiki .sjsA6{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#F8F8F2}html pre.shiki code .sFkSl, html code.shiki .sFkSl{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#E9F284}html pre.shiki code .sFB1V, html code.shiki .sFB1V{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#F1FA8C}html pre.shiki code .sHOzp, html code.shiki .sHOzp{--shiki-light:#795E26;--shiki-default:#795E26;--shiki-dark:#50FA7B}html pre.shiki code .s34zl, html code.shiki .s34zl{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#FF79C6}html .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 .sghk6, html code.shiki .sghk6{--shiki-light:#008000;--shiki-default:#008000;--shiki-dark:#6272A4}html pre.shiki code .spgvN, html code.shiki .spgvN{--shiki-light:#098658;--shiki-default:#098658;--shiki-dark:#BD93F9}html pre.shiki code .sl46w, html code.shiki .sl46w{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#FF79C6}html pre.shiki code .s3JHE, html code.shiki .s3JHE{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#F8F8F2}html pre.shiki code .saOXh, html code.shiki .saOXh{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#FF79C6}",{"title":922,"searchDepth":960,"depth":960,"links":2836},[2837,2838,2842,2846,2851,2857,2858,2859],{"id":909,"depth":960,"text":910},{"id":1129,"depth":960,"text":1130,"children":2839},[2840,2841],{"id":1134,"depth":966,"text":1135},{"id":1240,"depth":966,"text":1241},{"id":1331,"depth":960,"text":1332,"children":2843},[2844,2845],{"id":1350,"depth":966,"text":1351},{"id":1458,"depth":966,"text":1459},{"id":1552,"depth":960,"text":1553,"children":2847},[2848,2849,2850],{"id":1569,"depth":966,"text":1572},{"id":1738,"depth":966,"text":1252},{"id":1832,"depth":966,"text":1256},{"id":2010,"depth":960,"text":2011,"children":2852},[2853,2854,2855,2856],{"id":2024,"depth":966,"text":2025},{"id":2095,"depth":966,"text":2096},{"id":2161,"depth":966,"text":2162},{"id":2217,"depth":966,"text":2218},{"id":2381,"depth":960,"text":2382},{"id":2555,"depth":960,"text":2556},{"id":2717,"depth":960,"text":2718,"children":2860},[2861,2862,2863],{"id":2721,"depth":966,"text":2722},{"id":2753,"depth":966,"text":2754},{"id":2793,"depth":966,"text":2794},"How the IAM service sends transactional emails through Resend, which EJS templates ship out of the box, how to create custom templates, and how disposable-email and MX validation protect against abuse.","md","i-lucide-mail",{},null,"---\ntitle: Emails\ndescription: How the IAM service sends transactional emails through Resend, which EJS templates ship out of the box, how to create custom templates, and how disposable-email and MX validation protect against abuse.\nicon: i-lucide-mail\n---\n\nThe IAM service sends transactional emails through the [Resend](https:\u002F\u002Fresend.com\u002F) SDK. Every outbound email passes through a single function, `sendSystemEmail`, which resolves an [EJS](https:\u002F\u002Fejs.co\u002F) template by name, renders it with the provided data, and hands the resulting HTML to Resend for delivery.\n\nTwo categories of email ship out of the box: **OTP emails** (used by adaptive MFA, custom MFA, and email update flows) and **notification emails** (used by password reset confirmations, email change alerts, and any custom notification you define). Both categories use responsive HTML templates tested across major email clients.\n\nBefore any email is sent, the service can optionally validate the recipient address in two layers: a [disposable-email check](#disposable-email-detection) against an LMDB database and a [DNS MX lookup](#mx-record-validation) to confirm the domain accepts mail.\n\n---\n\n## Delivery pipeline\n\n`sendSystemEmail` is the single entry point for all outbound email. It accepts a recipient (or array of recipients), a subject line, a data object for template interpolation, and a template path relative to the emails directory.\n\n```ts\nimport { sendSystemEmail } from '@riavzon\u002Fauth'\n\nawait sendSystemEmail(\n  'user@example.com',\n  'Welcome to Our Service',\n  { name: 'Alice', loginUrl: 'https:\u002F\u002Fexample.com\u002Flogin' },\n  'welcome'\n)\n```\n\nInternally the function performs three steps:\n\n::steps{level=\"4\"}\n#### Template resolution\n\nThe function appends `.ejs` to the template name and searches three directories in order: `emails\u002F`, `dist\u002Femails\u002F`, and `src\u002FjwtAuth\u002Femails\u002F`. The first match wins. This search order lets you place custom templates in the top-level `emails\u002F` directory without modifying the source tree.\n\n#### EJS rendering\n\nThe data object is spread into the template as local variables. Templates use standard EJS syntax: `\u003C%= variable %>` for escaped output and `\u003C%- variable %>` for raw HTML (used by the notification template's `message` field).\n\n#### Resend delivery\n\nThe rendered HTML is sent via `resend.emails.send()` using the API key and sender address from the `email` configuration block. The function logs the Resend response and throws on render failures, but logs and returns silently on Resend API errors to avoid crashing the caller.\n::\n\n---\n\n## Built-in templates\n\n### OTP template\n\nPath: `OTP\u002Findex.ejs`\n\nThe OTP template is used by `sendTempMfaLink` (adaptive MFA) and `generateCustomMfaFlow` (custom MFA and email update). It renders a responsive email with five sections:\n\n| Section | Content |\n|---|---|\n| Banner | A configurable image at the top of the email (`banner_image`) |\n| Code display | The 7-digit OTP code shown in a bordered button that also links to the magic link URL |\n| Metadata row | Three columns showing **Device** (browser + OS), **Location** (IP-based), and **Date** (server timestamp) with configurable icons |\n| Security warning | A message warning the user to reset their password if they did not request the code, with a link to the configured reset-password page |\n| CTA button | A \"Verify Here\" button linking to the magic link URL |\n\nThe template uses the [Montserrat](https:\u002F\u002Ffonts.google.com\u002Fspecimen\u002FMontserrat) font family and is built with table-based layout for maximum email client compatibility, including Outlook (MSO conditional comments).\n\n### Notification template\n\nPath: `nottifications\u002Findex.ejs`\n\nThe notification template is used by `resetPasswordEmail` (password reset confirmation) and `sendEmailNotification` (generic notifications such as the email-change alert). It renders a simpler layout:\n\n| Section | Content |\n|---|---|\n| Header image | A configurable banner (`main_image`) |\n| Title and action | Bold title with a subtitle instruction line |\n| Body | A letter-style block: \"Dear {username}\", followed by the `message` field (supports raw HTML via `\u003C%-`), a security warning, and a signature with the website name |\n| CTA button | A configurable button label and link |\n| Footer | Privacy policy and contact page links |\n\nThe template uses the [Raleway](https:\u002F\u002Ffonts.google.com\u002Fspecimen\u002FRaleway) font family.\n\n---\n\n## Template variables\n\nEach template type expects a specific data shape. The service defines two TypeScript interfaces, `OTPEmails` and `NotificationEmails`, unified under the `EmailData` type.\n\n### OTP variables\n\n::field-group\n::field{name=\"link\" type=\"string\" required}\nThe full magic link URL the button points to.\n::\n\n::field{name=\"code\" type=\"string | number\" required}\nThe 7-digit OTP code displayed in the email body.\n::\n\n::field{name=\"device\" type=\"string\"}\nOS string shown in the Device column (e.g. `'macOS'`). Falls back to `'Unknown Device'`.\n::\n\n::field{name=\"browser\" type=\"string\"}\nBrowser name shown in the Device column (e.g. `'Chrome 125'`). Falls back to `'Unknown Browser'`.\n::\n\n::field{name=\"location\" type=\"string\"}\nIP-based location string shown in the Location column (e.g. `'Berlin, DE'`). Falls back to `'Unknown Location'`.\n::\n\n::field{name=\"date\" type=\"string\"}\nFormatted timestamp shown in the Date column. Generated server-side via `new Date().toLocaleString()`.\n::\n\n::field{name=\"cta\" type=\"string\"}\nButton label text. Default `'Verify Here'` for MFA emails.\n::\n\n::field{name=\"banner_image\" type=\"string\"}\nURL to the banner image displayed at the top of the email.\n::\n\n::field{name=\"device_image\" type=\"string\"}\nURL to the icon displayed above the Device column.\n::\n\n::field{name=\"location_image\" type=\"string\"}\nURL to the icon displayed above the Location column.\n::\n\n::field{name=\"date_image\" type=\"string\"}\nURL to the icon displayed above the Date column.\n::\n\n::field{name=\"link_to_reset_password\" type=\"string\"}\nURL to the password reset page, shown in the security warning section.\n::\n::\n\n### Notification variables\n\n::field-group\n::field{name=\"title\" type=\"string\" required}\nThe big header text at the top of the email body.\n::\n\n::field{name=\"action\" type=\"string\" required}\nSub-header instruction line below the title (e.g. `'Please reset your password'`).\n::\n\n::field{name=\"subject\" type=\"string\" required}\nThe email subject line. Also rendered inside the body as a \"Subject:\" heading.\n::\n\n::field{name=\"username\" type=\"string\" required}\nThe recipient's display name, used in the \"Dear {username}\" greeting.\n::\n\n::field{name=\"message\" type=\"string\" required}\nThe main body text. Supports raw HTML (rendered with `\u003C%-`). Use `\u003Cb>`, `\u003Cbr\u002F>`, and `\u003Ca>` tags for formatting.\n::\n\n::field{name=\"cta\" type=\"string\" required}\nButton label text (e.g. `'Change Password'`, `'Contact Support'`).\n::\n\n::field{name=\"cta_link\" type=\"string\" required}\nURL the CTA button points to.\n::\n\n::field{name=\"websiteName\" type=\"string\" required}\nYour website name, shown in the email signature.\n::\n\n::field{name=\"privacy_link\" type=\"string\" required}\nURL to your privacy policy page, linked in the footer.\n::\n\n::field{name=\"contact_link\" type=\"string\" required}\nURL to your contact page, linked in the footer.\n::\n\n::field{name=\"main_image\" type=\"string\" required}\nURL to the header banner image.\n::\n::\n\n---\n\n## Helper functions\n\nThree helper functions wrap `sendSystemEmail` with pre-configured templates and data shapes. Each one reads configuration values from `magic_links.emailImages` and `magic_links.notificationEmail`, so the caller only needs to provide the dynamic fields.\n\n### `mfaEmail`\n\nSends an OTP email using the `OTP\u002Findex` template. Called internally by `sendTempMfaLink` and `generateCustomMfaFlow`. This is an internal helper and is not exported from `@riavzon\u002Fauth`. Use `sendSystemEmail` for custom email delivery.\n\n```ts\n\u002F\u002F internal — called by sendTempMfaLink and generateCustomMfaFlow\nawait mfaEmail(\n  1234567,                               \u002F\u002F 7-digit OTP code\n  'user@example.com',                    \u002F\u002F recipient\n  'https:\u002F\u002Fexample.com\u002Fauth\u002Fbounce?...', \u002F\u002F full magic link URL\n  {\n    device: 'Chrome on macOS',\n    browser: 'Chrome 125',\n    location: 'Berlin, DE',\n  }\n)\n```\n\nThe function reads `emailImages.otp` for the four image URLs and `linkToResetPasswordPage` for the security warning link. The `date` field is generated automatically from `new Date().toLocaleString()`. The email subject is formatted as `Security Code - {code}`.\n\n### `resetPasswordEmail`\n\nSends a notification email using the `nottifications\u002Findex` template. Called internally by `sendTempPasswordResetLink` when a user requests a password reset. This is an internal helper and is not exported from `@riavzon\u002Fauth`.\n\n```ts\n\u002F\u002F internal — called by sendTempPasswordResetLink\nawait resetPasswordEmail(\n  'Alice',                               \u002F\u002F user's display name\n  'alice@example.com',                   \u002F\u002F recipient\n  'https:\u002F\u002Fexample.com\u002Fauth\u002Fbounce?...'  \u002F\u002F password reset URL\n)\n```\n\nThe function reads `emailImages.notificationBanner` for the header image and `notificationEmail.*` for the website name, privacy link, contact link, and change-password page link. The CTA button label is `'Change Password'` and the subject is `'Password Reset Request'`.\n\n### `sendEmailNotification`\n\nSends a customizable notification email. Called by the email update controller to alert the user that their email address has changed. This is an internal helper and is not exported from `@riavzon\u002Fauth`. Use `sendSystemEmail` for custom notifications.\n\n```ts\n\u002F\u002F internal — called by updateEmailController and verifyPasswordReset\nawait sendEmailNotification(\n  'alice@example.com',\n  'Alice',\n  {\n    title: 'Your Email Has Changed',\n    action: 'Notice of Change',\n    subject: 'Security Alert: Email Address Updated',\n    message:\n      'Your email has been updated to \u003Cb>new@example.com\u003C\u002Fb>.\u003Cbr\u002F>If you did not authorize this, contact support.',\n    cta: 'Contact Support',\n    cta_link: 'https:\u002F\u002Fexample.com\u002Fcontact',\n  }\n)\n```\n\nThe function merges the provided fields with defaults pulled from `notificationEmail` and `emailImages.notificationBanner`. Any field you omit falls back to the password-reset defaults (title, action, subject, message, CTA).\n\n---\n\n## Custom templates\n\nThe template manager lets you register, list, and remove custom [EJS](https:\u002F\u002Fejs.co\u002F) templates at runtime. Custom templates are written as `.ejs` files and stored alongside the built-in templates.\n\n### Creating a template\n\n```ts\nimport { makeEmailTemplate } from '@riavzon\u002Fauth'\n\nawait makeEmailTemplate(\n  '\u003Ch1>Welcome, \u003C%= name %>!\u003C\u002Fh1>\u003Cp>\u003Ca href=\"\u003C%= loginUrl %>\">Sign in\u003C\u002Fa>\u003C\u002Fp>',\n  'welcome'\n)\n```\n\nThe function writes a `welcome.ejs` file to the emails directory. If a template with the same name already exists, it throws an error to prevent accidental overwrites.\n\n### Listing templates\n\n```ts\nimport { listTemplates } from '@riavzon\u002Fauth'\n\nconst templates = await listTemplates()\n\u002F\u002F ['OTP\u002Findex.ejs', 'nottifications\u002Findex.ejs', 'welcome.ejs']\n```\n\nReturns all `.ejs` files found recursively in the emails directory, including subdirectories.\n\n### Deleting a template\n\n```ts\nimport { deleteTemplate } from '@riavzon\u002Fauth'\n\nawait deleteTemplate('welcome')\n```\n\nRemoves the `welcome.ejs` file from the emails directory. Throws if the file does not exist.\n\n### Using a custom template\n\nPass the template name (without `.ejs`) to `sendSystemEmail`. For templates inside subdirectories, include the path relative to the emails root:\n\n```ts\nawait sendSystemEmail(\n  'user@example.com',\n  'Welcome!',\n  { name: 'Alice', loginUrl: 'https:\u002F\u002Fexample.com\u002Flogin' },\n  'welcome'              \u002F\u002F resolves to welcome.ejs\n)\n\nawait sendSystemEmail(\n  'user@example.com',\n  'Your Invoice',\n  invoiceData,\n  'billing\u002Finvoice'      \u002F\u002F resolves to billing\u002Finvoice.ejs\n)\n```\n\n::tip\nThe template resolver searches `emails\u002F`, `dist\u002Femails\u002F`, and `src\u002FjwtAuth\u002Femails\u002F` in order. Place custom templates in `emails\u002F` at the project root so they are found first and survive rebuilds.\n::\n\n---\n\n## Disposable email detection\n\n`isDisposable` checks whether an email address belongs to a known disposable-email provider. The function extracts the domain, lowercases it, and looks it up in a pre-loaded [LMDB](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FLightning_Memory-Mapped_Database) map. If the domain exists in the map, the address is considered disposable.\n\n```ts\nimport { isDisposable } from '@riavzon\u002Fauth'\n\nconst blocked = await isDisposable('user@mailnull.com', log)\n\nif (blocked) {\n  res.status(400).json({ error: 'Disposable email addresses are not accepted.' })\n  return\n}\n```\n\nThe disposable-email list is loaded once at startup from a local database file managed by the [Shield Base CLI](\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Femail). The list is compiled from multiple open-source sources and updated by running the CLI with the `--email` flag.\n\n::warning\nThe LMDB database must be present on disk before the IAM service starts. If the file is missing, `isDisposable` returns `false` for all lookups (fails open).\n::\n\nThe [signup controller](\u002Fdocs\u002Fiam\u002Fessentials\u002Fsignup) calls `isDisposable` automatically before creating a new user account. You can also call it from any custom route that accepts an email address.\n\n---\n\n## MX record validation\n\n`isValidDomain` verifies that the email domain has valid mail exchange records by performing a [DNS MX lookup](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMX_record). Results are cached in an LRU cache with a 24-hour TTL to avoid repeated DNS queries for the same domain.\n\n```ts\nimport { isValidDomain } from '@riavzon\u002Fauth'\n\nconst hasMx = await isValidDomain('user@example.com', log)\n\nif (!hasMx) {\n  res.status(400).json({ error: 'Email domain does not accept mail.' })\n  return\n}\n```\n\nThe function handles internationalized domain names by converting them to ASCII with `domainToASCII` before the lookup. If a transient DNS failure occurs (anything other than `ENODATA` or `ENOTFOUND`), the domain is **allowed through** to avoid blocking legitimate users during DNS outages.\n\n::tip\nUse `isValidDomain` alongside `isDisposable` for a two-layer email validation pipeline. The [signup controller](\u002Fdocs\u002Fiam\u002Fessentials\u002Fsignup) runs both checks in sequence before creating any user record.\n::\n\n---\n\n## Configuration reference\n\n### Resend credentials\n\nAll outbound email uses the credentials in the `email` configuration block.\n\n::field-group\n::field{name=\"email.resend_key\" type=\"string\" required}\nYour [Resend](https:\u002F\u002Fresend.com\u002F) API key. Used to authenticate all outbound email requests.\n::\n\n::field{name=\"email.email\" type=\"string\" required}\nThe sender address for all outbound emails (e.g. `'no-reply@example.com'`). Must be a verified sender in your Resend account.\n::\n::\n\n### Email images\n\nImage URLs used by the built-in templates. Configured under `magic_links.emailImages`.\n\n::field-group\n::field{name=\"emailImages.otp.bannerImage\" type=\"string\"}\nURL to the banner image displayed at the top of OTP emails.\n::\n\n::field{name=\"emailImages.otp.device_image\" type=\"string\"}\nURL to the icon displayed above the Device metadata column in OTP emails.\n::\n\n::field{name=\"emailImages.otp.location_image\" type=\"string\"}\nURL to the icon displayed above the Location metadata column in OTP emails.\n::\n\n::field{name=\"emailImages.otp.date_image\" type=\"string\"}\nURL to the icon displayed above the Date metadata column in OTP emails.\n::\n\n::field{name=\"emailImages.notificationBanner\" type=\"string\"}\nURL to the header banner image used by notification emails (password reset, email change alerts).\n::\n::\n\n### Notification email\n\nText values used by notification templates. Configured under `magic_links.notificationEmail`.\n\n::field-group\n::field{name=\"notificationEmail.websiteName\" type=\"string\"}\nYour website name, shown in the email signature.\n::\n\n::field{name=\"notificationEmail.privacyPolicyLink\" type=\"string\"}\nURL to your privacy policy page, linked in the email footer.\n::\n\n::field{name=\"notificationEmail.contactPageLink\" type=\"string\"}\nURL to your contact page, linked in the email footer.\n::\n\n::field{name=\"notificationEmail.changePasswordPageLink\" type=\"string\"}\nURL to your change-password page, used as the CTA link in password reset notifications.\n::\n\n::field{name=\"notificationEmail.loginPageLink\" type=\"string\"}\nURL to your login page, linked in notification emails.\n::\n::\n",{"title":119,"description":2864},"TnbhImm4GPLAECg7w8qBzTXjEynUGzp-9draIHpAtmY",[2873,2874],{"title":115,"path":116,"stem":117,"children":-1},{"title":123,"path":124,"stem":125,"children":-1},{"id":851,"title":119,"body":2876,"description":2864,"extension":2865,"icon":2866,"meta":4385,"module":2868,"navigation":8,"path":120,"rawbody":2869,"seo":4386,"stem":121,"__hash__":2871},{"type":853,"value":2877,"toc":4356},[2878,2888,2894,2900,2902,2904,2908,3002,3004,3038,3040,3042,3044,3048,3054,3104,3109,3111,3115,3121,3169,3174,3176,3178,3186,3188,3254,3256,3316,3318,3320,3328,3332,3344,3446,3458,3462,3470,3524,3534,3538,3544,3678,3684,3686,3688,3695,3697,3753,3757,3759,3803,3807,3809,3851,3855,3857,3863,3989,4001,4003,4005,4012,4116,4122,4130,4136,4138,4140,4147,4253,4263,4273,4275,4277,4279,4283,4298,4300,4304,4326,4328,4332,4354],[856,2879,858,2880,866,2883,871,2885,877],{},[860,2881,865],{"href":862,"rel":2882},[864],[868,2884,870],{},[860,2886,876],{"href":874,"rel":2887},[864],[856,2889,880,2890,885,2892,889],{},[882,2891,884],{},[882,2893,888],{},[856,2895,892,2896,897,2898,902],{},[860,2897,896],{"href":895},[860,2899,901],{"href":900},[904,2901],{},[907,2903,910],{"id":909},[856,2905,2906,915],{},[868,2907,870],{},[917,2909,2910],{"className":919,"code":920,"language":921,"meta":922,"style":922},[868,2911,2912,2930,2934,2942,2952,2962,2990,2998],{"__ignoreMap":922},[926,2913,2914,2916,2918,2920,2922,2924,2926,2928],{"class":928,"line":929},[926,2915,933],{"class":932},[926,2917,937],{"class":936},[926,2919,870],{"class":940},[926,2921,943],{"class":936},[926,2923,946],{"class":932},[926,2925,950],{"class":949},[926,2927,954],{"class":953},[926,2929,957],{"class":949},[926,2931,2932],{"class":928,"line":960},[926,2933,963],{"emptyLinePlaceholder":8},[926,2935,2936,2938,2940],{"class":928,"line":966},[926,2937,969],{"class":932},[926,2939,973],{"class":972},[926,2941,976],{"class":936},[926,2943,2944,2946,2948,2950],{"class":928,"line":979},[926,2945,982],{"class":949},[926,2947,985],{"class":953},[926,2949,988],{"class":949},[926,2951,991],{"class":936},[926,2953,2954,2956,2958,2960],{"class":928,"line":994},[926,2955,982],{"class":949},[926,2957,999],{"class":953},[926,2959,988],{"class":949},[926,2961,991],{"class":936},[926,2963,2964,2966,2968,2970,2972,2974,2976,2978,2980,2982,2984,2986,2988],{"class":928,"line":1006},[926,2965,1009],{"class":936},[926,2967,1012],{"class":940},[926,2969,1016],{"class":1015},[926,2971,950],{"class":949},[926,2973,1021],{"class":953},[926,2975,988],{"class":949},[926,2977,1026],{"class":936},[926,2979,1029],{"class":940},[926,2981,1016],{"class":1015},[926,2983,950],{"class":949},[926,2985,1036],{"class":953},[926,2987,988],{"class":949},[926,2989,1041],{"class":936},[926,2991,2992,2994,2996],{"class":928,"line":1044},[926,2993,982],{"class":949},[926,2995,1049],{"class":953},[926,2997,957],{"class":949},[926,2999,3000],{"class":928,"line":1054},[926,3001,1057],{"class":936},[856,3003,1060],{},[1062,3005,3006,3008,3020,3022,3030,3032],{"level":1064},[1066,3007,1069],{"id":1068},[856,3009,1072,3010,1076,3012,1026,3014,1083,3016,1087,3018,1090],{},[868,3011,1075],{},[868,3013,1079],{},[868,3015,1082],{},[868,3017,1086],{},[868,3019,1079],{},[1066,3021,1094],{"id":1093},[856,3023,1097,3024,1101,3026,1105,3028,1109],{},[868,3025,1100],{},[868,3027,1104],{},[868,3029,1108],{},[1066,3031,1113],{"id":1112},[856,3033,1116,3034,1120,3036,1124],{},[868,3035,1119],{},[868,3037,1123],{},[904,3039],{},[907,3041,1130],{"id":1129},[1132,3043,1135],{"id":1134},[856,3045,1138,3046],{},[868,3047,1141],{},[856,3049,1144,3050,1148,3052,1152],{},[868,3051,1147],{},[868,3053,1151],{},[1154,3055,3056,3064],{},[1157,3057,3058],{},[1160,3059,3060,3062],{},[1163,3061,1165],{},[1163,3063,1168],{},[1170,3065,3066,3074,3080,3092,3098],{},[1160,3067,3068,3070],{},[1175,3069,1177],{},[1175,3071,1180,3072,1184],{},[868,3073,1183],{},[1160,3075,3076,3078],{},[1175,3077,1189],{},[1175,3079,1192],{},[1160,3081,3082,3084],{},[1175,3083,1197],{},[1175,3085,1200,3086,1204,3088,1208,3090,1212],{},[882,3087,1203],{},[882,3089,1207],{},[882,3091,1211],{},[1160,3093,3094,3096],{},[1175,3095,1217],{},[1175,3097,1220],{},[1160,3099,3100,3102],{},[1175,3101,1225],{},[1175,3103,1228],{},[856,3105,1231,3106,1237],{},[860,3107,1236],{"href":1234,"rel":3108},[864],[1132,3110,1241],{"id":1240},[856,3112,1138,3113],{},[868,3114,1246],{},[856,3116,1249,3117,1253,3119,1257],{},[868,3118,1252],{},[868,3120,1256],{},[1154,3122,3123,3131],{},[1157,3124,3125],{},[1160,3126,3127,3129],{},[1163,3128,1165],{},[1163,3130,1168],{},[1170,3132,3133,3141,3147,3157,3163],{},[1160,3134,3135,3137],{},[1175,3136,1274],{},[1175,3138,1277,3139,1184],{},[868,3140,1280],{},[1160,3142,3143,3145],{},[1175,3144,1285],{},[1175,3146,1288],{},[1160,3148,3149,3151],{},[1175,3150,1293],{},[1175,3152,1296,3153,1299,3155,1303],{},[868,3154,1108],{},[868,3156,1302],{},[1160,3158,3159,3161],{},[1175,3160,1225],{},[1175,3162,1310],{},[1160,3164,3165,3167],{},[1175,3166,1315],{},[1175,3168,1318],{},[856,3170,1231,3171,1326],{},[860,3172,1325],{"href":1323,"rel":3173},[864],[904,3175],{},[907,3177,1332],{"id":1331},[856,3179,1335,3180,1339,3182,1343,3184,1347],{},[868,3181,1338],{},[868,3183,1342],{},[868,3185,1346],{},[1132,3187,1351],{"id":1350},[1353,3189,3190,3194,3198,3206,3214,3222,3228,3234,3238,3242,3246,3250],{},[1356,3191,3192],{"name":1358,"type":1359,":required":1360},[856,3193,1363],{},[1356,3195,3196],{"name":868,"type":1366,":required":1360},[856,3197,1369],{},[1356,3199,3200],{"name":1372,"type":1359},[856,3201,1375,3202,1379,3204,1383],{},[868,3203,1378],{},[868,3205,1382],{},[1356,3207,3208],{"name":1386,"type":1359},[856,3209,1389,3210,1379,3212,1383],{},[868,3211,1392],{},[868,3213,1395],{},[1356,3215,3216],{"name":1398,"type":1359},[856,3217,1401,3218,1379,3220,1383],{},[868,3219,1404],{},[868,3221,1407],{},[1356,3223,3224],{"name":1410,"type":1359},[856,3225,1413,3226,1383],{},[868,3227,1416],{},[1356,3229,3230],{"name":1419,"type":1359},[856,3231,1422,3232,1426],{},[868,3233,1425],{},[1356,3235,3236],{"name":1183,"type":1359},[856,3237,1431],{},[1356,3239,3240],{"name":1434,"type":1359},[856,3241,1437],{},[1356,3243,3244],{"name":1440,"type":1359},[856,3245,1443],{},[1356,3247,3248],{"name":1446,"type":1359},[856,3249,1449],{},[1356,3251,3252],{"name":1452,"type":1359},[856,3253,1455],{},[1132,3255,1459],{"id":1458},[1353,3257,3258,3262,3268,3272,3276,3288,3296,3300,3304,3308,3312],{},[1356,3259,3260],{"name":1464,"type":1359,":required":1360},[856,3261,1467],{},[1356,3263,3264],{"name":1470,"type":1359,":required":1360},[856,3265,1473,3266,1477],{},[868,3267,1476],{},[1356,3269,3270],{"name":1480,"type":1359,":required":1360},[856,3271,1483],{},[1356,3273,3274],{"name":1486,"type":1359,":required":1360},[856,3275,1489],{},[1356,3277,3278],{"name":1108,"type":1359,":required":1360},[856,3279,1494,3280,1497,3282,1026,3284,1083,3286,1507],{},[868,3281,1302],{},[868,3283,1500],{},[868,3285,1503],{},[868,3287,1506],{},[1356,3289,3290],{"name":1419,"type":1359,":required":1360},[856,3291,1512,3292,1026,3294,1477],{},[868,3293,1515],{},[868,3295,1518],{},[1356,3297,3298],{"name":1521,"type":1359,":required":1360},[856,3299,1524],{},[1356,3301,3302],{"name":1527,"type":1359,":required":1360},[856,3303,1530],{},[1356,3305,3306],{"name":1533,"type":1359,":required":1360},[856,3307,1536],{},[1356,3309,3310],{"name":1539,"type":1359,":required":1360},[856,3311,1542],{},[1356,3313,3314],{"name":1280,"type":1359,":required":1360},[856,3315,1547],{},[904,3317],{},[907,3319,1553],{"id":1552},[856,3321,1556,3322,1559,3324,1339,3326,1566],{},[868,3323,870],{},[868,3325,1562],{},[868,3327,1565],{},[1132,3329,3330],{"id":1569},[868,3331,1572],{},[856,3333,1575,3334,1579,3336,1339,3338,1584,3340,1587,3342,1590],{},[868,3335,1578],{},[868,3337,1147],{},[868,3339,1151],{},[868,3341,954],{},[868,3343,870],{},[917,3345,3346],{"className":919,"code":1593,"language":921,"meta":922,"style":922},[868,3347,3348,3352,3360,3368,3380,3392,3396,3410,3424,3438,3442],{"__ignoreMap":922},[926,3349,3350],{"class":928,"line":929},[926,3351,1601],{"class":1600},[926,3353,3354,3356,3358],{"class":928,"line":960},[926,3355,969],{"class":932},[926,3357,1608],{"class":972},[926,3359,976],{"class":936},[926,3361,3362,3364,3366],{"class":928,"line":966},[926,3363,1616],{"class":1615},[926,3365,1619],{"class":936},[926,3367,1622],{"class":1600},[926,3369,3370,3372,3374,3376,3378],{"class":928,"line":979},[926,3371,982],{"class":949},[926,3373,985],{"class":953},[926,3375,988],{"class":949},[926,3377,1633],{"class":936},[926,3379,1636],{"class":1600},[926,3381,3382,3384,3386,3388,3390],{"class":928,"line":994},[926,3383,982],{"class":949},[926,3385,1643],{"class":953},[926,3387,988],{"class":949},[926,3389,1026],{"class":936},[926,3391,1650],{"class":1600},[926,3393,3394],{"class":928,"line":1006},[926,3395,1655],{"class":936},[926,3397,3398,3400,3402,3404,3406,3408],{"class":928,"line":1044},[926,3399,1660],{"class":940},[926,3401,1016],{"class":1015},[926,3403,950],{"class":949},[926,3405,1667],{"class":953},[926,3407,988],{"class":949},[926,3409,991],{"class":936},[926,3411,3412,3414,3416,3418,3420,3422],{"class":928,"line":1054},[926,3413,1676],{"class":940},[926,3415,1016],{"class":1015},[926,3417,950],{"class":949},[926,3419,1683],{"class":953},[926,3421,988],{"class":949},[926,3423,991],{"class":936},[926,3425,3426,3428,3430,3432,3434,3436],{"class":928,"line":1690},[926,3427,1693],{"class":940},[926,3429,1016],{"class":1015},[926,3431,950],{"class":949},[926,3433,1700],{"class":953},[926,3435,988],{"class":949},[926,3437,991],{"class":936},[926,3439,3440],{"class":928,"line":1707},[926,3441,1710],{"class":936},[926,3443,3444],{"class":928,"line":1713},[926,3445,1057],{"class":936},[856,3447,1718,3448,1722,3450,1726,3452,1729,3454,1732,3456,1383],{},[868,3449,1721],{},[868,3451,1725],{},[868,3453,1410],{},[868,3455,1416],{},[868,3457,1735],{},[1132,3459,3460],{"id":1738},[868,3461,1252],{},[856,3463,1743,3464,1579,3466,1750,3468,1383],{},[868,3465,1746],{},[868,3467,1749],{},[868,3469,954],{},[917,3471,3472],{"className":919,"code":1755,"language":921,"meta":922,"style":922},[868,3473,3474,3478,3486,3498,3510,3520],{"__ignoreMap":922},[926,3475,3476],{"class":928,"line":929},[926,3477,1762],{"class":1600},[926,3479,3480,3482,3484],{"class":928,"line":960},[926,3481,969],{"class":932},[926,3483,1769],{"class":972},[926,3485,976],{"class":936},[926,3487,3488,3490,3492,3494,3496],{"class":928,"line":966},[926,3489,982],{"class":949},[926,3491,1021],{"class":953},[926,3493,988],{"class":949},[926,3495,1619],{"class":936},[926,3497,1784],{"class":1600},[926,3499,3500,3502,3504,3506,3508],{"class":928,"line":979},[926,3501,982],{"class":949},[926,3503,1791],{"class":953},[926,3505,988],{"class":949},[926,3507,1796],{"class":936},[926,3509,1636],{"class":1600},[926,3511,3512,3514,3516,3518],{"class":928,"line":994},[926,3513,982],{"class":949},[926,3515,1643],{"class":953},[926,3517,988],{"class":949},[926,3519,1809],{"class":1600},[926,3521,3522],{"class":928,"line":1006},[926,3523,1057],{"class":936},[856,3525,1718,3526,1819,3528,1823,3530,1826,3532,1383],{},[868,3527,1818],{},[868,3529,1822],{},[868,3531,1515],{},[868,3533,1829],{},[1132,3535,3536],{"id":1832},[868,3537,1256],{},[856,3539,1837,3540,1587,3542,1842],{},[868,3541,954],{},[868,3543,870],{},[917,3545,3546],{"className":919,"code":1845,"language":921,"meta":922,"style":922},[868,3547,3548,3552,3560,3570,3580,3584,3598,3612,3626,3632,3642,3656,3670,3674],{"__ignoreMap":922},[926,3549,3550],{"class":928,"line":929},[926,3551,1852],{"class":1600},[926,3553,3554,3556,3558],{"class":928,"line":960},[926,3555,969],{"class":932},[926,3557,1859],{"class":972},[926,3559,976],{"class":936},[926,3561,3562,3564,3566,3568],{"class":928,"line":966},[926,3563,982],{"class":949},[926,3565,1791],{"class":953},[926,3567,988],{"class":949},[926,3569,991],{"class":936},[926,3571,3572,3574,3576,3578],{"class":928,"line":979},[926,3573,982],{"class":949},[926,3575,1021],{"class":953},[926,3577,988],{"class":949},[926,3579,991],{"class":936},[926,3581,3582],{"class":928,"line":994},[926,3583,1655],{"class":936},[926,3585,3586,3588,3590,3592,3594,3596],{"class":928,"line":1006},[926,3587,1890],{"class":940},[926,3589,1016],{"class":1015},[926,3591,950],{"class":949},[926,3593,1897],{"class":953},[926,3595,988],{"class":949},[926,3597,991],{"class":936},[926,3599,3600,3602,3604,3606,3608,3610],{"class":928,"line":1044},[926,3601,1906],{"class":940},[926,3603,1016],{"class":1015},[926,3605,950],{"class":949},[926,3607,1913],{"class":953},[926,3609,988],{"class":949},[926,3611,991],{"class":936},[926,3613,3614,3616,3618,3620,3622,3624],{"class":928,"line":1054},[926,3615,1922],{"class":940},[926,3617,1016],{"class":1015},[926,3619,950],{"class":949},[926,3621,1929],{"class":953},[926,3623,988],{"class":949},[926,3625,991],{"class":936},[926,3627,3628,3630],{"class":928,"line":1690},[926,3629,1938],{"class":940},[926,3631,1941],{"class":1015},[926,3633,3634,3636,3638,3640],{"class":928,"line":1707},[926,3635,1946],{"class":949},[926,3637,1949],{"class":953},[926,3639,988],{"class":949},[926,3641,991],{"class":936},[926,3643,3644,3646,3648,3650,3652,3654],{"class":928,"line":1713},[926,3645,1958],{"class":940},[926,3647,1016],{"class":1015},[926,3649,950],{"class":949},[926,3651,1965],{"class":953},[926,3653,988],{"class":949},[926,3655,991],{"class":936},[926,3657,3658,3660,3662,3664,3666,3668],{"class":928,"line":1972},[926,3659,1975],{"class":940},[926,3661,1016],{"class":1015},[926,3663,950],{"class":949},[926,3665,1982],{"class":953},[926,3667,988],{"class":949},[926,3669,991],{"class":936},[926,3671,3672],{"class":928,"line":1989},[926,3673,1710],{"class":936},[926,3675,3676],{"class":928,"line":1994},[926,3677,1057],{"class":936},[856,3679,1999,3680,1339,3682,2005],{},[868,3681,2002],{},[868,3683,1818],{},[904,3685],{},[907,3687,2011],{"id":2010},[856,3689,2014,3690,2018,3693,2021],{},[860,3691,876],{"href":874,"rel":3692},[864],[868,3694,1075],{},[1132,3696,2025],{"id":2024},[917,3698,3699],{"className":919,"code":2028,"language":921,"meta":922,"style":922},[868,3700,3701,3719,3723,3731,3741,3749],{"__ignoreMap":922},[926,3702,3703,3705,3707,3709,3711,3713,3715,3717],{"class":928,"line":929},[926,3704,933],{"class":932},[926,3706,937],{"class":936},[926,3708,2039],{"class":940},[926,3710,943],{"class":936},[926,3712,946],{"class":932},[926,3714,950],{"class":949},[926,3716,954],{"class":953},[926,3718,957],{"class":949},[926,3720,3721],{"class":928,"line":960},[926,3722,963],{"emptyLinePlaceholder":8},[926,3724,3725,3727,3729],{"class":928,"line":966},[926,3726,969],{"class":932},[926,3728,2060],{"class":972},[926,3730,976],{"class":936},[926,3732,3733,3735,3737,3739],{"class":928,"line":979},[926,3734,982],{"class":949},[926,3736,2069],{"class":953},[926,3738,988],{"class":949},[926,3740,991],{"class":936},[926,3742,3743,3745,3747],{"class":928,"line":994},[926,3744,982],{"class":949},[926,3746,1049],{"class":953},[926,3748,957],{"class":949},[926,3750,3751],{"class":928,"line":1006},[926,3752,1057],{"class":936},[856,3754,2088,3755,2092],{},[868,3756,2091],{},[1132,3758,2096],{"id":2095},[917,3760,3761],{"className":919,"code":2099,"language":921,"meta":922,"style":922},[868,3762,3763,3781,3785,3799],{"__ignoreMap":922},[926,3764,3765,3767,3769,3771,3773,3775,3777,3779],{"class":928,"line":929},[926,3766,933],{"class":932},[926,3768,937],{"class":936},[926,3770,2110],{"class":940},[926,3772,943],{"class":936},[926,3774,946],{"class":932},[926,3776,950],{"class":949},[926,3778,954],{"class":953},[926,3780,957],{"class":949},[926,3782,3783],{"class":928,"line":960},[926,3784,963],{"emptyLinePlaceholder":8},[926,3786,3787,3789,3791,3793,3795,3797],{"class":928,"line":966},[926,3788,2130],{"class":2129},[926,3790,2134],{"class":2133},[926,3792,2138],{"class":2137},[926,3794,2141],{"class":932},[926,3796,2144],{"class":972},[926,3798,2147],{"class":936},[926,3800,3801],{"class":928,"line":979},[926,3802,2152],{"class":1600},[856,3804,2155,3805,2158],{},[868,3806,1075],{},[1132,3808,2162],{"id":2161},[917,3810,3811],{"className":919,"code":2165,"language":921,"meta":922,"style":922},[868,3812,3813,3831,3835],{"__ignoreMap":922},[926,3814,3815,3817,3819,3821,3823,3825,3827,3829],{"class":928,"line":929},[926,3816,933],{"class":932},[926,3818,937],{"class":936},[926,3820,2176],{"class":940},[926,3822,943],{"class":936},[926,3824,946],{"class":932},[926,3826,950],{"class":949},[926,3828,954],{"class":953},[926,3830,957],{"class":949},[926,3832,3833],{"class":928,"line":960},[926,3834,963],{"emptyLinePlaceholder":8},[926,3836,3837,3839,3841,3843,3845,3847,3849],{"class":928,"line":966},[926,3838,969],{"class":932},[926,3840,2197],{"class":972},[926,3842,2200],{"class":936},[926,3844,988],{"class":949},[926,3846,1049],{"class":953},[926,3848,988],{"class":949},[926,3850,1057],{"class":936},[856,3852,2211,3853,2214],{},[868,3854,2091],{},[1132,3856,2218],{"id":2217},[856,3858,2221,3859,2224,3861,2227],{},[868,3860,1075],{},[868,3862,870],{},[917,3864,3865],{"className":919,"code":2230,"language":921,"meta":922,"style":922},[868,3866,3867,3875,3885,3895,3923,3933,3937,3941,3949,3959,3969,3975,3985],{"__ignoreMap":922},[926,3868,3869,3871,3873],{"class":928,"line":929},[926,3870,969],{"class":932},[926,3872,973],{"class":972},[926,3874,976],{"class":936},[926,3876,3877,3879,3881,3883],{"class":928,"line":960},[926,3878,982],{"class":949},[926,3880,985],{"class":953},[926,3882,988],{"class":949},[926,3884,991],{"class":936},[926,3886,3887,3889,3891,3893],{"class":928,"line":966},[926,3888,982],{"class":949},[926,3890,2257],{"class":953},[926,3892,988],{"class":949},[926,3894,991],{"class":936},[926,3896,3897,3899,3901,3903,3905,3907,3909,3911,3913,3915,3917,3919,3921],{"class":928,"line":979},[926,3898,1009],{"class":936},[926,3900,1012],{"class":940},[926,3902,1016],{"class":1015},[926,3904,950],{"class":949},[926,3906,1021],{"class":953},[926,3908,988],{"class":949},[926,3910,1026],{"class":936},[926,3912,1029],{"class":940},[926,3914,1016],{"class":1015},[926,3916,950],{"class":949},[926,3918,1036],{"class":953},[926,3920,988],{"class":949},[926,3922,1041],{"class":936},[926,3924,3925,3927,3929,3931],{"class":928,"line":994},[926,3926,982],{"class":949},[926,3928,1049],{"class":953},[926,3930,988],{"class":949},[926,3932,2300],{"class":1600},[926,3934,3935],{"class":928,"line":1006},[926,3936,1057],{"class":936},[926,3938,3939],{"class":928,"line":1044},[926,3940,963],{"emptyLinePlaceholder":8},[926,3942,3943,3945,3947],{"class":928,"line":1054},[926,3944,969],{"class":932},[926,3946,973],{"class":972},[926,3948,976],{"class":936},[926,3950,3951,3953,3955,3957],{"class":928,"line":1690},[926,3952,982],{"class":949},[926,3954,985],{"class":953},[926,3956,988],{"class":949},[926,3958,991],{"class":936},[926,3960,3961,3963,3965,3967],{"class":928,"line":1707},[926,3962,982],{"class":949},[926,3964,2333],{"class":953},[926,3966,988],{"class":949},[926,3968,991],{"class":936},[926,3970,3971,3973],{"class":928,"line":1713},[926,3972,2342],{"class":940},[926,3974,991],{"class":936},[926,3976,3977,3979,3981,3983],{"class":928,"line":1972},[926,3978,982],{"class":949},[926,3980,2351],{"class":953},[926,3982,988],{"class":949},[926,3984,2356],{"class":1600},[926,3986,3987],{"class":928,"line":1989},[926,3988,1057],{"class":936},[2362,3990,3991],{},[856,3992,2366,3993,1026,3995,1083,3997,2373,3999,2376],{},[868,3994,1079],{},[868,3996,1082],{},[868,3998,1086],{},[868,4000,1079],{},[904,4002],{},[907,4004,2382],{"id":2381},[856,4006,4007,2388,4009,2394],{},[868,4008,2387],{},[860,4010,2393],{"href":2391,"rel":4011},[864],[917,4013,4014],{"className":919,"code":2397,"language":921,"meta":922,"style":922},[868,4015,4016,4034,4038,4064,4068,4078,4108,4112],{"__ignoreMap":922},[926,4017,4018,4020,4022,4024,4026,4028,4030,4032],{"class":928,"line":929},[926,4019,933],{"class":932},[926,4021,937],{"class":936},[926,4023,2387],{"class":940},[926,4025,943],{"class":936},[926,4027,946],{"class":932},[926,4029,950],{"class":949},[926,4031,954],{"class":953},[926,4033,957],{"class":949},[926,4035,4036],{"class":928,"line":960},[926,4037,963],{"emptyLinePlaceholder":8},[926,4039,4040,4042,4044,4046,4048,4050,4052,4054,4056,4058,4060,4062],{"class":928,"line":966},[926,4041,2130],{"class":2129},[926,4043,2428],{"class":2133},[926,4045,2138],{"class":2137},[926,4047,2141],{"class":932},[926,4049,2435],{"class":972},[926,4051,2200],{"class":936},[926,4053,988],{"class":949},[926,4055,2442],{"class":953},[926,4057,988],{"class":949},[926,4059,1026],{"class":936},[926,4061,2449],{"class":940},[926,4063,1057],{"class":936},[926,4065,4066],{"class":928,"line":979},[926,4067,963],{"emptyLinePlaceholder":8},[926,4069,4070,4072,4074,4076],{"class":928,"line":994},[926,4071,2460],{"class":932},[926,4073,2463],{"class":936},[926,4075,2466],{"class":940},[926,4077,2469],{"class":936},[926,4079,4080,4082,4084,4086,4088,4090,4092,4094,4096,4098,4100,4102,4104,4106],{"class":928,"line":1006},[926,4081,2474],{"class":940},[926,4083,1383],{"class":936},[926,4085,2479],{"class":972},[926,4087,2200],{"class":936},[926,4089,2484],{"class":1615},[926,4091,1477],{"class":936},[926,4093,5],{"class":972},[926,4095,2491],{"class":936},[926,4097,2494],{"class":940},[926,4099,1016],{"class":1015},[926,4101,950],{"class":949},[926,4103,2501],{"class":953},[926,4105,988],{"class":949},[926,4107,2506],{"class":936},[926,4109,4110],{"class":928,"line":1044},[926,4111,2511],{"class":932},[926,4113,4114],{"class":928,"line":1054},[926,4115,2516],{"class":936},[856,4117,2519,4118,2523,4120,2527],{},[860,4119,2522],{"href":611},[868,4121,2526],{},[2529,4123,4124],{},[856,4125,2533,4126,2536,4128,2540],{},[868,4127,2387],{},[868,4129,2539],{},[856,4131,2543,4132,2547,4134,2550],{},[860,4133,2546],{"href":100},[868,4135,2387],{},[904,4137],{},[907,4139,2556],{"id":2555},[856,4141,4142,2562,4144,2567],{},[868,4143,2561],{},[860,4145,901],{"href":2565,"rel":4146},[864],[917,4148,4149],{"className":919,"code":2570,"language":921,"meta":922,"style":922},[868,4150,4151,4169,4173,4199,4203,4215,4245,4249],{"__ignoreMap":922},[926,4152,4153,4155,4157,4159,4161,4163,4165,4167],{"class":928,"line":929},[926,4154,933],{"class":932},[926,4156,937],{"class":936},[926,4158,2561],{"class":940},[926,4160,943],{"class":936},[926,4162,946],{"class":932},[926,4164,950],{"class":949},[926,4166,954],{"class":953},[926,4168,957],{"class":949},[926,4170,4171],{"class":928,"line":960},[926,4172,963],{"emptyLinePlaceholder":8},[926,4174,4175,4177,4179,4181,4183,4185,4187,4189,4191,4193,4195,4197],{"class":928,"line":966},[926,4176,2130],{"class":2129},[926,4178,2601],{"class":2133},[926,4180,2138],{"class":2137},[926,4182,2141],{"class":932},[926,4184,2608],{"class":972},[926,4186,2200],{"class":936},[926,4188,988],{"class":949},[926,4190,985],{"class":953},[926,4192,988],{"class":949},[926,4194,1026],{"class":936},[926,4196,2449],{"class":940},[926,4198,1057],{"class":936},[926,4200,4201],{"class":928,"line":979},[926,4202,963],{"emptyLinePlaceholder":8},[926,4204,4205,4207,4209,4211,4213],{"class":928,"line":994},[926,4206,2460],{"class":932},[926,4208,2463],{"class":936},[926,4210,2635],{"class":2137},[926,4212,2638],{"class":940},[926,4214,2469],{"class":936},[926,4216,4217,4219,4221,4223,4225,4227,4229,4231,4233,4235,4237,4239,4241,4243],{"class":928,"line":1006},[926,4218,2474],{"class":940},[926,4220,1383],{"class":936},[926,4222,2479],{"class":972},[926,4224,2200],{"class":936},[926,4226,2484],{"class":1615},[926,4228,1477],{"class":936},[926,4230,5],{"class":972},[926,4232,2491],{"class":936},[926,4234,2494],{"class":940},[926,4236,1016],{"class":1015},[926,4238,950],{"class":949},[926,4240,2667],{"class":953},[926,4242,988],{"class":949},[926,4244,2506],{"class":936},[926,4246,4247],{"class":928,"line":1044},[926,4248,2511],{"class":932},[926,4250,4251],{"class":928,"line":1054},[926,4252,2516],{"class":936},[856,4254,2682,4255,2686,4257,2690,4259,2694,4261,2698],{},[868,4256,2685],{},[868,4258,2689],{},[868,4260,2693],{},[882,4262,2697],{},[2362,4264,4265],{},[856,4266,2703,4267,2706,4269,2709,4271,2712],{},[868,4268,2561],{},[868,4270,2387],{},[860,4272,2546],{"href":100},[904,4274],{},[907,4276,2718],{"id":2717},[1132,4278,2722],{"id":2721},[856,4280,2725,4281,2728],{},[868,4282,1123],{},[1353,4284,4285,4292],{},[1356,4286,4287],{"name":2733,"type":1359,":required":1360},[856,4288,2736,4289,2740],{},[860,4290,865],{"href":862,"rel":4291},[864],[1356,4293,4294],{"name":2743,"type":1359,":required":1360},[856,4295,2746,4296,2750],{},[868,4297,2749],{},[1132,4299,2754],{"id":2753},[856,4301,2757,4302,1383],{},[868,4303,1562],{},[1353,4305,4306,4310,4314,4318,4322],{},[1356,4307,4308],{"name":2764,"type":1359},[856,4309,2767],{},[1356,4311,4312],{"name":2770,"type":1359},[856,4313,2773],{},[1356,4315,4316],{"name":2776,"type":1359},[856,4317,2779],{},[1356,4319,4320],{"name":2782,"type":1359},[856,4321,2785],{},[1356,4323,4324],{"name":1818,"type":1359},[856,4325,2790],{},[1132,4327,2794],{"id":2793},[856,4329,2797,4330,1383],{},[868,4331,1565],{},[1353,4333,4334,4338,4342,4346,4350],{},[1356,4335,4336],{"name":2804,"type":1359},[856,4337,1530],{},[1356,4339,4340],{"name":2809,"type":1359},[856,4341,2812],{},[1356,4343,4344],{"name":2815,"type":1359},[856,4345,2818],{},[1356,4347,4348],{"name":2821,"type":1359},[856,4349,2824],{},[1356,4351,4352],{"name":2827,"type":1359},[856,4353,2830],{},[2832,4355,2834],{},{"title":922,"searchDepth":960,"depth":960,"links":4357},[4358,4359,4363,4367,4372,4378,4379,4380],{"id":909,"depth":960,"text":910},{"id":1129,"depth":960,"text":1130,"children":4360},[4361,4362],{"id":1134,"depth":966,"text":1135},{"id":1240,"depth":966,"text":1241},{"id":1331,"depth":960,"text":1332,"children":4364},[4365,4366],{"id":1350,"depth":966,"text":1351},{"id":1458,"depth":966,"text":1459},{"id":1552,"depth":960,"text":1553,"children":4368},[4369,4370,4371],{"id":1569,"depth":966,"text":1572},{"id":1738,"depth":966,"text":1252},{"id":1832,"depth":966,"text":1256},{"id":2010,"depth":960,"text":2011,"children":4373},[4374,4375,4376,4377],{"id":2024,"depth":966,"text":2025},{"id":2095,"depth":966,"text":2096},{"id":2161,"depth":966,"text":2162},{"id":2217,"depth":966,"text":2218},{"id":2381,"depth":960,"text":2382},{"id":2555,"depth":960,"text":2556},{"id":2717,"depth":960,"text":2718,"children":4381},[4382,4383,4384],{"id":2721,"depth":966,"text":2722},{"id":2753,"depth":966,"text":2754},{"id":2793,"depth":966,"text":2794},{},{"title":119,"description":2864},1780436282231]