@vynelix/nestjs-multi-auth 0.3.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +309 -18
  3. package/dist/auth/auth.controller.d.ts +3 -2
  4. package/dist/auth/auth.controller.js +32 -5
  5. package/dist/auth/auth.controller.js.map +1 -1
  6. package/dist/auth/auth.module.js +116 -68
  7. package/dist/auth/auth.module.js.map +1 -1
  8. package/dist/auth/auth.service.d.ts +53 -26
  9. package/dist/auth/auth.service.js +239 -328
  10. package/dist/auth/auth.service.js.map +1 -1
  11. package/dist/auth/core/auth-mapper.d.ts +1 -1
  12. package/dist/auth/core/database-otp.provider.d.ts +12 -0
  13. package/dist/auth/core/database-otp.provider.js +122 -0
  14. package/dist/auth/core/database-otp.provider.js.map +1 -0
  15. package/dist/auth/dto/requests/magic-link.dto.d.ts +1 -0
  16. package/dist/auth/dto/requests/magic-link.dto.js +6 -0
  17. package/dist/auth/dto/requests/magic-link.dto.js.map +1 -1
  18. package/dist/auth/dto/requests/mfa.dto.d.ts +5 -1
  19. package/dist/auth/dto/requests/mfa.dto.js +29 -8
  20. package/dist/auth/dto/requests/mfa.dto.js.map +1 -1
  21. package/dist/auth/enums/identifier-type.enum.d.ts +11 -0
  22. package/dist/auth/enums/identifier-type.enum.js +17 -0
  23. package/dist/auth/enums/identifier-type.enum.js.map +1 -0
  24. package/dist/auth/enums/mfa-type.enum.d.ts +5 -0
  25. package/dist/auth/enums/mfa-type.enum.js +10 -0
  26. package/dist/auth/enums/mfa-type.enum.js.map +1 -0
  27. package/dist/auth/enums/otp-purpose.enum.d.ts +8 -0
  28. package/dist/auth/enums/otp-purpose.enum.js +13 -0
  29. package/dist/auth/enums/otp-purpose.enum.js.map +1 -0
  30. package/dist/auth/enums/session-event.enum.d.ts +7 -0
  31. package/dist/auth/enums/session-event.enum.js +12 -0
  32. package/dist/auth/enums/session-event.enum.js.map +1 -0
  33. package/dist/auth/interfaces/auth-module-options.interface.d.ts +36 -1
  34. package/dist/auth/interfaces/auth-notification-provider.interface.d.ts +7 -1
  35. package/dist/auth/interfaces/auth-otp-provider.interface.d.ts +60 -0
  36. package/dist/auth/interfaces/auth-otp-provider.interface.js +7 -0
  37. package/dist/auth/interfaces/auth-otp-provider.interface.js.map +1 -0
  38. package/dist/auth/interfaces/models.interface.d.ts +91 -0
  39. package/dist/auth/interfaces/models.interface.js +3 -0
  40. package/dist/auth/interfaces/models.interface.js.map +1 -0
  41. package/dist/auth/interfaces/oauth-strategy.interface.d.ts +2 -2
  42. package/dist/auth/interfaces/repositories.interface.d.ts +70 -0
  43. package/dist/auth/interfaces/repositories.interface.js +3 -0
  44. package/dist/auth/interfaces/repositories.interface.js.map +1 -0
  45. package/dist/auth/interfaces/repository-tokens.d.ts +7 -0
  46. package/dist/auth/interfaces/repository-tokens.js +11 -0
  47. package/dist/auth/interfaces/repository-tokens.js.map +1 -0
  48. package/dist/auth/interfaces/signup-event-body.interface.d.ts +1 -1
  49. package/dist/auth/strategies/local-auth.strategy.d.ts +3 -5
  50. package/dist/auth/strategies/local-auth.strategy.js +64 -99
  51. package/dist/auth/strategies/local-auth.strategy.js.map +1 -1
  52. package/dist/auth/strategies/oauth/apple.strategy.d.ts +4 -6
  53. package/dist/auth/strategies/oauth/apple.strategy.js +57 -70
  54. package/dist/auth/strategies/oauth/apple.strategy.js.map +1 -1
  55. package/dist/auth/strategies/oauth/facebook.strategy.d.ts +4 -6
  56. package/dist/auth/strategies/oauth/facebook.strategy.js +58 -71
  57. package/dist/auth/strategies/oauth/facebook.strategy.js.map +1 -1
  58. package/dist/auth/strategies/oauth/google.strategy.d.ts +4 -6
  59. package/dist/auth/strategies/oauth/google.strategy.js +84 -155
  60. package/dist/auth/strategies/oauth/google.strategy.js.map +1 -1
  61. package/dist/auth/strategies/oauth/oauth.strategy.d.ts +2 -2
  62. package/dist/database/prisma/prisma-auth.adapter.d.ts +11 -0
  63. package/dist/database/prisma/prisma-auth.adapter.js +64 -0
  64. package/dist/database/prisma/prisma-auth.adapter.js.map +1 -0
  65. package/dist/database/prisma/repositories/auth-identifier.repository.d.ts +16 -0
  66. package/dist/database/prisma/repositories/auth-identifier.repository.js +41 -0
  67. package/dist/database/prisma/repositories/auth-identifier.repository.js.map +1 -0
  68. package/dist/database/prisma/repositories/auth.repository.d.ts +19 -0
  69. package/dist/database/prisma/repositories/auth.repository.js +49 -0
  70. package/dist/database/prisma/repositories/auth.repository.js.map +1 -0
  71. package/dist/database/prisma/repositories/index.d.ts +7 -0
  72. package/dist/database/prisma/repositories/index.js +24 -0
  73. package/dist/database/prisma/repositories/index.js.map +1 -0
  74. package/dist/database/prisma/repositories/mfa-method.repository.d.ts +11 -0
  75. package/dist/database/prisma/repositories/mfa-method.repository.js +33 -0
  76. package/dist/database/prisma/repositories/mfa-method.repository.js.map +1 -0
  77. package/dist/database/prisma/repositories/oauth-provider.repository.d.ts +14 -0
  78. package/dist/database/prisma/repositories/oauth-provider.repository.js +39 -0
  79. package/dist/database/prisma/repositories/oauth-provider.repository.js.map +1 -0
  80. package/dist/database/prisma/repositories/otp-token.repository.d.ts +13 -0
  81. package/dist/database/prisma/repositories/otp-token.repository.js +52 -0
  82. package/dist/database/prisma/repositories/otp-token.repository.js.map +1 -0
  83. package/dist/database/prisma/repositories/session-log.repository.d.ts +12 -0
  84. package/dist/database/prisma/repositories/session-log.repository.js +42 -0
  85. package/dist/database/prisma/repositories/session-log.repository.js.map +1 -0
  86. package/dist/database/prisma/repositories/session.repository.d.ts +16 -0
  87. package/dist/database/prisma/repositories/session.repository.js +41 -0
  88. package/dist/database/prisma/repositories/session.repository.js.map +1 -0
  89. package/dist/database/typeorm/entities/auth-identify.entity.d.ts +23 -0
  90. package/dist/database/typeorm/entities/auth-identify.entity.js +61 -0
  91. package/dist/database/typeorm/entities/auth-identify.entity.js.map +1 -0
  92. package/dist/database/typeorm/entities/auth.entity.d.ts +45 -0
  93. package/dist/database/typeorm/entities/auth.entity.js +129 -0
  94. package/dist/database/typeorm/entities/auth.entity.js.map +1 -0
  95. package/dist/database/typeorm/entities/base.entity.d.ts +7 -0
  96. package/dist/database/typeorm/entities/base.entity.js +44 -0
  97. package/dist/database/typeorm/entities/base.entity.js.map +1 -0
  98. package/dist/database/typeorm/entities/entities.d.ts +7 -0
  99. package/dist/database/typeorm/entities/entities.js +18 -0
  100. package/dist/database/typeorm/entities/entities.js.map +1 -0
  101. package/dist/database/typeorm/entities/mfa-method.entity.d.ts +10 -0
  102. package/dist/database/typeorm/entities/mfa-method.entity.js +47 -0
  103. package/dist/database/typeorm/entities/mfa-method.entity.js.map +1 -0
  104. package/dist/database/typeorm/entities/oauth-provider.entity.d.ts +38 -0
  105. package/dist/database/typeorm/entities/oauth-provider.entity.js +88 -0
  106. package/dist/database/typeorm/entities/oauth-provider.entity.js.map +1 -0
  107. package/dist/database/typeorm/entities/otp-token.entity.d.ts +15 -0
  108. package/dist/database/typeorm/entities/otp-token.entity.js +53 -0
  109. package/dist/database/typeorm/entities/otp-token.entity.js.map +1 -0
  110. package/dist/database/typeorm/entities/session.entity.d.ts +21 -0
  111. package/dist/database/typeorm/entities/session.entity.js +71 -0
  112. package/dist/database/typeorm/entities/session.entity.js.map +1 -0
  113. package/dist/database/typeorm/entities/session_log.entity.d.ts +25 -0
  114. package/dist/database/typeorm/entities/session_log.entity.js +78 -0
  115. package/dist/database/typeorm/entities/session_log.entity.js.map +1 -0
  116. package/dist/database/typeorm/migrations/auth-entities.d.ts +7 -0
  117. package/dist/database/typeorm/migrations/auth-entities.js +18 -0
  118. package/dist/database/typeorm/migrations/auth-entities.js.map +1 -0
  119. package/dist/database/typeorm/migrations/auth-schema.initializer.d.ts +9 -0
  120. package/dist/database/typeorm/migrations/auth-schema.initializer.js +36 -0
  121. package/dist/database/typeorm/migrations/auth-schema.initializer.js.map +1 -0
  122. package/dist/database/typeorm/migrations/auth.migration.v1.d.ts +12 -0
  123. package/dist/database/typeorm/migrations/auth.migration.v1.js +157 -0
  124. package/dist/database/typeorm/migrations/auth.migration.v1.js.map +1 -0
  125. package/dist/database/typeorm/migrations/auth.migration.v2.d.ts +8 -0
  126. package/dist/database/typeorm/migrations/auth.migration.v2.js +23 -0
  127. package/dist/database/typeorm/migrations/auth.migration.v2.js.map +1 -0
  128. package/dist/database/typeorm/migrations/auth.migrations.d.ts +2 -0
  129. package/dist/database/typeorm/migrations/auth.migrations.js +10 -0
  130. package/dist/database/typeorm/migrations/auth.migrations.js.map +1 -0
  131. package/dist/database/typeorm/migrations/migration.service.d.ts +9 -0
  132. package/dist/database/typeorm/migrations/migration.service.js +75 -0
  133. package/dist/database/typeorm/migrations/migration.service.js.map +1 -0
  134. package/dist/database/typeorm/repositories/auth-identifier.repository.d.ts +18 -0
  135. package/dist/database/typeorm/repositories/auth-identifier.repository.js +64 -0
  136. package/dist/database/typeorm/repositories/auth-identifier.repository.js.map +1 -0
  137. package/dist/database/typeorm/repositories/auth.repository.d.ts +21 -0
  138. package/dist/database/typeorm/repositories/auth.repository.js +71 -0
  139. package/dist/database/typeorm/repositories/auth.repository.js.map +1 -0
  140. package/dist/database/typeorm/repositories/index.d.ts +7 -0
  141. package/dist/database/typeorm/repositories/index.js +24 -0
  142. package/dist/database/typeorm/repositories/index.js.map +1 -0
  143. package/dist/database/typeorm/repositories/mfa-method.repository.d.ts +13 -0
  144. package/dist/database/typeorm/repositories/mfa-method.repository.js +46 -0
  145. package/dist/database/typeorm/repositories/mfa-method.repository.js.map +1 -0
  146. package/dist/database/typeorm/repositories/oauth-provider.repository.d.ts +16 -0
  147. package/dist/database/typeorm/repositories/oauth-provider.repository.js +52 -0
  148. package/dist/database/typeorm/repositories/oauth-provider.repository.js.map +1 -0
  149. package/dist/database/typeorm/repositories/otp-token.repository.d.ts +13 -0
  150. package/dist/database/typeorm/repositories/otp-token.repository.js +52 -0
  151. package/dist/database/typeorm/repositories/otp-token.repository.js.map +1 -0
  152. package/dist/database/typeorm/repositories/session-log.repository.d.ts +12 -0
  153. package/dist/database/typeorm/repositories/session-log.repository.js +47 -0
  154. package/dist/database/typeorm/repositories/session-log.repository.js.map +1 -0
  155. package/dist/database/typeorm/repositories/session.repository.d.ts +18 -0
  156. package/dist/database/typeorm/repositories/session.repository.js +84 -0
  157. package/dist/database/typeorm/repositories/session.repository.js.map +1 -0
  158. package/dist/database/typeorm/typeorm-auth.adapter.d.ts +2 -0
  159. package/dist/database/typeorm/typeorm-auth.adapter.js +50 -0
  160. package/dist/database/typeorm/typeorm-auth.adapter.js.map +1 -0
  161. package/dist/index.d.ts +11 -9
  162. package/dist/index.js +18 -10
  163. package/dist/index.js.map +1 -1
  164. package/dist/tsconfig.tsbuildinfo +1 -1
  165. package/fix-imports.js +46 -0
  166. package/fix-syntax.js +66 -0
  167. package/package.json +22 -20
  168. package/patch-local-specs.js +52 -0
  169. package/patch-oauth-specs.js +41 -0
  170. package/patch-specs.js +36 -0
  171. package/prompts/database_adapter.md +157 -0
  172. package/prompts/otp_provider.md +292 -0
  173. package/scratch/create-prisma-repos-final.js +139 -0
  174. package/scratch/create-prisma-repos.js +280 -0
  175. package/scratch/fix-events-spec.js +12 -0
  176. package/scratch/fix-imports.js +53 -0
  177. package/scratch/fix-prisma-interfaces.js +41 -0
  178. package/scratch/fix-prisma-interfaces2.js +36 -0
  179. package/scratch/fix-prisma-interfaces3.js +26 -0
  180. package/scratch/fix-prisma.js +28 -0
  181. package/scratch/fix-test-imports.js +51 -0
  182. package/scratch/fix-tests-advanced.js +68 -0
  183. package/scratch/fix-tests-advanced2.js +23 -0
  184. package/scratch/fix-tests-concrete.js +40 -0
  185. package/scratch/fix-tests-final.js +35 -0
  186. package/scratch/fix-tests-final2.js +28 -0
  187. package/scratch/fix-tests-final3.js +26 -0
  188. package/scratch/fix-tests-methods.js +40 -0
  189. package/scratch/fix-tests-proxy.js +67 -0
  190. package/scratch/fix-tests-types.js +24 -0
  191. package/scratch/rewrite-tests.js +110 -0
  192. package/tsc_errors.txt +60 -0
  193. package/tsc_errors2.txt +93 -0
  194. package/tmp-cv-test/package-lock.json +0 -250
  195. package/tmp-cv-test/package.json +0 -17
  196. package/tmp-cv-test/test.ts +0 -11
