{"_id":"@ambushsoftworks/nestjs-auth-graphql","_rev":"31-18ed5a6d2dfa33344566a57095239f4e","name":"@ambushsoftworks/nestjs-auth-graphql","dist-tags":{"next":"0.9.0-rc.5","latest":"0.14.0"},"versions":{"0.1.3":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.1.3","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.1.3","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"4eb5016f0c42f21952b0db7db3ea1ebab2741649","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.1.3.tgz","fileCount":279,"integrity":"sha512-lRguSAbPM2rM5No6GExZU2VXrH3xQU6XXT1uQmZrI9JOiN8PEDXFbUJUC1lOJDKgLxQwRc0bVkCh2seuH7q7KA==","signatures":[{"sig":"MEUCIC74TXQLGhESgqCRvac4Ag3g8+0W8mrJ9MKp5ubadVP7AiEAqeIJzulF1wZIHH4W7ENHEEwoG6qZTyujhVp8xxyelTk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":501050},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/config":"^3.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.1.3_1763164910311_0.6109946897343874","host":"s3://npm-registry-packages-npm-production"}},"0.1.7":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.1.7","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.1.7","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"5b41e5d51432ea79063a824a0a0e4472ef3f1e9a","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.1.7.tgz","fileCount":291,"integrity":"sha512-HaRk5pb1dYB477wMAcFzBk/aVOJx6y3bEjT5zYQoA+OLB8Gm1aihd6XrrEkziYmkFkJwg7LyqbnKRnY4V78bdg==","signatures":[{"sig":"MEUCIQCMlaAa9VrkBGZsApbWxmGijoJd+2HPJ0/EMPwsEUrXxQIgN3ErGYzyRQCHQzpBaWxr9lcTbnj1W77nm1pEzAxOll8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":514892},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"c87aef98c76f520e68ca15a546827ec775a874e6","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.1.7_1763183803989_0.09683309023715991","host":"s3://npm-registry-packages-npm-production"}},"0.1.8":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.1.8","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.1.8","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"abc5b4665e1a386fc55debfaf9582a7500c6d1b8","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.1.8.tgz","fileCount":291,"integrity":"sha512-N35NpiVSBco0ItT87qE/u9iLd8S9MwppCOvVjq6v0Mb5l8HK19otIRYcM+iGYOaV0eXlcGEvAz/k5xCReXDm1g==","signatures":[{"sig":"MEQCIGxruPqRVTKRlDt5WnpmOP0gHTxqtptmsl96kfJbzOTEAiB3NCZS/FkgSTLTsAkkT00+JSPtUSom1DOzKcbK8aBfvA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":514709},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"ba97673e18911eabec957191a97583abe0f7b7e0","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.1.8_1763185014935_0.4250613811818573","host":"s3://npm-registry-packages-npm-production"}},"0.1.9":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.1.9","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.1.9","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"269cd1d709716f4833f0de8d8c55dc0484cfb0cb","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.1.9.tgz","fileCount":291,"integrity":"sha512-VMfSUlU7bCrpZZwCcOVAJp+HC0tooJvdsp7fCLs3F839HNNOzM1fvxJZbrA7zjpszJY+W6z1UbiEEuUPvGtwLQ==","signatures":[{"sig":"MEYCIQCtK5DUKAEH2ZQZJg44fHtLvJeoifydWAL+r6osaF+y6gIhAJXUQOhw9Kbaw0zfpywUtAwsJtIbvt4rVWDLf4BRDlHp","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":514871},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"eb5833b7a3675adb28e3fcfd2b3986cf60fdc9de","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.1.9_1763186495844_0.9892248259795706","host":"s3://npm-registry-packages-npm-production"}},"0.1.10":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.1.10","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.1.10","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"afa05534ef7d7cf33b9df02386dbf07741cb097d","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.1.10.tgz","fileCount":291,"integrity":"sha512-91HMol/wzQfC74aObafl091erN0k/k8fW4LnmqkauYTMa6UfzL52FwWj4r+lGZt7RhTmK1LOTyVibDTARhauXQ==","signatures":[{"sig":"MEUCIES5+OAfvlnS5ZmPPle1wSmPFOXoKXcrCpA7f0Z57+gBAiEAlpIVy35YbdlNg3qZsyEOEs8hcebZEnlb3bJdiCe9t0E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":515247},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"0e2a7249df00eb887c4b1c9104df288a4ccf1d10","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.1.10_1763187488055_0.8142889941752158","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.2.0","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.2.0","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"ae986ede80ffa5772366c8c101ac17d087450477","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.2.0.tgz","fileCount":295,"integrity":"sha512-uYWkGO3wf71bOGxdEMQxr3qcFYAFPj4nMIK7HIvMDSYb6ZPw21OzGKosu38tkKTPfnbQJykWQuZO1cphc1P3Xg==","signatures":[{"sig":"MEQCICBn0oDgCmJoTigxY6oZECB57WtaBOA6sJ7UXNjguw/RAiBaKMk2W31B9Z8dzt5F3cALuoPZ09XkQJ7uYJKoX3aK5w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":511836},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"2c67e611b65339e6add890d8f0e065a8f44d4bf8","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.2.0_1763229436906_0.12486089444608073","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.2.1","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.2.1","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"6c08404942bbb5526130ff6ff5bb4122547c4718","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.2.1.tgz","fileCount":335,"integrity":"sha512-uAB8U8x/CG6ZhkEQ4DD6qUqXZMHaTOGtZ9q/pxRZe+mhdZP9+DF0IbeCPpq7eVqJ24w9BVlS5nicMf1Sjhk8Pg==","signatures":[{"sig":"MEYCIQDmIaqs1jd8Z7mVxI3d3df5O4qa+yCGIWy89pg9pWufLAIhAOTEIQAHMAfGSlLm/XVZo2Jrij1C+x0KymjzL2xE3f83","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":617176},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"814b458ca2ac400a7c00965a7792e29c30cb802e","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.2.1_1763269018238_0.40226952602159627","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.3.0","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.3.0","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"2655d4403878c70f2e6333eef5a6c9db43db26b7","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.3.0.tgz","fileCount":375,"integrity":"sha512-AINk++MTW20xRZDSDALAiVCuJh8rdEOGCos1hu7+EuH/Spd0O47fLfRYi3BT+z6xNT/F6BiTdHVwiYWyQiJsuQ==","signatures":[{"sig":"MEUCIQCPXe2NnnITlLOkVHvdWflW+rnddR4tyktbbC2heEiGfAIgQdtUB1spU3BrmxfTNVz3RQr0+QIkQ6M9hX6d08nPnNU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":668303},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"39bb56f497f0778e729a321b2a90fd8192691e1b","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.3.0_1763312628755_0.01279749082167636","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.3.1","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.3.1","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"6be8af304819377571ea204add2fa9c0a88e4116","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.3.1.tgz","fileCount":375,"integrity":"sha512-NDw74aODO0D7ccxlYy8lUwUqmLpvFrYEFnQiysfpjJxaja4+0CXyoNK3M5rrIkgNs9oLjcHWTTjGT7b5Oh7d9w==","signatures":[{"sig":"MEQCIFEWKnYVxMFEeULUZP8Emm1IQPR+aqfn1x62SEGNjaYTAiBVo2TVoyOgwlVZgrV9X+dOfhaMSIxShMyq3R9BmQKe7Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":672293},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"39bb56f497f0778e729a321b2a90fd8192691e1b","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.3.1_1763316637990_0.8497752101980296","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.3.2","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.3.2","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"2e4b452d07d9149475f0db4076af709281e9041d","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.3.2.tgz","fileCount":375,"integrity":"sha512-I8WBveDxRThxXAJzPur25BANBCuFdkDM4ZFZ2I6aaR+pIIyJXwehBpB0XFaQstk/2lKQpfLY9auO5A44RgadLg==","signatures":[{"sig":"MEYCIQDmHOyBxC99uqmE2RI4s8hkMwQIAzEIMIQEkQ/G582ZqwIhALCAloHmu3yiGPggiEtmSrZCsYrPLyawXGCitXaY+ytG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":672327},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"8dc612b2fa31b07ad9fed2814676d53195e0b133","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.3.2_1763321586974_0.163811164061761","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.3.3","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.3.3","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"3e468c6082748ff19976ff6569f296e5fac81b15","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.3.3.tgz","fileCount":375,"integrity":"sha512-+4MBf7wDL9akKs1fUhI3HSDMoe6zoV9md7I7Aibb9DBh2tBd3zQ0FypBryYZsN8oxeLccwHRC51cZ/2gJuq09w==","signatures":[{"sig":"MEYCIQCCBvzwXY2n9DYsP6XV4zwXHLvtaOA07F+JpUOpkEOm9wIhAK7ZO/lQrqaojqTyki2FM4HTHrLDaZ3raSG50Dm7cDX7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":676650},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"3fb6ed4a1e88475c52e17ca44d0adde716bd0c2b","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.3.3_1763323038055_0.034415526294354404","host":"s3://npm-registry-packages-npm-production"}},"0.3.4":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.3.4","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.3.4","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"edf1750bb5005c6dd0c743078f70b0629a61ed14","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.3.4.tgz","fileCount":375,"integrity":"sha512-4j/2OfCYsfc3tByUJiummUKkgQzfKOWTeadDX+07K34EzpGhuxwwvJJx9OaaXApyPQy4swnONs/OZpqCqc57Cw==","signatures":[{"sig":"MEYCIQCxWpjGrEtEUE07SocOdlR9Uy9hsUqZYbzgFNkh9FyddAIhAMRr4FDSPqxEzc0V4gmGm+Y4R3pxHVbaOxvWgtghKPee","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":687204},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"30ebe936131490c6f81c9443125262379917dc33","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","passport":"^0.7.0","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","passport-jwt":"^4.0.1","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.3.4_1763342063342_0.31343415042754286","host":"s3://npm-registry-packages-npm-production"}},"0.3.5":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.3.5","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.3.5","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"91278e7e17af17a6546ce8a7c5df5630b740979d","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.3.5.tgz","fileCount":379,"integrity":"sha512-nDWsK8eqQGRwna5b8WtItBnKce3mTib9/me7M2UH9EyvMZDQWItLaHRSstpF/n5pGBg6w+dbT74HU0gsoKBimQ==","signatures":[{"sig":"MEYCIQDtIlKzV8t3XPiVAUWRWor70GDRbPNiYkw2H5nhZnI3ggIhAJ7shvHpFYjZPDZDJcrFG0On3Hfvm23Bj8p51+sm75xF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":692475},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"52ad2b9fd71ec54c715bcc08414bc7fa07cf8493","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.3.5_1763357478462_0.5727887822044","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.4.0","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.4.0","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"9753446fe4bbe6f3478007748fd9dc459ee50f0c","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.4.0.tgz","fileCount":383,"integrity":"sha512-1IJNYyaUh6JPAEApHeIFLrMDvz8vAVL02vEQmgJ9lNy67pq+28dJ579TvQydyezt7KabKybhRlay+MAY0+paSw==","signatures":[{"sig":"MEYCIQC/+jTozIy1UFpL7HQ0Wnv0oEAAa3fkkrDR0n202aWxvAIhANNdbGgw/q0sQLxPI6OzF3Hn89/qQgXlRJdwZPhZD9WF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":695770},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"15cd05d34d4bc25c2b4551cfc0eddfcf67f6125a","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"10.9.3","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0","@nestjs/core":"^10.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0","@nestjs/graphql":"^12.0.0","@nestjs/passport":"^10.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.4.0_1764087773906_0.0679629556221435","host":"s3://npm-registry-packages-npm-production"}},"0.6.5":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.6.5","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.6.5","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"e988c527f5dc2ae469be13bc309e10bdb0265acb","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.6.5.tgz","fileCount":495,"integrity":"sha512-fGwTmOhJtmXIOvDmiaNqWhIoZau9vpXi875HLWVmbHxeEZ/A6sdsvaCGDfTBb+jFulO4CoQmcmGQsuQtdSMz6A==","signatures":[{"sig":"MEYCIQDVSTYG7nutmPhL2GV1/6ZUpM50+usyTyq8m8S+ZXI4CwIhAPenj0o8Sk3hEkpk1wPyFnWI2f8MwdXh0jAttIjt3Zsh","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":829330},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"a71adac94e671b6154b850b9f5ce16639fc21ab7","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.10.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.22.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.6.5_1771020149777_0.05778911629194461","host":"s3://npm-registry-packages-npm-production"}},"0.6.7":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.6.7","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.6.7","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"cb5c195e09d767e332dc582fda492fea9877598e","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.6.7.tgz","fileCount":503,"integrity":"sha512-K48HKmWpN0+Dj/YgXvg91XghUKVwAB/gHT3b4kd5+K9LdjRSbbUOlLDjF62nNl4GEEAGxTd5qqGehu99kA0x8w==","signatures":[{"sig":"MEYCIQDo9/gZqN3KymgEGBQXuVQW0w9rFDv5AjP5TGIUyanifgIhAOtbs9F8Qhm9xcwW//ctwRymI9vmSbBmHUEjvDYQFywY","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.6.7","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":795238},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"1b7e2d467c1fe40bc33f51c72ffaf55dcdd77520","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.10.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.22.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.6.7_1771340907587_0.8550443002831254","host":"s3://npm-registry-packages-npm-production"}},"0.7.2":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.7.2","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.7.2","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"8d74f33460394850035b8988961ec02edd47eb10","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.7.2.tgz","fileCount":515,"integrity":"sha512-aHNoR8S1yIdZOtOskj+4rpA+XPOxTJ+koykaCEugNHwGPpO9FKkRUWTrTz3tSCu50TAI66xSW/8jvMh+ogLV6w==","signatures":[{"sig":"MEQCIF+6aTG095qB7NAUkn94pudKYLThv0tGlMbiHx4R0/l4AiAaPcsh/wi0KnMZeChE9dsT8Rw2RHLRZwGbrzYq8aDRMw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.7.2","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":812986},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"d5244b50384b3bae181fe84893ebc1d80257f60c","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.12.1","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.15.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.7.2_1778597208299_0.15106690490395436","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.8.0","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.8.0","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"12d838b4414b47e623d647f3bb9a44f181538fc3","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.8.0.tgz","fileCount":524,"integrity":"sha512-YA+/7fBR771qDFN9aAzEXOhKon3cXWf1m7sCD2E1B20NGAoAqYCReKEOsbQHrmLkAkfZqy90gPOk8rmlLECFHA==","signatures":[{"sig":"MEQCIHWOQdeQUZrkEJ+Dn5898dgbDX7gpJ6wvhnkgY3F0YbQAiB0+QAY2pckII7WxZQ2zErysFNexpiX/jJEvNgQdHpqjw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.8.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":849055},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"38fdca65ec0cdcaae3161f8abf65749ff1afc11d","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.12.1","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.15.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.8.0_1778851241778_0.48808615068940764","host":"s3://npm-registry-packages-npm-production"}},"0.9.0-rc.1":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.9.0-rc.1","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.9.0-rc.1","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"39ccab49b2350e6e13a092557247fb457de976ce","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.9.0-rc.1.tgz","fileCount":524,"integrity":"sha512-SfSj8SoGWcz8gBHbuhmUiHXa71H22buy8CHeeWzTDpoySieP7KqU3qUDJ3tIfebKuztzfprGydNVHsCzYi2TBg==","signatures":[{"sig":"MEQCIFKmw286Q9OoFkCoglR8hz8JNSVW5ooPbxFr+FrRzkobAiA6Bg5obsUvtqR2ZWXalOx0XUk3b4pDxc0HFygW2CZP7Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.9.0-rc.1","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":846086},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"f6fca746c0475ec01a51ade0cabc748e5ba82bab","scripts":{"lint":"eslint \"{src,tests}/**/*.ts\" --fix","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.17.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.19.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.9.0-rc.1_1786997451557_0.8793200831883514","host":"s3://npm-registry-packages-npm-production"}},"0.9.0-rc.2":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.9.0-rc.2","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.9.0-rc.2","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"4b46c23d4889de816fbe59dd4a8973c583d0fc2a","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.9.0-rc.2.tgz","fileCount":541,"integrity":"sha512-b6H1kcNZk62re2CkFf04GUYnDLx032TM7GNoEZkELLvJUTWUAuCIHk7SxPHLkZQAXfSYH/cI+rk8qzRd9s0+rQ==","signatures":[{"sig":"MEYCIQD3vODAUw0fjhWfUQ3dCkwGpiJK4ZnY9T/eAnDVDMSm5gIhAI/g6Za1RekUSI0KYXl9UfFU+k1nGvwSwTJ7jpK8dD/S","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIGz5Yw+n9NfaxbtleuMyABiKiIt/KGlmzW2MJaMAU+pgAiASRkH/cKzDJKnlBy2hrHzsSpvXieey4/ULaRUX25gNYQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":959576},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"c024816180e1cf5eee64f9d7e6551a8139b99f62","scripts":{"lint":"eslint \"src/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"src/**/*.ts\" --fix","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.1","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.22.0","dependencies":{"bcrypt":"^5.1.1","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^5.0.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.9.0-rc.2_1789267678905_0.42556567901514786","host":"s3://npm-registry-packages-npm-production"}},"0.9.0-rc.3":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.9.0-rc.3","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.9.0-rc.3","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"f6fd3da0085dd47d92b31aba19b4ef4f0017da5a","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.9.0-rc.3.tgz","fileCount":533,"integrity":"sha512-8INRp7LV95wLDmSOkFkWAoaBF7MXMaMxlZkOa3k2vkv09ApeGPbbmKXW6cgCVn44sWrt90sDT5/ZWyj4ZYnZrQ==","signatures":[{"sig":"MEYCIQCBFcODjp4YEMrdywyEPIeYmlLwdWdqyve06P7TM3z0NQIhAO+q3ionDz8HIUtN5oCwp9HCYa9MhE5+vKKuP/a3WQAq","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIDU/M/egqfvEiOWRqqBT2hZw74zt7YTpDdP6p6TTP3HBAiBObCfwKyhU+ecVaZDySZeFfot9bhL0nTCkA5Pi+hUAXw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.9.0-rc.3","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":911130},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"91ff2dd79412f80b395a43e1bded8d42d4f1a9c5","scripts":{"lint":"eslint \"src/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"src/**/*.ts\" --fix","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.21.0","dependencies":{"bcrypt":"^6.0.0","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^6.0.0","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.9.0-rc.3_1789344601973_0.8558050744582104","host":"s3://npm-registry-packages-npm-production"}},"0.9.0-rc.4":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.9.0-rc.4","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.9.0-rc.4","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"53a1600a936951f91b57ad831c9445a7bbec2fdc","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.9.0-rc.4.tgz","fileCount":533,"integrity":"sha512-AmqNdBkPTkxQyKNf4LeB7Lw0QVc4svGwlebOvX8Sw0plaS8BheWSu73K2T0wvZAY0u9HspjzRgtMTBWMAJOeMw==","signatures":[{"sig":"MEQCICXjmtnTApdfz9IBFDOXGzpmRKPDC2hF823KLv0+mb1IAiB4lcIa05u4EhfPLo7Ph0fEP7Ugd8xNecPF0uQW270GSg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIH6j6U9nYh8sq6iQMUl1CZ91DLkcPVMMuwM+KGc7xschAiEAl7qJQxyjU16hzzkHnC+dtS+6Z9CrLVy8JHIbEx25OxA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.9.0-rc.4","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":922198},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"22dd501177c79de7de3ed2971a89288420b2b2d0","scripts":{"lint":"eslint \"src/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"src/**/*.ts\" --fix","prebuild":"node -e \"for (const p of ['dist', 'tsconfig.tsbuildinfo']) require('fs').rmSync(p, { recursive: true, force: true })\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.21.0","dependencies":{"bcrypt":"^6.0.0","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^6.0.0","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.9.0-rc.4_1789405821663_0.6003054305935418","host":"s3://npm-registry-packages-npm-production"}},"0.9.0-rc.5":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.9.0-rc.5","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.9.0-rc.5","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"0dc19795e2c7c710af5189d5d03dd57c0c455f29","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.9.0-rc.5.tgz","fileCount":537,"integrity":"sha512-M4mw0Per+Runu9HyJf2DCZpC7J0pcniLonbMWQaAvlh1qtMwQzxe1cEEQiBxQ25jPh/p++pUixhABf9r0UXgQA==","signatures":[{"sig":"MEYCIQCEiN8zXK9mFYwu+B+tjFhzVt9hzcrK4m2tGxiihotLfQIhAIA3DrJkTo1yaDkDNoSoXBAUWZCu1HScQelWcfgpiPkl","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCbrySiPx+dI6e4X8ApB6C8UXP1lZDMhE9lUigPR+ktHQIgZ8ugJQgnBscPjpXTf6CPsEC89FfbvRdYMhwT1wudvkQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.9.0-rc.5","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":935885},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"90b2e21104a05e7040379554fd347d736a3e12f8","scripts":{"lint":"eslint \"src/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"src/**/*.ts\" --fix","prebuild":"node -e \"for (const p of ['dist', 'tsconfig.tsbuildinfo']) require('fs').rmSync(p, { recursive: true, force: true })\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.21.0","dependencies":{"bcrypt":"^6.0.0","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^6.0.0","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.9.0-rc.5_1789408575049_0.5229442995654467","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.9.0","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.9.0","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"a39936e9c689426848251eec3daf8e953d67a36b","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.9.0.tgz","fileCount":537,"integrity":"sha512-uYg1VU6TGla2MAQaq+KbINcx+UZzV7/oYQuZTLIH5cxTF++fifKB4TdSRi4PCB+R/J8ckub+GVlha6m7ZWRKmg==","signatures":[{"sig":"MEQCIEwFtEXMG55olVEzLOTCwYUdmuL3BlLLo3hzTrd3KiPbAiAaZxql6CUn6ILUtaoNXnuTpPttRNjB1fVCjyBwcCT8bw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCbIGlvZ8z7noiNEJdqa+lOmgz3NRXVQByZ/XzE+BuqswIhAKnY+6i/csT0nugv+SQr1RBhVnUsSxA+QaYNUGVTaATJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.9.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":935484},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"d57540ada21a8455cac07708733d0b5270265273","scripts":{"lint":"eslint \"src/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"src/**/*.ts\" --fix","prebuild":"node -e \"for (const p of ['dist', 'tsconfig.tsbuildinfo']) require('fs').rmSync(p, { recursive: true, force: true })\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.21.0","dependencies":{"bcrypt":"^6.0.0","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^6.0.0","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.9.0_1789411300982_0.97806887038139","host":"s3://npm-registry-packages-npm-production"}},"0.9.1":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.9.1","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.9.1","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"a90ba6d814d0fe621939ea38d251b0841884c31a","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.9.1.tgz","fileCount":537,"integrity":"sha512-HrnyPEI1eSlDNi1+7gC5QWp2i2swTvwOXJ+qqr26FYRTPcMm1UPJQ84ccXyhG8fN4aOENEicGkI9NgZkl/feSA==","signatures":[{"sig":"MEUCIQDSl14CIubHYddPss9vqPBpUU/Okp06OOkogy59TkSxJwIgI6hiNmGsFZ4srzjYgVNh4+HppdxZlcs4xOC/ZHwQI7A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIBb8I2cVgZRA5zH7d6sW8cNSOhoeWwE7Vg0h0OPiPQC5AiBUrR79poAx2m4ubcuLMsqmTNaCB30ZA5Zd4yjq8b9n9Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.9.1","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":941260},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"8b053eaa60fcb5a8bb83f7834ba6c4551e805518","scripts":{"lint":"eslint \"src/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"src/**/*.ts\" --fix","prebuild":"node -e \"for (const p of ['dist', 'tsconfig.tsbuildinfo']) require('fs').rmSync(p, { recursive: true, force: true })\"","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.21.0","dependencies":{"bcrypt":"^6.0.0","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^6.0.0","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.9.1_1789484929422_0.22812906281660417","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.10.0","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.10.0","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"d8d5c96ff76c06d987f9d121a5cbc936a59e2616","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.10.0.tgz","fileCount":545,"integrity":"sha512-AiODHoigKvAPAsLQDYIGtQEME5fZjXho0RZdgxoLMzqOSdToHlLQCrgMTuX0wf7oKOdL1AvDLRWHEkpkhEfTrw==","signatures":[{"sig":"MEUCIE9h5E8G2vyp/OsjqoF/XvTV0/5i9IHyYGh0mcq4EYCwAiEAqlsdN8WcyuXknTJUDWOhuMNVt4qrYXNeLIFH3x+pM88=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCCNK2sDEuX3vWRQYmOeYEqmQmg1cjyfNxLiNnT/KmrlAIhAPnUw/O0jA7BpYTkL2YIuO94z01cjfPZBSZkUM5xwWK6","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.10.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":967071},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"1eda5b7f38e0655fea0f4bb906e827b6181bcca9","scripts":{"lint":"eslint \"{src,test}/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","prebuild":"node -e \"for (const p of ['dist', 'tsconfig.tsbuildinfo']) require('fs').rmSync(p, { recursive: true, force: true })\"","test:cov":"jest --coverage","test:e2e":"jest --config test/e2e/jest.config.js --runInBand","test:watch":"jest --watch","build:watch":"tsc --watch","pretest:e2e":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.21.0","dependencies":{"bcrypt":"^6.0.0","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","supertest":"^7.2.2","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^6.0.0","@apollo/server":"^4.13.0","@nestjs/apollo":"^12.2.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","@types/supertest":"^7.2.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@nestjs/platform-express":"^10.4.22","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.10.0_1789489491232_0.025689988899885385","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.11.0","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.11.0","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"147cb220be81603f2b8b8c989f0d1c6ae7059873","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.11.0.tgz","fileCount":561,"integrity":"sha512-7XcRb1A5Yv0XIma9qrNacTOcYKsv9L6AybL9OqUbudn9M2FT6KyThuxusNaKOZvmkCs6iM6qh/S5qFuD4TZX0g==","signatures":[{"sig":"MEYCIQD2MKuLTylr7Y2It2kS3X/880yjNbV0pwu1VXS56h9spgIhAPEUvNAroGPJBCyvAf9m7MJvcdc25YsGfvzUT1i5CLv/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCJtEbAqylUenz+oD367/pSt9y48y/hzn3Zer6Uq8CqVwIhAOUOu0p688p7At3QzLtfO9bMfhGmRu8W21FP9ydwEKsh","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.11.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":1010821},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"ae69cdc10440870aa18a38b7d859b95562313aba","scripts":{"lint":"eslint \"{src,test}/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","prebuild":"node -e \"for (const p of ['dist', 'tsconfig.tsbuildinfo']) require('fs').rmSync(p, { recursive: true, force: true })\"","test:cov":"jest --coverage","test:e2e":"jest --config test/e2e/jest.config.js --runInBand","test:watch":"jest --watch","build:watch":"tsc --watch","pretest:e2e":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"24.21.0","dependencies":{"bcrypt":"^6.0.0","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.3","jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","supertest":"^7.2.2","graphql-ws":"^5.16.2","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^6.0.0","@apollo/server":"^4.13.0","@nestjs/apollo":"^12.2.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","@types/supertest":"^7.2.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@nestjs/platform-express":"^10.4.22","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.11.0_1789501604574_0.015424841315215376","host":"s3://npm-registry-packages-npm-production"}},"0.12.0":{"name":"@ambushsoftworks/nestjs-auth-graphql","version":"0.12.0","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"author":{"name":"Ambush Softworks"},"license":"MIT","_id":"@ambushsoftworks/nestjs-auth-graphql@0.12.0","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/issues"},"dist":{"shasum":"01d924c5a6a53d8ad29ff4782b95209e6dad3e30","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.12.0.tgz","fileCount":577,"integrity":"sha512-qyPm5bIybKYdHuS7uH3D/HODackiuf9/CWLcarRoIDljY/vsdUGrVnp2DvRpjr0Sm3fNbP4duQbXuOjJN0h+6w==","signatures":[{"sig":"MEQCIHHn9elt0bVgRsMLqhBpX+mk9YqQoPPhElkA2iAq1B7ZAiAZgIjldJCRcWDCesaw6u2R8HnruumbmZ9BwGQe20tDBw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCukTWWvqpRg0FkbrJ7Fxt+K4wAYJNKTjHxwGBwLMcMewIhAMjn98vmWYafUyVAWxmjTqelE8bYXIwtqG8emxktw5id","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1062256},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"0c5bf7390ee3a93c869daf8927856fe4de5bbde3","scripts":{"lint":"eslint \"{src,test}/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","prebuild":"node -e \"for (const p of ['dist', 'tsconfig.tsbuildinfo']) require('fs').rmSync(p, { recursive: true, force: true })\"","test:cov":"jest --coverage","test:e2e":"jest --config test/e2e/jest.config.js --runInBand","test:watch":"jest --watch","build:watch":"tsc --watch","pretest:e2e":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"ambushsoftworks","email":"lloyd@capson.ca"},"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.1","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"_nodeVersion":"22.22.0","dependencies":{"bcrypt":"^6.0.0","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.3","jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","supertest":"^7.2.2","graphql-ws":"^5.16.2","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^6.0.0","@apollo/server":"^4.13.0","@nestjs/apollo":"^12.2.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","@types/supertest":"^7.2.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@nestjs/platform-express":"^10.4.22","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-auth-graphql_0.12.0_1789956713306_0.7149414086291745","host":"s3://npm-registry-packages-npm-production"}},"0.14.0":{"_id":"@ambushsoftworks/nestjs-auth-graphql@0.14.0","bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/-/issues"},"dist":{"shasum":"c84116340ba5f8064af1584cee140516fc289cfb","tarball":"https://registry.npmjs.org/@ambushsoftworks/nestjs-auth-graphql/-/nestjs-auth-graphql-0.14.0.tgz","fileCount":565,"integrity":"sha512-MA93mZz+owCTDgHUl7Q1e1d9Sf33w+i1lGH+1KitP9e9coo5T84wODYM3wuTH/Gz01++S9h3XK8b0AddiAGpAQ==","signatures":[{"sig":"MEUCIETTnQtPogYUGxBAD+IADYFTjXImPNxpzWDrO2e3D9HRAiEA51WM0hQrNVkcBtUmfCywn1OG5swIe0nj+/XRXre2+Kg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDM8qV0XJi9xKNt75Onh8JponSHEeaVuv+hyAq+fap5lAIgITj4zuO1fd7rPQBt+Pl6NpAcAJFV/031dBBq2/7L2n8="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ambushsoftworks%2fnestjs-auth-graphql@0.14.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":1088819},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","name":"@ambushsoftworks/nestjs-auth-graphql","types":"dist/index.d.ts","author":{"name":"Ambush Softworks"},"engines":{"node":">=18"},"gitHead":"564dbdcae9491477eb3f43b13fd2793ef1d43533","license":"MIT","scripts":{"lint":"eslint \"{src,test}/**/*.ts\"","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","release":"node scripts/release.js","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","prebuild":"node -e \"for (const p of ['dist', 'tsconfig.tsbuildinfo']) require('fs').rmSync(p, { recursive: true, force: true })\"","test:cov":"jest --coverage","test:e2e":"jest --config test/e2e/jest.config.js --runInBand","test:watch":"jest --watch","build:watch":"tsc --watch","pretest:e2e":"npm run build","prepublishOnly":"npm run build","release:verify":"node scripts/verify-release.js"},"version":"0.14.0","_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"b3160308-e08c-4ff9-a0d5-1b1fcd8cface"}},"homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"_npmVersion":"11.19.0","description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","directories":{},"maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"_nodeVersion":"24.21.0","dependencies":{"bcrypt":"^6.0.0","twilio":"^5.10.4","@sendgrid/mail":"^8.1.6","class-validator":"^0.14.1","passport-custom":"^1.1.1","class-transformer":"^0.5.1","libphonenumber-js":"^1.12.26","google-auth-library":"^10.5.0","passport-google-oauth20":"^2.0.0"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.3","jest":"^29.7.0","rxjs":"^7.8.2","eslint":"^8.56.0","graphql":"^16.12.0","ts-jest":"^29.1.1","prettier":"^3.2.4","supertest":"^7.2.2","graphql-ws":"^5.16.2","typescript":"^5.3.3","@nestjs/cli":"^10.3.0","@types/jest":"^29.5.11","@types/node":"^20.11.5","@types/bcrypt":"^6.0.0","@apollo/server":"^4.13.0","@nestjs/apollo":"^12.2.2","@nestjs/config":"^3.3.0","@nestjs/testing":"^10.3.1","@types/supertest":"^7.2.1","reflect-metadata":"^0.2.2","@nestjs/throttler":"^6.4.0","@types/passport-jwt":"^4.0.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@nestjs/platform-express":"^10.4.22","@typescript-eslint/parser":"^6.19.0","@types/passport-google-oauth20":"^2.0.17","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"rxjs":"^7.0.0","resend":"^6.0.0","graphql":"^16.0.0","passport":"^0.7.0","@nestjs/jwt":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","passport-jwt":"^4.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/graphql":"^12.0.0 || ^13.0.0","@nestjs/passport":"^10.0.0 || ^11.0.0","reflect-metadata":"^0.2.0","@nestjs/throttler":"^6.0.0"},"peerDependenciesMeta":{"resend":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nestjs-auth-graphql_0.14.0_1790702166599_0.8561059527187012"}}},"time":{"created":"2025-11-15T00:01:50.146Z","modified":"2026-09-29T17:16:07.124Z","0.1.3":"2025-11-15T00:01:50.527Z","0.1.7":"2025-11-15T05:16:44.231Z","0.1.8":"2025-11-15T05:36:55.138Z","0.1.9":"2025-11-15T06:01:36.067Z","0.1.10":"2025-11-15T06:18:08.279Z","2.0.0":"2025-11-15T17:54:30.723Z","0.2.0":"2025-11-15T17:57:17.141Z","0.2.1":"2025-11-16T04:56:58.461Z","0.3.0":"2025-11-16T17:03:48.966Z","0.3.1":"2025-11-16T18:10:38.205Z","0.3.2":"2025-11-16T19:33:07.203Z","0.3.3":"2025-11-16T19:57:18.283Z","0.3.4":"2025-11-17T01:14:23.576Z","0.3.5":"2025-11-17T05:31:18.720Z","0.4.0":"2025-11-25T16:22:54.111Z","0.6.5":"2026-02-13T22:02:30.126Z","0.6.7":"2026-02-17T15:08:27.734Z","0.7.2":"2026-05-12T14:46:48.514Z","0.8.0":"2026-05-15T13:20:41.981Z","0.9.0-rc.1":"2026-08-17T20:10:51.710Z","0.9.0-rc.2":"2026-09-13T02:47:59.033Z","0.9.0-rc.3":"2026-09-14T00:10:02.071Z","0.9.0-rc.4":"2026-09-14T17:10:21.764Z","0.9.0-rc.5":"2026-09-14T17:56:15.168Z","0.9.0":"2026-09-14T18:41:41.077Z","0.9.1":"2026-09-15T15:08:49.510Z","0.10.0":"2026-09-15T16:24:51.345Z","0.11.0":"2026-09-15T19:46:44.666Z","0.12.0":"2026-09-21T02:11:53.408Z","0.14.0":"2026-09-29T17:16:06.693Z"},"bugs":{"url":"https://gitlab.com/ambushworks/nestjs-auth-graphql/-/issues"},"author":{"name":"Ambush Softworks"},"license":"MIT","homepage":"https://gitlab.com/ambushworks/nestjs-auth-graphql#readme","keywords":["nestjs","graphql","authentication","jwt","oauth","email-verification","sms-verification","biometric","social-login","google-oauth","facebook-oauth","refresh-token","brute-force-protection"],"repository":{"url":"git+https://gitlab.com/ambushworks/nestjs-auth-graphql.git","type":"git"},"description":"Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth","maintainers":[{"name":"ambushsoftworks","email":"lloyd@capson.ca"}],"readme":"# @ambushsoftworks/nestjs-auth-graphql\n\nProduction-grade authentication module for NestJS GraphQL + REST APIs. JWT, cookie auth, multi-tenancy, realm-based identity isolation, OAuth, email verification, and more -- with zero database coupling.\n\n## Table of Contents\n\n- [Design Principles](#design-principles)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Why BaseAuthResolver?](#why-baseauthresolver)\n- [Features](#features)\n  - [Cookie Authentication](#cookie-authentication)\n  - [Multi-Tenancy](#multi-tenancy)\n  - [Realm-Based Identity Isolation](#realm-based-identity-isolation)\n  - [API Key Authentication](#api-key-authentication)\n  - [External JWTs](#external-jwts)\n  - [Email System](#email-system)\n  - [Verification Modes](#verification-modes)\n  - [Phone \\& SMS Verification](#phone--sms-verification)\n  - [OAuth](#oauth)\n  - [Biometric Authentication](#biometric-authentication)\n  - [Brute Force Protection](#brute-force-protection)\n  - [Password Reset](#password-reset)\n  - [Password Policy](#password-policy)\n  - [Lifecycle Hooks](#lifecycle-hooks)\n  - [Account Status](#account-status)\n  - [Refresh Retries](#refresh-retries)\n  - [JWT Validation Modes](#jwt-validation-modes)\n  - [JWT Payload Factory](#jwt-payload-factory)\n- [Configuration Reference](#configuration-reference)\n  - [Required Options](#required-options)\n  - [Module Options](#module-options-forrootasync)\n  - [Common Options](#common-options)\n  - [Feature Flags](#feature-flags-features)\n  - [Security Secrets](#security-secrets)\n  - [Cookie Options](#cookie-options-cookie)\n  - [CSRF Options](#csrf-options-csrf)\n  - [Composable Email](#composable-email-email)\n  - [Verification Options](#verification-options-verification)\n  - [Biometric Options (`biometric`)](#biometric-options-biometric)\n  - [SendGrid Options (`sendgrid`)](#sendgrid-options-sendgrid)\n  - [Twilio Options (`twilio`)](#twilio-options-twilio)\n  - [Optional Instance Options](#optional-instance-options)\n- [Decorators](#decorators)\n- [Guards](#guards)\n  - [GraphQL Subscriptions](#graphql-subscriptions)\n- [Utilities](#utilities)\n- [Security Features](#security-features)\n- [Upgrading from 0.9.x](#upgrading-from-09x)\n- [Migrating to v0.12.0](#migrating-to-v0120)\n- [Migrating to v0.11.0](#migrating-to-v0110)\n- [Migrating to v0.10.0](#migrating-to-v0100)\n- [Migrating to v0.9.0](#migrating-to-v090)\n- [License](#license)\n\n---\n\n## Design Principles\n\n- **Interface-driven persistence** -- All storage is behind interfaces (`IUserRepository`, `IRefreshTokenRepository`, `ITenantRepository`, etc.). Bring your own database.\n- **Instance-based DI** -- Repositories and services are injected as instances via `useFactory`, not as classes.\n- **Consumer owns GraphQL types** -- The package provides `BaseAuthResolver<T>` with `protected perform*()` methods. You create your own resolver with `@Mutation()` decorators (see [Why BaseAuthResolver?](#why-baseauthresolver)).\n- **Guards are exported, not auto-registered** -- You register guards in your own `APP_GUARD` chain to control execution order.\n- **NoOp fallbacks** -- Every optional dependency has a no-op implementation, so the module works with minimal config.\n\n## Installation\n\n```bash\nnpm install @ambushsoftworks/nestjs-auth-graphql\n```\n\nRequires **Node.js 18 or later**. Passwords are hashed with the native `bcrypt` module, which ships prebuilt binaries for Linux (glibc and musl/Alpine; x64, arm64, arm), macOS, and Windows, so installing on those platforms needs no compiler toolchain.\n\n### Peer Dependencies\n\n```bash\nnpm install @nestjs/common @nestjs/core @nestjs/graphql @nestjs/jwt @nestjs/passport @nestjs/throttler graphql passport passport-jwt reflect-metadata rxjs\n```\n\n`resend` is an optional peer dependency -- install it only if using the Resend email sender.\n\nSupports NestJS 10 and NestJS 11. CI runs the unit and end-to-end suites on both: NestJS 10 with `@nestjs/graphql` 12, Express 4 and Apollo Server 4, and NestJS 11 with `@nestjs/graphql` 13, Express 5 and Apollo Server 5.\n\n## Quick Start\n\nMinimal setup: JWT authentication with email/password login.\n\n### 1. Implement the required repositories\n\n```typescript\n// users.repository.ts\nimport { Injectable } from '@nestjs/common';\nimport { IUserRepositoryCore, CreateUserData } from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Injectable()\nexport class UsersRepository implements IUserRepositoryCore<User> {\n  async findByEmail(email: string): Promise<User | null> { /* ... */ }\n  async findById(id: string): Promise<User | null> { /* ... */ }\n  async create(data: CreateUserData): Promise<User> { /* ... */ }\n  // ... implement remaining IUserRepositoryCore methods\n}\n```\n\n```typescript\n// refresh-token.repository.ts\nimport { Injectable } from '@nestjs/common';\nimport { IRefreshTokenRepository } from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Injectable()\nexport class RefreshTokenRepository implements IRefreshTokenRepository {\n  async create(data: {\n    userId: string;\n    token: string;\n    hashedToken: string;\n    expiresAt: Date;\n    deviceInfo?: string | null;\n  }): Promise<any> { /* ... */ }\n  async findByHashedToken(hashedToken: string): Promise<any | null> { /* ... */ }\n  async deleteByUserId(userId: string): Promise<number> { /* ... */ }\n  // ... implement remaining methods\n}\n```\n\n### 2. Register the module\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { AuthModule } from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Module({\n  imports: [\n    AuthModule.forRootAsync({\n      imports: [ConfigModule, DatabaseModule],\n      inject: [UsersRepository, RefreshTokenRepository, ConfigService],\n      useFactory: (usersRepo, tokenRepo, config) => ({\n        userRepositoryInstance: usersRepo,\n        refreshTokenRepositoryInstance: tokenRepo,\n        jwtSecret: config.get('JWT_SECRET'),\n      }),\n    }),\n  ],\n  providers: [UsersRepository, RefreshTokenRepository],\n})\nexport class AppModule {}\n```\n\n### 3. Create your auth resolver\n\n```typescript\nimport { Resolver, Mutation, Args, Context } from '@nestjs/graphql';\nimport { Inject } from '@nestjs/common';\nimport {\n  BaseAuthResolver,\n  CurrentUser,\n  AuthService,\n  BruteForceProtectionService,\n  USER_REPOSITORY,\n  AUTH_LOGGER,\n} from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Resolver()\nexport class AuthResolver extends BaseAuthResolver<User> {\n  constructor(\n    authService: AuthService,\n    bruteForceProtection: BruteForceProtectionService,\n    @Inject(USER_REPOSITORY) userRepository: any,\n    @Inject(AUTH_LOGGER) authLogger: any,\n  ) {\n    super(authService, bruteForceProtection, userRepository, authLogger);\n  }\n\n  @Mutation(() => AuthResponse)\n  async signup(@Args('input') input: SignupInput, @Context() ctx: any) {\n    return this.performSignup(input, ctx);\n  }\n\n  @Mutation(() => AuthResponse)\n  async login(@Args('input') input: LoginInput, @Context() ctx: any) {\n    return this.performLogin(input, ctx);\n  }\n\n  @Mutation(() => AuthResponse)\n  async refreshToken(@Args('input') input: RefreshTokenInput, @Context() ctx: any) {\n    return this.performRefreshToken(input, ctx);\n  }\n\n  @Mutation(() => LogoutResponse)\n  async logout(\n    @Args('input') input: LogoutInput,\n    @CurrentUser() user: User,\n    @Context() ctx: any,\n  ) {\n    return this.performLogout(input, user, ctx);\n  }\n}\n```\n\n### 4. Set up the guard chain\n\n```typescript\nimport { APP_GUARD } from '@nestjs/core';\nimport { createAuthGuard } from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Module({\n  providers: [\n    {\n      provide: APP_GUARD,\n      useClass: createAuthGuard(['jwt'], { allowPublic: true }),\n    },\n  ],\n})\nexport class AppModule {}\n```\n\nMark public routes with `@Public()`:\n\n```typescript\nimport { Public } from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Public()\n@Mutation(() => AuthResponse)\nasync login() { /* ... */ }\n```\n\n## Why BaseAuthResolver?\n\nTypeScript decorator metadata is not preserved when importing from compiled npm packages. If the package exported a resolver with `@Mutation(() => AuthResponse)`, NestJS would throw \"Cannot determine GraphQL output type\" at runtime.\n\n`BaseAuthResolver<T>` solves this by providing only business logic via `protected perform*()` methods. You add the GraphQL decorators in your own code, where metadata resolution works correctly.\n\nWhen cookie auth is enabled, pass the GraphQL `context` so tokens are set as HttpOnly cookies. The response body will contain empty strings for `accessToken`/`refreshToken`.\n\n**Reference template:** `examples/full-resolver-template.ts` ships in the published package and covers every `perform*` method with copy-paste-ready `@Mutation`/`@Query` decorators, `@Throttle` on auth-sensitive endpoints, and `@UseGuards(JwtAuthGuard)` on authenticated routes. It also demonstrates the `changePassword` + `issueAuthSession` keep-alive pattern. Each `perform*` method on `BaseAuthResolver` also has a method-specific JSDoc snippet you can lift directly.\n\n### Available `perform*()` methods\n\n**Authentication:**\n\n| Method | Purpose |\n|--------|---------|\n| `performSignup(input, context?)` | Create account |\n| `performLogin(input, context)` | Authenticate |\n| `performRefreshToken(input, context?)` | Rotate tokens |\n| `performLogout(input, user, context?)` | Invalidate token |\n| `performLogoutAll(user, context?)` | Invalidate all tokens |\n| `performGetCurrentUser(userId)` | Get current user |\n\n**Verification:**\n\n| Method | Purpose |\n|--------|---------|\n| `performVerifyEmail(input, context?)` | Email verification |\n| `performResendVerificationEmail(email)` | Resend verification email |\n| `performSendPhoneVerification(input, user)` | Send SMS verification code |\n| `performVerifyPhone(input, user)` | Verify phone with SMS code |\n| `performResendPhoneVerification(phoneNumber, user)` | Resend phone verification |\n| `performRemovePhoneNumber(user)` | Remove phone number from account |\n| `performPhoneVerificationStatus(user)` | Get phone verification status |\n\n**Password:**\n\n| Method | Purpose |\n|--------|---------|\n| `performRequestPasswordReset(input, context?)` | Send reset code/token |\n| `performResetPassword(input, context?)` | Reset password |\n| `performChangePassword(userId, current, new)` | Change password |\n\n**Other:**\n\n| Method | Purpose |\n|--------|---------|\n| `performCheckAccountLockStatus(email)` | Check brute force lock status |\n| `performCompleteFacebookSignUp(input)` | Facebook email fallback |\n\n---\n\n## Features\n\n### Cookie Authentication\n\nEnable `features.cookieAuth` to deliver tokens via HttpOnly cookies instead of response bodies.\n\n```typescript\nAuthModule.forRootAsync({\n  useFactory: () => ({\n    // ...required options\n    features: { cookieAuth: true },\n    cookie: {\n      httpOnly: true,     // default\n      secure: true,       // default\n      sameSite: 'lax',    // default\n      domain: undefined,  // browser uses request domain\n      useHostPrefix: true, // prefix names with __Host- for enhanced security\n    },\n  }),\n})\n```\n\nWhen `useHostPrefix: true`, cookie names become `__Host-access_token` and `__Host-refresh_token`. The module validates at startup that `secure` is true, `path` is `/`, and `domain` is unset (as required by the `__Host-` spec).\n\nYou can also customize cookie names and max ages -- see [Cookie Options](#cookie-options-cookie).\n\nThe JWT strategy automatically reads from cookies first, then falls back to `Authorization: Bearer` headers. `performRefreshToken` and `performLogout` are symmetric: when `cookieAuth` is on, they accept an empty `input.refreshToken` and pull the token from the refresh cookie instead. Browser SPAs cannot read HttpOnly cookies, so they should send `{ refreshToken: \"\" }` and rely on the credentialed request carrying the cookie. **Your consumer DTO must allow the empty value** — mark `refreshToken` `@IsOptional()` (or `@IsString()` without `@IsNotEmpty()`) in your `RefreshTokenInput` and `LogoutInput` when targeting browser cookie auth. Non-browser clients (mobile/CLI) keep passing the token explicitly and that path takes precedence.\n\n> **Note:** Reading cookies requires `cookie-parser` middleware (or the Fastify cookie plugin) to populate `req.cookies`. The JWT strategy depends on this already; the same setup serves refresh/logout.\n\n#### CSRF Protection\n\nWith cookie auth, register `CsrfGuard` to protect mutations. It validates that a configurable header (default: `X-Requested-With`) is present when the request is authenticated via cookies.\n\n```typescript\nimport { APP_GUARD } from '@nestjs/core';\nimport { createAuthGuard, CsrfGuard } from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Module({\n  providers: [\n    { provide: APP_GUARD, useClass: createAuthGuard(['jwt'], { allowPublic: true }) },\n    { provide: APP_GUARD, useClass: CsrfGuard },\n  ],\n})\n```\n\nConfigure via `csrf` options:\n\n```typescript\ncsrf: {\n  headerName: 'X-Requested-With',  // default\n  requireInProduction: true,        // default\n  exemptOperations: ['refreshToken'], // skip CSRF for specific operations\n}\n```\n\nThe guard automatically skips when:\n- The request uses `Authorization` header (Bearer/API key)\n- The route has `@Public()`\n- Cookie auth is not enabled\n- `requireInProduction` is false and not in production\n- The GraphQL operation is in `exemptOperations`\n\n### Multi-Tenancy\n\nEnable tenant resolution and permission checking across requests.\n\n```typescript\nAuthModule.forRootAsync({\n  useFactory: (tenantRepo, tenantExtractor) => ({\n    // ...required options\n    // Providing the tenant repository is what enables tenancy; there is no flag.\n    tenantRepositoryInstance: tenantRepo,\n    tenantExtractorInstance: tenantExtractor,\n  }),\n})\n```\n\n**Guard chain** (order matters):\n\n```typescript\nproviders: [\n  { provide: APP_GUARD, useClass: createAuthGuard(['jwt'], { allowPublic: true }) },\n  { provide: APP_GUARD, useClass: TenantGuard },\n  { provide: APP_GUARD, useClass: PermissionGuard },\n]\n```\n\n**`ITenantRepository`** resolves whether a user has access to a tenant:\n\n```typescript\n@Injectable()\nclass TenantRepository implements ITenantRepository {\n  async resolveTenant(userId: string, tenantId: string): Promise<ITenantContext | null> {\n    const membership = await this.db.membership.find({ userId, tenantId });\n    if (!membership) return null;\n    return {\n      tenantId,\n      permissions: membership.role.permissions,\n      metadata: { accountId: membership.accountId },\n    };\n  }\n}\n```\n\n**`ITenantExtractor`** pulls the tenant ID from the request. Use the built-in `HeaderTenantExtractor` (reads `x-tenant-id` header) or implement your own:\n\n```typescript\nimport { HeaderTenantExtractor } from '@ambushsoftworks/nestjs-auth-graphql';\n\n// Default: reads x-tenant-id header\nconst extractor = new HeaderTenantExtractor();\n\n// Custom header name\nconst extractor = new HeaderTenantExtractor('x-org-id');\n```\n\n`extractTenantId` may also return `Promise<string | null>`. `TenantGuard` awaits the result with no microtask overhead for sync returns. Async throws and rejected Promises are treated identically to a sync `null` return — the request is rejected with `400 Bad Request` and the internal cause is logged via Nest's `Logger` (never leaked to the client).\n\n**Access tenant context** in resolvers:\n\n```typescript\n@Query(() => [Item])\nasync items(@CurrentTenant() tenant: ITenantContext) {\n  return this.service.findByTenant(tenant.tenantId);\n}\n```\n\n**Skip tenant resolution** for routes that don't need it:\n\n```typescript\n@SkipTenant()\n@Query(() => User)\nasync me(@CurrentUser() user: User) { /* ... */ }\n```\n\n**Permission checking** with `@RequirePermissions()`:\n\n```typescript\n@RequirePermissions('clients:read')\n@Query(() => [Client])\nasync clients(@CurrentTenant() tenant: ITenantContext) { /* ... */ }\n```\n\nFor resource-scoped permissions, combine with `@ResourceScope()` and provide an `IResourcePermissionRepository`:\n\n```typescript\n@RequirePermissions('clients:write')\n@ResourceScope('client', 'clientId')\n@Mutation(() => Client)\nasync updateClient(@Args('clientId') clientId: string) { /* ... */ }\n```\n\n### Realm-Based Identity Isolation\n\nRealms partition the user identity space so that users in one realm are completely invisible to another. The same email address can exist independently in different realms, each with its own password, tokens, and verification state. This is useful for white-label platforms, multi-brand businesses, and franchise systems.\n\nRealms are opt-in: provide a `realmExtractorInstance` in `AuthModuleOptions`. No separate feature flag is needed. When not provided, everything works exactly as before.\n\n**Implement `IRealmExtractor`:**\n\n```typescript\nimport { Injectable } from '@nestjs/common';\nimport { IRealmExtractor } from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Injectable()\nexport class HostnameRealmExtractor implements IRealmExtractor {\n  extractRealm(request: Record<string, any>): string | null {\n    const host = request.headers?.host;\n    if (!host) return null;\n    // e.g., \"acme.example.com\" -> \"acme\"\n    const subdomain = host.split('.')[0];\n    return subdomain || null;\n  }\n}\n```\n\n**Async extractor (DB-backed lookup):** `extractRealm` may also return `Promise<string | null>`. `RealmMiddleware` awaits the result with no microtask overhead for sync returns (`instanceof Promise` gate). Async throws and rejected Promises are treated identically to a sync `null` return — the request is rejected with `400 Bad Request` and the internal cause is logged via Nest's `Logger` (never leaked to the client). The same widening applies to `ITenantExtractor.extractTenantId`.\n\n```typescript\n@Injectable()\nexport class DbRealmExtractor implements IRealmExtractor {\n  constructor(private readonly prisma: PrismaService) {}\n\n  async extractRealm(request: Record<string, any>): Promise<string | null> {\n    const host = request.headers?.host;\n    if (!host) return null;\n    const site = await this.prisma.site.findUnique({ where: { hostname: host } });\n    return site ? `site:${site.slug}` : null;\n  }\n}\n```\n\n**Register the module with realm support:**\n\n```typescript\nAuthModule.forRootAsync({\n  imports: [ConfigModule, DatabaseModule],\n  inject: [UsersRepository, RefreshTokenRepository, HostnameRealmExtractor, ConfigService],\n  useFactory: (usersRepo, tokenRepo, realmExtractor, config) => ({\n    userRepositoryInstance: usersRepo,\n    refreshTokenRepositoryInstance: tokenRepo,\n    jwtSecret: config.get('JWT_SECRET'),\n    realmExtractorInstance: realmExtractor,\n  }),\n})\n```\n\n`RealmMiddleware` is automatically registered by `AuthModule` — no manual middleware registration needed. When a `realmExtractorInstance` is provided, the middleware calls `extractor.extractRealm(request)` on every request before any guards run. If the extractor returns `null`, the request is rejected with `400 Bad Request` (strict mode).\n\n**Routes without a realm.** Health checks, inbound webhooks and public downloads have no realm by nature. Match them with `realm.skip`, and the middleware lets them through without calling the extractor:\n\n```typescript\nAuthModule.forRootAsync({\n  // ...\n  useFactory: (usersRepo, tokenRepo, realmExtractor, config) => ({\n    // ...required options\n    realmExtractorInstance: realmExtractor,\n    realm: {\n      skip: (path) => path === '/health' || path.startsWith('/hooks/'),\n    },\n  }),\n})\n```\n\n- `path` is the path the client requested, including any global prefix and without the query string. Match on it, not on `request.path` or `request.url`: Express rewrites both to `/` inside middleware. The request itself is the second argument.\n- A skipped request has no realm: `request._realm` stays undefined.\n- **Skip only routes that are unauthenticated or authenticate by other means.** A JWT's realm claim cannot match a request with no realm, so `JwtStrategy` answers 401. `BaseAuthResolver` flows and the OAuth routes answer `400 Realm required` rather than run outside a realm, which also contains a predicate that matches more than you meant.\n- `skip` must return a boolean synchronously. If it throws or returns anything else, such as the Promise from an `async` function, the request is not skipped and the error is logged.\n- Without `realmExtractorInstance`, `realm.skip` is ignored and a warning is logged at boot. A `realm.skip` that is not a function fails boot with `InvalidAuthConfigException`.\n\nWhy a predicate rather than route patterns: the same Nest route pattern matches different paths on NestJS 10 and NestJS 11 — `hooks/*` excludes `/hooks/glitchtip/issue` on 11 but not on 10 — so a pattern list would behave differently depending on your Nest version. A `@SkipRealm()` decorator cannot work either, because middleware runs before Nest resolves the route handler.\n\n**Use `@CurrentRealm()` in resolvers:**\n\n```typescript\nimport { CurrentRealm } from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Resolver()\nexport class AuthResolver extends BaseAuthResolver<User> {\n  @Mutation(() => AuthResponse)\n  async signup(\n    @Args('input') input: SignupInput,\n    @CurrentRealm() realm: string,\n    @Context() ctx: any,\n  ) {\n    return this.performSignup(input, ctx);\n  }\n}\n```\n\n`BaseAuthResolver` automatically extracts the realm from the GraphQL context via `getRealmFromContext()` and passes it to all service methods. Repository identity-resolution methods (`findByEmail`, `findByPhoneNumber`, `findByOAuthProvider`, `create`) receive the realm as a parameter so your implementation can scope queries accordingly.\n\n**JWT realm validation:** The JWT payload includes a `realm` claim. On subsequent requests, `JwtStrategy` validates that the realm in the token matches the realm resolved from the current request. A mismatch results in `401 Unauthorized`.\n\n**Rate limiter scoping:** When realms are enabled, rate limiter keys are automatically prefixed with the realm to prevent cross-realm interference (e.g., a lockout in realm A does not affect realm B).\n\n**Realms vs. Multi-Tenancy:**\n\n| Concern | Realms | Multi-Tenancy |\n|---------|--------|---------------|\n| Partitions | Identity (who the user _is_) | Authorization (what the user _can access_) |\n| Scope | User signup, login, tokens, verification | Permissions, resources, team membership |\n| Same email in multiple? | Yes -- fully independent users | Yes -- same user, different tenant contexts |\n| Guard layer | Middleware (before guards) | Guard (`TenantGuard`, after auth) |\n\nRealms and multi-tenancy are orthogonal and can be used together. For example, a white-label SaaS platform might use realms to isolate brand identities and tenancy to manage organizations within each brand.\n\n**Note:** Deprecated OAuth controller methods are not realm-aware. Use the current `BaseAuthResolver` OAuth methods for realm-scoped OAuth flows.\n\n### API Key Authentication\n\nFor machine-to-machine auth, provide an `IApiKeyRepository`:\n\n```typescript\nAuthModule.forRootAsync({\n  useFactory: (apiKeyRepo) => ({\n    // ...required options\n    apiKeyRepositoryInstance: apiKeyRepo,\n  }),\n})\n```\n\nThen use a multi-strategy guard:\n\n```typescript\n{ provide: APP_GUARD, useClass: createAuthGuard(['api-key', 'jwt'], { allowPublic: true }) }\n```\n\nThe `ApiKeyStrategy` hashes the bearer token with SHA-256 and calls `findByKeyHash()` on your repository. API keys and JWTs share the `Authorization: Bearer` header, and strategies are tried in the order listed. A request with no bearer token, or with one that matches no key, falls through to the next strategy, so `['api-key', 'jwt']` and `['jwt', 'api-key']` both accept either credential. A key that matches an inactive account is rejected with 401 and no other strategy runs. When every strategy fails, the guard answers 401.\n\nBefore 0.10.0 the API key strategy rejected an unknown bearer token itself, which stopped the chain: `['api-key', 'jwt']` rejected every JWT.\n\n#### Key options\n\n| Option | Example | Effect |\n|--------|---------|--------|\n| `apiKey.headerName` | `'X-API-Key'` | A header carrying the raw key, read before `Authorization: Bearer`, which keeps working. `CsrfGuard` treats a request carrying it as credentialed, as it already does for `Authorization` |\n| `apiKey.prefix` | `'ait_'` | The prefix every key you issue starts with. See below |\n\nBoth are read only with `apiKeyRepositoryInstance`, and `apiKey.prefix` without it warns at boot. `headerName` must be a header name other than `Authorization`, and `prefix` must not be empty -- an empty one matches every token, so every unknown bearer token, JWTs included, would be refused. Boot fails on either.\n\n**A prefix makes an unknown key unambiguous.** Without one, the strategy cannot tell a mistyped key from a JWT:\n\n| Token | Without `prefix` | With `prefix` |\n|-------|------------------|---------------|\n| Does not start with the prefix (a JWT, say) | Looked up, then passed to the next strategy | Passed to the next strategy, with no lookup |\n| Starts with it, matches no key | Passed to the next strategy; a single-strategy guard answers a generic 401 | `401 Invalid API key` -- it cannot be a JWT, so no other strategy tries it |\n| Matches a key | Authenticated, unless the key is inactive or expired | The same |\n\n#### Expiry, scopes and last use\n\n`IApiKeyAccount` carries optional `scopes?: string[]` and `expiresAt?: Date | null`, and `IApiKeyRepository` may implement `touchLastUsed?(id)`. Existing repositories keep working.\n\n- **Expiry.** A key whose `expiresAt` has passed is refused with `401 API key has expired`, and no other strategy tries it. A key without one never expires.\n- **Scopes.** Mark the operation and register `ScopeGuard` after your authentication guard:\n\n  ```typescript\n  @Get('tickets')\n  @UseGuards(createAuthGuard(['api-key', 'jwt']), ScopeGuard)\n  @RequireScopes('tickets:read')\n  listTickets() { /* ... */ }\n  ```\n\n  A key must hold every listed scope. One that does not gets 403 with `{ message: 'Insufficient scope', code: 'INSUFFICIENT_SCOPE', requiredScopes, statusCode: 403 }`, naming what the operation requires. A key with no `scopes` holds none. **Signed-in people pass**: scopes restrict keys, while a person's access is `PermissionGuard`'s job. With no authenticated principal at all, `ScopeGuard` answers 401 -- which is why it goes after the auth guard.\n- **Last use.** `touchLastUsed(id)` is called once per successful match, and only then -- never for a key that is refused. It is not awaited: a failure is logged and never fails the request.\n\n### External JWTs\n\n`createExternalJwtStrategy(name, options)` verifies tokens another system signs -- each app's backend signing for its own users, say. It registers a separate Passport strategy under `name`, with no realm check and no user lookup, so the package's own `jwt` strategy is untouched.\n\n```typescript\nexport const CustomerJwtStrategy = createExternalJwtStrategy('customer-jwt', {\n  inject: [AppSecretsService],           // optional; pass a plain options object instead\n  useFactory: (secrets: AppSecretsService) => ({\n    algorithms: ['HS256'],               // required\n    audience: 'ambush-desk',\n    secretProvider: (kid) => secrets.findSecret(kid),\n    mapClaims: (claims) => ({ id: claims.sub, app: claims.app, segments: claims.segments }),\n  }),\n});\n\n// providers: [CustomerJwtStrategy]\n// @UseGuards(createAuthGuard(['customer-jwt']))\n```\n\n| Option | Default | Description |\n|--------|---------|-------------|\n| `secretProvider(kid, request)` | -- | The key that verifies a token: a shared secret for `HS*`, a PEM public key for `RS*`, `PS*` and `ES*`. May be async. `null` rejects the token; so does a throw, which is logged |\n| `algorithms` | -- | **Required.** The algorithms the issuer signs with |\n| `issuer`, `audience` | -- | Required `iss` / `aud`, when set |\n| `clockToleranceSec` | `0` | Clock skew allowed on `exp` and `nbf` |\n| `maxTokenBytes` | `8192` | A longer token is refused before anything parses it |\n| `mapClaims(payload)` | the payload | Builds `request.user`, arrays and custom claims intact. `null`, `undefined` or a throw rejects the token |\n| `jwtFromRequest(request)` | `Authorization: Bearer` | Where the token comes from |\n\n**Algorithms are pinned, one family at a time.** Boot fails with `InvalidAuthConfigException` for missing or empty `algorithms`, for `none`, for an algorithm jsonwebtoken does not know, and for HMAC (`HS*`) mixed with asymmetric algorithms -- the mix that lets a public key be used as an HMAC secret. `'jwt'` and `'api-key'` are refused as names, since Passport would replace the package's own strategy.\n\n**Every rejection fails softly**, so the strategy composes: `createAuthGuard(['customer-jwt', 'jwt'])` accepts either kind of token, in either order, and answers 401 when both fail.\n\n### Email System\n\nThe email system uses a composable architecture: a **sender** (transport) and a **template renderer** (HTML generation).\n\n```typescript\nimport { SendGridEmailSender } from '@ambushsoftworks/nestjs-auth-graphql';\n\nAuthModule.forRootAsync({\n  useFactory: (config) => ({\n    // ...required options\n    email: {\n      sender: new SendGridEmailSender(config.get('SENDGRID_API_KEY')),\n      from: { email: 'noreply@example.com', name: 'MyApp' },\n      branding: {\n        appName: 'MyApp',\n        primaryColor: '#1976D2',\n        logoUrl: 'https://example.com/logo.png',\n        companyName: 'My Company',\n        supportEmail: 'support@example.com',\n      },\n    },\n  }),\n})\n```\n\n`email.branding` is required when using the default template renderer. If you provide a custom `email.templateRenderer`, branding can be omitted.\n\n**What the package sends.** Exactly three emails, each fired directly by an auth\nflow the package owns:\n\n| Email | Fired by |\n|---|---|\n| Verification | `signup`, `resendVerificationEmail` |\n| Password reset | `requestPasswordReset` |\n| Password changed | `resetPassword`, `changePassword` |\n\nEverything else — welcome, account-locked, account-linked/unlinked,\nlogin-from-new-device — is **consumer-owned**, wired from [lifecycle\nhooks](#lifecycle-hooks). The package does not fire them, so it does not\ndeclare them on `IEmailService`. The branded templates for several of them are\nstill available on `IEmailTemplateRenderer` (`renderWelcomeEmail`,\n`renderAccountLockedEmail`, `renderEmailChangedEmail`), so a hook can render\nwith the package's styling and hand the result to your own `IEmailSender`.\n\n**Built-in senders:** `SendGridEmailSender`, `ResendEmailSender`, `NoOpEmailSender`\n\n**Custom sender:** Implement `IEmailSender`:\n\n```typescript\nclass SmtpEmailSender implements IEmailSender {\n  async send(params: {\n    to: string;\n    from: { email: string; name?: string };\n    subject: string;\n    html: string;\n    text?: string;\n  }) {\n    // your SMTP logic\n  }\n}\n```\n\n**Custom template renderer:** Override `DefaultEmailTemplateRenderer` by providing `email.templateRenderer`:\n\n```typescript\nemail: {\n  sender: new SendGridEmailSender(apiKey),\n  from: { email: 'noreply@example.com' },\n  templateRenderer: new MyCustomRenderer(),\n}\n```\n\n### Verification Modes\n\nTwo modes for email verification and password reset:\n\n- **`'code'`** (default) -- 6-digit numeric codes, entered by the user\n- **`'token'`** -- high-entropy tokens delivered as a clickable link\n\n```typescript\nfeatures: { verificationMode: 'token' },\nverification: {\n  baseUrl: 'https://app.example.com', // REQUIRED in token mode\n  tokenLength: 64,          // bytes, default: 64\n  tokenExpiresInMinutes: 60, // default: 60\n},\n```\n\n| | `'code'` | `'token'` |\n|---|---|---|\n| Credential | 6-digit code | `tokenLength`-byte hex token |\n| Delivered as | code in the email body | link, no readable code |\n| Default expiry | 15 minutes | 60 minutes |\n| Hashing | HMAC-SHA256 | SHA-256 |\n| Attempts before invalidation | 3 | 3 |\n| `verification.baseUrl` | optional | **required** |\n\n**The modes differ in where the secret lives, not just in formatting.** In\ntoken mode the credential *is* the link — it travels in the query string and\nthe email body contains no readable code. In code mode the credential travels\nin the body and the link is a bare page URL carrying no secret at all, so it\nnever reaches browser history, referrer headers, or proxy logs. This is why\ncode mode does not simply put the 6-digit code into the URL, and why the\npackage refuses to render both in one email.\n\n**Link format (token mode).** The package builds the URL and both query\nparameters; you supply only `baseUrl`:\n\n```\nhttps://app.example.com/verify-email?token=<token>&email=<email>\nhttps://app.example.com/reset-password?token=<token>&email=<email>\n```\n\nYour frontend reads both parameters and passes them to `verifyEmail` /\n`resetPassword` — validation is per user keyed on email, so a link missing\neither parameter cannot be redeemed.\n\n**`baseUrl` is required in token mode**, enforced at boot with\n`InvalidAuthConfigException`. Token-mode emails contain no readable credential,\nso a missing base URL would produce mail that delivers successfully and cannot\nbe acted on. Failing at startup makes that a deploy-time error instead of a\nsupport ticket.\n\nIn `'code'` mode `baseUrl` stays optional. When set, it is used for the bare\npage link; otherwise the package falls back to the `FRONTEND_URL` environment\nvariable (deprecated — logged once). With neither, code-mode emails carry no\nlink and nothing is logged: the code is in the body, so no link is needed. The\ncode itself is never placed in a query string in either mode.\n\n#### One API, several brands: `baseUrl` per realm\n\nWith [realms](#realm-based-identity-isolation) enabled, one deployment serves\nseveral frontends and a link must open on the site the user actually came from.\n`baseUrl` accepts a resolver as well as a string; it is called with the realm of\nthe request the credential is being issued for:\n\n```typescript\nconst SITES: Record<string, string> = {\n  'site-a': 'https://a.example.com',\n  'site-b': 'https://b.example.com',\n};\n\nverification: {\n  baseUrl: (realm?: string) => SITES[realm ?? ''] ?? 'https://www.example.com',\n},\n```\n\nIt applies to both modes — the token link and the code page link — because both\nare built from the same resolved base. It is called once per link, so resolve\nfrom a map rather than a query, and it must be synchronous.\n\n**Boot validation is weaker for a resolver, by necessity.** A string is checked\nin full at startup. A resolver is only called once, with `undefined`, so the\nrealm-less case is checked and a per-realm return value is not — there is no\nrequest at startup to supply a realm. What it returns for a specific realm is\nchecked when the link is built, and the two modes differ exactly as they do\nelsewhere: token mode throws, because the link carries the only copy of the\ncredential; code mode logs a warning and sends the email without a link,\nbecause the code is in the body.\n\nReturning a value for `realm === undefined` is required. A request exempted by\n`realm.skip`, or a single-realm deployment, has no realm.\n\n**Custom `IEmailService` implementations.** Both send methods receive the\ncredential and its URL, and the mode determines which one is actionable:\n\n```typescript\nsendVerificationEmail(email, code, expiresInMinutes, verificationUrl?)\nsendPasswordResetEmail(email, resetToken, resetUrl, expiresInMinutes?)\n```\n\nIn token mode, render `verificationUrl` / `resetUrl` — never the raw token,\nwhich the recipient cannot type. In code mode, render the code and omit the\nlink. `expiresInMinutes` reflects the mode's real expiry, so render it rather\nthan hardcoding a duration. Both trailing parameters are optional, so existing\nimplementations continue to compile.\n\n### Phone & SMS Verification\n\nAn authenticated user adds a phone number, receives a 6-digit code by SMS, and\nconfirms it. All five methods take the current user, so they sit behind your\nauthentication guard — this is account management, not a sign-in path.\n\n| Method | Purpose |\n|---|---|\n| `performSendPhoneVerification(input, user)` | Store the number and send a code |\n| `performVerifyPhone(input, user)` | Confirm the code, mark the number verified |\n| `performResendPhoneVerification(phoneNumber, user)` | Send again, subject to the 60-second cooldown |\n| `performRemovePhoneNumber(user)` | Clear the number and its verified state |\n| `performPhoneVerificationStatus(user)` | Whether a number is present and verified |\n\nProvide `smsServiceInstance` and `verificationRepositoryInstance`. `ISmsService`\nhas a single method, so the seam is small:\n\n```typescript\nexport class TwilioSmsService implements ISmsService {\n  async sendVerificationSms(phoneNumber: string, code: string): Promise<void> {\n    await this.client.messages.create({ to: phoneNumber, body: `Your code is ${code}` });\n  }\n}\n```\n\nTwo things worth knowing:\n\n- **SMS is code-only.** `features.verificationMode: 'token'` governs email\n  verification and password reset. A phone always receives a 6-digit code,\n  because a link is not usable from a text message in the same way — so\n  `verification.baseUrl` is irrelevant here.\n- **Omitting `smsServiceInstance` does not fail loudly.** The package substitutes\n  a no-op that logs, so codes are generated and stored but never delivered.\n  Verification then only succeeds for someone reading your application logs.\n\nThe number's realm is scoped like any other identity field: with realms enabled,\n`findByPhoneNumber` receives the realm, so the same number can exist once per\nrealm.\n\n### OAuth\n\nGoogle and Facebook OAuth with encrypted token storage (AES-256-GCM).\n\n```typescript\nAuthModule.forRootAsync({\n  useFactory: (config) => ({\n    // ...required options\n    encryptionKey: config.get('ENCRYPTION_KEY'), // 32-byte hex string\n    oauth: {\n      google: {\n        clientId: config.get('GOOGLE_CLIENT_ID'),\n        clientSecret: config.get('GOOGLE_CLIENT_SECRET'),\n        callbackUrl: config.get('GOOGLE_CALLBACK_URL'),\n      },\n      facebook: {\n        clientId: config.get('FACEBOOK_CLIENT_ID'),\n        clientSecret: config.get('FACEBOOK_CLIENT_SECRET'),\n        callbackUrl: config.get('FACEBOOK_CALLBACK_URL'),\n      },\n    },\n  }),\n})\n```\n\n`OAuthController` mounts two token-exchange routes for native mobile sign-in: `POST /auth/google/token` with body `{ \"idToken\": \"...\" }`, and `POST /auth/facebook/token` with body `{ \"accessToken\": \"...\" }`. Both return `{ accessToken, refreshToken, user }`.\n\n**Not using them?** Leave them unmounted, and they answer 404 like any unknown path:\n\n```typescript\nAuthModule.forRootAsync({\n  oauthController: false, // beside useFactory, not inside it\n  useFactory: () => ({ /* ... */ }),\n})\n```\n\nIt sits beside `useFactory` because Nest fixes a module's controllers before async options resolve. GraphQL account linking does not use these routes and keeps working.\n\n**Errors.** The routes answer with an HTTP status and a body carrying `message`, `code` and `statusCode` at the root, plus the fields listed:\n\n| Status | `code` | When | Other fields |\n|--------|--------|------|--------------|\n| 404 | `OAUTH_PROVIDER_NOT_CONFIGURED` | The provider has no credentials in this deployment | `provider` |\n| 401 | `INVALID_OAUTH_TOKEN` | The provider rejected the token | `provider` |\n| 400 | `OAUTH_MISSING_DATA` | The provider returned no email, or an unverified one | `provider`, `missingField`; for a new Facebook user, `fallbackToken` and `providerId` |\n| 409 | `EMAIL_EXISTS_WITH_PASSWORD` | The email belongs to a password account | `email`, `linkingToken` |\n| 409 | `OAUTH_ACCOUNT_ALREADY_LINKED` | The account has a different ID linked for this provider | `provider` |\n| 403 | `ACCOUNT_LOCKED` | Brute-force lockout | `remainingLockoutTime` (seconds) |\n| 403 | `ACCOUNT_INACTIVE` | The account is suspended or deleted | -- |\n| 429 | `RATE_LIMIT_EXCEEDED` | The client IP exceeded `bruteForce.ipRateLimit` | -- |\n\nWith realms enabled, a request without a realm gets `400 Realm required` first. Before 0.10.0 the lockout, inactive-account, rate-limit and unconfigured-provider cases answered 500.\n\n### Biometric Authentication\n\nA device holds an ECDSA P-256 keypair, gated behind the OS biometric prompt. The\nserver stores the public key and verifies a signature over a challenge it issued.\n\n```typescript\nbiometricRepositoryInstance: myBiometricRepo,   // enables the capability\nbiometric: {\n  challengeExpirySeconds: 60,                   // default\n  challengeRateLimit: { maxAttempts: 5, windowMs: 60_000 },  // needs rateLimiterInstance\n},\n```\n\n#### ⚠ What a successful authentication actually proves\n\n**It proves the client still holds the private key. It does not prove a biometric\ncheck happened.** Nothing in an ECDSA signature attests to that, and the server\ncannot distinguish a key held in a hardware enclave from one generated in\nsoftware. Whether a fingerprint was scanned — or a PIN accepted instead, which\nmost mobile biometric APIs allow by default — is the client's word.\n\nTreat this as *possession of a device-bound key that the client promises to\ngate*. It is a good second factor and a good convenience login. Before making it\nthe sole factor for something sensitive, be clear that you are trusting the app,\nnot the biometric. WebAuthn's `userVerification` flag is what actually attests to\nuser verification, and is not this.\n\n#### The flow\n\n```typescript\n// 1. Enrol, authenticated. The package generates the credential id — keep it\n//    on the device alongside the private key.\nconst { credentialId } = await biometricAuth.enrolCredential({\n  userId: user.id,\n  publicKey,                  // PEM, SPKI\n  deviceName: 'iPhone 15',\n  metadata: { yourDeviceString: '...' },   // optional, opaque to the package\n});\n\n// 2. Request a challenge. No user id — the caller is usually signed out.\nconst challenge = await biometricAuth.requestChallenge(credentialId, {\n  ipAddress: req.ip,\n});\nif (!challenge) { /* rate limited */ }\n\n// 3. The client signs `challenge.challenge` (base64) with the private key.\n\n// 4. Verify and receive a session.\nconst session = await biometricAuth.authenticateWithBiometric(\n  { challengeId: challenge.challengeId, credentialId, signature },\n  { res, realm, ipAddress: req.ip },\n);\n```\n\nAlso `listCredentials(userId)` for a device list and `removeCredential(userId,\ncredentialId)` to deactivate one.\n\n#### What the package guarantees\n\n| | |\n|---|---|\n| Challenge | 32 random bytes, single use, 60s default |\n| Replay | A challenge is consumed **atomically** before anything is checked, so a retry loses the race — and a failed attempt still burns it |\n| Cross-credential | A challenge issued for one credential cannot be answered with another's key |\n| Algorithm | Pinned **per credential**. A credential enrolled as ES256 is only verified as ES256; no verifier for its algorithm means refusal, not a fallback |\n| Account status | The session comes from the same sink as every other login, so a suspended or soft-deleted user is refused **after** a valid signature |\n| Enumeration | Every biometric failure returns the same 401, and a challenge is issued even for a credential that does not exist |\n| Rate limiting | Per credential, and per IP so varying the credential id cannot evade it |\n\n#### Implementing `IBiometricRepository`\n\nOne method has a contract you cannot satisfy with a read followed by a write:\n\n```typescript\nasync consumeChallenge(challengeId: string) {\n  // Atomic: mark used and return it, only if it was unused and unexpired.\n  const { count } = await prisma.biometricChallenge.updateMany({\n    where: { id: challengeId, used: false, expiresAt: { gt: new Date() } },\n    data: { used: true, usedAt: new Date() },\n  });\n  if (count !== 1) return null;    // someone else claimed it, or it expired\n  return this.load(challengeId);\n}\n```\n\nRead-then-write lets two concurrent requests with one challenge both succeed,\nwhich is the replay single use exists to prevent.\n\nTwo more things your schema needs to know:\n\n- **`credentialId` on a challenge is not a foreign key.** A challenge is stored\n  for credential ids that do not exist, so that the signed-out request cannot be\n  used to discover which credentials are enrolled.\n- **No uniqueness on `deviceName` or any device string.** It is a display label,\n  never matched on. Key rotation is enrol-new then deactivate-old.\n\n`getCredential` must return deactivated credentials rather than hiding them — the\npackage decides, so that a deactivated credential and an unknown one produce the\nsame answer.\n\n**There is no no-op fallback.** Omit `biometricRepositoryInstance` and the\nbiometric services are not registered at all, rather than silently accepting\nenrolments that can never authenticate.\n\n### Brute Force Protection\n\nProvide a `bruteForceRepositoryInstance` and the module tracks failed login attempts and temporarily locks accounts. Without one, `NoOpBruteForceRepository` is used and no account is ever locked; there is no flag to set. The lockout policy (attempt thresholds, lockout duration) is determined by your `IBruteForceRepository` implementation.\n\n#### IP Rate Limiting\n\n`BruteForceProtectionService.checkIpRateLimit(ipAddress, realm?)` enforces a sliding-window rate limit per IP. Opt in by setting `bruteForce.ipRateLimit`:\n\n```typescript\nimport { RedisRateLimiter } from './redis-rate-limiter'; // your implementation\n\nAuthModule.forRootAsync({\n  inject: [RedisRateLimiter],\n  useFactory: (redisRateLimiter) => ({\n    // ...required options\n    rateLimiterInstance: redisRateLimiter,        // REQUIRED with ipRateLimit\n    bruteForce: {\n      ipRateLimit: { maxAttempts: 10, windowMs: 60_000 }, // 10 per minute per IP\n    },\n  }),\n})\n```\n\nWhen `bruteForce.ipRateLimit` is configured, `AuthModule.forRootAsync` requires an explicit `rateLimiterInstance` and throws `InvalidAuthConfigException` at boot otherwise:\n\n```\n[AuthModule] bruteForce.ipRateLimit is configured but rateLimiterInstance is undefined.\nThe default InMemoryRateLimiterService is unsafe for multi-replica deployments\n(per-replica counters do not coordinate) and is not auto-applied for IP rate limiting.\nProvide rateLimiterInstance explicitly: a Redis-backed implementation for production,\nor `new InMemoryRateLimiterService()` for single-replica deployments / dev.\nTo disable IP rate limiting, remove the bruteForce.ipRateLimit slot.\n```\n\n`checkIpRateLimit` reuses the same `IRateLimiter` infrastructure as password-reset throttling — implement once, reuse everywhere. For multi-replica production, back it with Redis (the same pattern documented for the `RefreshTokenService` cache applies). For single-replica or dev, `new InMemoryRateLimiterService()` is acceptable.\n\nThreshold is inclusive: with `maxAttempts: 5`, the user is blocked starting on the 5th attempt within the window (record-then-check ordering means `attempts >= maxAttempts` returns `true`). Tune your config accordingly — `maxAttempts: 5` is the first blocked attempt, not the first allowed-over.\n\nWhen realms are enabled, rate-limit keys are namespaced as `auth:ipRate:<realm>:<ipHash>` so a single shared store serves many realms without collisions. IPs are hashed via `hashIp(ip, salt)` (HMAC-SHA256, 16-char hex prefix) before becoming keys; raw IPs are never written to the store or to logs. The salt is resolved once at service construction with the following priority:\n\n1. `AUTH_IP_HASH_SALT` env var (recommended — dedicated, rotatable secret)\n2. `options.jwtSecret` (fallback; one-time INFO log when `bruteForce.ipRateLimit` is configured)\n3. Throws `InvalidAuthConfigException` if `bruteForce.ipRateLimit` is configured but neither salt source is available\n\nNote: the salt is read from `AuthModuleOptions` (not from `process.env.JWT_SECRET` directly), so consumers wiring their JWT secret via `@nestjs/config` / a secrets manager work correctly without populating `process.env.JWT_SECRET`.\n\nThe same salt hashes email addresses and IPs in the package's log lines (`emailHash=` / `ipHash=`), so an IP's log lines and its rate-limit key carry the same hash.\n\nWhen the limit is exceeded, `SecurityEvent.IP_RATE_LIMIT_EXCEEDED` is logged. The method returns `boolean` and never throws — callers branch and produce their own error envelope (typically HTTP 429).\n\n#### Brute-Force Cleanup\n\n`BruteForceProtectionService.cleanupOldAttempts(olderThan: Date): Promise<number>` deletes failed-attempt records older than the cutoff and returns the deletion count. The package does NOT ship a scheduler — wire one in your application:\n\n```typescript\nimport { Injectable, Logger } from '@nestjs/common';\nimport { Cron } from '@nestjs/schedule';\nimport { BruteForceProtectionService } from '@ambushsoftworks/nestjs-auth-graphql';\n\n@Injectable()\nexport class BruteForceCleanupJob {\n  private readonly logger = new Logger(BruteForceCleanupJob.name);\n\n  constructor(private readonly bruteForce: BruteForceProtectionService) {}\n\n  @Cron('0 3 * * *') // daily at 03:00\n  async cleanup() {\n    const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);\n    const deleted = await this.bruteForce.cleanupOldAttempts(ninetyDaysAgo);\n    this.logger.log(`Cleaned ${deleted} old brute-force-attempt rows`);\n  }\n}\n```\n\nThis requires `IBruteForceRepository.deleteOlderThan(beforeDate: Date): Promise<number>` on your repository implementation. Reference Prisma implementation: `return (await this.prisma.bruteForceAttempt.deleteMany({ where: { attemptedAt: { lt: beforeDate } } })).count;` — substitute whichever column records when the attempt happened, and check the name against your schema rather than copying it. Multi-replica deployments should coordinate at the cron layer (advisory lock, leader election) or accept the duplicate-delete cost — a timestamp-bounded `DELETE` is idempotent.\n\n#### Stay Logged In After Password Change\n\n`changePassword` revokes every refresh token for the user (logging out all devices). To keep the current device logged in while logging out the others, compose `changePassword` with `issueAuthSession`:\n\n```typescript\n@Mutation(() => ChangePasswordResponse)\n@UseGuards(JwtAuthGuard)\nasync changePassword(\n  @CurrentUser() user: User,\n  @Args('input') input: ChangePasswordInput,\n  @Context() ctx: any,\n): Promise<ChangePasswordResponse> {\n  const result = await this.performChangePassword(\n    user.id,\n    input.currentPassword,\n    input.newPassword,\n  );\n  // Mint a fresh session for THIS device. Other devices are already revoked.\n  // Use the inherited `getResponseFromContext` helper so cookies work under\n  // both Apollo (`ctx.res`) and Express/Fastify (`ctx.req.res`).\n  const res = this.getResponseFromContext(ctx);\n  const tokens = await this.authService.issueAuthSession(user.id, res);\n  return { ...result, accessToken: tokens.accessToken, refreshToken: tokens.refreshToken };\n}\n```\n\n`issueAuthSession(userId, res?, realm?)` mints a new access + refresh pair, persists the refresh token, and (when `features.cookieAuth` is enabled and `res` is supplied) sets the auth cookies on the response. The caller is responsible for verifying the user's identity — `issueAuthSession` takes a `userId` and trusts it. Pair it only with flows that have already authenticated the user (`changePassword`, MFA enrollment completion, admin-impersonation reissue, etc.). Emits `SecurityEvent.SESSION_ISSUED`.\n\n### Password Reset\n\nA reset is two calls: `performRequestPasswordReset` sends a 6-digit code, and\n`performResetPassword` redeems it. `performChangePassword` is the separate,\nauthenticated path for a signed-in user who knows their current password.\n\n```typescript\n@Mutation(() => PasswordResetResponse)\nrequestPasswordReset(@Args('input') input: RequestPasswordResetInput, @Context() ctx: any) {\n  return this.performRequestPasswordReset(input, ctx);\n}\n\n@Mutation(() => PasswordResetResponse)\nresetPassword(@Args('input') input: ResetPasswordInput, @Context() ctx: any) {\n  return this.performResetPassword(input, ctx);\n}\n```\n\nIt needs `verificationRepositoryInstance` to store the code and\n`emailServiceInstance` to deliver it. Without the first, codes are logged rather\nthan stored and no reset can complete.\n\n#### What the package enforces for you\n\nNone of this is configurable, and most of it is invisible until it bites:\n\n| | |\n|---|---|\n| Code | 6 digits, HMAC-SHA256 hashed at rest, never logged |\n| Expiry | 15 minutes |\n| Attempts | **3**, then the code is destroyed and a new one must be requested |\n| Per-user cooldown | 60 seconds, tracked on `passwordResetSentAt` |\n| Per-IP limit | 5 per hour, checked **before** the user lookup |\n| On success | **every refresh token for that user is revoked** — all devices are signed out |\n| Comparison | constant-time |\n\nThe IP limit runs before the lookup deliberately: checking it afterwards would\nmake a request for a non-existent address measurably faster than one for a real\naddress, which is the enumeration leak the generic message exists to prevent.\n\n#### The response never tells you what happened\n\n`requestPasswordReset` returns the same success payload whether the address does\nnot exist, belongs to a social-login account, or was actually sent a code. That\nis deliberate — the mutation is reachable unauthenticated, so any distinguishable\nresult is an oracle for whether an address is registered.\n\nIf you need to know, read your `IAuthLogger`. A skip is reported as\n`PASSWORD_RESET_REQUESTED` with `result: 'SKIPPED_SOCIAL_ONLY'` and the user ID.\nAn operator tool that creates accounts and invites by reset should assert on that\nevent, not on the mutation's return value.\n\n#### Accounts with no password\n\nAn account is refused only if it has an actual social identity — `googleId`,\n`facebookId` or `appleId`. A password-less account with none of those, which is\nhow an operator-provisioned account starts, receives a code and can redeem it.\nThis is the documented \"invite by password reset\" flow.\n\n**This changed in 0.12.0.** Before then the test was `passwordHash == null`, so\noperator-created accounts were skipped silently and could never sign in. See\n[Migrating to v0.12.0](#migrating-to-v0120) for the consequence worth deciding\non. The predicate is exported as `hasSocialIdentity(user)` if you want the same\ntest in your own code.\n\n#### Token mode\n\nWith `features.verificationMode: 'token'` the email carries a link rather than a\ncode, and `performResetPassword` takes the token lifted from that link in place\nof the 6-digit code. Everything above still applies. See\n[Verification Modes](#verification-modes).\n\n### Password Policy\n\n```typescript\npasswordPolicy: {\n  minLength: 12,            // default: 8\n  maxLength: 72,            // bcrypt limit\n  requireUppercase: true,   // default: true\n  requireLowercase: true,   // default: true\n  requireNumber: true,      // default: true\n  requireSpecialChar: true, // default: false\n  customValidator: async (password) => {\n    // Optional: dictionary checks, leaked password detection, etc.\n    const isCommon = await checkLeakedPasswords(password);\n    return {\n      isValid: !isCommon,\n      errors: isCommon ? ['Password found in data breaches'] : [],\n    };\n  },\n}\n```\n\n### Lifecycle Hooks\n\nReact to auth events without modifying core logic:\n\n```typescript\nlifecycleHooksInstance: {\n  async onSignup(user) { /* create default settings, send analytics */ },\n  async onLogin(user) { /* update metrics */ },\n  async onLogout(user) { /* cleanup */ },\n  async onEmailVerified(user) { /* unlock features */ },\n  async onPhoneVerified(user) { /* enable 2FA */ },\n  async onOAuthAccountLinked(user, provider) { /* sync data */ },\n  async onPasswordReset(user) { /* send security alert */ },\n  async onPasswordChanged(user) { /* notify user */ },\n  async onAccountDelete(user) { /* cleanup user data */ },\n  onAuthFailure(email, ip, reason) { /* security monitoring */ },\n  onAccountLocked(userId, email, ip, lockSeconds, realm) {\n    /* send account-locked notification email, alert security tooling */\n  },\n}\n```\n\nAll hooks are optional. Async hooks are awaited but failures are logged and do not block the auth operation. `onAuthFailure` and `onAccountLocked` are synchronous (fire-and-forget) — both are security signals and the underlying state (lock recorded, attempt logged) is already persisted by the time the hook fires, so hook failures must not roll it back.\n\n`onAccountLocked` fires from `BruteForceProtectionService.recordFailedAttempt` on the transition from \"not locked\" → \"locked\". Subsequent failed attempts while the account remains locked do **not** re-fire (use `onAuthFailure` for per-attempt signal). Wire it to send the account-locked email yourself — the package no longer ships a `sendAccountLockedEmail` method on `IEmailService`; notification surface area beyond verification, password-reset, and password-changed is consumer-owned via this hook.\n\n### Account Status\n\nSuspending or deleting a user takes effect on their next request. The package checks each user's `status` and `deletedAt` itself:\n\n| Where | Effect |\n|-------|--------|\n| `login` | Rejected after the password is verified, so the check cannot reveal to someone without the password that an address is suspended |\n| Every authenticated request (`jwtValidation: 'full'`) | Rejected on the next request, not at token expiry |\n| `refreshToken` | Rejected, including within the refresh grace period |\n| Any token issuance | Rejected, as a backstop for every flow that mints tokens |\n\nA rejected request throws `AccountInactiveException`: a GraphQL error with `extensions.code` `ACCOUNT_INACTIVE`, `statusCode` `403`, and the message `This account is no longer active.` It does not say whether the account was suspended or deleted. Unlike `AccountLockedException` it does not clear on its own, so clients should sign the user out rather than offer a retry. Each rejection logs `SecurityEvent.ACCOUNT_INACTIVE_BLOCKED` with a `phase` of `login`, `refresh`, `session` or `issue`.\n\n**Which accounts are inactive.** By default (`isUserActiveByDefault`), a user with `deletedAt` set, or whose `status` is `SUSPENDED` or `DELETED`, compared case-insensitively. Any other status — including one the package does not recognise — counts as active, so a status vocabulary that differs from `UserStatus` cannot lock everyone out. If yours differs, supply a predicate:\n\n```typescript\nisUserActive: (user) => user.status !== 'FROZEN' && user.status !== 'CLOSED' && !user.deletedAt,\n```\n\nIt must be synchronous and pure: it runs on every authenticated request, against the user already loaded.\n\n**Your repository must return inactive users.** `findById` and `findByEmail` should return suspended and soft-deleted users like any other. A repository that hides them turns `ACCOUNT_INACTIVE` into a \"not found\" failure, and the package can no longer tell the client why.\n\n### Refresh Retries\n\nRefresh tokens rotate: each refresh deletes the token it used. A client that loses the response — a dropped connection, a timeout, an HTTP client that retries — sends the used token again, which looks exactly like a stolen token being replayed. For `refreshGracePeriodSeconds` (default 10) the package remembers the result and answers the retry with the same token pair. `0` turns this off.\n\n**One instance:** nothing to do.\n\n**More than one instance:** give every instance the same store, or a retry that reaches a different instance gets `401` and signs the user out:\n\n```typescript\nAuthModule.forRootAsync({\n  inject: [PgRefreshRetryCache, PgRateLimiter, ConfigService],\n  useFactory: (retryCache, rateLimiter, config) => ({\n    // ...required options\n    refreshRetryCacheInstance: retryCache,\n    encryptionKey: config.getOrThrow('ENCRYPTION_KEY'), // required with a shared store, same on every instance\n    rateLimiterInstance: rateLimiter, // password-reset throttling needs sharing for the same reason\n  }),\n})\n```\n\n- Implement `IRefreshRetryCache` (`get`, `set(key, value, ttlMs)`, `delete`) over Redis, Postgres, or any store the instances share. Its JSDoc has a Postgres example.\n- The values are AES-256-GCM ciphertext, because they hold live tokens. Boot fails with `InvalidAuthConfigException` when `encryptionKey` is missing.\n- The package enforces expiry itself, so the store's TTL can be approximate.\n- A store that errors costs retries, never the refresh itself.\n\nAt boot the package warns for each in-memory default in use, `rateLimiterInstance` and `refreshRetryCacheInstance`, because it cannot tell how many instances run. Pass `new InMemoryRateLimiterService()` and `new InMemoryRefreshRetryCache()` explicitly to confirm a single instance and silence them.\n\nBefore 0.11.0 a retry got `401` whenever `IRefreshTokenRepository.delete` removed the used token, even on a single instance.\n\n### JWT Validation Modes\n\n- **`'full'`** (default) -- Calls `userRepository.findById()` on every request, rejecting the request if the user no longer exists or is no longer active (see [Account Status](#account-status)).\n- **`'payload-only'`** -- Returns `{ id, email }` from the JWT payload without a DB lookup. Faster, but nothing about the account is re-checked per request: a suspended or deleted user keeps working until their access token expires (`jwtExpiresIn`, 15 minutes by default). Refresh is still blocked, so one access-token lifetime is the whole window.\n\n```typescript\njwtValidation: 'payload-only',\n```\n\n### JWT Payload Factory\n\nCustomize JWT claims by providing an `IJwtPayloadFactory`:\n\n```typescript\njwtPayloadFactoryInstance: {\n  createPayload(user) {\n    return { sub: user.id, email: user.email, role: user.role };\n  },\n  extractUserId(payload) {\n    return payload.sub;\n  },\n}\n```\n\n---\n\n## Configuration Reference\n\n### Required Options\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `userRepositoryInstance` | `IUserRepository` | User persistence |\n| `refreshTokenRepositoryInstance` | `IRefreshTokenRepository` | Token persistence |\n| `jwtSecret` | `string` | JWT signing secret |\n\n### Module Options (`forRootAsync`)\n\nThese sit beside `useFactory`, not in the object it returns.\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `useFactory` | `(...deps) => AuthModuleOptions` | -- | Returns the options in the other tables. Required |\n| `inject` | `any[]` | `[]` | Providers passed to `useFactory` |\n| `imports` | `any[]` | `[]` | Modules that export those providers |\n| `oauthController` | `boolean` | `true` | Mount the REST OAuth token routes. See [OAuth](#oauth) |\n\n### Common Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `jwtExpiresIn` | `string` | `'15m'` | Access token TTL |\n| `refreshTokenExpiresIn` | `string` | `'30d'` | Refresh token TTL |\n| `jwtValidation` | `'full' \\| 'payload-only'` | `'full'` | JWT validation strategy |\n| `isUserActive` | `(user) => boolean` | `isUserActiveByDefault` | Decides whether an account may authenticate. See [Account Status](#account-status) |\n| `bcryptRounds` | `number` | `12` | Password hashing cost |\n| `nodeEnv` | `string` | `'production'` | Environment identifier |\n| `passwordPolicy` | `PasswordPolicyConfig` | See [Password Policy](#password-policy) | Password strength rules |\n| `encryptionKey` | `string` | -- | 32-byte hex string for AES-256-GCM (OAuth token encryption) |\n| `bruteForce.ipRateLimit` | `{ maxAttempts, windowMs }` | -- | IP rate-limit policy for `checkIpRateLimit`. When set, `rateLimiterInstance` MUST also be provided explicitly (boot fails with `InvalidAuthConfigException` otherwise). See [IP Rate Limiting](#ip-rate-limiting). |\n| `realm.skip` | `(path, request) => boolean` | -- | Requests that need no realm, such as health checks and webhooks. Read only with `realmExtractorInstance`. See [Realm-Based Identity Isolation](#realm-based-identity-isolation) |\n| `refreshGracePeriodSeconds` | `number` | `10` | How long a retried refresh gets the same token pair. `0` turns retries off. See [Refresh Retries](#refresh-retries) |\n| `apiKey.headerName` | `string` | -- | A header carrying the raw API key, e.g. `'X-API-Key'`, read before `Authorization`. See [API Key Authentication](#api-key-authentication) |\n| `apiKey.prefix` | `string` | -- | The prefix every API key you issue starts with, e.g. `'ait_'`. Makes an unknown key unambiguous. See [API Key Authentication](#api-key-authentication) |\n\n### Feature Flags (`features`)\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `cookieAuth` | `false` | Token delivery via HttpOnly cookies |\n| `preventEnumerationOnSignup` | `false` | Return synthetic success for duplicate emails |\n| `verificationMode` | `'code'` | `'code'` for 6-digit codes, `'token'` for URL tokens |\n\nCapabilities are not switched on by flags. They follow from what you configure:\n\n| Capability | Enabled by |\n|------------|------------|\n| Email verification | `email` or `emailServiceInstance` to deliver, `verificationRepositoryInstance` to store codes |\n| SMS verification | `smsServiceInstance`, plus `verificationRepositoryInstance` |\n| Google / Facebook sign-in | `oauth.google` / `oauth.facebook`, plus `encryptionKey` |\n| Biometric authentication | `biometricRepositoryInstance` |\n| Account lockout | `bruteForceRepositoryInstance` |\n| Multi-tenancy | `tenantRepositoryInstance` and `tenantExtractorInstance`, with `TenantGuard` in your guard chain |\n\nLeave one out and that capability quietly does nothing: the package substitutes a no-op implementation, or `TenantGuard` passes every request. The flags `emailVerification`, `smsVerification`, `googleOAuth`, `facebookOAuth`, `biometricAuth`, `bruteForceProtection` and `multiTenancy` were removed in 0.9.0 because nothing read them — see [Migrating to v0.9.0](#migrating-to-v090).\n\n### Security Secrets\n\nSeparate HMAC secrets for security isolation. Al","readmeFilename":"README.md"}