@nauth-toolkit/database-typeorm-mysql 0.1.108 → 0.1.109

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.
@@ -7,8 +7,8 @@ import { User } from './user.entity';
7
7
  * All field definitions and business logic are in the base class.
8
8
  *
9
9
  * **Database Integrity:**
10
- * - Unique constraint on (userId, type) prevents duplicate MFA devices per method
11
- * - This prevents race conditions where multiple devices of same type could be created
10
+ * - Multiple devices per method are allowed (e.g., multiple TOTP apps, multiple passkeys).
11
+ * - Passkeys are de-duplicated by unique constraint on (userId, type, credentialId).
12
12
  */
13
13
  export declare class MFADevice extends BaseMFADevice {
14
14
  id: number;
@@ -20,8 +20,8 @@ const user_entity_1 = require("./user.entity");
20
20
  * All field definitions and business logic are in the base class.
21
21
  *
22
22
  * **Database Integrity:**
23
- * - Unique constraint on (userId, type) prevents duplicate MFA devices per method
24
- * - This prevents race conditions where multiple devices of same type could be created
23
+ * - Multiple devices per method are allowed (e.g., multiple TOTP apps, multiple passkeys).
24
+ * - Passkeys are de-duplicated by unique constraint on (userId, type, credentialId).
25
25
  */
26
26
  let MFADevice = class MFADevice extends core_1.BaseMFADevice {
27
27
  user;
@@ -57,7 +57,7 @@ __decorate([
57
57
  __metadata("design:type", Object)
58
58
  ], MFADevice.prototype, "phoneNumber", void 0);
59
59
  __decorate([
60
- (0, typeorm_1.Column)({ type: 'text', nullable: true }),
60
+ (0, typeorm_1.Column)({ type: 'varchar', length: 512, nullable: true }),
61
61
  __metadata("design:type", Object)
62
62
  ], MFADevice.prototype, "credentialId", void 0);
63
63
  __decorate([
@@ -110,6 +110,6 @@ exports.MFADevice = MFADevice = __decorate([
110
110
  (0, typeorm_1.Index)(['userId']),
111
111
  (0, typeorm_1.Index)(['type']),
112
112
  (0, typeorm_1.Index)(['isActive']),
113
- (0, typeorm_1.Unique)('uq_mfa_device_user_type', ['userId', 'type'])
113
+ (0, typeorm_1.Unique)('uq_mfa_device_user_type_credential', ['userId', 'type', 'credentialId'])
114
114
  ], MFADevice);
115
115
  //# sourceMappingURL=mfa-device.entity.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mfa-device.entity.js","sourceRoot":"","sources":["../../src/entities/mfa-device.entity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mfa-device.entity.js","sourceRoot":"","sources":["../../src/entities/mfa-device.entity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm';
2
+ /**
3
+ * Allow multiple MFA devices per method (MySQL).
4
+ *
5
+ * WHY:
6
+ * - Users may enroll multiple devices for the same MFA method (e.g., multiple TOTP authenticators
7
+ * and multiple passkeys) for redundancy.
8
+ * - We retain passkey de-duplication by enforcing uniqueness on (userId, type, credentialId).
9
+ *
10
+ * MySQL note:
11
+ * - MySQL cannot create a unique index on a TEXT column without a prefix length, so we narrow
12
+ * `credentialId` to VARCHAR(512) first.
13
+ */
14
+ export declare class AllowMultipleMFADevices1769212800000 implements MigrationInterface {
15
+ name: string;
16
+ up(queryRunner: QueryRunner): Promise<void>;
17
+ down(queryRunner: QueryRunner): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=1769212800000-AllowMultipleMFADevices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1769212800000-AllowMultipleMFADevices.d.ts","sourceRoot":"","sources":["../../src/migrations/1769212800000-AllowMultipleMFADevices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1D;;;;;;;;;;;GAWG;AACH,qBAAa,oCAAqC,YAAW,kBAAkB;IAC7E,IAAI,SAA0C;IAEjC,EAAE,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB3C,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAe3D"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AllowMultipleMFADevices1769212800000 = void 0;
4
+ /**
5
+ * Allow multiple MFA devices per method (MySQL).
6
+ *
7
+ * WHY:
8
+ * - Users may enroll multiple devices for the same MFA method (e.g., multiple TOTP authenticators
9
+ * and multiple passkeys) for redundancy.
10
+ * - We retain passkey de-duplication by enforcing uniqueness on (userId, type, credentialId).
11
+ *
12
+ * MySQL note:
13
+ * - MySQL cannot create a unique index on a TEXT column without a prefix length, so we narrow
14
+ * `credentialId` to VARCHAR(512) first.
15
+ */
16
+ class AllowMultipleMFADevices1769212800000 {
17
+ name = 'AllowMultipleMFADevices1769212800000';
18
+ async up(queryRunner) {
19
+ // ============================================================================
20
+ // Drop legacy unique index (single device per method per user)
21
+ // ============================================================================
22
+ await queryRunner.query(`
23
+ DROP INDEX \`uq_mfa_device_user_type\` ON \`nauth_mfa_devices\`
24
+ `);
25
+ // ============================================================================
26
+ // Make credentialId indexable (required for uniqueness key)
27
+ // ============================================================================
28
+ await queryRunner.query(`
29
+ ALTER TABLE \`nauth_mfa_devices\`
30
+ MODIFY \`credentialId\` varchar(512) NULL
31
+ `);
32
+ // ============================================================================
33
+ // Add passkey-safe uniqueness (prevents duplicate credential registration)
34
+ // ============================================================================
35
+ await queryRunner.query(`
36
+ CREATE UNIQUE INDEX \`uq_mfa_device_user_type_credential\`
37
+ ON \`nauth_mfa_devices\` (\`userId\`, \`type\`, \`credentialId\`)
38
+ `);
39
+ }
40
+ async down(queryRunner) {
41
+ await queryRunner.query(`
42
+ DROP INDEX \`uq_mfa_device_user_type_credential\` ON \`nauth_mfa_devices\`
43
+ `);
44
+ await queryRunner.query(`
45
+ ALTER TABLE \`nauth_mfa_devices\`
46
+ MODIFY \`credentialId\` text NULL
47
+ `);
48
+ await queryRunner.query(`
49
+ CREATE UNIQUE INDEX \`uq_mfa_device_user_type\`
50
+ ON \`nauth_mfa_devices\` (\`userId\`, \`type\`)
51
+ `);
52
+ }
53
+ }
54
+ exports.AllowMultipleMFADevices1769212800000 = AllowMultipleMFADevices1769212800000;
55
+ //# sourceMappingURL=1769212800000-AllowMultipleMFADevices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1769212800000-AllowMultipleMFADevices.js","sourceRoot":"","sources":["../../src/migrations/1769212800000-AllowMultipleMFADevices.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;GAWG;AACH,MAAa,oCAAoC;IAC/C,IAAI,GAAG,sCAAsC,CAAC;IAEvC,KAAK,CAAC,EAAE,CAAC,WAAwB;QACtC,+EAA+E;QAC/E,+DAA+D;QAC/D,+EAA+E;QAC/E,MAAM,WAAW,CAAC,KAAK,CAAC;;KAEvB,CAAC,CAAC;QAEH,+EAA+E;QAC/E,4DAA4D;QAC5D,+EAA+E;QAC/E,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;QAEH,+EAA+E;QAC/E,2EAA2E;QAC3E,+EAA+E;QAC/E,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,WAAwB;QACxC,MAAM,WAAW,CAAC,KAAK,CAAC;;KAEvB,CAAC,CAAC;QAEH,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;QAEH,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;IACL,CAAC;CACF;AA3CD,oFA2CC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAIlD,MAAM,MAAM,oBAAoB,GAAG;IAAE,QAAQ,kBAAkB,CAAA;CAAE,CAAC;AAElE;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,oBAAoB,EAAkE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAKlD,MAAM,MAAM,oBAAoB,GAAG;IAAE,QAAQ,kBAAkB,CAAA;CAAE,CAAC;AAElE;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,oBAAoB,EAI5C,CAAC"}
@@ -3,8 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.migrations = void 0;
4
4
  const _1734600000000_Initial_1 = require("./1734600000000-Initial");
5
5
  const _1766480775000_AddSocialProviderSecrets_1 = require("./1766480775000-AddSocialProviderSecrets");
6
+ const _1769212800000_AllowMultipleMFADevices_1 = require("./1769212800000-AllowMultipleMFADevices");
6
7
  /**
7
8
  * Adapter-owned migrations for @nauth-toolkit/database-typeorm-mysql
8
9
  */
9
- exports.migrations = [_1734600000000_Initial_1.Initial1734600000000, _1766480775000_AddSocialProviderSecrets_1.AddSocialProviderSecrets1766480775000];
10
+ exports.migrations = [
11
+ _1734600000000_Initial_1.Initial1734600000000,
12
+ _1766480775000_AddSocialProviderSecrets_1.AddSocialProviderSecrets1766480775000,
13
+ _1769212800000_AllowMultipleMFADevices_1.AllowMultipleMFADevices1769212800000,
14
+ ];
10
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":";;;AACA,oEAA+D;AAC/D,sGAAiG;AAIjG;;GAEG;AACU,QAAA,UAAU,GAA2B,CAAC,6CAAoB,EAAE,+EAAqC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":";;;AACA,oEAA+D;AAC/D,sGAAiG;AACjG,oGAA+F;AAI/F;;GAEG;AACU,QAAA,UAAU,GAA2B;IAChD,6CAAoB;IACpB,+EAAqC;IACrC,6EAAoC;CACrC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nauth-toolkit/database-typeorm-mysql",
3
- "version": "0.1.108",
3
+ "version": "0.1.109",
4
4
  "description": "MySQL TypeORM adapter for nauth-toolkit",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  "format:check": "prettier --check \"src/**/*.ts\""
15
15
  },
16
16
  "peerDependencies": {
17
- "@nauth-toolkit/core": "^0.1.108",
17
+ "@nauth-toolkit/core": "^0.1.109",
18
18
  "typeorm": "^0.3.20",
19
19
  "mysql2": "^2.3.0 || ^3.0.0"
20
20
  },