{"_id":"@aranzatech/aranza-auth","_rev":"11-5f306aacbf5bc5094c958689c0ca8670","name":"@aranzatech/aranza-auth","dist-tags":{"latest":"0.3.2"},"versions":{"0.1.0":{"name":"@aranzatech/aranza-auth","version":"0.1.0","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.1.0","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aapa96/aranza-auth#readme","bugs":{"url":"https://github.com/aapa96/aranza-auth/issues"},"dist":{"shasum":"063d82ede74f899567dc2f6bb887662ad94a90cc","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.1.0.tgz","fileCount":19,"integrity":"sha512-h0VtPVedSb2BqIneM1k6RiHqSCF0SCvSWrvv6F99fIbeDa9sFzPh26YcvHsWDuNomdmCocDDKsHQELgj6eA3LA==","signatures":[{"sig":"MEYCIQDmiaGd1P4M6xhLOKYMRFqb2ShV403T6/MJ7WUK9gTLcgIhAPQB9HRwsUSCxfD20N1LfcY0RDctyYh9dSf+xqBe04en","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":227766},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"}},"gitHead":"dfb98ccda441e5371973f84339fd4124193229f3","scripts":{"dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"repository":{"url":"git+https://github.com/aapa96/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapter MongoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@nestjs/common":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@nestjs/common":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@nestjs/mongoose":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.1.0_1783092355157_0.2097722822496042","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@aranzatech/aranza-auth","version":"0.1.1","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.1.1","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aranzatech/aranza-auth#readme","bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"dist":{"shasum":"87b888f6863bf3835ce8ac20e5a8691d7f276bbd","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.1.1.tgz","fileCount":19,"integrity":"sha512-EjNS4iK/jjykmKn1/sHUfsuECqqOmy1Rv6wJuW1CMUSMmHQodGP7NBOLHkF1H+hAmT2HiOBRBPpGpXQ7GJ/2DA==","signatures":[{"sig":"MEUCIATQPkz64prmykgFaOjxt+gMA05KX/BJ31yOPjqAaT3KAiEAiOu/yL67Q9ivnFW9KrA2aUbeL0V50cUvJ/VAhjxNX34=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":231583},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"}},"gitHead":"0148b24c18c3c112dacd8a74119cae201ec262da","scripts":{"dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"repository":{"url":"git+https://github.com/aranzatech/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapter MongoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@nestjs/common":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@nestjs/common":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@nestjs/mongoose":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.1.1_1783093622862_0.7992440271534569","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@aranzatech/aranza-auth","version":"0.1.2","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.1.2","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aranzatech/aranza-auth#readme","bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"dist":{"shasum":"1f0ef33ff0686ffab8966482ce121240abb6c1c9","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.1.2.tgz","fileCount":19,"integrity":"sha512-i7hV83U/+7OQZYom9KIJSr8KZ3Cdi3zazqx6HBaK7pp5IJ/qggvwowijjRE+dk+8ARBY4qG1EcNrkhmAmnaHdg==","signatures":[{"sig":"MEUCIQCL04Bza1Q0SjWCZzgHc2Nvlerbrr4RM648Ch+o6cH/BwIgAhbSNFEHWCZ9gs2X057RCMlxt6LFE9tEcOFyjNSNqbM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":231916},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"}},"gitHead":"6d4fe2b21cd01bbd6bdc37b313b454a1ac0144c0","scripts":{"dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"repository":{"url":"git+https://github.com/aranzatech/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapter MongoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@nestjs/common":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@nestjs/common":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@nestjs/mongoose":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.1.2_1783096376595_0.6626234067948209","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@aranzatech/aranza-auth","version":"0.2.0","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.2.0","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aranzatech/aranza-auth#readme","bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"dist":{"shasum":"a817bc0fd6442cf5476531681bea3b526cf7779f","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.2.0.tgz","fileCount":20,"integrity":"sha512-ZSmsNz2FxhgEYHXrucwgRSH+pqQvYGAd+hN2IKarsHTCixkhwgPSC5QH5dy2NyvUaPkvokVotbTa2i1zccAQBw==","signatures":[{"sig":"MEUCIHnEGwK7j3xdCybpSwcyP/M3jBoZsjQE/F7lQvjqRi+pAiEA7x+jMsKzQBLcVb+osi7EJECZL9gWGK1/ZW2JBZpy7lA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":309230},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"}},"gitHead":"a6a66c58a8a81655f990eb10e6a22a630d6cbcb6","scripts":{"dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"repository":{"url":"git+https://github.com/aranzatech/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapter MongoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@nestjs/common":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@nestjs/common":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@nestjs/mongoose":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.2.0_1783100237437_0.9314737889045861","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@aranzatech/aranza-auth","version":"0.2.1","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.2.1","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aranzatech/aranza-auth#readme","bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"dist":{"shasum":"0b770c2baee14abd6032f5fc2225b883b61b09ec","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.2.1.tgz","fileCount":20,"integrity":"sha512-jeqM1Mdj7mzEY6GpEqQPRaQANf8+oRUJvhlwkGfsXBCxB46RWBmKK5hmDA+t70u0Mh1fsrcH+znQa+r9nt2kaA==","signatures":[{"sig":"MEUCIAdooF2kzRtVEA7oSxHHiYUjXuPaHNtUTKkL9gT0caz3AiEApwGgLk5vqbtZvVoIFVrPkv/0/t4s18uIGmOkx3Et/MU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":309230},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"}},"gitHead":"fd5ddc735796049b005e0de164892cde858c13a2","scripts":{"dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"repository":{"url":"git+https://github.com/aranzatech/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapter MongoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@nestjs/common":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@nestjs/common":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@nestjs/mongoose":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.2.1_1783103732951_0.05823793865531046","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@aranzatech/aranza-auth","version":"0.2.2","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.2.2","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aranzatech/aranza-auth#readme","bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"dist":{"shasum":"fc76032f9559397aae834c6811cce802ff55a59b","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.2.2.tgz","fileCount":20,"integrity":"sha512-ZCR3xeSFyKGkHQJAcTKulW3uCC8OdQ8YiuKjxakZvvnZ6eDDozi0Syib8KudQmDOL3x40xtgVN1UYk9H+FbKWQ==","signatures":[{"sig":"MEUCIADtDZQHtsc2+ne25ysY+FxyDVJh+xi980y9lIm+1mhsAiEA/MQscmz34zoTVZJtQSSXEfLpi/9f4bvcaoKxkbQ6Azw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":451229},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"}},"gitHead":"1d8dc2ac9bf0b24f4ec1b3de3e8b2123073d7766","scripts":{"ci":"npm run lint && npm run test:coverage && node scripts/coverage-threshold.mjs && npm audit --audit-level=high && npm run build","dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"overrides":{"multer":"^2.2.0","esbuild":"^0.28.1"},"repository":{"url":"git+https://github.com/aranzatech/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapter MongoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","supertest":"^7.1.1","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@nestjs/common":"^11.0.1","@nestjs/swagger":"^11.4.5","@nestjs/testing":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","@types/supertest":"^6.0.3","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7","@nestjs/platform-express":"^11.0.1"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@nestjs/common":">=11","@nestjs/swagger":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@nestjs/mongoose":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.2.2_1783117594687_0.37308021007141945","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@aranzatech/aranza-auth","version":"0.2.3","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.2.3","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aranzatech/aranza-auth#readme","bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"dist":{"shasum":"27daa690d5283568a9818d6a131215fb3a74faa7","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.2.3.tgz","fileCount":20,"integrity":"sha512-0L42x/AqZJHpQvnCCSXmquL5BoGrDVdB/6juHgzy9Sr9edKVhpLMLl9Y5PqehhBq/N5sdJpdcH42GPGoqsHnmg==","signatures":[{"sig":"MEUCIQCpe1JxSH6v4L7BJIa7d6D7bTpOoBpnPdh/x4o6RfOKiQIgAacTEd/+KpJApnq7jEl/CncZrtcfoVxJA/GxV86Nlo8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":453401},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"}},"gitHead":"5a2a163c31d0fcb3bbcb67cb488329d794f6423c","scripts":{"ci":"npm run lint && npm run test:coverage && node scripts/coverage-threshold.mjs && npm audit --audit-level=high && npm run build","dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"overrides":{"multer":"^2.2.0","esbuild":"^0.28.1"},"repository":{"url":"git+https://github.com/aranzatech/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapter MongoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","supertest":"^7.1.1","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@nestjs/common":"^11.0.1","@nestjs/swagger":"^11.4.5","@nestjs/testing":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","@types/supertest":"^6.0.3","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7","@nestjs/platform-express":"^11.0.1"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@nestjs/common":">=11","@nestjs/swagger":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@nestjs/mongoose":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.2.3_1783117936224_0.01924266797848362","host":"s3://npm-registry-packages-npm-production"}},"0.2.4":{"name":"@aranzatech/aranza-auth","version":"0.2.4","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.2.4","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aranzatech/aranza-auth#readme","bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"dist":{"shasum":"c2cf0ea80cc10d3f6f6454d060c1819f367b7b4d","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.2.4.tgz","fileCount":20,"integrity":"sha512-Bl7mvNHobal4jNB07ifRr4bGyvv2KlsrrwygtkHoPv4JyqjJc0Z/tCDDwol0QHKs0b8JYcwKWfbaA2lKJVrK5Q==","signatures":[{"sig":"MEQCIFnQp6OjsxcaulXI8W+asC2goC2acOUCsPXRhXypDSjWAiAvMRNKlXo00g1F5wu3LY3xewTHNMhRDZGZFAYpxbaRDA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":453694},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"}},"gitHead":"7fdbe1bf211fc93feb33a464308231838d1d8468","scripts":{"ci":"npm run lint && npm run test:coverage && node scripts/coverage-threshold.mjs && npm audit --audit-level=high && npm run build","dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"overrides":{"multer":"^2.2.0","esbuild":"^0.28.1"},"repository":{"url":"git+https://github.com/aranzatech/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapter MongoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","supertest":"^7.1.1","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@nestjs/common":"^11.0.1","@nestjs/swagger":"^11.4.5","@nestjs/testing":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","@types/supertest":"^6.0.3","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7","@nestjs/platform-express":"^11.0.1"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@nestjs/common":">=11","@nestjs/swagger":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@nestjs/mongoose":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.2.4_1783136424566_0.03975610432556498","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@aranzatech/aranza-auth","version":"0.3.0","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.3.0","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aranzatech/aranza-auth#readme","bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"dist":{"shasum":"6c40a4b9f5ba273bb3e43fca516b995b4a02987c","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.3.0.tgz","fileCount":40,"integrity":"sha512-ECHbw6DVRH+/BPzEq/CvwRmdeFe4YB69+RxceR6kXl6Pt7/DeQus9Q2Tp19TypRl2BuzVijY3Dl6bGKp76Au0A==","signatures":[{"sig":"MEQCIHIr3yXrmb6CTeGiQ/1Z7n/35fTy+b0Zpig+Tzip4W6dAiBQB6OVyJ8z6iD5J3I/8Xu0qXdNCI0r8gfDQPqph/9DRA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":729906},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"},"./cosmos":{"types":"./dist/cosmos/index.d.ts","import":"./dist/cosmos/index.js","require":"./dist/cosmos/index.cjs"},"./dynamo":{"types":"./dist/dynamo/index.d.ts","import":"./dist/dynamo/index.js","require":"./dist/dynamo/index.cjs"},"./prisma":{"types":"./dist/prisma/index.d.ts","import":"./dist/prisma/index.js","require":"./dist/prisma/index.cjs"}},"gitHead":"916d940227e33f9952abc5e5918f3d872e45b7d8","scripts":{"ci":"npm run lint && npm run test:coverage && node scripts/coverage-threshold.mjs && npm audit --audit-level=high && npm run build","dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","test:coverage":"vitest run --coverage","test:smoke:sql":"npm run test:smoke:postgres","prisma:test:push":"prisma db push --schema __tests__/fixtures/prisma/schema.prisma --skip-generate","test:smoke:mongo":"RUN_REAL_MONGO_SMOKE=1 vitest run __tests__/smoke/mongo-auth.repository.smoke.test.ts","test:smoke:cosmos":"RUN_REAL_COSMOS_SMOKE=1 vitest run __tests__/smoke/cosmos-auth.repository.smoke.test.ts","test:smoke:dynamo":"RUN_REAL_DYNAMO_SMOKE=1 vitest run __tests__/smoke/dynamo-auth.repository.smoke.test.ts","test:smoke:postgres":"npm run prisma:smoke:postgres:generate && npm run prisma:smoke:postgres:push && RUN_REAL_PRISMA_POSTGRES_SMOKE=1 vitest run __tests__/smoke/prisma-postgres-auth.repository.smoke.test.ts","prisma:test:generate":"prisma generate --schema __tests__/fixtures/prisma/schema.prisma","test:integration:local":"npm run test:integration:mongo && npm run test:integration:prisma","test:integration:mongo":"RUN_MONGO_INTEGRATION=1 vitest run __tests__/integration/mongo-auth.repository.integration.test.ts","test:integration:cosmos":"RUN_COSMOS_INTEGRATION=1 vitest run __tests__/integration/cosmos-auth.repository.integration.test.ts","test:integration:dynamo":"RUN_DYNAMO_INTEGRATION=1 vitest run __tests__/integration/dynamo-auth.repository.integration.test.ts","test:integration:prisma":"npm run prisma:test:generate && npm run prisma:test:push && RUN_PRISMA_INTEGRATION=1 vitest run __tests__/integration/prisma-auth.repository.integration.test.ts","test:integration:emulated":"npm run test:integration:dynamo","prisma:smoke:postgres:push":"test \"$PRISMA_SMOKE_ALLOW_SCHEMA_PUSH\" = \"1\" && prisma db push --schema __tests__/fixtures/prisma-postgres-smoke/schema.prisma --skip-generate","prisma:smoke:postgres:generate":"prisma generate --schema __tests__/fixtures/prisma-postgres-smoke/schema.prisma"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"overrides":{"multer":"^2.2.0","esbuild":"^0.28.1"},"repository":{"url":"git+https://github.com/aranzatech/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapters MongoDB/Prisma/Cosmos/DynamoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","prisma":"^6.19.3","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","supertest":"^7.1.1","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@azure/cosmos":"^4.9.3","@nestjs/common":"^11.0.1","@prisma/client":"^6.19.3","@nestjs/swagger":"^11.4.5","@nestjs/testing":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","@types/supertest":"^6.0.3","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7","@aws-sdk/lib-dynamodb":"^3.1081.0","mongodb-memory-server":"^11.2.0","@aws-sdk/client-dynamodb":"^3.1081.0","@nestjs/platform-express":"^11.0.1"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@azure/cosmos":">=4","@nestjs/common":">=11","@prisma/client":">=5","@nestjs/swagger":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5","@aws-sdk/lib-dynamodb":">=3","@aws-sdk/client-dynamodb":">=3"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@azure/cosmos":{"optional":true},"@prisma/client":{"optional":true},"@nestjs/mongoose":{"optional":true},"@aws-sdk/lib-dynamodb":{"optional":true},"@aws-sdk/client-dynamodb":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.3.0_1783469514852_0.39410382246157205","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@aranzatech/aranza-auth","version":"0.3.1","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"author":{"name":"AranzaTech"},"license":"MIT","_id":"@aranzatech/aranza-auth@0.3.1","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"homepage":"https://github.com/aranzatech/aranza-auth#readme","bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"dist":{"shasum":"1c8203832ff9be5f6a152d502dc43ff9a78236d3","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.3.1.tgz","fileCount":72,"integrity":"sha512-9u4oRUGPIPWacBWLbU3NOuw2RnSofFsPOosaV7QlNLleQCRGM4OXCts8NMU3KLt0qEL8kqFoIbV0POF+O2Vzig==","signatures":[{"sig":"MEUCIA3AJo6xwaLDLKDCRVxOSR4UieZGYmDj2uCDFdgd1gyiAiEAzn2X6k99JjtfUV423AF2pLzEeOM1nDyJUalDORboM5U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1051853},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"},"./cosmos":{"types":"./dist/cosmos/index.d.ts","import":"./dist/cosmos/index.js","require":"./dist/cosmos/index.cjs"},"./dynamo":{"types":"./dist/dynamo/index.d.ts","import":"./dist/dynamo/index.js","require":"./dist/dynamo/index.cjs"},"./prisma":{"types":"./dist/prisma/index.d.ts","import":"./dist/prisma/index.js","require":"./dist/prisma/index.cjs"}},"gitHead":"6924151c7d41edf1bfc2701775383e8710e5d47c","scripts":{"ci":"npm run lint && npm run test:coverage && node scripts/coverage-threshold.mjs && npm audit --audit-level=high && npm run build && npm run test:package:exports && npm run test:identity:openapi && npm run test:examples:types","dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","ci:local":"npm run ci","deploy:npm":"npm install && npm run build && npm publish --access public","test:watch":"vitest","release:check":"npm run ci:local && npm run test:package:pack","test:coverage":"vitest run --coverage","test:smoke:sql":"npm run test:smoke:postgres","prisma:test:push":"prisma db push --schema __tests__/fixtures/prisma/schema.prisma --skip-generate","test:smoke:mongo":"RUN_REAL_MONGO_SMOKE=1 vitest run __tests__/smoke/mongo-auth.repository.smoke.test.ts","test:package:pack":"npm pack --dry-run --cache /tmp/aranza-auth-npm-cache","test:smoke:cosmos":"RUN_REAL_COSMOS_SMOKE=1 vitest run __tests__/smoke/cosmos-auth.repository.smoke.test.ts","test:smoke:dynamo":"RUN_REAL_DYNAMO_SMOKE=1 vitest run __tests__/smoke/dynamo-auth.repository.smoke.test.ts","test:examples:types":"tsc -p examples/nest-mongo/tsconfig.json --noEmit && tsc -p examples/nest-prisma-postgres/tsconfig.json --noEmit","test:smoke:postgres":"npm run prisma:smoke:postgres:generate && npm run prisma:smoke:postgres:push && RUN_REAL_PRISMA_POSTGRES_SMOKE=1 vitest run __tests__/smoke/prisma-postgres-auth.repository.smoke.test.ts","prisma:test:generate":"prisma generate --schema __tests__/fixtures/prisma/schema.prisma","test:package:exports":"node scripts/check-package-exports.mjs","test:identity:openapi":"node scripts/check-identity-openapi.mjs","test:integration:local":"npm run test:integration:mongo && npm run test:integration:prisma","test:integration:mongo":"RUN_MONGO_INTEGRATION=1 vitest run __tests__/integration/mongo-auth.repository.integration.test.ts","test:integration:cosmos":"RUN_COSMOS_INTEGRATION=1 vitest run __tests__/integration/cosmos-auth.repository.integration.test.ts","test:integration:dynamo":"RUN_DYNAMO_INTEGRATION=1 vitest run __tests__/integration/dynamo-auth.repository.integration.test.ts","test:integration:prisma":"npm run prisma:test:generate && npm run prisma:test:push && RUN_PRISMA_INTEGRATION=1 vitest run __tests__/integration/prisma-auth.repository.integration.test.ts","test:integration:emulated":"npm run test:integration:dynamo","prisma:smoke:postgres:push":"test \"$PRISMA_SMOKE_ALLOW_SCHEMA_PUSH\" = \"1\" && prisma db push --schema __tests__/fixtures/prisma-postgres-smoke/schema.prisma --skip-generate","prisma:smoke:postgres:generate":"prisma generate --schema __tests__/fixtures/prisma-postgres-smoke/schema.prisma"},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"overrides":{"multer":"^2.2.0","esbuild":"^0.28.1"},"repository":{"url":"git+https://github.com/aranzatech/aranza-auth.git","type":"git"},"_npmVersion":"10.9.8","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapters MongoDB/Prisma/Cosmos/DynamoDB","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.2","tsup":"^8.1.0","prisma":"^6.19.3","vitest":"^4.1.5","bcryptjs":"^3.0.3","mongoose":"^8.19.1","passport":"^0.7.0","supertest":"^7.1.1","typescript":"^5.4.5","@nestjs/jwt":"^11.0.2","@nestjs/core":"^11.0.1","passport-jwt":"^4.0.1","@azure/cosmos":"^4.9.3","@nestjs/common":"^11.0.1","@prisma/client":"^6.19.3","@nestjs/swagger":"^11.4.5","@nestjs/testing":"^11.0.1","@types/bcryptjs":"^2.4.6","class-validator":"^0.14.4","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","@types/supertest":"^6.0.3","reflect-metadata":"^0.2.2","class-transformer":"^0.5.1","@types/passport-jwt":"^4.0.1","@vitest/coverage-v8":"^4.1.7","@aws-sdk/lib-dynamodb":"^3.1081.0","mongodb-memory-server":"^11.2.0","@aws-sdk/client-dynamodb":"^3.1081.0","@nestjs/platform-express":"^11.0.1"},"peerDependencies":{"bcryptjs":">=2","mongoose":">=8","passport":">=0.7","@nestjs/jwt":">=11","@nestjs/core":">=11","passport-jwt":">=4","@azure/cosmos":">=4","@nestjs/common":">=11","@prisma/client":">=5","@nestjs/swagger":">=11","class-validator":">=0.14","@nestjs/mongoose":">=11","@nestjs/passport":">=11","reflect-metadata":">=0.2","class-transformer":">=0.5","@aws-sdk/lib-dynamodb":">=3","@aws-sdk/client-dynamodb":">=3"},"peerDependenciesMeta":{"mongoose":{"optional":true},"@azure/cosmos":{"optional":true},"@prisma/client":{"optional":true},"@nestjs/mongoose":{"optional":true},"@aws-sdk/lib-dynamodb":{"optional":true},"@aws-sdk/client-dynamodb":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aranza-auth_0.3.1_1783485994333_0.6569713205702259","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@aranzatech/aranza-auth","version":"0.3.2","description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapters MongoDB/Prisma/Cosmos/DynamoDB","license":"MIT","author":{"name":"AranzaTech"},"keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"repository":{"type":"git","url":"git+https://github.com/aranzatech/aranza-auth.git"},"bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"homepage":"https://github.com/aranzatech/aranza-auth#readme","publishConfig":{"access":"public"},"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./cosmos":{"types":"./dist/cosmos/index.d.ts","import":"./dist/cosmos/index.js","require":"./dist/cosmos/index.cjs"},"./dynamo":{"types":"./dist/dynamo/index.d.ts","import":"./dist/dynamo/index.js","require":"./dist/dynamo/index.cjs"},"./mongo":{"types":"./dist/mongo/index.d.ts","import":"./dist/mongo/index.js","require":"./dist/mongo/index.cjs"},"./prisma":{"types":"./dist/prisma/index.d.ts","import":"./dist/prisma/index.js","require":"./dist/prisma/index.cjs"}},"scripts":{"build":"tsup","dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","test:integration:mongo":"RUN_MONGO_INTEGRATION=1 vitest run __tests__/integration/mongo-auth.repository.integration.test.ts","prisma:test:generate":"prisma generate --schema __tests__/fixtures/prisma/schema.prisma","prisma:test:push":"prisma db push --schema __tests__/fixtures/prisma/schema.prisma --skip-generate","test:integration:prisma":"npm run prisma:test:generate && npm run prisma:test:push && RUN_PRISMA_INTEGRATION=1 vitest run __tests__/integration/prisma-auth.repository.integration.test.ts","test:integration:local":"npm run test:integration:mongo && npm run test:integration:prisma","test:integration:dynamo":"RUN_DYNAMO_INTEGRATION=1 vitest run __tests__/integration/dynamo-auth.repository.integration.test.ts","test:integration:cosmos":"RUN_COSMOS_INTEGRATION=1 vitest run __tests__/integration/cosmos-auth.repository.integration.test.ts","test:integration:emulated":"npm run test:integration:dynamo","test:smoke:mongo":"RUN_REAL_MONGO_SMOKE=1 vitest run __tests__/smoke/mongo-auth.repository.smoke.test.ts","test:smoke:dynamo":"RUN_REAL_DYNAMO_SMOKE=1 vitest run __tests__/smoke/dynamo-auth.repository.smoke.test.ts","test:smoke:cosmos":"RUN_REAL_COSMOS_SMOKE=1 vitest run __tests__/smoke/cosmos-auth.repository.smoke.test.ts","prisma:smoke:postgres:generate":"prisma generate --schema __tests__/fixtures/prisma-postgres-smoke/schema.prisma","prisma:smoke:postgres:push":"test \"$PRISMA_SMOKE_ALLOW_SCHEMA_PUSH\" = \"1\" && prisma db push --schema __tests__/fixtures/prisma-postgres-smoke/schema.prisma --skip-generate","test:smoke:postgres":"npm run prisma:smoke:postgres:generate && npm run prisma:smoke:postgres:push && RUN_REAL_PRISMA_POSTGRES_SMOKE=1 vitest run __tests__/smoke/prisma-postgres-auth.repository.smoke.test.ts","test:smoke:sql":"npm run test:smoke:postgres","test:package:exports":"node scripts/check-package-exports.mjs","test:identity:openapi":"node scripts/check-identity-openapi.mjs","test:identity:service-blueprint":"node scripts/check-identity-service-blueprint.mjs","test:identity:python":"python3 -m unittest discover examples/identity-python -p \"*_test.py\"","test:examples:types":"tsc -p examples/nest-mongo/tsconfig.json --noEmit && tsc -p examples/nest-prisma-postgres/tsconfig.json --noEmit","test:package:pack":"npm pack --dry-run --cache /tmp/aranza-auth-npm-cache","ci":"npm run lint && npm run test:coverage && node scripts/coverage-threshold.mjs && npm audit --audit-level=high && npm run build && npm run test:package:exports && npm run test:identity:openapi && npm run test:identity:service-blueprint && npm run test:identity:python && npm run test:examples:types","ci:local":"npm run ci","release:check":"npm run ci:local && npm run test:package:pack","deploy:npm":"npm install && npm run build && npm publish --access public"},"peerDependencies":{"@aws-sdk/client-dynamodb":">=3","@aws-sdk/lib-dynamodb":">=3","@azure/cosmos":">=4","@nestjs/common":">=11","@nestjs/core":">=11","@nestjs/jwt":">=11","@nestjs/mongoose":">=11","@nestjs/passport":">=11","@nestjs/swagger":">=11","@prisma/client":">=5","bcryptjs":">=2","class-transformer":">=0.5","class-validator":">=0.14","mongoose":">=8","passport":">=0.7","passport-jwt":">=4","reflect-metadata":">=0.2"},"peerDependenciesMeta":{"@nestjs/mongoose":{"optional":true},"mongoose":{"optional":true},"@prisma/client":{"optional":true},"@azure/cosmos":{"optional":true},"@aws-sdk/client-dynamodb":{"optional":true},"@aws-sdk/lib-dynamodb":{"optional":true}},"devDependencies":{"@aws-sdk/client-dynamodb":"^3.1081.0","@aws-sdk/lib-dynamodb":"^3.1081.0","@azure/cosmos":"^4.9.3","@nestjs/common":"^11.0.1","@nestjs/core":"^11.0.1","@nestjs/jwt":"^11.0.2","@nestjs/mongoose":"^11.0.4","@nestjs/passport":"^11.0.5","@nestjs/platform-express":"^11.0.1","@nestjs/swagger":"^11.4.5","@nestjs/testing":"^11.0.1","@prisma/client":"^6.19.3","@types/bcryptjs":"^2.4.6","@types/passport-jwt":"^4.0.1","@types/supertest":"^6.0.3","@vitest/coverage-v8":"^4.1.7","bcryptjs":"^3.0.3","class-transformer":"^0.5.1","class-validator":"^0.14.4","mongodb-memory-server":"^11.2.0","mongoose":"^8.19.1","passport":"^0.7.0","passport-jwt":"^4.0.1","prisma":"^6.19.3","reflect-metadata":"^0.2.2","rxjs":"^7.8.2","supertest":"^7.1.1","tsup":"^8.1.0","typescript":"^5.4.5","vitest":"^4.1.5"},"overrides":{"esbuild":"^0.28.1","multer":"^2.2.0"},"_id":"@aranzatech/aranza-auth@0.3.2","gitHead":"37dd3fa8d25cfc40ff9bc2ac167d7895bd8e013f","_nodeVersion":"22.23.1","_npmVersion":"10.9.8","dist":{"integrity":"sha512-MbQnyd+yX9vfWIt6FpKNWROixzQ14KdI5r3mlMjCoORGtc+XTZCBCJnk/E4pEcP/qMAh701WDGdSEz0v27OvHQ==","shasum":"e217c59aaf1c9a79a0f47aa4956527983be56cfc","tarball":"https://registry.npmjs.org/@aranzatech/aranza-auth/-/aranza-auth-0.3.2.tgz","fileCount":80,"unpackedSize":1158800,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDA/SNo5slL1+0/G4aouUqbXrbyrMgqdY19FRqHR3ikRgIgWaW6VUEg3/wxd7FPZfWPbsljt9M8N6BrTBIGDscfqgY="}]},"_npmUser":{"name":"_aranza","email":"aapa96@outlook.com"},"directories":{},"maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/aranza-auth_0.3.2_1783550266290_0.12527010839693054"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-03T15:25:54.963Z","modified":"2026-07-08T22:37:46.563Z","0.1.0":"2026-07-03T15:25:55.334Z","0.1.1":"2026-07-03T15:47:03.017Z","0.1.2":"2026-07-03T16:32:56.746Z","0.2.0":"2026-07-03T17:37:17.589Z","0.2.1":"2026-07-03T18:35:33.084Z","0.2.2":"2026-07-03T22:26:34.834Z","0.2.3":"2026-07-03T22:32:16.397Z","0.2.4":"2026-07-04T03:40:24.712Z","0.3.0":"2026-07-08T00:11:55.123Z","0.3.1":"2026-07-08T04:46:34.494Z","0.3.2":"2026-07-08T22:37:46.446Z"},"bugs":{"url":"https://github.com/aranzatech/aranza-auth/issues"},"author":{"name":"AranzaTech"},"license":"MIT","homepage":"https://github.com/aranzatech/aranza-auth#readme","keywords":["nestjs","auth","authentication","jwt","refresh-token","passport","mongodb","mongoose","aranzatech"],"repository":{"type":"git","url":"git+https://github.com/aranzatech/aranza-auth.git"},"description":"Módulo de autenticación extensible para NestJS — JWT, refresh tokens, register/login y adapters MongoDB/Prisma/Cosmos/DynamoDB","maintainers":[{"name":"_aranza","email":"aapa96@outlook.com"}],"readme":"# @aranzatech/aranza-auth\n\nMódulo de autenticación **extensible** para NestJS. JWT, refresh tokens, register/login y adapters MongoDB/Prisma/Cosmos/DynamoDB — sin acoplar tu dominio (org, roles, users, etc.).\n\nIdeal para reutilizar auth en todos tus proyectos AranzaTech: instalas, configuras, extiendes el modelo y listo.\n\n---\n\n## Tabla de contenidos\n\n- [Instalación](#instalación)\n- [Inicio rápido (5 minutos)](#inicio-rápido-5-minutos)\n- [Variables de entorno](#variables-de-entorno)\n- [Configuración del módulo](#configuración-del-módulo)\n- [Feature flags](#feature-flags)\n- [Endpoints](#endpoints)\n- [Proteger rutas propias](#proteger-rutas-propias)\n- [Rate limiting (producción)](#rate-limiting-producción)\n- [Swagger / OpenAPI](#swagger--openapi)\n- [Seguridad en producción](#seguridad-en-producción)\n- [Extender con AuthHooks](#extender-con-authhooks)\n- [Ejemplos Nest reales](#ejemplos-nest-reales)\n- [Extender el schema MongoDB](#extender-el-schema-mongodb)\n- [Matriz de adapters](#matriz-de-adapters)\n- [Adapter Prisma](#adapter-prisma)\n- [Adapter Cosmos DB](#adapter-cosmos-db)\n- [Adapter DynamoDB](#adapter-dynamodb)\n- [Flujos opcionales (email y password)](#flujos-opcionales-email-y-password)\n- [Multi-session / multi-device](#multi-session--multi-device)\n- [Exports públicos](#exports-públicos)\n- [Estabilidad de API pública](#estabilidad-de-api-pública)\n- [Auditoría y eventos](#auditoría-y-eventos)\n- [Identity scope](#identity-scope)\n- [Identity service roadmap](#identity-service-roadmap)\n- [Identity Node client](#identity-node-client)\n- [Requisitos del proyecto consumidor](#requisitos-del-proyecto-consumidor)\n- [Limitaciones conocidas (v0.4.x)](#limitaciones-conocidas-v04x)\n- [Licencia](#licencia)\n\n---\n\n## Instalación\n\n```bash\nnpm install @aranzatech/aranza-auth\n```\n\n**Peer dependencies** (instalar en tu app Nest):\n\n```bash\nnpm install @nestjs/common @nestjs/core @nestjs/jwt @nestjs/passport \\\n  passport passport-jwt bcryptjs \\\n  class-validator class-transformer reflect-metadata @nestjs/swagger\n```\n\nPara MongoDB agrega `@nestjs/mongoose mongoose`. Para Prisma agrega `@prisma/client` y tu `PrismaService`. Para Cosmos agrega `@azure/cosmos`. Para DynamoDB agrega `@aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb`.\n\n> NestJS **11+** recomendado.\n\n---\n\n## Inicio rápido (5 minutos)\n\n### 1. Variables de entorno\n\n```env\nMONGODB_URI=mongodb://localhost:27017/myapp\nJWT_SECRET=your-access-secret-min-32-chars\nJWT_REFRESH_SECRET=your-refresh-secret-min-32-chars\n```\n\n### 2. Conectar el módulo\n\n```typescript\n// app.module.ts\nimport { Module } from \"@nestjs/common\";\nimport { ConfigModule, ConfigService } from \"@nestjs/config\";\nimport { MongooseModule } from \"@nestjs/mongoose\";\nimport { AuthModule } from \"@aranzatech/aranza-auth\";\nimport { MongoAuthModule } from \"@aranzatech/aranza-auth/mongo\";\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({ isGlobal: true }),\n    MongooseModule.forRoot(process.env.MONGODB_URI!),\n    AuthModule.forRootAsync({\n      imports: [ConfigModule, MongoAuthModule.forFeature()],\n      inject: [ConfigService],\n      useFactory: (config: ConfigService) => ({\n        secret: config.getOrThrow(\"JWT_SECRET\"),\n        refreshSecret: config.getOrThrow(\"JWT_REFRESH_SECRET\"),\n        expiresIn: \"1h\",\n        refreshExpiresIn: \"7d\",\n        identifierField: \"email\",\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### 3. Habilitar validación global (requerido)\n\nLos DTOs usan `class-validator`. Activa el pipe global en `main.ts`:\n\n```typescript\nimport { ValidationPipe } from \"@nestjs/common\";\n\napp.useGlobalPipes(\n  new ValidationPipe({\n    whitelist: true,\n    forbidNonWhitelisted: true,\n    transform: true,\n  }),\n);\n```\n\n### 4. Probar\n\n```bash\n# Register\ncurl -X POST http://localhost:3000/auth/register \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"user@example.com\",\"password\":\"SecurePass123!\"}'\n\n# Login\ncurl -X POST http://localhost:3000/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"user@example.com\",\"password\":\"SecurePass123!\"}'\n\n# Me (usa el accessToken del login)\ncurl http://localhost:3000/auth/me \\\n  -H \"Authorization: Bearer <accessToken>\"\n```\n\nCon eso ya tienes auth funcional para un POC.\n\n---\n\n## Variables de entorno\n\n| Variable | Requerida | Descripción |\n|----------|-----------|-------------|\n| `MONGODB_URI` | Según adapter | Connection string de MongoDB |\n| `DATABASE_URL` | Según adapter | Connection string de Prisma/SQL |\n| `JWT_SECRET` | Sí | Secret para access tokens |\n| `JWT_REFRESH_SECRET` | Sí | Secret para refresh tokens (distinto al anterior) |\n| `JWT_EXPIRES_IN` | No | TTL access token (default `1h` si lo mapeas en config) |\n| `JWT_REFRESH_EXPIRES_IN` | No | TTL refresh token (default `7d`) |\n| `JWT_ISSUER` / `JWT_AUDIENCE` | No | Solo si configuras `jwtIssuer` / `jwtAudience` |\n| `FRONTEND_URL` | No | Base URL para links en emails (verify/reset) |\n\nVer `.env.example` en el repo como plantilla para apps consumidoras (la lib no lee `.env` directamente).\n\n---\n\n## Configuración del módulo\n\n`AuthModule.forRootAsync()` acepta un objeto `AuthModuleOptions`:\n\n```typescript\nAuthModule.forRootAsync({\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: (config: ConfigService) => ({\n    // ── JWT (requerido) ──────────────────────────────────\n    secret: config.getOrThrow(\"JWT_SECRET\"),\n    refreshSecret: config.getOrThrow(\"JWT_REFRESH_SECRET\"),\n    expiresIn: \"1h\",           // access token  (default: \"1h\")\n    refreshExpiresIn: \"7d\",    // refresh token (default: \"7d\")\n\n    // ── Identificador de login ───────────────────────────\n    identifierField: \"email\",  // \"email\" | \"username\" (default: \"email\")\n\n    // ── Features opcionales ──────────────────────────────\n    features: {\n      emailVerification: false,   // default: false\n      passwordReset: false,       // default: false\n      refreshTokenRotation: true, // default: true\n      accountLockout: false,      // default: false\n    },\n\n    // ── Lockout (si accountLockout: true) ────────────────\n    lockout: {\n      maxAttempts: 5,              // default: 5\n      lockoutDurationMs: 15 * 60_000, // default: 15 min\n    },\n\n    // ── JWT issuer/audience (opcional) ───────────────────\n    jwtIssuer: \"my-api\",\n    jwtAudience: \"my-app\",\n\n    // ── Performance (opcional) ───────────────────────────\n    jwtValidationCacheTtlMs: 0,  // 0 = siempre validar en DB; max 300000 (5 min)\n\n    // ── Ruta del controller ──────────────────────────────\n    routePrefix: \"auth\",  // default: \"auth\" → /auth/login\n\n    // ── Password policy ──────────────────────────────────\n    bcryptRounds: 10,           // 10–14, default 10\n    passwordComplexity: false,  // upper + lower + digit\n\n    // ── TTL de tokens de email/reset ─────────────────────\n    emailVerificationTokenTtlMs: 24 * 60 * 60 * 1000,  // 24h\n    passwordResetTokenTtlMs: 15 * 60 * 1000,           // 15min\n\n    // ── Hooks personalizados ─────────────────────────────\n    hooks: AppAuthHooks,       // default: DefaultAuthHooks (Nest DI vía ModuleRef)\n    // hooksProvider: { ... }, // alternativa: provider Nest completo\n  }),\n  // routePrefix y hooks también pueden ir aquí (nivel forRootAsync):\n  // routePrefix: \"auth\",\n  // hooks: AppAuthHooks,\n}),\n```\n\n`AuthModule.forRoot(options)` acepta las mismas opciones de forma síncrona (sin `imports`/`inject`).\n\n### Orden de imports\n\nEl adapter de persistencia debe importarse **dentro** de `AuthModule.forRootAsync`:\n\n```typescript\nAuthModule.forRootAsync({\n  imports: [ConfigModule, MongoAuthModule.forFeature()],\n  // ...\n}),\n```\n\nCon Prisma:\n\n```typescript\nimport { PrismaService } from \"./prisma.service\";\nimport { PrismaAuthModule } from \"@aranzatech/aranza-auth/prisma\";\n\nAuthModule.forRootAsync({\n  imports: [\n    ConfigModule,\n    PrismaAuthModule.forFeature({\n      prismaServiceToken: PrismaService,\n      modelName: \"authAccount\",\n    }),\n  ],\n  // ...\n}),\n```\n\n```typescript\nimports: [\n  MongooseModule.forRoot(...),\n  AuthModule.forRootAsync({\n    imports: [MongoAuthModule.forFeature(), ConfigModule],\n    // ...\n  }),\n]\n```\n\n---\n\n## Feature flags\n\nTodo está **desactivado por defecto**. Sin declarar `features`, obtienes el mínimo para POCs.\n\n| Flag | Default | Qué hace |\n|------|---------|----------|\n| `emailVerification` | `false` | Envía email al register, bloquea login hasta verificar |\n| `passwordReset` | `false` | Habilita `forgot-password` y `reset-password` |\n| `refreshTokenRotation` | `true` | Guarda hash del refresh token en DB y lo rota |\n| `accountLockout` | `false` | Bloquea cuenta tras N intentos fallidos de login |\n\n### Modo POC (solo login/register)\n\n```typescript\n// No declares features — o déjalo vacío:\nAuthModule.forRootAsync({\n  useFactory: () => ({\n    secret: \"...\",\n    refreshSecret: \"...\",\n  }),\n}),\n```\n\n- Register crea cuenta con `emailVerified: true` → login inmediato.\n- Endpoints `verify-email`, `resend-verification`, `forgot-password`, `reset-password` responden **404**.\n\n### Modo producción\n\n```typescript\nfeatures: {\n  emailVerification: true,\n  passwordReset: true,\n  refreshTokenRotation: true,\n},\nhooks: AppAuthHooks,  // debe implementar sendEmail\n```\n\n> Si activas `emailVerification` o `passwordReset`, **debes** implementar `AuthHooks.sendEmail`. Si no, register/forgot fallará con un error claro.\n\n---\n\n## Endpoints\n\n| Método | Ruta | Auth | Feature | Body | Respuesta |\n|--------|------|------|---------|------|-----------|\n| `POST` | `/auth/register` | — | — | `{ email?, username?, password }` | `{ registered: true }` |\n| `POST` | `/auth/login` | — | — | `{ email?, username?, password }` | `{ accessToken, refreshToken }` (**HTTP 200**) |\n| `POST` | `/auth/refresh` | — | — | `{ refreshToken }` | `{ accessToken, refreshToken }` |\n| `POST` | `/auth/logout` | Bearer | — | — | `{ loggedOut: true }` |\n| `GET` | `/auth/me` | Bearer | — | — | objeto enriquecido via hooks |\n| `POST` | `/auth/verify-email` | — | `emailVerification` | `{ token }` | `{ verified: true }` |\n| `POST` | `/auth/resend-verification` | — | `emailVerification` | `{ email }` | `{ sent: true }` |\n| `POST` | `/auth/forgot-password` | — | `passwordReset` | `{ email }` | `{ sent: true }` |\n| `POST` | `/auth/reset-password` | — | `passwordReset` | `{ token, newPassword }` | `{ reset: true }` |\n| `POST` | `/auth/change-password` | Bearer | — | `{ currentPassword, newPassword }` | `{ changed: true }` |\n\n> Rutas usan `routePrefix` (default `auth`). Ej: `routePrefix: \"v1/auth\"` → `/v1/auth/login`.\n\n### Errores comunes\n\n| Código | Mensaje | Causa |\n|--------|---------|-------|\n| `401` | `INVALID_CREDENTIALS` | Email/username o password incorrectos |\n| `401` | `EMAIL_NOT_VERIFIED` | Feature `emailVerification` activa y email sin verificar |\n| `401` | `ACCOUNT_DISABLED` | Cuenta desactivada |\n| `401` | `ACCOUNT_LOCKED` | Demasiados intentos fallidos (`features.accountLockout`) |\n| `401` | `PASSWORD_CHANGED` | Access token emitido antes del último cambio de contraseña |\n| `401` | `REFRESH_TOKEN_REUSE` | Refresh reutilizado; sesiones revocadas |\n| `401` | `INVALID_CURRENT_PASSWORD` | Contraseña actual incorrecta en change-password |\n| `401` | `INVALID_REFRESH_TOKEN` | Refresh expirado, revocado o inválido |\n| `401` | `UNAUTHORIZED` | Sin Bearer token o token inválido en ruta protegida |\n| `404` | — | Feature desactivada (endpoint no disponible) |\n| `400` | `TOKEN_INVALID_OR_EXPIRED` | Token de verify/reset inválido o expirado |\n| `400` | `PASSWORD_UNCHANGED` | Nueva contraseña igual a la actual |\n\n---\n\n## Proteger rutas propias\n\nUsa el guard y el decorador exportados por la lib:\n\n```typescript\nimport { Controller, Get, UseGuards } from \"@nestjs/common\";\nimport {\n  JwtAuthGuard,\n  CurrentUser,\n  type AuthJwtPayload,\n} from \"@aranzatech/aranza-auth\";\n\n@Controller(\"projects\")\nexport class ProjectsController {\n  @Get()\n  @UseGuards(JwtAuthGuard)\n  list(@CurrentUser() user: AuthJwtPayload) {\n    // user.sub  → ID de la cuenta auth\n    // user.email, user.orgId, etc. → lo que agregues en buildJwtPayload\n    return { ownerId: user.sub };\n  }\n}\n```\n\nTambién puedes registrar `JwtAuthGuard` como guard global:\n\n```typescript\n{ provide: APP_GUARD, useClass: JwtAuthGuard }\n```\n\n---\n\n## Rate limiting (producción)\n\nLa librería **no incluye** throttling interno — debes aplicarlo en tu app con `@nestjs/throttler`:\n\n```bash\nnpm install @nestjs/throttler\n```\n\n```typescript\nimport { ThrottlerModule, ThrottlerGuard } from \"@nestjs/throttler\";\nimport { APP_GUARD } from \"@nestjs/core\";\nimport { AUTH_RATE_LIMIT_PRESETS } from \"@aranzatech/aranza-auth\";\n\n@Module({\n  imports: [\n    ThrottlerModule.forRoot([\n      AUTH_RATE_LIMIT_PRESETS.default,\n      AUTH_RATE_LIMIT_PRESETS.credentials,\n      AUTH_RATE_LIMIT_PRESETS.passwordReset,\n    ]),\n    // ...\n  ],\n  providers: [{ provide: APP_GUARD, useClass: ThrottlerGuard }],\n})\nexport class AppModule {}\n```\n\nPresets exportados:\n\n| Preset | Uso recomendado | Límite |\n|--------|-----------------|--------|\n| `default` | Rutas auth generales | 10 req/min |\n| `credentials` | `/auth/login`, `/auth/register`, `/auth/refresh` | 5 req/min |\n| `passwordReset` | `/auth/forgot-password`, `/auth/reset-password`, `/auth/resend-verification` | 3 req/min |\n\nMapa por ruta (`AUTH_RATE_LIMIT_ROUTES`):\n\n```typescript\nimport { AUTH_RATE_LIMIT_ROUTES } from \"@aranzatech/aranza-auth\";\n// AUTH_RATE_LIMIT_ROUTES.login → preset credentials\n// AUTH_RATE_LIMIT_ROUTES[\"resend-verification\"] → preset passwordReset\n```\n\n> Aplica `@Throttle()` por controlador o ruta según tu política de seguridad.\n\n### Refresh token en cookie (opcional)\n\n```typescript\nimport { buildRefreshTokenCookie } from \"@aranzatech/aranza-auth\";\n\n@Post(\"login\")\nasync login(@Body() dto: LoginDto, @Res({ passthrough: true }) res: Response) {\n  const tokens = await this.authService.login(dto);\n  res.setHeader(\"Set-Cookie\", buildRefreshTokenCookie(tokens.refreshToken));\n  return { accessToken: tokens.accessToken };\n}\n```\n\n---\n\n## Swagger / OpenAPI\n\nInstala `@nestjs/swagger` en tu app (peer dependency):\n\n```bash\nnpm install @nestjs/swagger\n```\n\nEn `main.ts`:\n\n```typescript\nimport { setupAuthSwagger } from \"@aranzatech/aranza-auth\";\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n\n  setupAuthSwagger(app, {\n    title: \"Mi API\",\n    description: \"Documentación OpenAPI\",\n    path: \"api\", // → http://localhost:3000/api\n    version: \"1.0\",\n    features: {\n      emailVerification: true,\n      passwordReset: true,\n      accountLockout: true,\n    },\n    exportPath: \"./openapi.json\", // opcional: escribe el spec al arrancar\n  });\n\n  await app.listen(3000);\n}\n```\n\nLos endpoints `/auth/*` aparecen bajo el tag **`auth`**. Rutas protegidas usan **Bearer JWT** (`access-token`).\n\nPara probar en Swagger UI:\n1. `POST /auth/login` → copia `accessToken`\n2. Click **Authorize** → pega el token\n3. Llama `GET /auth/me` o tus rutas con `@ApiBearerAuth('access-token')`\n\n---\n\n## Seguridad en producción\n\nDesde **v0.2.0** la lib valida configuración al arrancar (secrets ≥32 chars, access ≠ refresh).\n\n### Opciones recomendadas\n\n```typescript\nAuthModule.forRootAsync({\n  useFactory: (config: ConfigService) => ({\n    secret: config.getOrThrow(\"JWT_SECRET\"),\n    refreshSecret: config.getOrThrow(\"JWT_REFRESH_SECRET\"),\n    expiresIn: \"30m\",           // access corto en prod\n    refreshExpiresIn: \"7d\",\n    bcryptRounds: 12,           // opcional, default 10\n    passwordComplexity: true,   // upper + lower + digit\n    features: {\n      emailVerification: true,\n      passwordReset: true,\n      refreshTokenRotation: true,\n      accountLockout: true,\n    },\n    lockout: {\n      maxAttempts: 5,\n      lockoutDurationMs: 15 * 60_000,\n    },\n  }),\n});\n```\n\n### Refresh tokens en cookies (recomendado)\n\nUsa los helpers exportados (HttpOnly, Secure, SameSite=strict):\n\n```typescript\nimport { buildRefreshTokenCookie, buildClearRefreshTokenCookie } from \"@aranzatech/aranza-auth\";\n\nres.setHeader(\"Set-Cookie\", buildRefreshTokenCookie(tokens.refreshToken));\n// logout:\nres.setHeader(\"Set-Cookie\", buildClearRefreshTokenCookie());\n```\n\nAlternativa manual:\n\n```typescript\nres.cookie(\"refreshToken\", tokens.refreshToken, {\n  httpOnly: true,\n  secure: true,\n  sameSite: \"strict\",\n  maxAge: 7 * 24 * 60 * 60 * 1000,\n});\n```\n\n### Códigos de error\n\n```typescript\nimport { AuthErrorCode } from \"@aranzatech/aranza-auth\";\n\n// AuthErrorCode.REFRESH_TOKEN_REUSE → posible robo de token; sesiones revocadas\n```\n\nVer [SECURITY.md](./SECURITY.md) para tradeoffs (logout vs access JWT) y reporte de vulnerabilidades.\n\n---\n\n## Extender con AuthHooks\n\nLa lib maneja auth genérico. Tu dominio (org, roles, users) va en **hooks**:\n\n```typescript\n// app-auth.hooks.ts\nimport { Injectable } from \"@nestjs/common\";\nimport type { AuthHooks, BaseAuthAccount } from \"@aranzatech/aranza-auth\";\n\ninterface MyAuthAccount extends BaseAuthAccount {\n  orgId: string;\n  roleId: string;\n}\n\n@Injectable()\nexport class AppAuthHooks implements AuthHooks<MyAuthAccount> {\n  constructor(private readonly orgService: OrgService) {}\n\n  /** Campos extra en el JWT (no incluyas `sub` — lo añade la lib) */\n  async buildJwtPayload(account: MyAuthAccount) {\n    return {\n      orgId: account.orgId,\n      roleId: account.roleId,\n    };\n  }\n\n  /** Respuesta de GET /auth/me */\n  async enrichMe(account: MyAuthAccount) {\n    const org = await this.orgService.findById(account.orgId);\n    return {\n      id: account.id,\n      email: account.email,\n      org: { id: org.id, name: org.name },\n    };\n  }\n\n  /** Validaciones antes de crear cuenta */\n  async onBeforeRegister(input) {\n    // ej: verificar invitación, orgId, etc.\n  }\n\n  /** Envío de emails (requerido si activas emailVerification o passwordReset) */\n  async sendEmail(type: \"verify\" | \"reset\", to: string, token: string) {\n    const base = process.env.FRONTEND_URL ?? \"http://localhost:3001\";\n    const path = type === \"verify\" ? \"verify-email\" : \"reset-password\";\n    const url = `${base}/auth/${path}?token=${token}`;\n    // await this.mailer.send({ to, subject: \"...\", html: url });\n  }\n\n  /** Eventos estables para auditoría, métricas o webhooks */\n  async onAuthEvent(event) {\n    // await this.audit.write(event);\n  }\n}\n```\n\nRegistra los hooks en la config:\n\n```typescript\nAuthModule.forRootAsync({\n  useFactory: () => ({\n    secret: \"...\",\n    refreshSecret: \"...\",\n    hooks: AppAuthHooks,\n  }),\n}),\n```\n\n### Métodos disponibles en AuthHooks\n\n| Método | Cuándo se ejecuta | Requerido |\n|--------|-------------------|-----------|\n| `buildJwtPayload` | Login, refresh | Sí |\n| `enrichMe` | GET /auth/me | No (usa default) |\n| `onBeforeRegister` | Antes de crear cuenta | No |\n| `onAfterRegister` | Después de crear cuenta | No |\n| `onAfterLogin` | Después de login exitoso | No |\n| `onAuthEvent` | Register/login/refresh/logout/email/password | No |\n| `sendEmail` | Register (verify) o forgot (reset) | Sí si features de email activas |\n\n`onAuthEvent` emite eventos estables como `login.succeeded`, `login.failed`, `refresh.reuse_detected`, `logout.succeeded`, `email_verification.requested`, `password_reset.succeeded` y `password_change.succeeded`. La librería no los persiste: tu app decide si van a logs, métricas, webhooks o una futura API Identity.\n\nCuando usas el controller incluido, cada evento puede traer `context.ipAddress`, `context.userAgent` y `context.requestId` extraídos del request HTTP. Si usas `AuthService` directamente, puedes pasar ese contexto como parámetro opcional.\n\n---\n\n## Ejemplos Nest reales\n\nLa fase de adopción vive en ejemplos pequeños y copiables:\n\n| Ejemplo | Backend | Ruta |\n|---------|---------|------|\n| Nest + Mongo | Mongoose/MongoDB | `examples/nest-mongo` |\n| Nest + Prisma/Postgres | Prisma + PostgreSQL | `examples/nest-prisma-postgres` |\n\nLa guía completa para integrar la librería en apps Nest reales está en `docs/NEST_APP_GUIDE.md`.\n\n---\n\n## Extender el schema MongoDB\n\nEl schema base incluye: `email`, `username`, `passwordHash`, `refreshTokenHash`, `emailVerified`, `disabled` y campos de tokens.\n\n### Agregar campos de dominio\n\n```typescript\nimport { Prop, Schema, SchemaFactory } from \"@nestjs/mongoose\";\nimport { Types } from \"mongoose\";\nimport { baseAuthAccountSchema } from \"@aranzatech/aranza-auth/mongo\";\n\n@Schema()\nexport class AuthAccount {\n  @Prop({ type: Types.ObjectId, ref: \"Organization\", required: true })\n  orgId!: Types.ObjectId;\n\n  @Prop({ type: Types.ObjectId, ref: \"Role\", required: true })\n  roleId!: Types.ObjectId;\n}\n\nexport const AuthAccountSchema = SchemaFactory.createForClass(AuthAccount);\nAuthAccountSchema.add(baseAuthAccountSchema);\n```\n\n### Registrar schema extendido\n\n```typescript\nimport { AuthAccount, AuthAccountSchema } from \"./schemas/auth-account.schema\";\n\nMongoAuthModule.forFeature({\n  name: AuthAccount.name,\n  schema: AuthAccountSchema,\n  identifierField: \"username\",  // si login es por username\n}),\n```\n\n> `identifierField` en `MongoAuthModule.forFeature()` debe coincidir con el de `AuthModule`.\n\n### Métodos extra en `MongoAuthRepository`\n\nÚtiles para admin o scripts (inyecta `MongoAuthRepository` o implementa en tu propio repo):\n\n| Método | Uso |\n|--------|-----|\n| `setAccountDisabled(id, disabled)` | Deshabilitar/habilitar cuenta |\n| `findUnverifiedByEmail(email)` | Buscar cuenta pendiente de verificación |\n\nÍndice compuesto `{ email: 1, disabled: 1 }` incluido para lookups frecuentes.\n\n---\n\n## Matriz de adapters\n\nLos cuatro adapters oficiales implementan `IAuthRepository`. La diferencia real está en cómo cada base garantiza unicidad, consultas secundarias y updates condicionales.\n\n| Capacidad | Mongo | Prisma/SQL | Cosmos DB | DynamoDB |\n|-----------|-------|------------|-----------|----------|\n| Register/login por email | Sí | Sí | Sí | Sí |\n| Register/login por username | Sí | Sí | Sí | Sí |\n| Refresh token rotation atómica | Sí | Sí | Sí, con `_etag` | Sí, con condition expression |\n| Email verification | Sí | Sí | Sí | Sí |\n| Password reset | Sí | Sí | Sí | Sí |\n| Account lockout | Sí | Sí | Sí | Sí |\n| Disable/enable account | Sí | Sí | Sí | Sí |\n| Multi-session | Sí | Sí | Sí | Sí |\n| Unicidad de email/username | Índices unique | `@unique` | Unique key policy recomendada | Sentinels transaccionales |\n| Infra creada por la librería | Schema Mongoose | No | No | No |\n\nRequisitos mínimos por adapter:\n\n| Adapter | Infra requerida |\n|---------|-----------------|\n| Mongo | `MongooseModule.forRoot(...)` y `MongoAuthModule.forFeature(...)` |\n| Prisma | Modelos compatibles, `PrismaService` y delegates configurados |\n| Cosmos DB | `Container` existente con partición consistente; unique keys recomendadas |\n| DynamoDB | Tabla, GSIs de lookup, GSI de sesiones por cuenta y `DynamoDBDocumentClient` |\n\n---\n\n## Adapter Prisma\n\nEl adapter Prisma implementa el mismo `IAuthRepository` que Mongo. Tu app aporta el `PrismaService`; la librería usa el delegate configurado, por defecto `prisma.authAccount`.\n\n### Modelo sugerido\n\n```prisma\nmodel AuthAccount {\n  id                             String    @id @default(cuid())\n  email                          String?   @unique\n  username                       String?   @unique\n  passwordHash                   String\n  refreshTokenHash               String?\n  emailVerified                  Boolean   @default(false)\n  disabled                       Boolean   @default(false)\n  emailVerificationTokenHash     String?\n  emailVerificationExpiresAt     DateTime?\n  resetTokenHash                 String?\n  resetTokenExpiresAt            DateTime?\n  failedLoginAttempts            Int       @default(0)\n  lockedUntil                    DateTime?\n  lastLoginAt                    DateTime?\n  passwordChangedAt              DateTime?\n  createdAt                      DateTime  @default(now())\n  updatedAt                      DateTime  @updatedAt\n\n  @@index([email, disabled])\n  @@index([emailVerificationTokenHash])\n  @@index([resetTokenHash])\n  @@index([emailVerificationExpiresAt])\n  @@index([resetTokenExpiresAt])\n}\n\nmodel AuthSession {\n  sessionId        String    @id\n  accountId        String\n  refreshTokenHash String\n  expiresAt        DateTime\n  revokedAt        DateTime?\n  createdAt        DateTime  @default(now())\n  updatedAt        DateTime  @updatedAt\n\n  @@index([accountId, revokedAt])\n  @@index([expiresAt])\n}\n```\n\n### Registro en Nest\n\n```typescript\nimport { Module } from \"@nestjs/common\";\nimport { AuthModule } from \"@aranzatech/aranza-auth\";\nimport { PrismaAuthModule } from \"@aranzatech/aranza-auth/prisma\";\nimport { PrismaService } from \"./prisma.service\";\n\n@Module({\n  providers: [PrismaService],\n  imports: [\n    AuthModule.forRootAsync({\n      imports: [\n        PrismaAuthModule.forFeature({\n          prismaServiceToken: PrismaService,\n          modelName: \"authAccount\",\n        }),\n      ],\n      useFactory: () => ({\n        secret: process.env.JWT_SECRET!,\n        refreshSecret: process.env.JWT_REFRESH_SECRET!,\n        identifierField: \"email\",\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\nSi tu modelo Prisma tiene otro nombre, cambia `modelName` para que coincida con el delegate generado (`userAuth` → `prisma.userAuth`).\nSi usas `features.multiSession`, el adapter usa por defecto el delegate `prisma.authSession`; puedes cambiarlo con `sessionModelName`.\n\n---\n\n## Adapter Cosmos DB\n\nEl adapter Cosmos usa un `Container` compatible con `@azure/cosmos`. La app consumidora crea el cliente, database y container; la librería solo recibe el provider del container.\n\n### Documento sugerido\n\n```json\n{\n  \"kind\": \"auth_account\",\n  \"id\": \"auth-id\",\n  \"email\": \"user@example.com\",\n  \"username\": null,\n  \"passwordHash\": \"...\",\n  \"refreshTokenHash\": null,\n  \"emailVerified\": false,\n  \"disabled\": false,\n  \"emailVerificationTokenHash\": null,\n  \"emailVerificationExpiresAt\": null,\n  \"resetTokenHash\": null,\n  \"resetTokenExpiresAt\": null,\n  \"failedLoginAttempts\": 0,\n  \"lockedUntil\": null,\n  \"lastLoginAt\": null,\n  \"passwordChangedAt\": null,\n  \"createdAt\": \"2026-01-01T00:00:00.000Z\",\n  \"updatedAt\": \"2026-01-01T00:00:00.000Z\"\n}\n```\n\nPara `features.multiSession`, configura un container de sesiones. Puede ser el mismo container si tu `uniqueKeyPolicy` no bloquea documentos sin `email`/`username`; en producción suele ser más limpio usar un container dedicado y pasarlo con `sessionContainerToken`.\n\n```json\n{\n  \"kind\": \"auth_session\",\n  \"id\": \"session-id\",\n  \"sessionId\": \"session-id\",\n  \"accountId\": \"auth-id\",\n  \"refreshTokenHash\": \"...\",\n  \"expiresAt\": \"2026-01-08T00:00:00.000Z\",\n  \"revokedAt\": null,\n  \"createdAt\": \"2026-01-01T00:00:00.000Z\",\n  \"updatedAt\": \"2026-01-01T00:00:00.000Z\"\n}\n```\n\nUsa partition key `/id` para el modo simple. Si particionas por otro campo, pásalo como `partitionKeyField`.\n\nPara producción, crea el container con unique keys para el identificador que uses:\n\n```json\n{\n  \"uniqueKeyPolicy\": {\n    \"uniqueKeys\": [\n      { \"paths\": [\"/email\"] },\n      { \"paths\": [\"/username\"] }\n    ]\n  }\n}\n```\n\nLa librería hace un preflight anti-duplicado, pero la unique key policy es la barrera que cierra carreras concurrentes.\n\n### Registro en Nest\n\n```typescript\nimport { CosmosClient } from \"@azure/cosmos\";\nimport { CosmosAuthModule } from \"@aranzatech/aranza-auth/cosmos\";\n\nconst COSMOS_AUTH_CONTAINER = \"CosmosAuthContainer\";\n\n@Module({\n  providers: [\n    {\n      provide: COSMOS_AUTH_CONTAINER,\n      useFactory: () => {\n        const client = new CosmosClient(process.env.COSMOS_CONNECTION_STRING!);\n        return client.database(\"app\").container(\"auth_accounts\");\n      },\n    },\n  ],\n  imports: [\n    AuthModule.forRootAsync({\n      imports: [\n        CosmosAuthModule.forFeature({\n          containerToken: COSMOS_AUTH_CONTAINER,\n          sessionContainerToken: COSMOS_AUTH_CONTAINER,\n          partitionKeyField: \"id\",\n        }),\n      ],\n      useFactory: () => ({\n        secret: process.env.JWT_SECRET!,\n        refreshSecret: process.env.JWT_REFRESH_SECRET!,\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n---\n\n## Adapter DynamoDB\n\nEl adapter DynamoDB usa `DynamoDBDocumentClient` y commands de `@aws-sdk/lib-dynamodb`, pasados por provider para mantener el SDK como dependencia opcional.\n\n### Tabla sugerida\n\n- Partition key: `id` (`String`)\n- GSI `email-index`: partition key `email`\n- GSI `username-index`: partition key `username` si usas `identifierField: \"username\"`\n- GSI `email-verification-token-index`: partition key `emailVerificationTokenHash`\n- GSI `reset-token-index`: partition key `resetTokenHash`\n- GSI `session-account-index`: partition key `accountId` para revocar todas las sesiones de una cuenta cuando `features.multiSession` está activo\n\nLas fechas se guardan como strings ISO para que las comparaciones de expiración sean ordenables.\n\n### Registro en Nest\n\n```typescript\nimport { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport {\n  DynamoDBDocumentClient,\n  GetCommand,\n  PutCommand,\n  QueryCommand,\n  TransactWriteCommand,\n  UpdateCommand,\n} from \"@aws-sdk/lib-dynamodb\";\nimport { DynamoAuthModule } from \"@aranzatech/aranza-auth/dynamo\";\n\nconst DYNAMO_AUTH_CLIENT = \"DynamoAuthDocumentClient\";\nconst DYNAMO_AUTH_COMMANDS = \"DynamoAuthCommands\";\n\n@Module({\n  providers: [\n    {\n      provide: DYNAMO_AUTH_CLIENT,\n      useFactory: () => DynamoDBDocumentClient.from(new DynamoDBClient({})),\n    },\n    {\n      provide: DYNAMO_AUTH_COMMANDS,\n      useValue: {\n        GetCommand,\n        PutCommand,\n        QueryCommand,\n        TransactWriteCommand,\n        UpdateCommand,\n      },\n    },\n  ],\n  imports: [\n    AuthModule.forRootAsync({\n      imports: [\n        DynamoAuthModule.forFeature({\n          clientToken: DYNAMO_AUTH_CLIENT,\n          commandsToken: DYNAMO_AUTH_COMMANDS,\n          tableName: \"auth_accounts\",\n          emailIndexName: \"email-index\",\n          usernameIndexName: \"username-index\",\n          emailVerificationTokenHashIndexName:\n            \"email-verification-token-index\",\n          resetTokenHashIndexName: \"reset-token-index\",\n          sessionAccountIdIndexName: \"session-account-index\",\n        }),\n      ],\n      useFactory: () => ({\n        secret: process.env.JWT_SECRET!,\n        refreshSecret: process.env.JWT_REFRESH_SECRET!,\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n---\n\n## Flujos opcionales (email y password)\n\n### Verificación de email\n\n1. Activa `features.emailVerification: true`\n2. Implementa `sendEmail` en hooks\n3. Register envía email con token → usuario visita link → `POST /auth/verify-email` con `{ token }`\n4. Si el usuario no recibió el email: `POST /auth/resend-verification` con `{ email }` → siempre `{ sent: true }`\n5. Login bloqueado hasta `emailVerified: true`\n\nSi usas `identifierField: \"username\"`, el register **debe incluir `email`** además del username.\n\n### Forgot / Reset password\n\n1. Activa `features.passwordReset: true`\n2. Implementa `sendEmail` en hooks\n3. `POST /auth/forgot-password` con `{ email }` → siempre responde `{ sent: true }` (no revela si el email existe)\n4. Usuario recibe link → `POST /auth/reset-password` con `{ token, newPassword }`\n5. Reset invalida refresh tokens activos\n\n---\n\n## Multi-session / multi-device\n\nDesde `0.4.0`, la librería incluye el contrato `IAuthSessionRepository` y el feature flag `features.multiSession`.\n\nCuando `multiSession` está apagado, la librería conserva el comportamiento histórico: una sola sesión refresh por cuenta usando `refreshTokenHash` en el account.\n\nCuando `multiSession` está activo:\n\n- cada login crea una sesión independiente\n- el refresh JWT incluye `sid`\n- refresh rota el hash de esa sesión\n- logout revoca solo la sesión actual si el access token trae `sid`\n- reset/change password revocan todas las sesiones de la cuenta\n- refresh token reuse revoca todas las sesiones de la cuenta\n\nLos adapters oficiales registran `AUTH_SESSION_REPOSITORY` desde su `forFeature()` cuando tienen la infraestructura necesaria:\n\n| Adapter | Requisito multi-session |\n|---------|--------------------------|\n| Mongo | `MongoAuthModule.forFeature()` registra schema y repository automáticamente |\n| Prisma | Modelo/delegate `AuthSession`, por defecto `prisma.authSession` |\n| Cosmos DB | Container configurado; por defecto usa el mismo `containerToken` |\n| DynamoDB | `sessionAccountIdIndexName` para revocar todas las sesiones de una cuenta |\n\n```typescript\nAuthModule.forRootAsync({\n  imports: [MongoAuthModule.forFeature()],\n  useFactory: () => ({\n    secret: process.env.JWT_SECRET!,\n    refreshSecret: process.env.JWT_REFRESH_SECRET!,\n    features: {\n      refreshTokenRotation: true,\n      multiSession: true,\n    },\n  }),\n});\n```\n\nPara adapters propios, registra un provider para `AUTH_SESSION_REPOSITORY` que implemente `IAuthSessionRepository`.\n\n---\n\n## Exports públicos\n\n| Import | Contenido |\n|--------|-----------|\n| `@aranzatech/aranza-auth` | `AuthModule`, `AuthService`, guards, DTOs, `setupAuthSwagger`, `AuthErrorCode`, cookie helpers, rate-limit presets |\n| `@aranzatech/aranza-auth/cosmos` | `CosmosAuthModule`, `CosmosAuthRepository`, `CosmosAuthSessionRepository`, tipos estructurales del adapter |\n| `@aranzatech/aranza-auth/dynamo` | `DynamoAuthModule`, `DynamoAuthRepository`, `DynamoAuthSessionRepository`, tipos estructurales del adapter |\n| `@aranzatech/aranza-auth/mongo` | `MongoAuthModule`, `MongoAuthRepository`, `MongoAuthSessionRepository`, `baseAuthAccountSchema`, `authSessionSchema` |\n| `@aranzatech/aranza-auth/prisma` | `PrismaAuthModule`, `PrismaAuthRepository`, `PrismaAuthSessionRepository`, tipos estructurales del adapter |\n\nPrincipales exports:\n\n| Símbolo | Uso |\n|---------|-----|\n| `AuthErrorCode` | Códigos de error (`INVALID_CREDENTIALS`, `UNAUTHORIZED`, …) |\n| `AUTH_RATE_LIMIT_PRESETS` / `AUTH_RATE_LIMIT_ROUTES` | Throttling con `@nestjs/throttler` |\n| `buildRefreshTokenCookie` / `buildClearRefreshTokenCookie` | Cookies HttpOnly para refresh |\n| `IAuthRepository` / `CreateAccountData` | Contrato estable para adapters propios |\n| `IAuthSessionRepository` / `AuthSession` | Contrato de sesiones multi-device |\n| `AuthHooks` / `AuthEvent` / `BaseAuthAccount` / `AuthTokens` | Contratos estables para extensión de dominio y auditoría |\n| `MeResponseDto` / `ResendVerificationDto` | Swagger + tipos |\n| `AuthHooksConstructor` | Tipado de hooks custom con Nest DI |\n| `setupAuthSwagger` | Swagger UI + Bearer JWT |\n| `buildIdentityScopeClaims` / `readIdentityScopeFromClaims` | Claims estándar para `tenantId`, `clientId`, `organizationId` |\n| `createAuthEventForwarder` | Forwarder HTTP opcional para enviar `AuthEvent` a un endpoint externo |\n\n### Tokens de inyección\n\n```typescript\nimport {\n  AUTH_MODULE_OPTIONS,\n  AUTH_HOOKS,\n  AUTH_REPOSITORY,\n  AUTH_SESSION_REPOSITORY,\n} from \"@aranzatech/aranza-auth\";\n```\n\nÚtiles si necesitas acceder a config o reemplazar el repository manualmente. `AUTH_SESSION_REPOSITORY` se usa cuando `features.multiSession` está activo.\n\n---\n\n## Estabilidad de API pública\n\nDesde `0.3.0`, la librería separa explícitamente lo estable de lo interno para poder crecer hacia más adapters y, luego, hacia Identity-as-a-Service.\n\n### Estable para apps consumidoras\n\nEstos exports forman parte del contrato público:\n\n| Área | Contrato |\n|------|----------|\n| Módulo Nest | `AuthModule`, `AuthModuleOptions`, `AuthModuleAsyncOptions` |\n| Flujos auth | DTOs públicos, `AuthService`, `TokenService`, `JwtAuthGuard`, `CurrentUser` |\n| Extensión | `AuthHooks`, `AuthHooksConstructor`, `AuthEvent`, `BaseAuthAccount`, `AuthTokens`, `RegisterInput` |\n| Persistencia | `IAuthRepository`, `CreateAccountData`, `AUTH_REPOSITORY` |\n| Sesiones | `IAuthSessionRepository`, `AuthSession`, `AUTH_SESSION_REPOSITORY` |\n| Errores y seguridad | `AuthErrorCode`, cookie helpers, rate-limit presets/routes |\n| Adapters | `MongoAuthModule`, `PrismaAuthModule`, `CosmosAuthModule`, `DynamoAuthModule` |\n\n### Contrato de adapters\n\nTodos los adapters deben implementar `IAuthRepository`. Eso significa que Mongo, Prisma, Cosmos, Dynamo y cualquier adapter futuro deben soportar las mismas capacidades base:\n\n- register/login por identificador\n- refresh token y rotación atómica\n- cambio y reset de password\n- verificación de email\n- lockout por intentos fallidos\n- enable/disable de cuentas\n- lecturas públicas sin secretos y lecturas internas con hashes\n\nLos tipos estructurales como `PrismaAuthDelegate`, `CosmosAuthContainer` o `DynamoAuthDocumentClient` son públicos porque permiten integrar infraestructura real de la app consumidora, pero son contratos de bajo nivel del adapter. Si cambia el SDK externo de Prisma, Azure o AWS, podrían necesitar ajustes en una versión minor o major según el impacto.\n\n### Interno, no garantizado\n\nNo se considera API pública:\n\n- archivos dentro de `__tests__/`\n- fixtures, harnesses in-memory y smoke tests\n- estructura interna de servicios, estrategias o utilidades no exportadas\n- campos privados de documentos/tablas que no estén representados en `BaseAuthAccount` o `AuthAccountWithSecrets`\n\n### Política semver\n\n| Versión | Qué puede cambiar |\n|---------|-------------------|\n| Patch | Fixes, documentación, tests, mejoras internas sin romper tipos públicos |\n| Minor | Nuevos adapters, nuevos exports, nuevos campos opcionales, nuevas features apagadas por defecto |\n| Major | Cambios incompatibles en DTOs, endpoints, `IAuthRepository`, `AuthHooks`, errores o comportamiento por defecto |\n\nMientras estemos en `0.x`, vamos a tratar `IAuthRepository`, `IAuthSessionRepository`, `AuthHooks`, DTOs públicos y entrypoints de adapters como contratos estables. Si necesitamos romperlos para multi-tenant, OAuth/OIDC o Identity-as-a-Service, lo correcto será planearlo como minor o major según el impacto real.\n\n---\n\n## Auditoría y eventos\n\nLa guía completa está en `docs/AUDIT_EVENTS.md`.\n\nReglas rápidas:\n\n- usa `AuthHooks.onAuthEvent` para logs, métricas, webhooks o forwarding hacia Identity\n- usa `createAuthEventForwarder` si quieres enviar eventos a un endpoint HTTP externo\n- no guardes passwords, refresh tokens, verification tokens ni reset tokens\n- trata `identifier` como dato personal porque puede ser email o username\n- usa `context.requestId` para correlación entre logs\n- monitorea `refresh.reuse_detected` como señal de riesgo alto\n\nEl forwarder es fail-open por defecto: si el endpoint externo cae, el login/refresh no se bloquea. Puedes usar `failOpen: false` cuando tu modelo de cumplimiento requiera bloquear el flujo si no se pudo auditar.\n\n---\n\n## Identity scope\n\nLa guía completa está en `docs/IDENTITY_SCOPE.md`.\n\nLa librería define un vocabulario opcional para preparar multi-tenant / multi-app sin imponerlo:\n\n| Campo | Uso |\n|-------|-----|\n| `tenantId` | Frontera de tenant/customer |\n| `clientId` | App/cliente que consume auth |\n| `organizationId` | Organización/workspace dentro de un tenant |\n\nPuedes usar `buildIdentityScopeClaims(account)` dentro de `AuthHooks.buildJwtPayload` y `readIdentityScopeFromClaims(user)` dentro de guards propios.\n\nLos headers `x-tenant-id`, `x-client-id` y `x-organization-id` se copian a `AuthEvent.context.scope` como metadata de auditoría. No deben usarse solos para autorizar acceso.\n\n---\n\n## Identity service roadmap\n\nLa librería Nest sigue siendo integración local. El futuro Identity service debe vivir como producto HTTP separado y OpenAPI-first.\n\nDocumentos actuales:\n\n| Documento | Uso |\n|-----------|-----|\n| `docs/IDENTITY_SERVICE_OPENAPI.md` | Mapa de recursos, endpoints, versionado y milestones |\n| `docs/identity-service.openapi.yaml` | Draft OpenAPI 3.1 para tenants, clients, users, auth, sessions, audit y discovery |\n| `docs/SDK_GENERATION.md` | Estrategia para SDKs Node/Python/etc. generados desde OpenAPI |\n| `docs/IDENTITY_HTTP_CONTRACT.md` | Reglas HTTP para errores, paginacion, scope headers y request IDs |\n| `docs/IDENTITY_SERVICE_STARTER.md` | Starter del futuro servicio separado `AranzaIdentity` |\n| `docs/IDENTITY_SERVICE_HANDOFF.md` | Handoff hacia el proyecto `AranzaIdentity` |\n\nEste contrato reutiliza `AuthEvent`, `AuthIdentityScope`, sesiones y tokens como vocabulario común para futuros SDKs Node/Python/etc.\n\n---\n\n## Identity Node client\n\nLa guía completa está en `docs/IDENTITY_NODE_CLIENT.md`.\n\nLa librería incluye un cliente mínimo para prototipos y primeros consumidores del futuro Identity service:\n\n```typescript\nimport { createIdentityClient } from \"@aranzatech/aranza-auth\";\n\nconst identity = createIdentityClient({\n  baseUrl: \"https://identity.example.com\",\n  serviceToken: process.env.IDENTITY_SERVICE_TOKEN,\n});\n\nawait identity.ingestAuthEvent(event);\n```\n\nEste cliente es un puente de fase 5, no un SDK generado final. Está alineado con `docs/identity-service.openapi.yaml`.\n\n---\n\n## Requisitos del proyecto consumidor\n\n- [ ] NestJS 11+\n- [ ] `ValidationPipe` global activo\n- [ ] `reflect-metadata` importado al inicio de `main.ts`\n- [ ] Un adapter configurado: Mongo, Prisma, Cosmos o Dynamo\n- [ ] La base correspondiente conectada en la app consumidora\n- [ ] Secrets JWT distintos para access y refresh\n- [ ] **`@nestjs/throttler`** en rutas `/auth/*` (ver [Rate limiting](#rate-limiting-producción))\n- [ ] Access token TTL corto (15–60 min) en producción\n- [ ] Si usas features de email: implementar `AuthHooks.sendEmail`\n\n---\n\n## Limitaciones conocidas (v0.4.x)\n\n| Limitación | Workaround / versión futura |\n|------------|----------------------------|\n| Adapters Prisma/Cosmos/Dynamo estructurales; schema/infra viven en la app consumidora | Usar los modelos sugeridos o implementar `IAuthRepository` propio |\n| Sin OAuth (Google, GitHub, etc.) | Roadmap futuro |\n| Multi-session es opt-in | Activar `features.multiSession` y configurar la infraestructura de sesiones del adapter |\n| `jwtValidationCacheTtlMs > 0` retrasa revoke/disable en access tokens | Usar `0` si necesitas revocación inmediata |\n\n---\n\n## Migración desde ≤0.2.1\n\n1. Actualiza a `@aranzatech/aranza-auth@0.2.2`.\n2. **Re-login obligatorio**: refresh JWT y hashes almacenados cambiaron (payload mínimo + HMAC-SHA256).\n3. Los clientes deben parsear `AuthErrorCode` en `message` (no strings legibles).\n4. Activa `forbidNonWhitelisted: true` en `ValidationPipe`.\n5. Opcional: `jwtIssuer` / `jwtAudience`, cookies con `buildRefreshTokenCookie()`.\n\n---\n\n## Desarrollo\n\n```bash\nnpm install\nnpm run ci    # lint + tests (unit + e2e) + coverage gates + audit + build\nnpm run ci:local # alias local de ci\nnpm run release:check # ci local + npm pack dry-run\nnpm run test:identity:openapi # valida el draft OpenAPI de Identity\nnpm run test:identity:service-blueprint # valida el starter del servicio Identity separado\nnpm run test:identity:python # valida el cliente Python de referencia\nnpm test      # solo tests\n```\n\nEl plan de estabilización vive en `docs/STABILIZATION.md`.\n\n### Adapter contract tests\n\nLos adapters deben cumplir el mismo contrato `IAuthRepository`. La suite reusable vive en:\n\n```text\n__tests__/helpers/auth-repository-contract.ts\n```\n\nHoy corre contra Mongo, Prisma, Cosmos y Dynamo con harnesses in-memory:\n\n```text\n__tests__/mongo-auth.repository.contract.test.ts\n__tests__/prisma-auth.repository.contract.test.ts\n__tests__/cosmos-auth.repository.contract.test.ts\n__tests__/dynamo-auth.repository.contract.test.ts\n```\n\nPara nuevos adapters, crea un harness que devuelva un repositorio fresco y llama:\n\n```typescript\ndescribeAuthRepositoryContract(\"MyAuthRepository\", {\n  createRepository: () => new MyAuthRepository(...),\n});\n```\n\n### Validaciones locales y emuladas\n\nLa suite rápida usa harnesses in-memory. Para validar adapters contra engines reales/emulados, corre estos comandos localmente antes de publicar o cuando cambies un adapter:\n\n```bash\nnpm run test:integration:local      # MongoMemoryServer + Prisma SQLite\nnpm run test:integration:mongo      # Mongo real en memoria\nnpm run test:integration:prisma     # Prisma Client + SQLite\nnpm run test:integration:dynamo     # requiere DynamoDB Local en DYNAMODB_LOCAL_ENDPOINT\nnpm run test:integration:cosmos     # requiere COSMOS_ENDPOINT + COSMOS_KEY\n```\n\nEl workflow de GitHub Actions queda intencionalmente liviano para no gastar minutos:\n\n- `test`: lint, coverage, threshold, audit y build.\n\nLas integraciones Mongo/Prisma/Dynamo/Cosmos son locales/manuales. Nota: la imagen oficial de Cosmos DB emulator publica `linux/amd64`; en Macs Apple Silicon puede terminar con `Exited (139)` bajo carga del SDK. Para validación local estable en Mac usa un recurso Cosmos de prueba con `COSMOS_ENDPOINT`/`COSMOS_KEY`.\n\n### Smoke tests reales\n\nLos smoke tests apuntan a infraestructura real y están apagados por defecto. Úsalos solo contra recursos temporales o dedicados de prueba:\n\n```bash\nnpm run test:smoke:mongo      # requiere MONGO_SMOKE_URI\nnpm run test:smoke:dynamo     # requiere credenciales AWS o DYNAMODB_SMOKE_ENDPOINT\nnpm run test:smoke:cosmos     # requiere COSMOS_SMOKE_ENDPOINT + COSMOS_SMOKE_KEY\nnpm run test:smoke:postgres   # requiere PRISMA_SMOKE_DATABASE_URL + PRISMA_SMOKE_ALLOW_SCHEMA_PUSH=1\n```\n\nVariables útiles:\n\n| Smoke | Variables |\n|-------|-----------|\n| Mongo | `MONGO_SMOKE_URI`, opcional `MONGO_SMOKE_DATABASE` |\n| DynamoDB | `AWS_REGION`/credenciales AWS, opcional `DYNAMODB_SMOKE_ENDPOINT`, `DYNAMODB_SMOKE_TABLE` |\n| Cosmos DB | `COSMOS_SMOKE_ENDPOINT`, `COSMOS_SMOKE_KEY`, opcional `COSMOS_SMOKE_DATABASE_ID`, `COSMOS_SMOKE_CONTAINER_ID`, `COSMOS_SMOKE_KEEP_DATABASE=1` |\n| PostgreSQL/Prisma | `PRISMA_SMOKE_DATABASE_URL`, `PRISMA_SMOKE_ALLOW_SCHEMA_PUSH=1` |\n\nLos smoke tests crean recursos con prefijo `aranza-auth-smoke-*` cuando pueden y los eliminan al terminar. Para PostgreSQL usa una base dedicada: el script ejecuta `prisma db push` sobre `PRISMA_SMOKE_DATABASE_URL`.\n\n## Licencia\n\nMIT © [AranzaTech](https://github.com/aranzatech)\n","readmeFilename":"README.md"}