package/fix-imports.js ADDED
@@ -0,0 +1,46 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const specsDir = path.join(__dirname, 'src', 'auth', 'specs');
5
+
6
+ const filesToFix = ['auth.controller.spec.ts', 'jwt.strategy.spec.ts', 'account-linking.spec.ts'];
7
+
8
+ for (const file of filesToFix) {
9
+ const filePath = path.join(specsDir, file);
10
+ if (fs.existsSync(filePath)) {
11
+ let content = fs.readFileSync(filePath, 'utf8');
12
+ if (!content.includes('SESSION_LOG_REPOSITORY_TOKEN } from')) {
13
+ content = `import { SESSION_LOG_REPOSITORY_TOKEN } from '../interfaces/repository-tokens';\n` + content;
14
+ fs.writeFileSync(filePath, content, 'utf8');
15
+ console.log(`Fixed import in ${file}`);
16
+ }
17
+ }
18
+ }
19
+
20
+ // Also fix mfa-logic.spec.ts syntax again because it was badly formatted:
21
+ const mfaPath = path.join(specsDir, 'mfa-logic.spec.ts');
22
+ let mfaContent = fs.readFileSync(mfaPath, 'utf8');
23
+ if (mfaContent.includes('useValue: { }, { provide: AUTH_IDENTIFIER_REPOSITORY_TOKEN')) {
24
+ mfaContent = mfaContent.replace(/useValue: { }, { provide: AUTH_IDENTIFIER_REPOSITORY_TOKEN/g, 'useValue: { } }, { provide: AUTH_IDENTIFIER_REPOSITORY_TOKEN');
25
+ fs.writeFileSync(mfaPath, mfaContent, 'utf8');
26
+ console.log(`Fixed mfa-logic.spec.ts syntax again`);
27
+ }
28
+
29
+ // Ensure IdentifierType is in login-verification.spec.ts
30
+ const lvPath = path.join(specsDir, 'login-verification.spec.ts');
31
+ let lvContent = fs.readFileSync(lvPath, 'utf8');
32
+ if (!lvContent.includes('IdentifierType')) {
33
+ lvContent = lvContent.replace(/import { AuthStrategy } from '\.\.\/enums\/auth-type.enum';/, "import { AuthStrategy } from '../enums/auth-type.enum';\nimport { IdentifierType } from '../enums/identifier-type.enum';");
34
+ fs.writeFileSync(lvPath, lvContent, 'utf8');
35
+ console.log(`Fixed IdentifierType import`);
36
+ }
37
+
38
+ // Ensure MfaType is in mfa-logic.spec.ts
39
+ if (!mfaContent.includes('MfaType')) {
40
+ mfaContent = mfaContent.replace(/import { AuthStrategy } from '\.\.\/enums\/auth-type.enum';/, "import { AuthStrategy } from '../enums/auth-type.enum';\nimport { MfaType } from '../enums/mfa-type.enum';");
41
+ if (!mfaContent.includes('MfaType')) {
42
+ mfaContent = `import { MfaType } from '../enums/mfa-type.enum';\n` + mfaContent;
43
+ }
44
+ fs.writeFileSync(mfaPath, mfaContent, 'utf8');
45
+ console.log(`Fixed MfaType import`);
46
+ }
package/fix-syntax.js ADDED
@@ -0,0 +1,66 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const specsDir = path.join(__dirname, 'src', 'auth', 'specs');
5
+ const files = fs.readdirSync(specsDir).filter(f => f.endsWith('.spec.ts'));
6
+
7
+ for (const file of files) {
8
+ const filePath = path.join(specsDir, file);
9
+ let content = fs.readFileSync(filePath, 'utf8');
10
+ let changed = false;
11
+
12
+ // Fix syntax error from previous AI
13
+ if (content.includes('useValue: { }, { provide: AUTH_IDENTIFIER_REPOSITORY_TOKEN')) {
14
+ content = content.replace(/useValue: { }, { provide: AUTH_IDENTIFIER_REPOSITORY_TOKEN/g, 'useValue: { } }, { provide: AUTH_IDENTIFIER_REPOSITORY_TOKEN');
15
+ changed = true;
16
+ }
17
+
18
+ if (content.includes('useValue: mockRepo }, { provide: AUTH_IDENTIFIER_REPOSITORY_TOKEN')) {
19
+ // This one is actually syntactically okay but might be weirdly formatted:
20
+ // { provide: AUTH_REPOSITORY_TOKEN, useValue: mockRepo }, { provide: AUTH_IDENTIFIER_REPOSITORY_TOKEN, ... },
21
+ // Wait, in events.spec.ts it was:
22
+ // { provide: AUTH_REPOSITORY_TOKEN, useValue: mockRepo }, { provide: ... }
23
+ // This is two elements on one line, which is valid JS!
24
+ }
25
+
26
+ // Fix IdentifierType missing
27
+ if (file === 'login-verification.spec.ts' && !content.includes('IdentifierType')) {
28
+ content = content.replace(/import { AuthStrategy } from '\.\.\/enums\/auth-type.enum';/, "import { AuthStrategy } from '../enums/auth-type.enum';\nimport { IdentifierType } from '../enums/identifier-type.enum';");
29
+ changed = true;
30
+ }
31
+
32
+ // Fix MfaType missing
33
+ if (file === 'mfa-logic.spec.ts' && !content.includes('MfaType')) {
34
+ content = content.replace(/import { AuthStrategy } from '\.\.\/enums\/auth-type.enum';/, "import { AuthStrategy } from '../enums/auth-type.enum';\nimport { MfaType } from '../enums/mfa-type.enum';");
35
+ if (!content.includes('MfaType')) {
36
+ // if AuthStrategy wasn't imported
37
+ content = `import { MfaType } from '../enums/mfa-type.enum';\n` + content;
38
+ }
39
+ changed = true;
40
+ }
41
+
42
+ // Fix missing imports in auth.controller.spec.ts
43
+ if (file === 'auth.controller.spec.ts' && !content.includes('SESSION_LOG_REPOSITORY_TOKEN')) {
44
+ content = content.replace(/import\s+{([^}]+)}\s+from\s+['"]\.\.\/interfaces\/repository-tokens['"];/, (match, p1) => {
45
+ return `import { ${p1.trim()}, SESSION_LOG_REPOSITORY_TOKEN } from '../interfaces/repository-tokens';`;
46
+ });
47
+ changed = true;
48
+ }
49
+ if (file === 'jwt.strategy.spec.ts' && !content.includes('SESSION_LOG_REPOSITORY_TOKEN')) {
50
+ content = content.replace(/import\s+{([^}]+)}\s+from\s+['"]\.\.\/interfaces\/repository-tokens['"];/, (match, p1) => {
51
+ return `import { ${p1.trim()}, SESSION_LOG_REPOSITORY_TOKEN } from '../interfaces/repository-tokens';`;
52
+ });
53
+ changed = true;
54
+ }
55
+ if (file === 'account-linking.spec.ts' && !content.includes('SESSION_LOG_REPOSITORY_TOKEN')) {
56
+ content = content.replace(/import\s+{([^}]+)}\s+from\s+['"]\.\.\/interfaces\/repository-tokens['"];/, (match, p1) => {
57
+ return `import { ${p1.trim()}, SESSION_LOG_REPOSITORY_TOKEN } from '../interfaces/repository-tokens';`;
58
+ });
59
+ changed = true;
60
+ }
61
+
62
+ if (changed) {
63
+ fs.writeFileSync(filePath, content, 'utf8');
64
+ console.log(`Fixed syntax in ${file}`);
65
+ }
66
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vynelix/nestjs-multi-auth",
3
- "version": "0.3.1",
3
+ "version": "1.0.0",
4
4
  "description": "An authentication service/module for NestJs that supports multiple authentication methods such as email, phone, username, OAuth, SSO, etc",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -55,47 +55,49 @@
