{"_id":"@codeimplants/authkit","_rev":"7-3662715cffd728832c3299df3f6822fe","name":"@codeimplants/authkit","dist-tags":{"latest":"2.1.0"},"versions":{"1.0.0":{"name":"@codeimplants/authkit","version":"1.0.0","keywords":["authentication","jwt","otp","nodejs","express","auth","middleware","mongoose","oauth","email-verification","typescript"],"author":{"name":"Code Implants Software Technologies Pvt. Ltd."},"license":"MIT","_id":"@codeimplants/authkit@1.0.0","maintainers":[{"name":"codeimplants","email":"codeimplants@gmail.com"}],"dist":{"shasum":"d7a5d749bedda645906e9c4593cfb9fa4eef4aed","tarball":"https://registry.npmjs.org/@codeimplants/authkit/-/authkit-1.0.0.tgz","fileCount":61,"integrity":"sha512-F496m1us+dXleuxPl7p4R0QgS0xfa9xabAFACoFwoYTqnJ+NGOVlyfaMx1qf7AlW9pJcbUQGTQcNvovRCm2L/w==","signatures":[{"sig":"MEUCIQCLt0sG3zGrKWjoAdsiptx8rKP+FztSoZSvtUFvxSuFwAIgDEucZneTw7/2x3vzZYUP67oyNNz48x8xijb4vzofdP8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":133553},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","gitHead":"4d62753ad24a7e431b2b87a7e622cb629740e0b4","private":false,"scripts":{"dev":"tsc -w","docs":"jsdoc src/ -d docs","lint":"eslint src/","test":"echo \"Error: no test specified\" && exit 1","build":"tsc","clean":"rm -rf dist","start":"node dist/index.js","format":"prettier --write src/"},"_npmUser":{"name":"codeimplants","actor":{"name":"codeimplants","type":"user","email":"codeimplants@gmail.com"},"email":"codeimplants@gmail.com"},"_npmVersion":"10.9.0","description":"Reusable authentication module for Node.js with OTP, JWT, and role-based authorization.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"axios":"^1.10.0","crypto":"^1.0.1","express":"^4.x || ^5.x","jsonwebtoken":"^9.0.2","express-validator":"^7.2.1"},"_hasShrinkwrap":false,"devDependencies":{"nodemon":"^3.1.10","typescript":"^5.2.0","@types/node":"^20.0.0","@types/express":"^5.0.3","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"cors":"^2.x","dotenv":"^16.x","express":"^4.x || ^5.x","mongoose":"^8.x","cookie-parser":"^1.x","express-rate-limit":"^7.x"},"_npmOperationalInternal":{"tmp":"tmp/authkit_1.0.0_1751538095550_0.7280326012565312","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@codeimplants/authkit","version":"1.0.1","keywords":["authentication","jwt","otp","nodejs","express","auth","middleware","mongoose","oauth","email-verification","typescript"],"author":{"name":"Code Implants Software Technologies Pvt. Ltd."},"license":"MIT","_id":"@codeimplants/authkit@1.0.1","maintainers":[{"name":"codeimplants","email":"codeimplants@gmail.com"}],"dist":{"shasum":"5a5cc77d4bb5695148fccc98ce536913b4870729","tarball":"https://registry.npmjs.org/@codeimplants/authkit/-/authkit-1.0.1.tgz","fileCount":61,"integrity":"sha512-sBRG93IXeNLrwTzGp5+ZnE+U4/7d6v5XvkzwhFXEYVcMZqkV/pI3ESYxjgOgH46Wh4eV4Uu9cR6W11ApHc3sNA==","signatures":[{"sig":"MEUCIBFLnNVuJE1NwK6p+j6ZYDvHfsZ/qJQdazZFGK86YLZdAiEArbbudukCWR7DBthyI/hFI5CN3JkT8n6603dUPkG3nzQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":136476},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","gitHead":"4b6a48ba899263d7f447a469d8a31f495b2d492b","scripts":{"dev":"tsc -w","docs":"jsdoc src/ -d docs","lint":"eslint src/","test":"echo \"Error: no test specified\" && exit 1","build":"tsc","clean":"rm -rf dist","start":"node dist/index.js","format":"prettier --write src/"},"_npmUser":{"name":"codeimplants","actor":{"name":"codeimplants","type":"user","email":"codeimplants@gmail.com"},"email":"codeimplants@gmail.com"},"_npmVersion":"10.9.0","description":"Reusable authentication module for Node.js with OTP, JWT, and role-based authorization.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"axios":"^1.10.0","crypto":"^1.0.1","express":"^4.x || ^5.x","jsonwebtoken":"^9.0.2","express-validator":"^7.2.1"},"_hasShrinkwrap":false,"devDependencies":{"nodemon":"^3.1.10","typescript":"^5.2.0","@types/node":"^20.0.0","@types/express":"^5.0.3","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"cors":"^2.x","dotenv":"^16.x","express":"^4.x || ^5.x","mongoose":"^8.x","cookie-parser":"^1.x","express-rate-limit":"^7.x"},"_npmOperationalInternal":{"tmp":"tmp/authkit_1.0.1_1751742213859_0.7260005959921567","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@codeimplants/authkit","version":"1.0.2","keywords":["authentication","jwt","otp","nodejs","express","auth","middleware","mongoose","oauth","email-verification","typescript"],"author":{"name":"Code Implants Software Technologies Pvt. Ltd."},"license":"MIT","_id":"@codeimplants/authkit@1.0.2","maintainers":[{"name":"codeimplants","email":"codeimplants@gmail.com"}],"dist":{"shasum":"1d7aeaddfd35811a54cce94b94aeb9dbe40bb865","tarball":"https://registry.npmjs.org/@codeimplants/authkit/-/authkit-1.0.2.tgz","fileCount":61,"integrity":"sha512-cqTkXk5P06gay9Z9SXdhfqDs8PenZgggtxDimdaP+pyheztI6Obw/Kxtg0GR02AlC/jEPwjxwmr8D64DmnFmiQ==","signatures":[{"sig":"MEUCIQCqTnOi4G3GqVWjczQc4TrYhy6P7LRrJCvm22ltInbPugIgdj+LBjIe7PzjkFCiXMk34hKDo+3IptXedUzmBYuimIQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":139584},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","gitHead":"89edbb8fb84d1b94712aa9a3f72d8bda0f1f5c77","scripts":{"dev":"tsc -w","docs":"jsdoc src/ -d docs","lint":"eslint src/","test":"echo \"Error: no test specified\" && exit 1","build":"tsc","clean":"rm -rf dist","start":"node dist/index.js","format":"prettier --write src/"},"_npmUser":{"name":"codeimplants","actor":{"name":"codeimplants","type":"user","email":"codeimplants@gmail.com"},"email":"codeimplants@gmail.com"},"_npmVersion":"10.9.0","description":"Reusable authentication module for Node.js with OTP, JWT, and role-based authorization.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"axios":"^1.10.0","debug":"^4.4.1","crypto":"^1.0.1","express":"^4.x || ^5.x","jsonwebtoken":"^9.0.2","express-validator":"^7.2.1"},"_hasShrinkwrap":false,"devDependencies":{"nodemon":"^3.1.10","typescript":"^5.2.0","@types/node":"^20.0.0","@types/debug":"^4.1.12","@types/express":"^5.0.3","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"cors":"^2.x","dotenv":"^16.x","express":"^4.x || ^5.x","mongoose":"^8.x","cookie-parser":"^1.x","express-rate-limit":"^7.x"},"_npmOperationalInternal":{"tmp":"tmp/authkit_1.0.2_1751886293786_0.23018110409409798","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@codeimplants/authkit","version":"1.0.3","keywords":["authentication","jwt","otp","nodejs","express","auth","middleware","mongoose","oauth","email-verification","typescript"],"author":{"name":"Code Implants Software Technologies Pvt. Ltd."},"license":"MIT","_id":"@codeimplants/authkit@1.0.3","maintainers":[{"name":"codeimplants","email":"codeimplants@gmail.com"}],"dist":{"shasum":"f2da63104a728c566fa19429dbc595dcc7c755e8","tarball":"https://registry.npmjs.org/@codeimplants/authkit/-/authkit-1.0.3.tgz","fileCount":62,"integrity":"sha512-kamMjMWjUHc1twPfzWfj7TZb0jzaZFqYyr5PR1/LeS6mAZUDLefEkZY4m6rYETuMovlm+HcF2GPQcZpUTYkSRQ==","signatures":[{"sig":"MEUCIGdJu+2+QMix3eUDIW6OkNVSMs54NSVhriR3Wdtr4D/KAiEAzonRwAazbt6Hd9CUrVYJW/Z5rYkNfard72BaVGiLIps=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":161192},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","gitHead":"8c80134e76657331fcabfa65d1fa715cede0d041","scripts":{"dev":"tsc -w","docs":"jsdoc src/ -d docs","lint":"eslint src/","test":"echo \"Error: no test specified\" && exit 1","build":"tsc","clean":"rm -rf dist","start":"node dist/index.js","format":"prettier --write src/"},"_npmUser":{"name":"codeimplants","email":"codeimplants@gmail.com"},"_npmVersion":"10.9.0","description":"Reusable authentication module for Node.js with OTP, JWT, and role-based authorization.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"axios":"^1.10.0","debug":"^4.4.1","crypto":"^1.0.1","express":"^4.x || ^5.x","nodemailer":"^6.9.0","jsonwebtoken":"^9.0.2","express-validator":"^7.2.1"},"_hasShrinkwrap":false,"devDependencies":{"nodemon":"^3.1.10","typescript":"^5.2.0","@types/node":"^20.0.0","@types/debug":"^4.1.12","@types/express":"^5.0.3","@types/nodemailer":"^6.4.0","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"cors":"^2.x","dotenv":"^16.x","express":"^4.x || ^5.x","mongoose":"^8.x","cookie-parser":"^1.x","express-rate-limit":"^7.x"},"_npmOperationalInternal":{"tmp":"tmp/authkit_1.0.3_1753614087576_0.3099637155727504","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@codeimplants/authkit","version":"1.0.4","keywords":["authentication","jwt","otp","nodejs","express","auth","middleware","mongoose","oauth","email-verification","typescript"],"author":{"name":"Code Implants Software Technologies Pvt. Ltd."},"license":"MIT","_id":"@codeimplants/authkit@1.0.4","maintainers":[{"name":"codeimplants","email":"codeimplants@gmail.com"}],"dist":{"shasum":"cc2f9dcf6006f2fd3b96af8caa6e1cf42ef795f8","tarball":"https://registry.npmjs.org/@codeimplants/authkit/-/authkit-1.0.4.tgz","fileCount":82,"integrity":"sha512-L5qg1twFyPnfdsjY9rg55PmG2n++2CA2McOYj6ju5Iz9oWFLVLCfcNjV/KnpZDhah6SAJJK+mIrYz2YxFd/IZQ==","signatures":[{"sig":"MEUCIQCy5hp/LCQBfaOdEj9XBddFB0Zp3cP5I8mnxXobNrCYKwIgYcWmGAGG2F4EbcdBPIgSt9SHZ0b6UJpZ/d554eWOj1E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":237847},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","gitHead":"b9ce01ec639c1d6d5166bffbc729ad03b3f60c30","scripts":{"dev":"tsc -w","docs":"jsdoc src/ -d docs","lint":"eslint src/","test":"echo \"Error: no test specified\" && exit 1","build":"tsc","clean":"rm -rf dist","start":"node dist/index.js","format":"prettier --write src/"},"_npmUser":{"name":"codeimplants","email":"codeimplants@gmail.com"},"_npmVersion":"10.9.0","description":"Reusable authentication module for Node.js with OTP, JWT, and role-based authorization.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"axios":"^1.10.0","debug":"^4.4.1","bcrypt":"^6.0.0","crypto":"^1.0.1","express":"^4.x || ^5.x","nodemailer":"^6.9.0","jsonwebtoken":"^9.0.2","express-validator":"^7.2.1"},"_hasShrinkwrap":false,"devDependencies":{"nodemon":"^3.1.10","typescript":"^5.2.0","@types/node":"^20.0.0","@types/debug":"^4.1.12","@types/bcrypt":"^5.0.2","@types/express":"^5.0.3","@types/nodemailer":"^6.4.0","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"cors":"^2.x","dotenv":"^16.x","express":"^4.x || ^5.x","mongoose":"^8.x","cookie-parser":"^1.x","express-rate-limit":"^7.x"},"_npmOperationalInternal":{"tmp":"tmp/authkit_1.0.4_1754205013039_0.3879035939684645","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@codeimplants/authkit","version":"1.0.5","keywords":["authentication","jwt","otp","nodejs","express","auth","middleware","mongoose","oauth","email-verification","typescript"],"author":{"name":"Code Implants Software Technologies Pvt. Ltd."},"license":"MIT","_id":"@codeimplants/authkit@1.0.5","maintainers":[{"name":"codeimplants","email":"codeimplants@gmail.com"}],"dist":{"shasum":"234ca0b368491ac2304277056689e9c0ef4a9aee","tarball":"https://registry.npmjs.org/@codeimplants/authkit/-/authkit-1.0.5.tgz","fileCount":78,"integrity":"sha512-ykQYr7Lw6y0Cz3zmtgjdWixzqhU5UE9KsM6rdv9blB/McKHan6g1ITOCpNtS/R3WaNerriB5GsJPqx6CMmD6tQ==","signatures":[{"sig":"MEQCIF5wpKS4/rTOFDZQPIc0h9xkkgtqhsEfxRtcq48OnI3SAiAHlWgaKmTPU0heVCsRpnuy1zIzbEOPLKCxAK0MBggVpw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":223459},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","gitHead":"bb1cd9946b5a70c20485769009238d26c17ece93","scripts":{"dev":"tsc -w","docs":"jsdoc src/ -d docs","lint":"eslint src/","test":"echo \"Error: no test specified\" && exit 1","build":"tsc","clean":"rm -rf dist","start":"node dist/index.js","format":"prettier --write src/"},"_npmUser":{"name":"codeimplants","email":"codeimplants@gmail.com"},"_npmVersion":"10.9.0","description":"Reusable authentication module for Node.js with OTP, JWT, and role-based authorization.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"axios":"^1.10.0","debug":"^4.4.1","bcrypt":"^6.0.0","crypto":"^1.0.1","express":"^4.x || ^5.x","nodemailer":"^6.9.0","jsonwebtoken":"^9.0.2","express-validator":"^7.2.1"},"_hasShrinkwrap":false,"devDependencies":{"nodemon":"^3.1.10","typescript":"^5.2.0","@types/node":"^20.0.0","@types/debug":"^4.1.12","@types/bcrypt":"^5.0.2","@types/express":"^5.0.3","@types/nodemailer":"^6.4.0","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"cors":"^2.x","dotenv":"^16.x","express":"^4.x || ^5.x","mongoose":"^8.x","cookie-parser":"^1.x","express-rate-limit":"^7.x"},"_npmOperationalInternal":{"tmp":"tmp/authkit_1.0.5_1758532134261_0.2361006911744048","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@codeimplants/authkit","version":"2.1.0","description":"Multi-platform authentication module for Node.js with web and mobile support. Includes OTP, JWT, email/password authentication, and role-based authorization.","main":"dist/index.js","types":"dist/index.d.ts","type":"module","scripts":{"build":"tsc","dev":"tsc -w","test":"echo \"Error: no test specified\" && exit 1","start":"node dist/index.js","lint":"eslint src/","format":"prettier --write src/","docs":"jsdoc src/ -d docs","clean":"rm -rf dist"},"keywords":["authentication","jwt","otp","nodejs","express","auth","middleware","mongoose","oauth","email-verification","typescript","mobile","react-native","flutter","ionic","capacitor","multi-platform","web","cookies","bearer-token"],"author":{"name":"Code Implants Software Technologies Pvt. Ltd."},"license":"MIT","dependencies":{"axios":"^1.10.0","bcrypt":"^6.0.0","crypto":"^1.0.1","debug":"^4.4.1","express":"^4.x || ^5.x","express-validator":"^7.2.1","jsonwebtoken":"^9.0.2","nodemailer":"^6.9.0"},"devDependencies":{"@types/bcrypt":"^5.0.2","@types/debug":"^4.1.12","@types/express":"^5.0.3","@types/jsonwebtoken":"^9.0.0","@types/mongoose":"^5.11.96","@types/node":"^20.0.0","@types/nodemailer":"^6.4.0","express-rate-limit":"^8.2.1","mongoose":"^9.1.5","nodemon":"^3.1.10","typescript":"^5.2.0"},"peerDependencies":{"cookie-parser":"^1.x","cors":"^2.x","dotenv":"^16.x","express":"^4.x || ^5.x","express-rate-limit":"^7.x","mongoose":"^8.x"},"gitHead":"89445770e0c3d06cb0a877ad7588d2aa28c83ec4","_id":"@codeimplants/authkit@2.1.0","_nodeVersion":"22.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-/GipKMCpSoOxgvK12ooG8OjfLc3mLK8sDpY5Sk7Sh2ZJQSfJ4BkHXtsYDV6Tp0YmEXNVHK2VO0fUdLtScf0zEA==","shasum":"65e1cc9f2c742770185f420e07b03ccc660f1c3b","tarball":"https://registry.npmjs.org/@codeimplants/authkit/-/authkit-2.1.0.tgz","fileCount":83,"unpackedSize":241149,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDSJriO3fy7PpZoKomr5IwfiYdYov/lS8hyW5GjPB6ilAiBtE6i+A7BmxQuEinVTrixfzwSlaOzzxl77HaVte+beLg=="}]},"_npmUser":{"name":"codeimplants","email":"codeimplants@gmail.com"},"directories":{},"maintainers":[{"name":"codeimplants","email":"codeimplants@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/authkit_2.1.0_1770321946812_0.5613955591755644"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-03T10:21:35.433Z","modified":"2026-02-05T20:05:47.112Z","1.0.0":"2025-07-03T10:21:35.780Z","1.0.1":"2025-07-05T19:03:34.036Z","1.0.2":"2025-07-07T11:04:53.950Z","1.0.3":"2025-07-27T11:01:27.749Z","1.0.4":"2025-08-03T07:10:13.211Z","1.0.5":"2025-09-22T09:08:54.437Z","2.1.0":"2026-02-05T20:05:46.980Z"},"author":{"name":"Code Implants Software Technologies Pvt. Ltd."},"license":"MIT","keywords":["authentication","jwt","otp","nodejs","express","auth","middleware","mongoose","oauth","email-verification","typescript","mobile","react-native","flutter","ionic","capacitor","multi-platform","web","cookies","bearer-token"],"description":"Multi-platform authentication module for Node.js with web and mobile support. Includes OTP, JWT, email/password authentication, and role-based authorization.","maintainers":[{"name":"codeimplants","email":"codeimplants@gmail.com"}],"readme":"# 🔐 Auth Package\r\n\r\nA comprehensive, production-ready authentication package for Node.js applications with **full TypeScript support**, **web and mobile platform support**, and multiple authentication methods including OTP, JWT, and role-based authorization.\r\n\r\n## ✨ Features\r\n\r\n- **🔑 JWT Authentication** - Access and refresh token management\r\n- **📧 Email/Password Authentication** - Traditional email and password login with bcrypt encryption\r\n- **📱 Phone OTP** - SMS-based one-time password verification\r\n- **📧 Email OTP** - Email-based verification (ready for integration)\r\n- **🔒 Role-based Authorization** - Flexible permission system\r\n- **🌐 Multi-Platform Support** - Automatic detection and handling of web (cookies) and mobile (JSON) clients\r\n- **🔄 Hybrid App Support** - Seamless authentication for React + Capacitor, Ionic, and other hybrid frameworks\r\n- **🍪 Cookie-based Tokens** - Secure token storage for web applications\r\n- **📱 JSON Response Mode** - Token delivery in JSON for mobile applications (React Native, Flutter, Ionic, etc.)\r\n- **🔄 Automatic Token Refresh** - Seamless session management for both web and mobile\r\n- **⚡ Express Middleware** - Easy integration with Express apps\r\n- **📝 Input Validation** - Built-in request validation\r\n- **🛡️ Security Features** - Rate limiting, secure cookies, environment-based configs\r\n- **📘 Full TypeScript Support** - Complete type definitions and IntelliSense\r\n\r\n## 🚀 Quick Start\r\n\r\n### Installation\r\n\r\n```bash\r\nnpm install @codeimplants/authkit\r\n```\r\n\r\n### Basic Usage (JavaScript)\r\n\r\n```javascript\r\nimport express from \"express\";\r\nimport mongoose from \"mongoose\";\r\nimport { AuthManager } from \"@codeimplants/authkit\";\r\n\r\n// Define your User model\r\nconst userSchema = new mongoose.Schema({\r\n  name: String,\r\n  phoneNumber: { type: String, unique: true },\r\n  userRole: { type: String, default: \"user\" },\r\n  // ... other fields\r\n});\r\nconst User = mongoose.model(\"User\", userSchema);\r\n\r\n// Initialize Auth Manager\r\nconst authManager = new AuthManager({\r\n  User,\r\n  jwtAccessSecret: process.env.JWT_ACCESS_SECRET,\r\n  jwtRefreshSecret: process.env.JWT_REFRESH_SECRET,\r\n  otpUrl: process.env.OTP_URL,\r\n  otpApiKey: process.env.OTP_API_KEY,\r\n  otptemplate: process.env.OTP_TEMPLATE,\r\n  security: {\r\n    responseMode: \"auto\", // 'auto', 'cookie', or 'json'\r\n  },\r\n});\r\n\r\n// Set up routes\r\napp.post(\r\n  \"/send-register-otp\",\r\n  authManager.validators.validateSendOtp,\r\n  authManager.controllers.otp.sendRegisterOTP,\r\n);\r\napp.post(\r\n  \"/send-login-otp\",\r\n  authManager.validators.validateSendOtp,\r\n  authManager.controllers.otp.sendLoginOTP,\r\n);\r\napp.post(\r\n  \"/verify-otp\",\r\n  authManager.validators.validateVerifyOtp,\r\n  authManager.controllers.otp.verifyOtp,\r\n);\r\n\r\n// Email OTP routes\r\napp.post(\"/send-email-otp\", authManager.controllers.emailOtp.sendEmailOtp);\r\napp.post(\"/verify-email-otp\", authManager.controllers.emailOtp.verifyEmailOtp);\r\n\r\napp.post(\"/refresh-token\", authManager.controllers.auth.refreshAccessToken);\r\napp.post(\"/logout\", authManager.controllers.auth.logoutUser);\r\n\r\n// Protected route\r\napp.get(\"/profile\", authManager.middleware.protect, (req, res) => {\r\n  res.json({ user: req.user });\r\n});\r\n```\r\n\r\n## 🌐 Web vs Mobile Support\r\n\r\n### Automatic Detection (Recommended)\r\n\r\nThe package automatically detects whether the client is a web browser or mobile app and responds accordingly:\r\n\r\n```javascript\r\nconst authManager = new AuthManager({\r\n  User,\r\n  jwtAccessSecret: process.env.JWT_ACCESS_SECRET,\r\n  jwtRefreshSecret: process.env.JWT_REFRESH_SECRET,\r\n  security: {\r\n    responseMode: \"auto\", // Automatically detects client type\r\n  },\r\n});\r\n```\r\n\r\n**Detection Priority (in order):**\r\n\r\n1. **`X-Client-Type: web`** → Always uses cookie-based authentication (HTTP-only cookies)\r\n2. **`X-Client-Type: mobile`** → Always uses JSON-based authentication (tokens in response)\r\n3. **User-Agent fallback** → Checks for mobile indicators: Mobile, Android, iPhone, iPad, React Native, Ionic, Flutter\r\n\r\n> **⚠️ Important for Hybrid Apps (React + Capacitor, Ionic, etc.):**  \r\n> Always send the `X-Client-Type` header to ensure correct authentication mode. The User-Agent alone cannot reliably distinguish between web and mobile versions of hybrid apps.\r\n\r\n### Manual Configuration\r\n\r\nYou can also manually set the response mode:\r\n\r\n```javascript\r\n// Force cookie mode (web only)\r\nsecurity: {\r\n  responseMode: \"cookie\";\r\n}\r\n\r\n// Force JSON mode (mobile only)\r\nsecurity: {\r\n  responseMode: \"json\";\r\n}\r\n```\r\n\r\n## 🔄 Hybrid App Support (React + Capacitor, Ionic, etc.)\r\n\r\n### The Challenge\r\n\r\nHybrid apps (React + Capacitor, Ionic, etc.) can run in **two different environments**:\r\n\r\n- **Web**: Running in a browser → Needs cookie-based authentication\r\n- **Mobile**: Running as a native app on iOS/Android → Needs JSON token authentication\r\n\r\nUsing the wrong authentication mode can lead to **security vulnerabilities**!\r\n\r\n### The Solution\r\n\r\nAlways send the `X-Client-Type` header based on the runtime platform:\r\n\r\n```typescript\r\nimport { Capacitor } from \"@capacitor/core\";\r\nimport axios from \"axios\";\r\n\r\n// Detect if running as native mobile app\r\nconst isNativePlatform = () => {\r\n  return Capacitor.isNativePlatform(); // true for iOS/Android, false for web\r\n};\r\n\r\n// Get the appropriate client type\r\nconst getClientType = () => {\r\n  return isNativePlatform() ? \"mobile\" : \"web\";\r\n};\r\n\r\n// Create axios instance with dynamic configuration\r\nconst api = axios.create({\r\n  baseURL: \"https://api.example.com\",\r\n  withCredentials: !isNativePlatform(), // Only for web (cookies)\r\n});\r\n\r\n// Add interceptor to set X-Client-Type header\r\napi.interceptors.request.use((config) => {\r\n  config.headers[\"X-Client-Type\"] = getClientType();\r\n\r\n  // For mobile: Add access token from secure storage\r\n  if (isNativePlatform()) {\r\n    const accessToken = await SecureStore.getItemAsync(\"accessToken\");\r\n    if (accessToken) {\r\n      config.headers[\"Authorization\"] = `Bearer ${accessToken}`;\r\n    }\r\n  }\r\n  // For web: Cookies are sent automatically\r\n\r\n  return config;\r\n});\r\n\r\nexport default api;\r\n```\r\n\r\n### Login Flow for Hybrid Apps\r\n\r\n```typescript\r\nimport api from \"./api\";\r\nimport * as SecureStore from \"expo-secure-store\";\r\n\r\nconst login = async (phoneNumber: string, otp: string) => {\r\n  const response = await api.post(\"/auth/verify-otp\", {\r\n    phoneNumber,\r\n    otp,\r\n  });\r\n\r\n  if (isNativePlatform()) {\r\n    // Mobile: Store tokens in secure storage\r\n    const { accessToken, refreshToken } = response.data;\r\n    await SecureStore.setItemAsync(\"accessToken\", accessToken);\r\n    await SecureStore.setItemAsync(\"refreshToken\", refreshToken);\r\n  }\r\n  // Web: Tokens are automatically stored in HTTP-only cookies\r\n\r\n  return response.data;\r\n};\r\n```\r\n\r\n### Why This Matters\r\n\r\n| Scenario         | Without X-Client-Type                        | With X-Client-Type                    |\r\n| ---------------- | -------------------------------------------- | ------------------------------------- |\r\n| Capacitor Web    | ❌ May get JSON tokens (insecure in browser) | ✅ Gets HTTP-only cookies (secure)    |\r\n| Capacitor Mobile | ⚠️ May get cookies (won't work)              | ✅ Gets JSON tokens (works correctly) |\r\n| Pure Web         | ✅ Gets cookies                              | ✅ Gets cookies                       |\r\n| Pure Mobile      | ✅ Gets JSON tokens                          | ✅ Gets JSON tokens                   |\r\n\r\n## 📱 Mobile Client Integration\r\n\r\n### React Native Example\r\n\r\n```javascript\r\n// Login request\r\nconst login = async (email, password) => {\r\n  const response = await fetch(\"https://api.example.com/auth/login\", {\r\n    method: \"POST\",\r\n    headers: {\r\n      \"Content-Type\": \"application/json\",\r\n      \"X-Client-Type\": \"mobile\", // Ensures JSON response\r\n    },\r\n    body: JSON.stringify({ email, password }),\r\n  });\r\n\r\n  const data = await response.json();\r\n\r\n  // Store tokens in secure storage\r\n  await SecureStore.setItemAsync(\"accessToken\", data.accessToken);\r\n  await SecureStore.setItemAsync(\"refreshToken\", data.refreshToken);\r\n\r\n  return data;\r\n};\r\n\r\n// Protected API request\r\nconst fetchProfile = async () => {\r\n  const accessToken = await SecureStore.getItemAsync(\"accessToken\");\r\n\r\n  const response = await fetch(\"https://api.example.com/profile\", {\r\n    headers: {\r\n      Authorization: `Bearer ${accessToken}`,\r\n      \"X-Client-Type\": \"mobile\",\r\n    },\r\n  });\r\n\r\n  // Check for token refresh\r\n  const newAccessToken = response.headers.get(\"X-New-Access-Token\");\r\n  const newRefreshToken = response.headers.get(\"X-New-Refresh-Token\");\r\n\r\n  if (newAccessToken) {\r\n    await SecureStore.setItemAsync(\"accessToken\", newAccessToken);\r\n    await SecureStore.setItemAsync(\"refreshToken\", newRefreshToken);\r\n  }\r\n\r\n  return response.json();\r\n};\r\n\r\n// Refresh token\r\nconst refreshToken = async () => {\r\n  const refreshToken = await SecureStore.getItemAsync(\"refreshToken\");\r\n\r\n  const response = await fetch(\"https://api.example.com/auth/refresh-token\", {\r\n    method: \"POST\",\r\n    headers: {\r\n      \"Content-Type\": \"application/json\",\r\n      \"X-Client-Type\": \"mobile\",\r\n      \"X-Refresh-Token\": refreshToken,\r\n    },\r\n  });\r\n\r\n  const data = await response.json();\r\n\r\n  await SecureStore.setItemAsync(\"accessToken\", data.accessToken);\r\n  await SecureStore.setItemAsync(\"refreshToken\", data.refreshToken);\r\n\r\n  return data;\r\n};\r\n```\r\n\r\n### Flutter Example\r\n\r\n```dart\r\nimport 'package:flutter_secure_storage/flutter_secure_storage.dart';\r\nimport 'package:http/http.dart' as http;\r\nimport 'dart:convert';\r\n\r\nclass AuthService {\r\n  final storage = FlutterSecureStorage();\r\n  final String baseUrl = 'https://api.example.com';\r\n\r\n  Future<Map<String, dynamic>> login(String email, String password) async {\r\n    final response = await http.post(\r\n      Uri.parse('$baseUrl/auth/login'),\r\n      headers: {\r\n        'Content-Type': 'application/json',\r\n        'X-Client-Type': 'mobile',\r\n      },\r\n      body: jsonEncode({'email': email, 'password': password}),\r\n    );\r\n\r\n    final data = jsonDecode(response.body);\r\n\r\n    // Store tokens securely\r\n    await storage.write(key: 'accessToken', value: data['accessToken']);\r\n    await storage.write(key: 'refreshToken', value: data['refreshToken']);\r\n\r\n    return data;\r\n  }\r\n\r\n  Future<Map<String, dynamic>> fetchProfile() async {\r\n    final accessToken = await storage.read(key: 'accessToken');\r\n\r\n    final response = await http.get(\r\n      Uri.parse('$baseUrl/profile'),\r\n      headers: {\r\n        'Authorization': 'Bearer $accessToken',\r\n        'X-Client-Type': 'mobile',\r\n      },\r\n    );\r\n\r\n    // Check for token refresh\r\n    final newAccessToken = response.headers['x-new-access-token'];\r\n    final newRefreshToken = response.headers['x-new-refresh-token'];\r\n\r\n    if (newAccessToken != null) {\r\n      await storage.write(key: 'accessToken', value: newAccessToken);\r\n      await storage.write(key: 'refreshToken', value: newRefreshToken);\r\n    }\r\n\r\n    return jsonDecode(response.body);\r\n  }\r\n}\r\n```\r\n\r\n## 🌐 Web Client Integration\r\n\r\nFor web clients, tokens are automatically stored in HTTP-only cookies:\r\n\r\n```javascript\r\n// Login request (browser)\r\nconst login = async (email, password) => {\r\n  const response = await fetch(\"/api/auth/login\", {\r\n    method: \"POST\",\r\n    headers: {\r\n      \"Content-Type\": \"application/json\",\r\n    },\r\n    credentials: \"include\", // Important: Include cookies\r\n    body: JSON.stringify({ email, password }),\r\n  });\r\n\r\n  const data = await response.json();\r\n  // Tokens are automatically stored in cookies\r\n  return data;\r\n};\r\n\r\n// Protected API request (browser)\r\nconst fetchProfile = async () => {\r\n  const response = await fetch(\"/api/profile\", {\r\n    credentials: \"include\", // Important: Include cookies\r\n  });\r\n\r\n  return response.json();\r\n};\r\n```\r\n\r\n## 📋 Response Formats\r\n\r\n### Web Response (Cookie Mode)\r\n\r\n**Login/Register Response:**\r\n\r\n```json\r\n{\r\n  \"_id\": \"user_id\",\r\n  \"isVerified\": true,\r\n  \"message\": \"Authentication successful\"\r\n}\r\n```\r\n\r\nTokens are set in HTTP-only cookies:\r\n\r\n- `jwt` - Access token\r\n- `refreshToken` - Refresh token\r\n\r\n### Mobile Response (JSON Mode)\r\n\r\n**Login/Register Response:**\r\n\r\n```json\r\n{\r\n  \"_id\": \"user_id\",\r\n  \"isVerified\": true,\r\n  \"message\": \"Authentication successful\",\r\n  \"accessToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\r\n  \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\r\n  \"tokenType\": \"Bearer\",\r\n  \"expiresIn\": 900\r\n}\r\n```\r\n\r\n## 📋 Configuration Options\r\n\r\n### Required Configuration\r\n\r\n```typescript\r\n{\r\n    User: mongoose.Model,           // Your Mongoose User model\r\n    jwtAccessSecret: string,        // Secret for access tokens\r\n    jwtRefreshSecret: string,       // Secret for refresh tokens\r\n}\r\n```\r\n\r\n### Optional Configuration\r\n\r\n```typescript\r\n{\r\n    // OTP Configuration\r\n    otp: {\r\n        ttl: 5,                     // OTP time-to-live in minutes\r\n        length: 6,                  // OTP length\r\n        retryLimit: 3,              // Maximum retry attempts\r\n        retryDelay: 60,             // Delay between retries (seconds)\r\n    },\r\n\r\n    // JWT Configuration\r\n    jwt: {\r\n        accessExpiresIn: '15m',     // Access token expiration\r\n        refreshExpiresIn: '7d',     // Refresh token expiration\r\n    },\r\n\r\n    // Security Configuration\r\n    security: {\r\n        nodeEnv: 'development',     // Environment\r\n        cookieSecure: false,        // Secure cookies (auto-set based on env)\r\n        cookieSameSite: 'Lax',      // SameSite cookie attribute\r\n        responseMode: 'auto',       // 'auto', 'cookie', or 'json'\r\n    },\r\n\r\n    // OTP Service Configuration\r\n    otpUrl: string,                 // OTP service URL\r\n    otpApiKey: string,              // OTP service API key\r\n    otptemplate: string,            // OTP template name\r\n\r\n    // Email Configuration (for Email OTP)\r\n    email: {\r\n        provider: 'nodemailer',     // Email provider: 'nodemailer', 'sendgrid', 'aws-ses'\r\n        fromEmail: 'noreply@yourapp.com',\r\n        nodemailer: {\r\n            host: 'smtp.gmail.com', // SMTP host\r\n            port: 587,              // SMTP port\r\n            secure: false,          // true for 465, false for other ports\r\n            auth: {\r\n                user: 'your-email@gmail.com',\r\n                pass: 'your-app-password'\r\n            },\r\n            service: 'gmail'        // Optional: service name\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## 🔧 API Reference\r\n\r\n### Controllers\r\n\r\n#### Email/Password Controller\r\n\r\n- `registerUser(req: Request, res: Response)` - Register new user with email and password\r\n- `loginUser(req: Request, res: Response)` - Login user with email and password\r\n- `changePassword(req: Request, res: Response)` - Change password (authenticated)\r\n- `resetPassword(req: Request, res: Response)` - Reset password (unauthenticated)\r\n\r\n#### OTP Controller\r\n\r\n- `sendOtp(req: Request, res: Response)` - Send OTP to phone number\r\n- `verifyOtp(req: Request, res: Response)` - Verify OTP and authenticate user\r\n\r\n#### Email OTP Controller\r\n\r\n- `sendEmailOtp(req: Request, res: Response)` - Send OTP to email\r\n- `verifyEmailOtp(req: Request, res: Response)` - Verify email OTP and authenticate user\r\n\r\n#### Auth Controller\r\n\r\n- `refreshAccessToken(req: Request, res: Response)` - Refresh access token using refresh token\r\n- `logoutUser(req: Request, res: Response)` - Logout user and clear tokens\r\n\r\n### Middleware\r\n\r\n#### Protect Middleware\r\n\r\n```typescript\r\napp.get(\"/protected\", authManager.middleware.protect, (req: any, res) => {\r\n  // req.user contains authenticated user with full type safety\r\n  const user = req.user as IUser;\r\n  res.json({ user });\r\n});\r\n```\r\n\r\n**Token Sources (in order of priority):**\r\n\r\n1. Authorization header: `Bearer <token>`\r\n2. Cookie: `jwt`\r\n3. Custom header: `X-Refresh-Token` (for refresh tokens)\r\n\r\n#### Authorization Middleware\r\n\r\n```typescript\r\napp.get(\r\n  \"/admin\",\r\n  authManager.middleware.protect,\r\n  authManager.middleware.authorize(\"admin\"),\r\n  (req: any, res) => {\r\n    const user = req.user as IUser;\r\n    res.json({ message: \"Admin access granted\", user });\r\n  },\r\n);\r\n```\r\n\r\n## 📱 Authentication Flow\r\n\r\n### Phone OTP Flow\r\n\r\n1. **Send OTP**\r\n\r\n   ```http\r\n   POST /api/auth/send-otp\r\n   Content-Type: application/json\r\n   X-Client-Type: mobile\r\n\r\n   {\r\n     \"phoneNumber\": \"+1234567890\"\r\n   }\r\n   ```\r\n\r\n2. **Verify OTP**\r\n\r\n   ```http\r\n   POST /api/auth/verify-otp\r\n   Content-Type: application/json\r\n   X-Client-Type: mobile\r\n\r\n   {\r\n     \"phoneNumber\": \"+1234567890\",\r\n     \"otp\": \"123456\"\r\n   }\r\n   ```\r\n\r\n   **Mobile Response:**\r\n\r\n   ```json\r\n   {\r\n     \"_id\": \"user_id\",\r\n     \"isVerified\": true,\r\n     \"message\": \"Authentication successful\",\r\n     \"accessToken\": \"...\",\r\n     \"refreshToken\": \"...\",\r\n     \"tokenType\": \"Bearer\",\r\n     \"expiresIn\": 900\r\n   }\r\n   ```\r\n\r\n3. **Access Protected Resources**\r\n   ```http\r\n   GET /api/profile\r\n   Authorization: Bearer <access-token>\r\n   X-Client-Type: mobile\r\n   ```\r\n\r\n### Token Refresh Flow\r\n\r\n**Web (Cookie):**\r\n\r\n```http\r\nPOST /api/auth/refresh-token\r\nCookie: refreshToken=<refresh-token>\r\n```\r\n\r\n**Mobile (JSON):**\r\n\r\n```http\r\nPOST /api/auth/refresh-token\r\nContent-Type: application/json\r\nX-Client-Type: mobile\r\nX-Refresh-Token: <refresh-token>\r\n\r\nOR\r\n\r\n{\r\n  \"refreshToken\": \"<refresh-token>\"\r\n}\r\n```\r\n\r\n## 🛡️ Security Features\r\n\r\n- **HTTP-Only Cookies**: Tokens stored in secure HTTP-only cookies (web)\r\n- **Secure Storage**: Tokens delivered in JSON for secure storage (mobile)\r\n- **Automatic Token Refresh**: Seamless token renewal in middleware for both platforms\r\n- **Environment-Based Security**: Different security settings for dev/prod\r\n- **Input Validation**: Built-in request validation using express-validator\r\n- **Rate Limiting**: Built-in rate limiting for OTP and password endpoints\r\n- **Account Lockout**: Automatic account lockout after failed attempts\r\n- **Multi-Platform Support**: Automatic detection and handling of web/mobile clients\r\n\r\n## 🔮 Migration Guide\r\n\r\n### Updating from Cookie-Only Version\r\n\r\nIf you're upgrading from a version that only supported cookies, no changes are required! The package is backward compatible:\r\n\r\n1. **Default behavior**: Set `responseMode: 'auto'` to automatically detect client type\r\n2. **Web-only apps**: Keep using `responseMode: 'cookie'` or omit the setting\r\n3. **Mobile apps**: Add `X-Client-Type: mobile` header in requests or set `responseMode: 'json'`\r\n\r\n### Mobile App Checklist\r\n\r\n- [ ] Add `X-Client-Type: mobile` header to all requests\r\n- [ ] Use `Authorization: Bearer <token>` header for authenticated requests\r\n- [ ] Store tokens in secure storage (SecureStore, Keychain, etc.)\r\n- [ ] Handle token refresh by checking response headers\r\n- [ ] Implement token refresh logic when access token expires\r\n\r\n### Hybrid App Checklist (React + Capacitor, Ionic, etc.)\r\n\r\n- [ ] Use `Capacitor.isNativePlatform()` to detect runtime environment\r\n- [ ] Send `X-Client-Type: web` when running in browser\r\n- [ ] Send `X-Client-Type: mobile` when running as native app\r\n- [ ] Use `withCredentials: true` for web, `false` for mobile\r\n- [ ] Store tokens in secure storage for mobile, rely on cookies for web\r\n- [ ] Add request interceptor to automatically set correct headers\r\n- [ ] Test authentication in both web and mobile environments\r\n\r\n## 📝 Environment Variables\r\n\r\nCreate a `.env` file:\r\n\r\n```env\r\n# JWT Secrets\r\nJWT_ACCESS_SECRET=your-super-secret-access-key\r\nJWT_REFRESH_SECRET=your-super-secret-refresh-key\r\n\r\n# OTP Service (for production)\r\nOTP_URL=https://your-otp-service.com/api\r\nOTP_API_KEY=your-otp-api-key\r\nOTP_TEMPLATE=your-otp-template\r\n\r\n# App Configuration\r\nNODE_ENV=development\r\nPORT=5000\r\nFRONTEND_URL=http://localhost:3000\r\n\r\n# Email Configuration (for Email OTP with Nodemailer)\r\nFROM_EMAIL=noreply@yourapp.com\r\nSMTP_HOST=smtp.gmail.com\r\nSMTP_PORT=587\r\nSMTP_SECURE=false\r\nSMTP_USER=your-email@gmail.com\r\nSMTP_PASS=your-app-password\r\nSMTP_SERVICE=gmail\r\n```\r\n\r\n## 🔮 Roadmap\r\n\r\n- [x] Multi-platform support (Web & Mobile)\r\n- [x] Automatic client detection\r\n- [x] JSON response mode for mobile\r\n- [x] Hybrid app support with X-Client-Type header\r\n- [ ] OAuth providers (Google, GitHub, Facebook)\r\n- [ ] Two-factor authentication (2FA)\r\n- [ ] Session management\r\n- [ ] Audit logging\r\n- [ ] Enhanced TypeScript types for better IntelliSense\r\n\r\n## 📚 Quick Reference\r\n\r\n### Platform Configuration Summary\r\n\r\n| Platform                                | X-Client-Type Header | withCredentials | Token Storage     | Authorization Header                    |\r\n| --------------------------------------- | -------------------- | --------------- | ----------------- | --------------------------------------- |\r\n| **Pure Web** (React, Vue, Angular)      | `web` or omit        | `true`          | HTTP-only cookies | Not needed (cookies sent automatically) |\r\n| **Pure Mobile** (React Native, Flutter) | `mobile`             | `false`         | Secure storage    | `Bearer <accessToken>`                  |\r\n| **Capacitor/Ionic Web**                 | `web`                | `true`          | HTTP-only cookies | Not needed (cookies sent automatically) |\r\n| **Capacitor/Ionic Mobile**              | `mobile`             | `false`         | Secure storage    | `Bearer <accessToken>`                  |\r\n\r\n### Response Format by Client Type\r\n\r\n| Client Type                          | Access Token Location    | Refresh Token Location            | Additional Data in Response                              |\r\n| ------------------------------------ | ------------------------ | --------------------------------- | -------------------------------------------------------- |\r\n| **Web** (`X-Client-Type: web`)       | `jwt` cookie (HTTP-only) | `refreshToken` cookie (HTTP-only) | `_id`, `isVerified`, `message`                           |\r\n| **Mobile** (`X-Client-Type: mobile`) | `accessToken` in JSON    | `refreshToken` in JSON            | `_id`, `isVerified`, `message`, `tokenType`, `expiresIn` |\r\n\r\n### Common Integration Patterns\r\n\r\n#### Web App (React/Vue/Angular)\r\n\r\n```javascript\r\n// Set once in your API client\r\naxios.defaults.withCredentials = true;\r\n\r\n// No need to set X-Client-Type (defaults to web)\r\n// Tokens are automatically managed via cookies\r\n```\r\n\r\n#### Mobile App (React Native/Flutter)\r\n\r\n```javascript\r\n// Always send X-Client-Type header\r\nheaders: { 'X-Client-Type': 'mobile' }\r\n\r\n// Store tokens in secure storage\r\n// Send access token in Authorization header\r\n```\r\n\r\n#### Hybrid App (Capacitor/Ionic)\r\n\r\n```typescript\r\n// Detect platform and configure accordingly\r\nconst isNative = Capacitor.isNativePlatform();\r\n\r\napi.defaults.headers[\"X-Client-Type\"] = isNative ? \"mobile\" : \"web\";\r\napi.defaults.withCredentials = !isNative;\r\n```\r\n\r\n## 📄 License\r\n\r\nMIT\r\n\r\n## 🤝 Contributing\r\n\r\nContributions are welcome! Please feel free to submit a Pull Request.\r\n","readmeFilename":"README.md"}