nuxt-users 1.6.6 → 1.6.7
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.
- package/CHANGELOG.md +32 -0
- package/dist/cli.mjs +1 -1
- package/dist/module.d.mts +4 -70
- package/dist/module.d.ts +4 -70
- package/dist/module.json +1 -1
- package/dist/module.mjs +12 -7
- package/dist/runtime/server/api/auth/login.post.js +4 -2
- package/dist/runtime/server/tasks/cleanup-tokens.d.ts +2 -0
- package/dist/runtime/server/tasks/cleanup-tokens.js +30 -0
- package/dist/runtime/server/utils/index.d.ts +1 -1
- package/dist/runtime/server/utils/index.js +1 -1
- package/dist/runtime/server/utils/user.d.ts +20 -0
- package/dist/runtime/server/utils/user.js +45 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v1.6.7
|
|
5
|
+
|
|
6
|
+
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.6.6...v1.6.7)
|
|
7
|
+
|
|
8
|
+
### 🩹 Fixes
|
|
9
|
+
|
|
10
|
+
- Authentication middleware logic ([18a3bb5](https://github.com/rrd108/nuxt-users/commit/18a3bb5))
|
|
11
|
+
- Password validation and UI ([07b44b3](https://github.com/rrd108/nuxt-users/commit/07b44b3))
|
|
12
|
+
- Type errors ([c403645](https://github.com/rrd108/nuxt-users/commit/c403645))
|
|
13
|
+
|
|
14
|
+
### 💅 Refactors
|
|
15
|
+
|
|
16
|
+
- API routes ([3c7603f](https://github.com/rrd108/nuxt-users/commit/3c7603f))
|
|
17
|
+
- Authentication components and logic ([4da544f](https://github.com/rrd108/nuxt-users/commit/4da544f))
|
|
18
|
+
- Token cleanup task and middleware ([d47a4a5](https://github.com/rrd108/nuxt-users/commit/d47a4a5))
|
|
19
|
+
|
|
20
|
+
### 🏡 Chore
|
|
21
|
+
|
|
22
|
+
- **release:** V1.6.6 ([7b37694](https://github.com/rrd108/nuxt-users/commit/7b37694))
|
|
23
|
+
|
|
24
|
+
### ✅ Tests
|
|
25
|
+
|
|
26
|
+
- Fix mock ([791dc94](https://github.com/rrd108/nuxt-users/commit/791dc94))
|
|
27
|
+
- Adds unit tests for auth API endpoints ([d844630](https://github.com/rrd108/nuxt-users/commit/d844630))
|
|
28
|
+
- Remove unused test ([3dc23ad](https://github.com/rrd108/nuxt-users/commit/3dc23ad))
|
|
29
|
+
- Fix response ([db3b03c](https://github.com/rrd108/nuxt-users/commit/db3b03c))
|
|
30
|
+
- Fix mysql field type ([2faf0c6](https://github.com/rrd108/nuxt-users/commit/2faf0c6))
|
|
31
|
+
|
|
32
|
+
### ❤️ Contributors
|
|
33
|
+
|
|
34
|
+
- Rrd108 ([@rrd108](https://github.com/rrd108))
|
|
35
|
+
|
|
4
36
|
## v1.6.6
|
|
5
37
|
|
|
6
38
|
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.6.5...v1.6.6)
|
package/dist/cli.mjs
CHANGED
package/dist/module.d.mts
CHANGED
|
@@ -9,76 +9,7 @@ type DatabaseConfig = {
|
|
|
9
9
|
password?: string;
|
|
10
10
|
database?: string;
|
|
11
11
|
};
|
|
12
|
-
interface
|
|
13
|
-
connector?: {
|
|
14
|
-
name: DatabaseType;
|
|
15
|
-
options: DatabaseConfig;
|
|
16
|
-
};
|
|
17
|
-
tables?: {
|
|
18
|
-
migrations?: string;
|
|
19
|
-
users?: string;
|
|
20
|
-
personalAccessTokens?: string;
|
|
21
|
-
passwordResetTokens?: string;
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* Mailer configuration options for sending emails (e.g., password resets)
|
|
25
|
-
* Uses nodemailer
|
|
26
|
-
*/
|
|
27
|
-
mailer?: MailerOptions;
|
|
28
|
-
/**
|
|
29
|
-
* Base URL for password reset links
|
|
30
|
-
* @default 'http://localhost:3000' // Example, will be set in module defaults
|
|
31
|
-
*/
|
|
32
|
-
passwordResetBaseUrl?: string;
|
|
33
|
-
/**
|
|
34
|
-
* Skip database checks during module setup to prevent hanging
|
|
35
|
-
* @default false
|
|
36
|
-
*/
|
|
37
|
-
auth?: {
|
|
38
|
-
/**
|
|
39
|
-
* Whitelisted routes that do not require authentication
|
|
40
|
-
* @default ['/login']
|
|
41
|
-
* @example ['/login', '/register']
|
|
42
|
-
*/
|
|
43
|
-
whitelist?: string[];
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Password validation configuration
|
|
47
|
-
*/
|
|
48
|
-
passwordValidation?: {
|
|
49
|
-
/**
|
|
50
|
-
* Minimum password length
|
|
51
|
-
* @default 8
|
|
52
|
-
*/
|
|
53
|
-
minLength?: number;
|
|
54
|
-
/**
|
|
55
|
-
* Require uppercase letters
|
|
56
|
-
* @default true
|
|
57
|
-
*/
|
|
58
|
-
requireUppercase?: boolean;
|
|
59
|
-
/**
|
|
60
|
-
* Require lowercase letters
|
|
61
|
-
* @default true
|
|
62
|
-
*/
|
|
63
|
-
requireLowercase?: boolean;
|
|
64
|
-
/**
|
|
65
|
-
* Require numbers
|
|
66
|
-
* @default true
|
|
67
|
-
*/
|
|
68
|
-
requireNumbers?: boolean;
|
|
69
|
-
/**
|
|
70
|
-
* Require special characters
|
|
71
|
-
* @default true
|
|
72
|
-
*/
|
|
73
|
-
requireSpecialChars?: boolean;
|
|
74
|
-
/**
|
|
75
|
-
* Prevent common passwords
|
|
76
|
-
* @default true
|
|
77
|
-
*/
|
|
78
|
-
preventCommonPasswords?: boolean;
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
interface ModuleOptions extends Omit<RuntimeModuleOptions, 'tables' | 'auth' | 'passwordValidation'> {
|
|
12
|
+
interface ModuleOptions {
|
|
82
13
|
connector: {
|
|
83
14
|
name: DatabaseType;
|
|
84
15
|
options: DatabaseConfig;
|
|
@@ -89,8 +20,11 @@ interface ModuleOptions extends Omit<RuntimeModuleOptions, 'tables' | 'auth' | '
|
|
|
89
20
|
personalAccessTokens: string;
|
|
90
21
|
passwordResetTokens: string;
|
|
91
22
|
};
|
|
23
|
+
mailer?: MailerOptions;
|
|
24
|
+
passwordResetBaseUrl?: string;
|
|
92
25
|
auth: {
|
|
93
26
|
whitelist: string[];
|
|
27
|
+
tokenExpiration: number;
|
|
94
28
|
};
|
|
95
29
|
passwordValidation: {
|
|
96
30
|
minLength: number;
|
package/dist/module.d.ts
CHANGED
|
@@ -9,76 +9,7 @@ type DatabaseConfig = {
|
|
|
9
9
|
password?: string;
|
|
10
10
|
database?: string;
|
|
11
11
|
};
|
|
12
|
-
interface
|
|
13
|
-
connector?: {
|
|
14
|
-
name: DatabaseType;
|
|
15
|
-
options: DatabaseConfig;
|
|
16
|
-
};
|
|
17
|
-
tables?: {
|
|
18
|
-
migrations?: string;
|
|
19
|
-
users?: string;
|
|
20
|
-
personalAccessTokens?: string;
|
|
21
|
-
passwordResetTokens?: string;
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* Mailer configuration options for sending emails (e.g., password resets)
|
|
25
|
-
* Uses nodemailer
|
|
26
|
-
*/
|
|
27
|
-
mailer?: MailerOptions;
|
|
28
|
-
/**
|
|
29
|
-
* Base URL for password reset links
|
|
30
|
-
* @default 'http://localhost:3000' // Example, will be set in module defaults
|
|
31
|
-
*/
|
|
32
|
-
passwordResetBaseUrl?: string;
|
|
33
|
-
/**
|
|
34
|
-
* Skip database checks during module setup to prevent hanging
|
|
35
|
-
* @default false
|
|
36
|
-
*/
|
|
37
|
-
auth?: {
|
|
38
|
-
/**
|
|
39
|
-
* Whitelisted routes that do not require authentication
|
|
40
|
-
* @default ['/login']
|
|
41
|
-
* @example ['/login', '/register']
|
|
42
|
-
*/
|
|
43
|
-
whitelist?: string[];
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Password validation configuration
|
|
47
|
-
*/
|
|
48
|
-
passwordValidation?: {
|
|
49
|
-
/**
|
|
50
|
-
* Minimum password length
|
|
51
|
-
* @default 8
|
|
52
|
-
*/
|
|
53
|
-
minLength?: number;
|
|
54
|
-
/**
|
|
55
|
-
* Require uppercase letters
|
|
56
|
-
* @default true
|
|
57
|
-
*/
|
|
58
|
-
requireUppercase?: boolean;
|
|
59
|
-
/**
|
|
60
|
-
* Require lowercase letters
|
|
61
|
-
* @default true
|
|
62
|
-
*/
|
|
63
|
-
requireLowercase?: boolean;
|
|
64
|
-
/**
|
|
65
|
-
* Require numbers
|
|
66
|
-
* @default true
|
|
67
|
-
*/
|
|
68
|
-
requireNumbers?: boolean;
|
|
69
|
-
/**
|
|
70
|
-
* Require special characters
|
|
71
|
-
* @default true
|
|
72
|
-
*/
|
|
73
|
-
requireSpecialChars?: boolean;
|
|
74
|
-
/**
|
|
75
|
-
* Prevent common passwords
|
|
76
|
-
* @default true
|
|
77
|
-
*/
|
|
78
|
-
preventCommonPasswords?: boolean;
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
interface ModuleOptions extends Omit<RuntimeModuleOptions, 'tables' | 'auth' | 'passwordValidation'> {
|
|
12
|
+
interface ModuleOptions {
|
|
82
13
|
connector: {
|
|
83
14
|
name: DatabaseType;
|
|
84
15
|
options: DatabaseConfig;
|
|
@@ -89,8 +20,11 @@ interface ModuleOptions extends Omit<RuntimeModuleOptions, 'tables' | 'auth' | '
|
|
|
89
20
|
personalAccessTokens: string;
|
|
90
21
|
passwordResetTokens: string;
|
|
91
22
|
};
|
|
23
|
+
mailer?: MailerOptions;
|
|
24
|
+
passwordResetBaseUrl?: string;
|
|
92
25
|
auth: {
|
|
93
26
|
whitelist: string[];
|
|
27
|
+
tokenExpiration: number;
|
|
94
28
|
};
|
|
95
29
|
passwordValidation: {
|
|
96
30
|
minLength: number;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver, addPlugin, addImportsDir,
|
|
1
|
+
import { defineNuxtModule, createResolver, addPlugin, addImportsDir, addRouteMiddleware, addServerHandler, addComponent } from '@nuxt/kit';
|
|
2
2
|
import { defu } from 'defu';
|
|
3
3
|
|
|
4
4
|
const defaultOptions = {
|
|
@@ -31,7 +31,9 @@ const defaultOptions = {
|
|
|
31
31
|
},
|
|
32
32
|
passwordResetBaseUrl: "http://localhost:3000",
|
|
33
33
|
auth: {
|
|
34
|
-
whitelist: ["/login"]
|
|
34
|
+
whitelist: ["/login"],
|
|
35
|
+
tokenExpiration: 24 * 60
|
|
36
|
+
// 24 hours
|
|
35
37
|
},
|
|
36
38
|
passwordValidation: {
|
|
37
39
|
minLength: 8,
|
|
@@ -61,7 +63,8 @@ const module = defineNuxtModule({
|
|
|
61
63
|
passwordResetTokens: options.tables?.passwordResetTokens || defaultOptions.tables.passwordResetTokens
|
|
62
64
|
},
|
|
63
65
|
auth: {
|
|
64
|
-
whitelist: [...defaultOptions.auth?.whitelist || [], ...options.auth?.whitelist || []]
|
|
66
|
+
whitelist: [...defaultOptions.auth?.whitelist || [], ...options.auth?.whitelist || []],
|
|
67
|
+
tokenExpiration: options.auth?.tokenExpiration || defaultOptions.auth.tokenExpiration
|
|
65
68
|
}
|
|
66
69
|
};
|
|
67
70
|
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
|
|
@@ -83,10 +86,6 @@ const module = defineNuxtModule({
|
|
|
83
86
|
mode: "server"
|
|
84
87
|
});
|
|
85
88
|
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
86
|
-
addServerHandler({
|
|
87
|
-
middleware: true,
|
|
88
|
-
handler: resolver.resolve("./runtime/server/middleware/auth.server")
|
|
89
|
-
});
|
|
90
89
|
addRouteMiddleware({
|
|
91
90
|
name: "auth.client",
|
|
92
91
|
path: resolver.resolve("./runtime/middleware/auth.client"),
|
|
@@ -122,6 +121,12 @@ const module = defineNuxtModule({
|
|
|
122
121
|
method: "post",
|
|
123
122
|
handler: resolver.resolve("./runtime/server/api/auth/update-password.post")
|
|
124
123
|
});
|
|
124
|
+
nuxt.hook("nitro:config", async (nitroConfig) => {
|
|
125
|
+
nitroConfig.experimental = nitroConfig.experimental || {};
|
|
126
|
+
nitroConfig.experimental.tasks = true;
|
|
127
|
+
nitroConfig.scanDirs = nitroConfig.scanDirs || [];
|
|
128
|
+
nitroConfig.scanDirs.push(resolver.resolve("./runtime/server/tasks"));
|
|
129
|
+
});
|
|
125
130
|
addComponent({
|
|
126
131
|
name: "LoginForm",
|
|
127
132
|
filePath: resolver.resolve("./runtime/components/LoginForm.vue")
|
|
@@ -35,9 +35,11 @@ export default defineEventHandler(async (event) => {
|
|
|
35
35
|
}
|
|
36
36
|
const token = crypto.randomBytes(64).toString("hex");
|
|
37
37
|
const tokenName = "auth_token";
|
|
38
|
+
const expiresAt = /* @__PURE__ */ new Date();
|
|
39
|
+
expiresAt.setMinutes(expiresAt.getMinutes() + options.auth.tokenExpiration);
|
|
38
40
|
await db.sql`
|
|
39
|
-
INSERT INTO {${personalAccessTokensTable}} (tokenable_type, tokenable_id, name, token, created_at, updated_at)
|
|
40
|
-
VALUES ('user', ${user.id}, ${tokenName}, ${token}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
|
41
|
+
INSERT INTO {${personalAccessTokensTable}} (tokenable_type, tokenable_id, name, token, expires_at, created_at, updated_at)
|
|
42
|
+
VALUES ('user', ${user.id}, ${tokenName}, ${token}, ${expiresAt.toISOString().slice(0, 19).replace("T", " ")}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
|
41
43
|
`;
|
|
42
44
|
setCookie(event, "auth_token", token, {
|
|
43
45
|
httpOnly: true,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { defineTask } from "nitropack/runtime/task";
|
|
2
|
+
export default defineTask({
|
|
3
|
+
meta: {
|
|
4
|
+
name: "nuxt-users:cleanup-tokens",
|
|
5
|
+
description: "Clean up expired personal access tokens and tokens without expiration"
|
|
6
|
+
},
|
|
7
|
+
async run({ payload }) {
|
|
8
|
+
const { useRuntimeConfig } = await import("#imports");
|
|
9
|
+
const { cleanupPersonalAccessTokens } = await import("../utils/index.js");
|
|
10
|
+
const { nuxtUsers } = useRuntimeConfig();
|
|
11
|
+
const options = nuxtUsers;
|
|
12
|
+
if (!options) {
|
|
13
|
+
throw new Error("Nuxt Users module not configured");
|
|
14
|
+
}
|
|
15
|
+
const includeNoExpiration = payload?.includeNoExpiration ?? true;
|
|
16
|
+
try {
|
|
17
|
+
const result = await cleanupPersonalAccessTokens(options, includeNoExpiration);
|
|
18
|
+
return {
|
|
19
|
+
result: "success",
|
|
20
|
+
expiredTokensRemoved: result.expiredCount,
|
|
21
|
+
noExpirationTokensRemoved: result.noExpirationCount,
|
|
22
|
+
totalTokensCleaned: result.totalCount,
|
|
23
|
+
includeNoExpiration
|
|
24
|
+
};
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error("[Nuxt Users] Token cleanup failed:", error);
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { useDb, checkTableExists } from './db.js';
|
|
2
|
-
export { createUser, findUserByEmail, updateUserPassword, getCurrentUserFromToken, hasAnyUsers } from './user.js';
|
|
2
|
+
export { createUser, findUserByEmail, updateUserPassword, getCurrentUserFromToken, hasAnyUsers, deleteExpiredPersonalAccessTokens, deleteTokensWithoutExpiration, cleanupPersonalAccessTokens, revokeUserTokens } from './user.js';
|
|
3
3
|
export { createUsersTable } from './create-users-table.js';
|
|
4
4
|
export { createPersonalAccessTokensTable } from './create-personal-access-tokens-table.js';
|
|
5
5
|
export { createPasswordResetTokensTable } from './create-password-reset-tokens-table.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { useDb, checkTableExists } from "./db.js";
|
|
2
|
-
export { createUser, findUserByEmail, updateUserPassword, getCurrentUserFromToken, hasAnyUsers } from "./user.js";
|
|
2
|
+
export { createUser, findUserByEmail, updateUserPassword, getCurrentUserFromToken, hasAnyUsers, deleteExpiredPersonalAccessTokens, deleteTokensWithoutExpiration, cleanupPersonalAccessTokens, revokeUserTokens } from "./user.js";
|
|
3
3
|
export { createUsersTable } from "./create-users-table.js";
|
|
4
4
|
export { createPersonalAccessTokensTable } from "./create-personal-access-tokens-table.js";
|
|
5
5
|
export { createPasswordResetTokensTable } from "./create-password-reset-tokens-table.js";
|
|
@@ -24,4 +24,24 @@ export declare const hasAnyUsers: (options: ModuleOptions) => Promise<boolean>;
|
|
|
24
24
|
* Gets the current user from an authentication token.
|
|
25
25
|
*/
|
|
26
26
|
export declare const getCurrentUserFromToken: <T extends boolean = false>(token: string, options: ModuleOptions, withPass?: T) => Promise<T extends true ? User | null : UserWithoutPassword | null>;
|
|
27
|
+
/**
|
|
28
|
+
* Deletes expired personal access tokens from the database.
|
|
29
|
+
*/
|
|
30
|
+
export declare const deleteExpiredPersonalAccessTokens: (options: ModuleOptions) => Promise<number>;
|
|
31
|
+
/**
|
|
32
|
+
* Deletes tokens without expiration dates (legacy tokens or security cleanup).
|
|
33
|
+
*/
|
|
34
|
+
export declare const deleteTokensWithoutExpiration: (options: ModuleOptions) => Promise<number>;
|
|
35
|
+
/**
|
|
36
|
+
* Comprehensive token cleanup: removes expired tokens and optionally tokens without expiration.
|
|
37
|
+
*/
|
|
38
|
+
export declare const cleanupPersonalAccessTokens: (options: ModuleOptions, includeNoExpiration?: boolean) => Promise<{
|
|
39
|
+
expiredCount: number;
|
|
40
|
+
noExpirationCount: number;
|
|
41
|
+
totalCount: number;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Revokes all tokens for a specific user.
|
|
45
|
+
*/
|
|
46
|
+
export declare const revokeUserTokens: (userId: number, options: ModuleOptions) => Promise<void>;
|
|
27
47
|
export {};
|
|
@@ -76,13 +76,19 @@ export const getCurrentUserFromToken = async (token, options, withPass = false)
|
|
|
76
76
|
const personalAccessTokensTable = options.tables.personalAccessTokens;
|
|
77
77
|
const usersTable = options.tables.users;
|
|
78
78
|
const tokenResult = await db.sql`
|
|
79
|
-
SELECT tokenable_id FROM {${personalAccessTokensTable}}
|
|
79
|
+
SELECT tokenable_id, expires_at FROM {${personalAccessTokensTable}}
|
|
80
80
|
WHERE token = ${token}
|
|
81
|
+
AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)
|
|
81
82
|
`;
|
|
82
83
|
if (tokenResult.rows.length === 0) {
|
|
83
84
|
return null;
|
|
84
85
|
}
|
|
85
86
|
const userId = tokenResult.rows[0].tokenable_id;
|
|
87
|
+
await db.sql`
|
|
88
|
+
UPDATE {${personalAccessTokensTable}}
|
|
89
|
+
SET last_used_at = CURRENT_TIMESTAMP
|
|
90
|
+
WHERE token = ${token}
|
|
91
|
+
`;
|
|
86
92
|
const userResult = await db.sql`
|
|
87
93
|
SELECT * FROM {${usersTable}}
|
|
88
94
|
WHERE id = ${userId}
|
|
@@ -97,3 +103,41 @@ export const getCurrentUserFromToken = async (token, options, withPass = false)
|
|
|
97
103
|
const { password: _, ...userWithoutPassword } = user;
|
|
98
104
|
return userWithoutPassword;
|
|
99
105
|
};
|
|
106
|
+
export const deleteExpiredPersonalAccessTokens = async (options) => {
|
|
107
|
+
const db = await useDb(options);
|
|
108
|
+
const personalAccessTokensTable = options.tables.personalAccessTokens;
|
|
109
|
+
const result = await db.sql`
|
|
110
|
+
DELETE FROM {${personalAccessTokensTable}}
|
|
111
|
+
WHERE expires_at IS NOT NULL AND expires_at <= CURRENT_TIMESTAMP
|
|
112
|
+
`;
|
|
113
|
+
const deletedCount = result.rows?.length || 0;
|
|
114
|
+
console.log(`[Nuxt Users] ${deletedCount} expired personal access tokens deleted.`);
|
|
115
|
+
return deletedCount;
|
|
116
|
+
};
|
|
117
|
+
export const deleteTokensWithoutExpiration = async (options) => {
|
|
118
|
+
const db = await useDb(options);
|
|
119
|
+
const personalAccessTokensTable = options.tables.personalAccessTokens;
|
|
120
|
+
const result = await db.sql`
|
|
121
|
+
DELETE FROM {${personalAccessTokensTable}}
|
|
122
|
+
WHERE expires_at IS NULL
|
|
123
|
+
`;
|
|
124
|
+
const deletedCount = result.rows?.length || 0;
|
|
125
|
+
console.log(`[Nuxt Users] ${deletedCount} tokens without expiration deleted.`);
|
|
126
|
+
return deletedCount;
|
|
127
|
+
};
|
|
128
|
+
export const cleanupPersonalAccessTokens = async (options, includeNoExpiration = true) => {
|
|
129
|
+
const expiredCount = await deleteExpiredPersonalAccessTokens(options);
|
|
130
|
+
const noExpirationCount = includeNoExpiration ? await deleteTokensWithoutExpiration(options) : 0;
|
|
131
|
+
const totalCount = expiredCount + noExpirationCount;
|
|
132
|
+
console.log(`[Nuxt Users] Token cleanup completed: ${expiredCount} expired + ${noExpirationCount} without expiration = ${totalCount} total tokens removed.`);
|
|
133
|
+
return { expiredCount, noExpirationCount, totalCount };
|
|
134
|
+
};
|
|
135
|
+
export const revokeUserTokens = async (userId, options) => {
|
|
136
|
+
const db = await useDb(options);
|
|
137
|
+
const personalAccessTokensTable = options.tables.personalAccessTokens;
|
|
138
|
+
await db.sql`
|
|
139
|
+
DELETE FROM {${personalAccessTokensTable}}
|
|
140
|
+
WHERE tokenable_type = 'user' AND tokenable_id = ${userId}
|
|
141
|
+
`;
|
|
142
|
+
console.log(`[Nuxt Users] All tokens revoked for user ID: ${userId}`);
|
|
143
|
+
};
|