55
55
  "@nestjs/jwt": "^11.0.2",
56
56
  "@nestjs/passport": "^11.0.5",
57
57
  "@nestjs/swagger": "^11.2.6",
58
- "@nestjs/typeorm": "^11.0.0",
59
58
  "@nestjs/throttler": "^6.5.0",
59
+ "@nestjs/typeorm": "^11.0.0",
60
60
  "@types/passport-jwt": "^4.0.1",
61
+ "class-transformer": "^0.5.1",
61
62
  "class-validator": "^0.15.1",
62
63
  "crypto": "^1.0.1",
63
64
  "express": "^5.2.1",
64
65
  "google-auth-library": "^9.15.1",
65
- "passport-jwt": "^4.0.1",
66
66
  "otplib": "^12.0.1",
67
- "class-transformer": "^0.5.1",
67
+ "passport-jwt": "^4.0.1",
68
68
  "typeorm": "^0.3.28"
69
69
  },
70
70
  "devDependencies": {
71
+ "@nestjs/common": "^11.1.15",
72
+ "@nestjs/config": "^4.0.3",
73
+ "@nestjs/core": "^11.1.15",
71
74
  "@nestjs/event-emitter": "^3.0.1",
75
+ "@nestjs/jwt": "^11.0.2",
76
+ "@nestjs/passport": "^11.0.5",
77
+ "@nestjs/swagger": "^11.2.6",
72
78
  "@nestjs/testing": "^11.1.15",
79
+ "@nestjs/typeorm": "^11.0.0",
80
+ "@prisma/client": "^6.19.3",
73
81
  "@types/bcrypt": "^6.0.0",
74
82
  "@types/jest": "^30.0.0",
83
+ "@types/passport-jwt": "^4.0.1",
75
84
  "@types/supertest": "^7.2.0",
76
85
  "bcrypt": "^6.0.0",
86
+ "class-validator": "^0.15.1",
87
+ "express": "^5.2.1",
88
+ "google-auth-library": "^9.15.1",
77
89
  "jest": "^30.2.0",
90
+ "passport-jwt": "^4.0.1",
91
+ "prisma": "^6.19.3",
92
+ "reflect-metadata": "^0.2.2",
93
+ "rxjs": "^7.8.1",
78
94
  "supertest": "^7.2.2",
79
95
  "ts-jest": "^29.4.6",
80
- "typescript": "^5.7.3",
81
- "@nestjs/common": "^11.1.15",
82
- "@nestjs/core": "^11.1.15",
83
- "@nestjs/jwt": "^11.0.2",
84
- "@nestjs/typeorm": "^11.0.0",
85
96
  "typeorm": "^0.3.28",
86
- "reflect-metadata": "^0.2.2",
87
- "rxjs": "^7.8.1",
88
- "@nestjs/swagger": "^11.2.6",
89
- "@nestjs/config": "^4.0.3",
90
- "@nestjs/passport": "^11.0.5",
91
- "google-auth-library": "^9.15.1",
92
- "class-validator": "^0.15.1",
93
- "express": "^5.2.1",
94
- "passport-jwt": "^4.0.1",
95
- "@types/passport-jwt": "^4.0.1"
97
+ "typescript": "^5.7.3"
96
98
  },
97
99
  "dependencies": {
98
100
  "commander": "^14.0.3",
99
101
  "ts-node": "^10.9.2"
100
102
  }
101
- }
103
+ }
@@ -0,0 +1,52 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const specsToPatch = [
5
+ 'local-auth.strategy.spec.ts',
6
+ 'password-features.spec.ts',
7
+ 'mfa-logic.spec.ts'
8
+ ];
9
+
10
+ specsToPatch.forEach(file => {
11
+ const filePath = path.join('/home/isaiah/devspace/my-open-source-projects/nestjs-multi-auth/src/auth/specs', file);
12
+ if (!fs.existsSync(filePath)) return;
13
+ let content = fs.readFileSync(filePath, 'utf8');
14
+
15
+ // Add findByValue
16
+ if (!content.includes('findByValue: jest.fn(),')) {
17
+ content = content.replace('findByUidAndNamespace: jest.fn(),', 'findByUidAndNamespace: jest.fn(),\n findByValue: jest.fn(),');
18
+ }
19
+
20
+ // Add findByUidAndStrategies
21
+ if (!content.includes('findByUidAndStrategies: jest.fn(),')) {
22
+ content = content.replace('findByValue: jest.fn(),', 'findByValue: jest.fn(),\n findByUidAndStrategies: jest.fn(),');
23
+ }
24
+
25
+ // Add findByUidAndType
26
+ if (!content.includes('findByUidAndType: jest.fn(),')) {
27
+ content = content.replace('findByUidAndStrategies: jest.fn(),', 'findByUidAndStrategies: jest.fn(),\n findByUidAndType: jest.fn(),');
28
+ }
29
+
30
+ // For password-features.spec.ts
31
+ if (file === 'password-features.spec.ts') {
32
+ // otpProvider.verify should return success: true
33
+ content = content.replace(
34
+ /otpProvider\.verify\.mockResolvedValue\(\{ valid: true \}\);/g,
35
+ 'otpProvider.verify.mockResolvedValue({ success: true, valid: true });'
36
+ );
37
+ content = content.replace(
38
+ /expect\(otpRepo\.save\)\.toHaveBeenCalled\(\);/g,
39
+ 'expect(otpProvider.issue).toHaveBeenCalled();'
40
+ );
41
+ // authIdentifierRepo.findWithAuthByValue
42
+ if (!content.includes('authIdentifierRepo.findWithAuthByValue.mockResolvedValue')) {
43
+ content = content.replace(
44
+ /authRepo\.query\.mockResolvedValue\(\[\{ value: 'test@test\.com'/g,
45
+ "authIdentifierRepo.findWithAuthByValue.mockResolvedValue({ identifier: { value: 'test@test.com', type: 'EMAIL' }, auth: { id: 'auth-id', uid: 'user-uid' } });\n authRepo.query.mockResolvedValue([{ value: 'test@test.com'"
46
+ );
47
+ }
48
+ }
49
+
50
+ fs.writeFileSync(filePath, content);
51
+ console.log('Patched', file);
52
+ });
@@ -0,0 +1,41 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const specs = [
5
+ 'apple.strategy.spec.ts',
6
+ 'facebook.strategy.spec.ts',
7
+ 'google.strategy.spec.ts'
8
+ ];
9
+
10
+ specs.forEach(file => {
11
+ const filePath = path.join('/home/isaiah/devspace/my-open-source-projects/nestjs-multi-auth/src/auth/specs', file);
12
+ let content = fs.readFileSync(filePath, 'utf8');
13
+
14
+ // Add findByValue, findWithAuthByValue, findWithIdentifiers to createMockRepo
15
+ if (!content.includes('findByValue: jest.fn(),')) {
16
+ content = content.replace('findWithAuthByValue: jest.fn(),', 'findWithAuthByValue: jest.fn(),\n findByValue: jest.fn(),\n findWithIdentifiers: jest.fn(),');
17
+ } else if (!content.includes('findWithIdentifiers: jest.fn(),')) {
18
+ content = content.replace('findByValue: jest.fn(),', 'findByValue: jest.fn(),\n findWithIdentifiers: jest.fn(),');
19
+ }
20
+
21
+ if (!content.includes('findWithIdentifiers: jest.fn(),')) {
22
+ content = content.replace('findByUidAndEnabled: jest.fn(),', 'findByUidAndEnabled: jest.fn(),\n findWithIdentifiers: jest.fn(),');
23
+ }
24
+
25
+ // Google specific mocks
26
+ if (file === 'google.strategy.spec.ts') {
27
+ content = content.replace(
28
+ 'findOne: jest.fn(),',
29
+ 'findOne: jest.fn(),\n findWithAuthByValue: jest.fn(),\n findByValue: jest.fn(),'
30
+ );
31
+ }
32
+
33
+ // Also replace `authRepo.findWithIdentifiers` in google test to avoid error
34
+ content = content.replace(
35
+ 'const updatedAuth = await this.authRepo.findWithIdentifiers(auth.id);',
36
+ 'const updatedAuth = await this.authRepo.findWithIdentifiers(auth.id);'
37
+ );
38
+
39
+ fs.writeFileSync(filePath, content);
40
+ console.log('Patched', file);
41
+ });
package/patch-specs.js ADDED
@@ -0,0 +1,36 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const specsDir = path.join(__dirname, 'src', 'auth', 'specs');
5
+ const files = fs.readdirSync(specsDir).filter(f => f.endsWith('.spec.ts'));
6
+
7
+ for (const file of files) {
8
+ const filePath = path.join(specsDir, file);
9
+ let content = fs.readFileSync(filePath, 'utf8');
10
+ let changed = false;
11
+
12
+ // 1. Add import
13
+ if (content.includes('interfaces/repository-tokens') && !content.includes('SESSION_LOG_REPOSITORY_TOKEN')) {
14
+ content = content.replace(/import\s+{([^}]+)}\s+from\s+['"]\.\.\/interfaces\/repository-tokens['"];/, (match, p1) => {
15
+ return `import { ${p1.trim()}, SESSION_LOG_REPOSITORY_TOKEN } from '../interfaces/repository-tokens';`;
16
+ });
17
+ changed = true;
18
+ }
19
+
20
+ // 2. Add provider
21
+ if (content.includes('Test.createTestingModule') && content.includes('providers:') && !content.includes('SESSION_LOG_REPOSITORY_TOKEN,')) {
22
+ const useValueStr = content.includes('mockRepo') ? 'mockRepo' : '{}';
23
+ content = content.replace(/providers:\s*\[([\s\S]*?)\]/, (match, p1) => {
24
+ if (!p1.includes('SESSION_LOG_REPOSITORY_TOKEN')) {
25
+ return `providers: [${p1} { provide: SESSION_LOG_REPOSITORY_TOKEN, useValue: ${useValueStr} },\n ]`;
26
+ }
27
+ return match;
28
+ });
29
+ changed = true;
30
+ }
31
+
32
+ if (changed) {
33
+ fs.writeFileSync(filePath, content, 'utf8');
34
+ console.log(`Patched ${file}`);
35
+ }
36
+ }
@@ -0,0 +1,157 @@
1
+ # Decouple the Authentication Core from TypeORM — nestjs-multi-auth
2
+
3
+ ## Context
4
+
5
+ You are working on **nestjs-multi-auth**, a production-grade authentication library for NestJS.
6
+
7
+ ## Objective
8
+
9
+ Refactor the authentication library so that **all persistence is abstracted behind repository interfaces**, removing any hard dependency on TypeORM from the authentication core.
10
+
11
+ ## Problem
12
+
13
+ The authentication core currently depends directly on TypeORM. It imports and uses:
14
+
15
+ - `Repository`
16
+ - `Entity`
17
+ - `QueryBuilder`
18
+ - TypeORM decorators
19
+ - Raw SQL
20
+
21
+ This couples core authentication logic to a single ORM, making it difficult or impossible for developers to use **Prisma**, **Drizzle ORM**, **MikroORM**, **Sequelize**, **MongoDB**, or a custom data store without forking the library.
22
+
23
+ ## Design Principles
24
+
25
+ ### The authentication core IS responsible for
26
+
27
+ - Authentication and authorization business logic
28
+ - Identity verification workflows
29
+ - Session lifecycle rules
30
+ - OTP orchestration
31
+ - MFA orchestration
32
+ - OAuth provider linking logic
33
+ - All validation and decision-making
34
+
35
+ ### The authentication core is NOT responsible for
36
+
37
+ - How data is queried or persisted
38
+ - Which database or ORM is used
39
+ - Schema definitions
40
+ - Query construction, connection management, or transactions specific to any ORM
41
+
42
+ Persistence mechanics are the responsibility of a **repository adapter**, never the core.
43
+
44
+ ---
45
+
46
+ ## New Architecture
47
+
48
+ ### 1. Repository Interfaces (NEW)
49
+
50
+ Define abstract repository interfaces for every persisted concern in the library, including at minimum:
51
+
52
+ - `AuthMethodRepository`
53
+ - `IdentifierRepository`
54
+ - `SessionRepository`
55
+ - `OtpRepository`
56
+ - `MfaRepository`
57
+ - `OAuthProviderRepository`
58
+
59
+ Each interface should:
60
+
61
+ - Expose only the operations the authentication core actually needs (e.g. `findByIdentifier`, `create`, `update`, `delete`, `markUsed`) — not generic ORM-style methods.
62
+ - Use plain domain types (not ORM entities) for inputs and outputs.
63
+ - Contain no TypeORM types, decorators, or query-builder references anywhere in their signatures.
64
+
65
+ **Example shape:**
66
+
67
+ ```typescript
68
+ export interface SessionRepository {
69
+ create(session: CreateSessionInput): Promise<AuthSession>;
70
+ findById(id: string): Promise<AuthSession | null>;
71
+ revoke(id: string): Promise<void>;
72
+ findActiveByAuthId(authId: string): Promise<AuthSession[]>;
73
+ }
74
+ ```
75
+
76
+ ### 2. Domain Models (NEW)
77
+
78
+ Introduce plain TypeScript interfaces/types (e.g. `AuthSession`, `AuthMethod`, `AuthIdentifier`, `OtpRecord`, `MfaFactor`, `OAuthLink`) that represent persisted data within the core. These types must be:
79
+
80
+ - Free of TypeORM decorators (`@Entity`, `@Column`, `@ManyToOne`, etc.)
81
+ - The only shapes the authentication core ever operates on
82
+ - Mapped to and from ORM entities exclusively inside adapters
83
+
84
+ ### 3. First-Party TypeORM Adapter
85
+
86
+ Provide a `TypeOrmAuthAdapter` package/module that:
87
+
88
+ - Implements every repository interface using TypeORM `Repository`, `Entity`, and `QueryBuilder` as needed.
89
+ - Preserves 100% of current behavior — this is the default, drop-in implementation.
90
+ - Contains all TypeORM-specific code, entity definitions, and migrations.
91
+ - Is the **only** place in the library where TypeORM is imported.
92
+
93
+ ### 4. Adapter Extensibility
94
+
95
+ The architecture must make it straightforward to build equivalent adapters for:
96
+
97
+ - Prisma
98
+ - Drizzle ORM
99
+ - MikroORM
100
+ - Sequelize
101
+ - MongoDB (or other non-relational stores)
102
+ - Fully custom data stores
103
+
104
+ An adapter author should only need to implement the repository interfaces and provide domain-model mapping — no changes to the authentication core should ever be required.
105
+
106
+ ---
107
+
108
+ ## Dependency Injection
109
+
110
+ - Introduce injection tokens for each repository interface (e.g. `SESSION_REPOSITORY`, `OTP_REPOSITORY`, `AUTH_METHOD_REPOSITORY`, etc.), following the same pattern as existing tokens like `AUTH_NOTIFICATION_PROVIDER`.
111
+ - If no adapter is registered, automatically register the `TypeOrmAuthAdapter` implementations so existing applications continue to work without any change.
112
+ - Allow applications to override individual repositories independently (e.g. use the TypeORM adapter for sessions but a custom repository for OTPs), rather than forcing an all-or-nothing swap.
113
+
114
+ ---
115
+
116
+ ## `AuthService` and Core Changes
117
+
118
+ - Remove all direct TypeORM imports, `@InjectRepository()` usages, and query-builder calls from the authentication core.
119
+ - Replace all persistence calls with calls to the appropriate repository interface.
120
+ - Ensure business logic (validation, expiration checks, state transitions, error handling) stays in the core services — adapters should contain **no business logic**, only data access and mapping.
121
+
122
+ **Before:**
123
+
124
+ ```typescript
125
+ const session = await this.sessionRepo
126
+ .createQueryBuilder('session')
127
+ .where('session.authId = :authId', { authId })
128
+ .getOne();
129
+ ```
130
+
131
+ **After:**
132
+
133
+ ```typescript
134
+ const session = await this.sessionRepository.findActiveByAuthId(authId);
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Backward Compatibility
140
+
141
+ This refactor must **not** break existing applications.
142
+
143
+ - Applications using the library today (implicitly relying on TypeORM) should continue to work with **zero configuration changes**, since `TypeOrmAuthAdapter` is registered by default.
144
+ - Only developers who wish to switch persistence layers need to provide alternate repository implementations.
145
+ - Public authentication API surface (methods, DTOs, module configuration options unrelated to persistence) must remain unchanged.
146
+
147
+ ---
148
+
149
+ ## Code Quality Requirements
150
+
151
+ - Follow SOLID principles, in particular the Dependency Inversion Principle — the core depends on abstractions, not on TypeORM.
152
+ - Keep all TypeORM-specific code isolated inside the `TypeOrmAuthAdapter`; no leakage into shared/core packages.
153
+ - Avoid leaking ORM-specific types (entities, query builders, decorators) across the core/adapter boundary in either direction.
154
+ - Ensure each repository interface is small and focused (Interface Segregation) rather than one large generic repository.
155
+ - Ensure the authentication core is fully unit testable using in-memory or mock repository implementations, with no database required.
156
+ - Preserve all current tests and behavior where possible; add adapter-level tests against the interfaces.
157
+ - Document the repository interfaces clearly enough that a third party could implement a new adapter without reading the core source.