nuxt-users 1.34.7 → 1.36.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.
- package/CHANGELOG.md +98 -0
- package/dist/cli.mjs +111 -0
- package/dist/module.d.mts +1 -1
- package/dist/module.d.ts +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +38 -3
- package/dist/runtime/assets/nuxt-users.css +1 -1
- package/dist/runtime/components/NUsersEmailConfirmation.d.vue.ts +38 -0
- package/dist/runtime/components/NUsersEmailConfirmation.vue.d.ts +3 -2
- package/dist/runtime/components/NUsersGoogleLoginButton.d.vue.ts +31 -0
- package/dist/runtime/components/NUsersGoogleLoginButton.vue +75 -0
- package/dist/runtime/components/NUsersGoogleLoginButton.vue.d.ts +31 -0
- package/dist/runtime/components/NUsersList.d.vue.ts +0 -0
- package/dist/runtime/components/NUsersLoginForm.d.vue.ts +48 -0
- package/dist/runtime/components/NUsersLoginForm.vue.d.ts +5 -4
- package/dist/runtime/components/NUsersLogoutLink.d.vue.ts +38 -0
- package/dist/runtime/components/NUsersLogoutLink.vue.d.ts +5 -4
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.d.vue.ts +13 -0
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue.d.ts +2 -1
- package/dist/runtime/components/NUsersProfileInfo.d.vue.ts +3 -0
- package/dist/runtime/components/NUsersProfileInfo.vue.d.ts +2 -1
- package/dist/runtime/components/NUsersRegisterForm.d.vue.ts +61 -0
- package/dist/runtime/components/NUsersRegisterForm.vue.d.ts +5 -4
- package/dist/runtime/components/NUsersResetPasswordForm.d.vue.ts +18 -0
- package/dist/runtime/components/NUsersResetPasswordForm.vue.d.ts +4 -3
- package/dist/runtime/components/NUsersUserCard.d.vue.ts +44 -0
- package/dist/runtime/components/NUsersUserCard.vue.d.ts +3 -2
- package/dist/runtime/components/NUsersUserForm.d.vue.ts +15 -0
- package/dist/runtime/components/NUsersUserForm.vue.d.ts +2 -1
- package/dist/runtime/composables/useAuthentication.d.ts +1 -1
- package/dist/runtime/composables/useAuthentication.js +26 -8
- package/dist/runtime/middleware/authorization.client.js +9 -7
- package/dist/runtime/server/api/nuxt-users/auth/google/callback.get.d.ts +2 -0
- package/dist/runtime/server/api/nuxt-users/auth/google/callback.get.js +68 -0
- package/dist/runtime/server/api/nuxt-users/auth/google/redirect.get.d.ts +2 -0
- package/dist/runtime/server/api/nuxt-users/auth/google/redirect.get.js +39 -0
- package/dist/runtime/server/api/nuxt-users/inactive.get.js +1 -1
- package/dist/runtime/server/api/nuxt-users/index.get.js +1 -1
- package/dist/runtime/server/api/nuxt-users/session/index.post.d.ts +1 -1
- package/dist/runtime/server/api/nuxt-users/session/index.post.js +6 -0
- package/dist/runtime/server/services/password.js +8 -0
- package/dist/runtime/server/services/registration.js +14 -1
- package/dist/runtime/server/utils/add-google-oauth-fields.d.ts +2 -0
- package/dist/runtime/server/utils/add-google-oauth-fields.js +22 -0
- package/dist/runtime/server/utils/create-users-table.js +7 -1
- package/dist/runtime/server/utils/google-oauth.d.ts +33 -0
- package/dist/runtime/server/utils/google-oauth.js +142 -0
- package/dist/runtime/server/utils/index.d.ts +1 -0
- package/dist/runtime/server/utils/index.js +1 -0
- package/dist/runtime/server/utils/migrate.js +5 -0
- package/dist/runtime/server/utils/user.js +24 -3
- package/dist/shared/{nuxt-users.BTVH9EyH.d.mts → nuxt-users.SXaMnaEL.d.mts} +45 -1
- package/dist/shared/{nuxt-users.BTVH9EyH.d.ts → nuxt-users.SXaMnaEL.d.ts} +45 -1
- package/dist/utils.d.mts +1 -1
- package/dist/utils.d.ts +1 -1
- package/package.json +8 -6
- package/scripts/check-peer-dependencies.js +0 -0
- package/scripts/post-build.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,104 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v1.36.0
|
|
5
|
+
|
|
6
|
+
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.35.0...v1.36.0)
|
|
7
|
+
|
|
8
|
+
### 🚀 Enhancements
|
|
9
|
+
|
|
10
|
+
- Implement google authentication ([e830872](https://github.com/rrd108/nuxt-users/commit/e830872))
|
|
11
|
+
- Add google auth to the playground ([2b43ca0](https://github.com/rrd108/nuxt-users/commit/2b43ca0))
|
|
12
|
+
- Add migration ([0280eca](https://github.com/rrd108/nuxt-users/commit/0280eca))
|
|
13
|
+
- Unregistered user gets error message ([eefbdf5](https://github.com/rrd108/nuxt-users/commit/eefbdf5))
|
|
14
|
+
- Enhances project info command output ([2d91bd9](https://github.com/rrd108/nuxt-users/commit/2d91bd9))
|
|
15
|
+
|
|
16
|
+
### 🩹 Fixes
|
|
17
|
+
|
|
18
|
+
- Add api endpoints to public endpoints ([16aefa9](https://github.com/rrd108/nuxt-users/commit/16aefa9))
|
|
19
|
+
- Completes Google OAuth user fetch on client ([6c95b94](https://github.com/rrd108/nuxt-users/commit/6c95b94))
|
|
20
|
+
- **deps:** Update nuxtjs monorepo to v4 ([0c4b199](https://github.com/rrd108/nuxt-users/commit/0c4b199))
|
|
21
|
+
- Ts errors ([44f5d9e](https://github.com/rrd108/nuxt-users/commit/44f5d9e))
|
|
22
|
+
- Add nuxt builder ([aaa8288](https://github.com/rrd108/nuxt-users/commit/aaa8288))
|
|
23
|
+
- Ts errors ([d488513](https://github.com/rrd108/nuxt-users/commit/d488513))
|
|
24
|
+
- **docs:** Updates last release timestamp ([3d3e0d8](https://github.com/rrd108/nuxt-users/commit/3d3e0d8))
|
|
25
|
+
|
|
26
|
+
### 📖 Documentation
|
|
27
|
+
|
|
28
|
+
- Adds Google OAuth authentication ([463c19f](https://github.com/rrd108/nuxt-users/commit/463c19f))
|
|
29
|
+
- Adds Google OAuth registration ([2e0eebf](https://github.com/rrd108/nuxt-users/commit/2e0eebf))
|
|
30
|
+
- Adds project info command to troubleshooting ([8768090](https://github.com/rrd108/nuxt-users/commit/8768090))
|
|
31
|
+
|
|
32
|
+
### 🏡 Chore
|
|
33
|
+
|
|
34
|
+
- Remove unused files ([8bd3e58](https://github.com/rrd108/nuxt-users/commit/8bd3e58))
|
|
35
|
+
- Replace googleapis package with google-auth ([0e8e3d4](https://github.com/rrd108/nuxt-users/commit/0e8e3d4))
|
|
36
|
+
- Fix lint errors ([3ed5bcc](https://github.com/rrd108/nuxt-users/commit/3ed5bcc))
|
|
37
|
+
- Update lock ([8cd4a97](https://github.com/rrd108/nuxt-users/commit/8cd4a97))
|
|
38
|
+
- **release:** V1.35.0 ([41cb690](https://github.com/rrd108/nuxt-users/commit/41cb690))
|
|
39
|
+
- Add snyk ([9c932c8](https://github.com/rrd108/nuxt-users/commit/9c932c8))
|
|
40
|
+
- Remove unsued import ([04fd61d](https://github.com/rrd108/nuxt-users/commit/04fd61d))
|
|
41
|
+
- Package updates ([3173073](https://github.com/rrd108/nuxt-users/commit/3173073))
|
|
42
|
+
|
|
43
|
+
### ✅ Tests
|
|
44
|
+
|
|
45
|
+
- Google OAuth authentication ([7d7bd68](https://github.com/rrd108/nuxt-users/commit/7d7bd68))
|
|
46
|
+
- Add oauth flow test ([b805718](https://github.com/rrd108/nuxt-users/commit/b805718))
|
|
47
|
+
- Fix db setup ([a097c4a](https://github.com/rrd108/nuxt-users/commit/a097c4a))
|
|
48
|
+
- Replace smoke test with middleware test ([7ee1893](https://github.com/rrd108/nuxt-users/commit/7ee1893))
|
|
49
|
+
- Add security checks ([a206962](https://github.com/rrd108/nuxt-users/commit/a206962))
|
|
50
|
+
- Fix ts errors ([d7e6c61](https://github.com/rrd108/nuxt-users/commit/d7e6c61))
|
|
51
|
+
- Fix gauth ([b925cf2](https://github.com/rrd108/nuxt-users/commit/b925cf2))
|
|
52
|
+
|
|
53
|
+
### ❤️ Contributors
|
|
54
|
+
|
|
55
|
+
- Rrd108 ([@rrd108](https://github.com/rrd108))
|
|
56
|
+
|
|
57
|
+
## v1.35.0
|
|
58
|
+
|
|
59
|
+
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.34.7...v1.35.0)
|
|
60
|
+
|
|
61
|
+
### 🚀 Enhancements
|
|
62
|
+
|
|
63
|
+
- Implement google authentication ([e830872](https://github.com/rrd108/nuxt-users/commit/e830872))
|
|
64
|
+
- Add google auth to the playground ([2b43ca0](https://github.com/rrd108/nuxt-users/commit/2b43ca0))
|
|
65
|
+
- Add migration ([0280eca](https://github.com/rrd108/nuxt-users/commit/0280eca))
|
|
66
|
+
- Unregistered user gets error message ([eefbdf5](https://github.com/rrd108/nuxt-users/commit/eefbdf5))
|
|
67
|
+
|
|
68
|
+
### 🩹 Fixes
|
|
69
|
+
|
|
70
|
+
- Prevents database connection issues during build ([8a3aa38](https://github.com/rrd108/nuxt-users/commit/8a3aa38))
|
|
71
|
+
- Add api endpoints to public endpoints ([16aefa9](https://github.com/rrd108/nuxt-users/commit/16aefa9))
|
|
72
|
+
- Completes Google OAuth user fetch on client ([6c95b94](https://github.com/rrd108/nuxt-users/commit/6c95b94))
|
|
73
|
+
|
|
74
|
+
### 📖 Documentation
|
|
75
|
+
|
|
76
|
+
- Fix github link ([28662ca](https://github.com/rrd108/nuxt-users/commit/28662ca))
|
|
77
|
+
- Adds Google OAuth authentication ([463c19f](https://github.com/rrd108/nuxt-users/commit/463c19f))
|
|
78
|
+
- Adds Google OAuth registration ([2e0eebf](https://github.com/rrd108/nuxt-users/commit/2e0eebf))
|
|
79
|
+
|
|
80
|
+
### 🏡 Chore
|
|
81
|
+
|
|
82
|
+
- Lint fix ([8d75930](https://github.com/rrd108/nuxt-users/commit/8d75930))
|
|
83
|
+
- **release:** V1.34.7 ([b9d061c](https://github.com/rrd108/nuxt-users/commit/b9d061c))
|
|
84
|
+
- Remove unused files ([8bd3e58](https://github.com/rrd108/nuxt-users/commit/8bd3e58))
|
|
85
|
+
- Replace googleapis package with google-auth ([0e8e3d4](https://github.com/rrd108/nuxt-users/commit/0e8e3d4))
|
|
86
|
+
- Fix lint errors ([3ed5bcc](https://github.com/rrd108/nuxt-users/commit/3ed5bcc))
|
|
87
|
+
- Update lock ([8cd4a97](https://github.com/rrd108/nuxt-users/commit/8cd4a97))
|
|
88
|
+
|
|
89
|
+
### ✅ Tests
|
|
90
|
+
|
|
91
|
+
- Google OAuth authentication ([7d7bd68](https://github.com/rrd108/nuxt-users/commit/7d7bd68))
|
|
92
|
+
- Add oauth flow test ([b805718](https://github.com/rrd108/nuxt-users/commit/b805718))
|
|
93
|
+
- Fix db setup ([a097c4a](https://github.com/rrd108/nuxt-users/commit/a097c4a))
|
|
94
|
+
- Replace smoke test with middleware test ([7ee1893](https://github.com/rrd108/nuxt-users/commit/7ee1893))
|
|
95
|
+
- Add security checks ([a206962](https://github.com/rrd108/nuxt-users/commit/a206962))
|
|
96
|
+
- Fix ts errors ([d7e6c61](https://github.com/rrd108/nuxt-users/commit/d7e6c61))
|
|
97
|
+
|
|
98
|
+
### ❤️ Contributors
|
|
99
|
+
|
|
100
|
+
- Rrd108 ([@rrd108](https://github.com/rrd108))
|
|
101
|
+
|
|
4
102
|
## v1.34.7
|
|
5
103
|
|
|
6
104
|
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.34.6...v1.34.7)
|
package/dist/cli.mjs
CHANGED
|
@@ -7,6 +7,8 @@ import { defu } from 'defu';
|
|
|
7
7
|
import { runMigrations, createUser as createUser$1, createUsersTable as createUsersTable$1, createPersonalAccessTokensTable as createPersonalAccessTokensTable$1, createPasswordResetTokensTable as createPasswordResetTokensTable$1, createMigrationsTable as createMigrationsTable$1 } from '../dist/runtime/server/utils/index.js';
|
|
8
8
|
import { g as getPasswordValidationOptions, v as validatePassword } from './shared/nuxt-users.BnOQs2LI.mjs';
|
|
9
9
|
import { addActiveToUsers as addActiveToUsers$1 } from '../dist/runtime/server/utils/add-active-to-users.js';
|
|
10
|
+
import { useDb, checkTableExists } from '../dist/runtime/server/utils/db.js';
|
|
11
|
+
import { getAppliedMigrations } from '../dist/runtime/server/utils/migrate.js';
|
|
10
12
|
import '../dist/runtime/server/internal/index.js';
|
|
11
13
|
|
|
12
14
|
const getOptionsFromEnv = () => {
|
|
@@ -245,6 +247,78 @@ const addActiveToUsers = defineCommand({
|
|
|
245
247
|
}
|
|
246
248
|
});
|
|
247
249
|
|
|
250
|
+
const addGoogleOauthFields = defineCommand({
|
|
251
|
+
meta: {
|
|
252
|
+
name: "add-google-oauth-fields",
|
|
253
|
+
description: "Add Google OAuth fields (google_id, profile_picture) to existing users table"
|
|
254
|
+
},
|
|
255
|
+
async run() {
|
|
256
|
+
console.log("[Nuxt Users] Adding Google OAuth fields to users table...");
|
|
257
|
+
const options = await loadOptions();
|
|
258
|
+
const connectorName = options.connector.name;
|
|
259
|
+
const db = await useDb(options);
|
|
260
|
+
const tableName = options.tables.users;
|
|
261
|
+
console.log(`[Nuxt Users] DB:Migrate ${connectorName} Users Table Adding Google OAuth fields...`);
|
|
262
|
+
try {
|
|
263
|
+
if (connectorName === "sqlite") {
|
|
264
|
+
const tableInfo = await db.sql`PRAGMA table_info(${tableName})`;
|
|
265
|
+
const columnNames = tableInfo.rows.map((row) => row.name);
|
|
266
|
+
if (!columnNames.includes("google_id")) {
|
|
267
|
+
await db.sql`ALTER TABLE {${tableName}} ADD COLUMN google_id TEXT`;
|
|
268
|
+
console.log("[Nuxt Users] Added google_id column to SQLite users table \u2705");
|
|
269
|
+
}
|
|
270
|
+
if (!columnNames.includes("profile_picture")) {
|
|
271
|
+
await db.sql`ALTER TABLE {${tableName}} ADD COLUMN profile_picture TEXT`;
|
|
272
|
+
console.log("[Nuxt Users] Added profile_picture column to SQLite users table \u2705");
|
|
273
|
+
}
|
|
274
|
+
if (!columnNames.includes("last_login_at")) {
|
|
275
|
+
await db.sql`ALTER TABLE {${tableName}} ADD COLUMN last_login_at DATETIME`;
|
|
276
|
+
console.log("[Nuxt Users] Added last_login_at column to SQLite users table \u2705");
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (connectorName === "mysql") {
|
|
280
|
+
const checkColumns = await db.sql`
|
|
281
|
+
SELECT COLUMN_NAME
|
|
282
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
283
|
+
WHERE TABLE_SCHEMA = DATABASE()
|
|
284
|
+
AND TABLE_NAME = ${tableName}
|
|
285
|
+
AND COLUMN_NAME IN ('google_id', 'profile_picture')
|
|
286
|
+
`;
|
|
287
|
+
const existingColumns = checkColumns.rows.map((row) => row.COLUMN_NAME);
|
|
288
|
+
if (!existingColumns.includes("google_id")) {
|
|
289
|
+
await db.sql`ALTER TABLE {${tableName}} ADD COLUMN google_id VARCHAR(255) UNIQUE`;
|
|
290
|
+
console.log("[Nuxt Users] Added google_id column to MySQL users table \u2705");
|
|
291
|
+
}
|
|
292
|
+
if (!existingColumns.includes("profile_picture")) {
|
|
293
|
+
await db.sql`ALTER TABLE {${tableName}} ADD COLUMN profile_picture TEXT`;
|
|
294
|
+
console.log("[Nuxt Users] Added profile_picture column to MySQL users table \u2705");
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (connectorName === "postgresql") {
|
|
298
|
+
const checkColumns = await db.sql`
|
|
299
|
+
SELECT column_name
|
|
300
|
+
FROM information_schema.columns
|
|
301
|
+
WHERE table_name = ${tableName}
|
|
302
|
+
AND column_name IN ('google_id', 'profile_picture')
|
|
303
|
+
`;
|
|
304
|
+
const existingColumns = checkColumns.rows.map((row) => row.column_name);
|
|
305
|
+
if (!existingColumns.includes("google_id")) {
|
|
306
|
+
await db.sql`ALTER TABLE {${tableName}} ADD COLUMN google_id VARCHAR(255) UNIQUE`;
|
|
307
|
+
console.log("[Nuxt Users] Added google_id column to PostgreSQL users table \u2705");
|
|
308
|
+
}
|
|
309
|
+
if (!existingColumns.includes("profile_picture")) {
|
|
310
|
+
await db.sql`ALTER TABLE {${tableName}} ADD COLUMN profile_picture TEXT`;
|
|
311
|
+
console.log("[Nuxt Users] Added profile_picture column to PostgreSQL users table \u2705");
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
console.log("[Nuxt Users] Google OAuth fields migration completed successfully! \u2705");
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error("[Nuxt Users] DB:Migration Error:", error);
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
|
|
248
322
|
const projectInfo = defineCommand({
|
|
249
323
|
meta: {
|
|
250
324
|
name: "project-info",
|
|
@@ -261,9 +335,45 @@ const projectInfo = defineCommand({
|
|
|
261
335
|
if (nuxtUsersConfig) {
|
|
262
336
|
console.log("[Nuxt Users] \u{1F527} Nuxt Users module configuration:");
|
|
263
337
|
console.log("[Nuxt Users] Database connector:", nuxtUsersConfig.connector?.name);
|
|
338
|
+
if (nuxtUsersConfig.connector?.options) {
|
|
339
|
+
const options = nuxtUsersConfig.connector.options;
|
|
340
|
+
if (options.host) {
|
|
341
|
+
console.log("[Nuxt Users] Database host:", options.host);
|
|
342
|
+
}
|
|
343
|
+
if (options.port) {
|
|
344
|
+
console.log("[Nuxt Users] Database port:", options.port);
|
|
345
|
+
}
|
|
346
|
+
if (options.user) {
|
|
347
|
+
console.log("[Nuxt Users] Database user:", options.user);
|
|
348
|
+
}
|
|
349
|
+
if (options.database) {
|
|
350
|
+
console.log("[Nuxt Users] Database name:", options.database);
|
|
351
|
+
}
|
|
352
|
+
if (options.path) {
|
|
353
|
+
console.log("[Nuxt Users] Database path:", options.path);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
264
356
|
console.log("[Nuxt Users] Users table:", nuxtUsersConfig.tables?.users);
|
|
265
357
|
console.log("[Nuxt Users] Personal access tokens table:", nuxtUsersConfig.tables?.personalAccessTokens);
|
|
266
358
|
console.log("[Nuxt Users] Password reset tokens table:", nuxtUsersConfig.tables?.passwordResetTokens);
|
|
359
|
+
try {
|
|
360
|
+
const migrationsTableExists = await checkTableExists(nuxtUsersConfig, "migrations");
|
|
361
|
+
if (migrationsTableExists) {
|
|
362
|
+
const appliedMigrations = await getAppliedMigrations(nuxtUsersConfig);
|
|
363
|
+
console.log("[Nuxt Users] \u{1F4CA} Migrations:");
|
|
364
|
+
console.log("[Nuxt Users] Migrations table exists: \u2705");
|
|
365
|
+
console.log("[Nuxt Users] Applied migrations count:", appliedMigrations.length);
|
|
366
|
+
if (appliedMigrations.length > 0) {
|
|
367
|
+
console.log("[Nuxt Users] Applied migrations:", appliedMigrations.join(", "));
|
|
368
|
+
}
|
|
369
|
+
} else {
|
|
370
|
+
console.log("[Nuxt Users] \u{1F4CA} Migrations:");
|
|
371
|
+
console.log("[Nuxt Users] Migrations table exists: \u274C");
|
|
372
|
+
console.log('[Nuxt Users] Run "npx nuxt-users migrate" to set up the database');
|
|
373
|
+
}
|
|
374
|
+
} catch (error) {
|
|
375
|
+
console.log("[Nuxt Users] \u26A0\uFE0F Could not check migrations:", error instanceof Error ? error.message : "Unknown error");
|
|
376
|
+
}
|
|
267
377
|
} else {
|
|
268
378
|
console.log("[Nuxt Users] \u26A0\uFE0F Nuxt Users module not configured in runtime config");
|
|
269
379
|
}
|
|
@@ -304,6 +414,7 @@ const main = defineCommand({
|
|
|
304
414
|
"create-password-reset-tokens-table": createPasswordResetTokensTable,
|
|
305
415
|
"create-migrations-table": createMigrationsTable,
|
|
306
416
|
"add-active-to-users": addActiveToUsers,
|
|
417
|
+
"add-google-oauth-fields": addGoogleOauthFields,
|
|
307
418
|
"project-info": projectInfo
|
|
308
419
|
}
|
|
309
420
|
});
|
package/dist/module.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.
|
|
2
|
+
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.SXaMnaEL.mjs';
|
|
3
3
|
export * from '../dist/runtime/server/internal/index.js';
|
|
4
4
|
|
|
5
5
|
declare const defaultOptions: ModuleOptions;
|
package/dist/module.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.
|
|
2
|
+
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.SXaMnaEL.js';
|
|
3
3
|
export * from '../dist/runtime/server/internal/index.js';
|
|
4
4
|
|
|
5
5
|
declare const defaultOptions: ModuleOptions;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -65,11 +65,14 @@ const module = defineNuxtModule({
|
|
|
65
65
|
nuxt.options.runtimeConfig.nuxtUsers = {
|
|
66
66
|
...runtimeConfigOptions,
|
|
67
67
|
auth: {
|
|
68
|
-
|
|
68
|
+
tokenExpiration: runtimeConfigOptions.auth.tokenExpiration,
|
|
69
|
+
rememberMeExpiration: runtimeConfigOptions.auth.rememberMeExpiration,
|
|
70
|
+
permissions: runtimeConfigOptions.auth.permissions,
|
|
71
|
+
...runtimeConfigOptions.auth.google && { google: runtimeConfigOptions.auth.google },
|
|
69
72
|
whitelist: (() => {
|
|
70
73
|
const combinedWhitelist = [...defaultOptions.auth?.whitelist || [], ...runtimeConfigOptions.auth?.whitelist || []];
|
|
74
|
+
const apiBasePath = runtimeConfigOptions.apiBasePath || defaultOptions.apiBasePath;
|
|
71
75
|
if (combinedWhitelist.includes("/register")) {
|
|
72
|
-
const apiBasePath = runtimeConfigOptions.apiBasePath || defaultOptions.apiBasePath;
|
|
73
76
|
const registrationEndpoints = [
|
|
74
77
|
"/confirm-email",
|
|
75
78
|
// Page route for email confirmation
|
|
@@ -84,6 +87,17 @@ const module = defineNuxtModule({
|
|
|
84
87
|
}
|
|
85
88
|
});
|
|
86
89
|
}
|
|
90
|
+
if (runtimeConfigOptions.auth?.google) {
|
|
91
|
+
const googleOAuthEndpoints = [
|
|
92
|
+
`${apiBasePath}/auth/google/redirect`,
|
|
93
|
+
`${apiBasePath}/auth/google/callback`
|
|
94
|
+
];
|
|
95
|
+
googleOAuthEndpoints.forEach((endpoint) => {
|
|
96
|
+
if (!combinedWhitelist.includes(endpoint)) {
|
|
97
|
+
combinedWhitelist.push(endpoint);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
87
101
|
return combinedWhitelist;
|
|
88
102
|
})()
|
|
89
103
|
}
|
|
@@ -94,8 +108,8 @@ const module = defineNuxtModule({
|
|
|
94
108
|
auth: {
|
|
95
109
|
whitelist: (() => {
|
|
96
110
|
const combinedWhitelist = [...defaultOptions.auth?.whitelist || [], ...runtimeConfigOptions.auth?.whitelist || []];
|
|
111
|
+
const apiBasePath = runtimeConfigOptions.apiBasePath || defaultOptions.apiBasePath;
|
|
97
112
|
if (combinedWhitelist.includes("/register")) {
|
|
98
|
-
const apiBasePath = runtimeConfigOptions.apiBasePath || defaultOptions.apiBasePath;
|
|
99
113
|
const registrationEndpoints = [
|
|
100
114
|
"/confirm-email",
|
|
101
115
|
// Page route for email confirmation
|
|
@@ -110,6 +124,17 @@ const module = defineNuxtModule({
|
|
|
110
124
|
}
|
|
111
125
|
});
|
|
112
126
|
}
|
|
127
|
+
if (runtimeConfigOptions.auth?.google) {
|
|
128
|
+
const googleOAuthEndpoints = [
|
|
129
|
+
`${apiBasePath}/auth/google/redirect`,
|
|
130
|
+
`${apiBasePath}/auth/google/callback`
|
|
131
|
+
];
|
|
132
|
+
googleOAuthEndpoints.forEach((endpoint) => {
|
|
133
|
+
if (!combinedWhitelist.includes(endpoint)) {
|
|
134
|
+
combinedWhitelist.push(endpoint);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
113
138
|
return combinedWhitelist;
|
|
114
139
|
})(),
|
|
115
140
|
permissions: runtimeConfigOptions.auth?.permissions || defaultOptions.auth.permissions
|
|
@@ -177,6 +202,16 @@ const module = defineNuxtModule({
|
|
|
177
202
|
method: "get",
|
|
178
203
|
handler: resolver.resolve("./runtime/server/api/nuxt-users/confirm-email.get")
|
|
179
204
|
});
|
|
205
|
+
addServerHandler({
|
|
206
|
+
route: `${base}/auth/google/redirect`,
|
|
207
|
+
method: "get",
|
|
208
|
+
handler: resolver.resolve("./runtime/server/api/nuxt-users/auth/google/redirect.get")
|
|
209
|
+
});
|
|
210
|
+
addServerHandler({
|
|
211
|
+
route: `${base}/auth/google/callback`,
|
|
212
|
+
method: "get",
|
|
213
|
+
handler: resolver.resolve("./runtime/server/api/nuxt-users/auth/google/callback.get")
|
|
214
|
+
});
|
|
180
215
|
addServerHandler({
|
|
181
216
|
route: `${base}`,
|
|
182
217
|
method: "get",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--nu-color-primary:#3b82f6;--nu-color-primary-dark:#2563eb;--nu-color-primary-light:#60a5fa;--nu-color-white:#fff;--nu-color-gray-50:#f9fafb;--nu-color-gray-500:#6b7280;--nu-color-gray-600:#4b5563;--nu-color-gray-700:#374151;--nu-color-gray-900:#111827;--nu-color-success:#059669;--nu-color-success-light:#f0fdf4;--nu-color-success-border:#9ae6b4;--nu-color-error:#dc2626;--nu-color-error-light:#fef2f2;--nu-color-error-border:#fecaca;--nu-color-error-alt:#db5050;--nu-color-error-dark:#b91c1c;--nu-color-border:#e5e7eb;--nu-color-border-light:#d1d5db;--nu-color-border-dark:#ccc;--nu-color-bg-primary:#fff;--nu-color-bg-secondary:#f9fafb;--nu-color-bg-tertiary:#f3f4f6;--nu-color-text-primary:#000;--nu-color-text-secondary:#6b7280;--nu-color-strength-bg:#e9ecef;--nu-color-validation-passed:#28a745;--nu-color-validation-failed:#dc3545;--nu-color-validation-hint:#6c757d}.dark :root{--nu-color-primary:#60a5fa;--nu-color-primary-dark:#3b82f6;--nu-color-primary-light:#93c5fd;--nu-color-white:#000;--nu-color-gray-50:#111827;--nu-color-gray-500:#9ca3af;--nu-color-gray-600:#d1d5db;--nu-color-gray-700:#e5e7eb;--nu-color-gray-900:#f9fafb;--nu-color-success:#10b981;--nu-color-success-light:#064e3b;--nu-color-success-border:#065f46;--nu-color-error:#ef4444;--nu-color-error-light:#450a0a;--nu-color-error-border:#7f1d1d;--nu-color-error-alt:#f87171;--nu-color-error-dark:#dc2626;--nu-color-border:#374151;--nu-color-border-light:#4b5563;--nu-color-border-dark:#6b7280;--nu-color-bg-primary:#111827;--nu-color-bg-secondary:#1f2937;--nu-color-bg-tertiary:#374151;--nu-color-text-primary:#fff;--nu-color-text-secondary:#9ca3af;--nu-color-strength-bg:#374151;--nu-color-validation-passed:#22c55e;--nu-color-validation-failed:#ef4444;--nu-color-validation-hint:#9ca3af}.n-users-form-group{display:flex;flex-direction:column;gap:.5rem;margin-bottom:1rem;width:100%}.n-users-form-group.n-users-form-group-narrow{width:90%}.n-users-form-group label,.n-users-form-label{color:var(--nu-color-text-primary,#000);display:block;font-size:1rem;font-weight:500;margin-bottom:.5rem}.n-users-form-group input,.n-users-form-group select,.n-users-form-input{border:1px solid var(--nu-color-border,#ccc);border-radius:.25rem;font-size:1rem;padding:.5rem;transition:border-color .2s,box-shadow .2s;width:100%}.n-users-form-group input:focus,.n-users-form-group select:focus,.n-users-form-input:focus{border-color:var(--nu-color-primary);box-shadow:0 0 0 .1rem rgba(59,130,246,.1);outline:none}.n-users-form-group input:disabled,.n-users-form-input:disabled{background-color:var(--nu-color-bg-secondary,#f9fafb);cursor:not-allowed}.n-users-form-group input.error,.n-users-form-input.error{border-color:var(--nu-color-error,#dc3545)}.n-users-form-group input[type=email],.n-users-form-group input[type=password],.n-users-form-group input[type=text]{background-color:var(--nu-color-bg-secondary);border:1px solid var(--nu-color-border-light);border-radius:.5em;box-sizing:border-box;color:var(--nu-color-gray-700);font-size:.875rem;padding:.75em 1em;transition:all .2s ease-in-out;width:100%}.n-users-form-group input[type=email]:focus,.n-users-form-group input[type=password]:focus,.n-users-form-group input[type=text]:focus{background-color:var(--nu-color-bg-primary);border-color:var(--nu-color-primary);box-shadow:0 0 0 3px rgba(59,130,246,.1);outline:none}.n-users-form-group input[type=checkbox]{margin:0;width:auto}.n-users-btn,.n-users-cancel-btn,.n-users-delete-btn,.n-users-edit-btn,.n-users-submit-btn{align-self:flex-start;border:none;border-radius:.25rem;cursor:pointer;display:inline-block;font-size:1rem;font-weight:500;padding:.5rem 1rem;text-decoration:none;transition:background-color .2s,transform .1s}.n-users-btn:hover,.n-users-edit-btn:hover,.n-users-submit-btn:hover{background-color:var(--nu-color-primary-dark,#2563eb);transform:translateY(-1px)}.n-users-btn:disabled,.n-users-submit-btn:disabled{cursor:not-allowed;opacity:.6;transform:none}.n-users-btn-primary,.n-users-edit-btn,.n-users-submit-btn{background-color:var(--nu-color-primary,#3b82f6);color:#fff}.n-users-btn-secondary,.n-users-cancel-btn{background-color:var(--nu-color-gray-500,#6b7280);color:#fff}.n-users-cancel-btn:hover{background-color:var(--nu-color-gray-600,#4b5563)}.n-users-delete-btn{background-color:var(--nu-color-error,#ef4444);color:#fff}.n-users-delete-btn:hover{background-color:var(--nu-color-error-alt,#dc2626)}.n-users-login-section button[type=submit],.n-users-register-section button[type=submit],.n-users-reset-password-container button[type=submit],.n-users-user-form button[type=submit],form.n-users-form button[type=submit]{align-items:center;background-color:var(--nu-color-primary);border:1px solid var(--nu-color-primary);border-radius:.5em;color:var(--nu-color-white);cursor:pointer;display:flex;font-size:.875rem;font-weight:500;gap:.5rem;justify-content:center;min-height:44px;padding:.75em 1em;transition:all .2s ease-in-out;width:100%}.n-users-login-section button[type=submit]:hover:not(:disabled),.n-users-register-section button[type=submit]:hover:not(:disabled),.n-users-reset-password-container button[type=submit]:hover:not(:disabled),.n-users-user-form button[type=submit]:hover:not(:disabled),form.n-users-form button[type=submit]:hover:not(:disabled){background-color:var(--nu-color-primary-dark);border-color:var(--nu-color-primary-dark)}.n-users-login-section button[type=submit]:disabled,.n-users-register-section button[type=submit]:disabled,.n-users-reset-password-container button[type=submit]:disabled,.n-users-user-form button[type=submit]:disabled,form.n-users-form button[type=submit]:disabled{cursor:not-allowed;opacity:.6}.n-users-error-message,.n-users-error-text{background-color:var(--nu-color-error-light,#fef2f2);border:1px solid var(--nu-color-error-border,#fecaca);border-radius:.5rem;color:var(--nu-color-error,#dc3545);font-size:.875rem;margin-top:.5rem;padding:.75rem 1rem}.n-users-success-message{background-color:var(--nu-color-success-light,#f0fff4);border:1px solid var(--nu-color-success-border,#9ae6b4);border-radius:.5rem;color:var(--nu-color-success,#10b981);font-size:.875rem;margin-top:.5rem;padding:.75rem 1rem}.n-users-grid{display:grid;gap:1rem}.n-users-grid-2{grid-template-columns:1fr 5fr}.n-users-grid-auto{grid-template-columns:repeat(auto-fill,minmax(12em,1fr))}.n-users-form-actions{align-items:center;display:flex;gap:1rem;margin-top:1.5rem}.n-users-loading-spinner{animation:n-users-spin 1s linear infinite;border:2px solid var(--nu-color-white,#fff);border-radius:50%;border-top:2px solid transparent;height:16px;width:16px}@keyframes n-users-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.n-users-card{background-color:var(--nu-color-bg-primary,#fff);border:1px solid var(--nu-color-border,#e5e7eb);border-radius:.5rem;padding:1rem}.n-users-section{margin:0 auto;max-width:42em;padding:1em}.n-users-section-header{border-bottom:.1em solid var(--nu-color-border,#e5e7eb);margin-bottom:1rem;padding-bottom:.5rem}.n-users-form-help{color:var(--nu-color-text-secondary,#6b7280);font-size:.75rem;margin-top:.25rem}.n-users-strength-bar{background-color:var(--nu-color-strength-bg,#e9ecef);border-radius:2px;height:4px;margin-bottom:4px;overflow:hidden;width:100%}.n-users-strength-fill{height:100%;transition:width .3s ease,background-color .3s ease}.n-users-strength-text{font-size:.75rem;font-weight:500}.n-users-validation-container{background-color:#f8f9fa;border:1px solid #e9ecef;border-radius:4px;margin-top:12px;padding:12px}.n-users-container-title{color:#495057;font-size:.875rem;font-weight:600;margin-bottom:8px}.n-users-list-unstyled{list-style:none;margin:0;padding-left:0}.n-users-list-item{align-items:center;display:flex;font-size:.875rem;margin-bottom:6px;transition:color .2s ease}.n-users-list-item:last-child{margin-bottom:0}.n-users-icon{font-weight:700;margin-right:8px;min-width:16px;text-align:center}.n-users-text{flex:1}.n-users-list ul{list-style:none}.n-users-login-section form,.n-users-register-section form,.n-users-reset-password-container form,.n-users-user-form form,form.n-users-form{display:flex;flex-direction:column;gap:1.5rem}.n-users-login-section{background:linear-gradient(135deg,var(--nu-color-bg-primary) 0,var(--nu-color-bg-secondary) 100%);border:1px solid var(--nu-color-border);border-radius:.75em;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);max-width:25rem}.n-users-login-header{margin-bottom:1em;text-align:center}.n-users-login-title{color:var(--nu-color-gray-700);font-size:1.875rem;font-weight:700;line-height:1.2;margin:0 0 .5em}.n-users-login-subtitle{color:var(--nu-color-gray-700);font-size:.875rem;line-height:1.5;margin:0}.n-users-remember-me{align-items:center;display:flex;gap:.5rem}.n-users-remember-me label{color:var(--nu-color-gray-700);font-size:.875rem;margin:0}.n-users-login-footer{margin-top:1em;text-align:center}.n-users-forgot-password{margin:0}.n-users-forgot-link{align-items:center;color:var(--nu-color-primary);display:inline-flex;font-size:.875rem;gap:.5rem;text-decoration:none;transition:color .2s ease-in-out}.n-users-forgot-link:hover:not(.loading){color:var(--nu-color-primary-dark);text-decoration:underline}.n-users-forgot-link.loading{cursor:not-allowed;opacity:.6;pointer-events:none}.n-users-password-strength{margin-top:8px}.n-users-validation-rules{margin-top:12px}.n-users-rules-title{margin-bottom:8px}.n-users-rules-list{padding-left:0}.n-users-rule-item{margin-bottom:6px}.n-users-rule-item:last-child{margin-bottom:0}.n-users-rule-passed{color:var(--nu-color-validation-passed,#28a745)}.n-users-rule-failed{color:var(--nu-color-validation-failed,#dc3545)}.n-users-rule-icon{margin-right:8px}.n-users-rule-text{flex:1}.n-users-validation-errors{margin-top:8px}.n-users-error-text:last-child{margin-bottom:0}.n-users-password-hints{margin-top:8px}.n-users-hint-title{margin-bottom:8px}.n-users-hint-list{padding-left:16px}.n-users-hint-item{color:var(--nu-color-validation-hint,#6c757d);margin-bottom:4px}.n-users-hint-item:last-child{margin-bottom:0}.n-users-logout-link{background:var(--nu-color-error);border:2px solid transparent;border-color:var(--nu-color-error-dark);border-radius:.5em;color:#fff;padding:.5em 1em;text-decoration:none}.n-users-logout-link:hover{border-color:var(--nu-color-primary)}.n-users-user-card dd{margin:0}.n-users-user-card-actions{display:flex;gap:.5rem;margin-top:1rem}.n-users-user-form{margin:0 auto;max-width:500px}.n-users-form-group input.error{border-color:#dc3545}.n-users-profile-info{background-color:var(--nu-color-bg-primary);border-top-left-radius:.5em;border-top-right-radius:.5em}.n-users-profile-details{font-size:1rem;list-style:none;margin:0;padding:0}.n-users-reset-password-container{background-color:var(--nu-color-bg-primary);border-bottom-left-radius:.5em;border-bottom-right-radius:.5em}@media (max-width:480px){.n-users-login-title{font-size:1.5rem}}.n-users-list-enter-active,.n-users-list-leave-active,.n-users-list-move{transition:all .3s ease}.n-users-list-enter-from,.n-users-list-leave-to{opacity:0;transform:translateX(2rem)}.n-users-list-leave-active{position:absolute}.n-users-list-move{transition-timing-function:ease}
|
|
1
|
+
:root{--nu-color-primary:#3b82f6;--nu-color-primary-dark:#2563eb;--nu-color-primary-light:#60a5fa;--nu-color-white:#fff;--nu-color-gray-50:#f9fafb;--nu-color-gray-500:#6b7280;--nu-color-gray-600:#4b5563;--nu-color-gray-700:#374151;--nu-color-gray-900:#111827;--nu-color-success:#059669;--nu-color-success-light:#f0fdf4;--nu-color-success-border:#9ae6b4;--nu-color-error:#dc2626;--nu-color-error-light:#fef2f2;--nu-color-error-border:#fecaca;--nu-color-error-alt:#db5050;--nu-color-error-dark:#b91c1c;--nu-color-border:#e5e7eb;--nu-color-border-light:#d1d5db;--nu-color-border-dark:#ccc;--nu-color-bg-primary:#fff;--nu-color-bg-secondary:#f9fafb;--nu-color-bg-tertiary:#f3f4f6;--nu-color-text-primary:#000;--nu-color-text-secondary:#6b7280;--nu-color-strength-bg:#e9ecef;--nu-color-validation-passed:#28a745;--nu-color-validation-failed:#dc3545;--nu-color-validation-hint:#6c757d}.dark :root{--nu-color-primary:#60a5fa;--nu-color-primary-dark:#3b82f6;--nu-color-primary-light:#93c5fd;--nu-color-white:#000;--nu-color-gray-50:#111827;--nu-color-gray-500:#9ca3af;--nu-color-gray-600:#d1d5db;--nu-color-gray-700:#e5e7eb;--nu-color-gray-900:#f9fafb;--nu-color-success:#10b981;--nu-color-success-light:#064e3b;--nu-color-success-border:#065f46;--nu-color-error:#ef4444;--nu-color-error-light:#450a0a;--nu-color-error-border:#7f1d1d;--nu-color-error-alt:#f87171;--nu-color-error-dark:#dc2626;--nu-color-border:#374151;--nu-color-border-light:#4b5563;--nu-color-border-dark:#6b7280;--nu-color-bg-primary:#111827;--nu-color-bg-secondary:#1f2937;--nu-color-bg-tertiary:#374151;--nu-color-text-primary:#fff;--nu-color-text-secondary:#9ca3af;--nu-color-strength-bg:#374151;--nu-color-validation-passed:#22c55e;--nu-color-validation-failed:#ef4444;--nu-color-validation-hint:#9ca3af}.n-users-form-group{display:flex;flex-direction:column;gap:.5rem;margin-bottom:1rem;width:100%}.n-users-form-group.n-users-form-group-narrow{width:90%}.n-users-form-group label,.n-users-form-label{color:var(--nu-color-text-primary,#000);display:block;font-size:1rem;font-weight:500;margin-bottom:.5rem}.n-users-form-group input,.n-users-form-group select,.n-users-form-input{border:1px solid var(--nu-color-border,#ccc);border-radius:.25rem;font-size:1rem;padding:.5rem;transition:border-color .2s,box-shadow .2s;width:100%}.n-users-form-group input:focus,.n-users-form-group select:focus,.n-users-form-input:focus{border-color:var(--nu-color-primary);box-shadow:0 0 0 .1rem rgba(59,130,246,.1);outline:none}.n-users-form-group input:disabled,.n-users-form-input:disabled{background-color:var(--nu-color-bg-secondary,#f9fafb);cursor:not-allowed}.n-users-form-group input.error,.n-users-form-input.error{border-color:var(--nu-color-error,#dc3545)}.n-users-form-group input[type=email],.n-users-form-group input[type=password],.n-users-form-group input[type=text]{background-color:var(--nu-color-bg-secondary);border:1px solid var(--nu-color-border-light);border-radius:.5em;box-sizing:border-box;color:var(--nu-color-gray-700);font-size:.875rem;padding:.75em 1em;transition:all .2s ease-in-out;width:100%}.n-users-form-group input[type=email]:focus,.n-users-form-group input[type=password]:focus,.n-users-form-group input[type=text]:focus{background-color:var(--nu-color-bg-primary);border-color:var(--nu-color-primary);box-shadow:0 0 0 3px rgba(59,130,246,.1);outline:none}.n-users-form-group input[type=checkbox]{margin:0;width:auto}.n-users-google-btn{align-items:center;display:inline-flex;gap:8px;justify-content:center}.n-users-google-logo{flex-shrink:0}.n-users-btn,.n-users-cancel-btn,.n-users-delete-btn,.n-users-edit-btn,.n-users-google-btn,.n-users-submit-btn{align-self:flex-start;border:none;border-radius:.25rem;cursor:pointer;display:inline-block;font-size:1rem;font-weight:500;padding:.5rem 1rem;text-decoration:none;transition:background-color .2s,transform .1s}.n-users-btn:hover,.n-users-edit-btn:hover,.n-users-submit-btn:hover{background-color:var(--nu-color-primary-dark,#2563eb);transform:translateY(-1px)}.n-users-btn:disabled,.n-users-submit-btn:disabled{cursor:not-allowed;opacity:.6;transform:none}.n-users-btn-primary,.n-users-edit-btn,.n-users-submit-btn{background-color:var(--nu-color-primary,#3b82f6);color:#fff}.n-users-btn-secondary,.n-users-cancel-btn{background-color:var(--nu-color-gray-500,#6b7280);color:#fff}.n-users-cancel-btn:hover{background-color:var(--nu-color-gray-600,#4b5563)}.n-users-delete-btn{background-color:var(--nu-color-error,#ef4444);color:#fff}.n-users-delete-btn:hover{background-color:var(--nu-color-error-alt,#dc2626)}.n-users-login-section button[type=submit],.n-users-register-section button[type=submit],.n-users-reset-password-container button[type=submit],.n-users-user-form button[type=submit],form.n-users-form button[type=submit]{align-items:center;background-color:var(--nu-color-primary);border:1px solid var(--nu-color-primary);border-radius:.5em;color:var(--nu-color-white);cursor:pointer;display:flex;font-size:.875rem;font-weight:500;gap:.5rem;justify-content:center;min-height:44px;padding:.75em 1em;transition:all .2s ease-in-out;width:100%}.n-users-login-section button[type=submit]:hover:not(:disabled),.n-users-register-section button[type=submit]:hover:not(:disabled),.n-users-reset-password-container button[type=submit]:hover:not(:disabled),.n-users-user-form button[type=submit]:hover:not(:disabled),form.n-users-form button[type=submit]:hover:not(:disabled){background-color:var(--nu-color-primary-dark);border-color:var(--nu-color-primary-dark)}.n-users-login-section button[type=submit]:disabled,.n-users-register-section button[type=submit]:disabled,.n-users-reset-password-container button[type=submit]:disabled,.n-users-user-form button[type=submit]:disabled,form.n-users-form button[type=submit]:disabled{cursor:not-allowed;opacity:.6}.n-users-error-message,.n-users-error-text{background-color:var(--nu-color-error-light,#fef2f2);border:1px solid var(--nu-color-error-border,#fecaca);border-radius:.5rem;color:var(--nu-color-error,#dc3545);font-size:.875rem;margin-top:.5rem;padding:.75rem 1rem}.n-users-success-message{background-color:var(--nu-color-success-light,#f0fff4);border:1px solid var(--nu-color-success-border,#9ae6b4);border-radius:.5rem;color:var(--nu-color-success,#10b981);font-size:.875rem;margin-top:.5rem;padding:.75rem 1rem}.n-users-grid{display:grid;gap:1rem}.n-users-grid-2{grid-template-columns:1fr 5fr}.n-users-grid-auto{grid-template-columns:repeat(auto-fill,minmax(12em,1fr))}.n-users-form-actions{align-items:center;display:flex;gap:1rem;margin-top:1.5rem}.n-users-loading-spinner{animation:n-users-spin 1s linear infinite;border:2px solid var(--nu-color-white,#fff);border-radius:50%;border-top:2px solid transparent;height:16px;width:16px}@keyframes n-users-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.n-users-card{background-color:var(--nu-color-bg-primary,#fff);border:1px solid var(--nu-color-border,#e5e7eb);border-radius:.5rem;padding:1rem}.n-users-section{margin:0 auto;max-width:42em;padding:1em}.n-users-section-header{border-bottom:.1em solid var(--nu-color-border,#e5e7eb);margin-bottom:1rem;padding-bottom:.5rem}.n-users-form-help{color:var(--nu-color-text-secondary,#6b7280);font-size:.75rem;margin-top:.25rem}.n-users-strength-bar{background-color:var(--nu-color-strength-bg,#e9ecef);border-radius:2px;height:4px;margin-bottom:4px;overflow:hidden;width:100%}.n-users-strength-fill{height:100%;transition:width .3s ease,background-color .3s ease}.n-users-strength-text{font-size:.75rem;font-weight:500}.n-users-validation-container{background-color:#f8f9fa;border:1px solid #e9ecef;border-radius:4px;margin-top:12px;padding:12px}.n-users-container-title{color:#495057;font-size:.875rem;font-weight:600;margin-bottom:8px}.n-users-list-unstyled{list-style:none;margin:0;padding-left:0}.n-users-list-item{align-items:center;display:flex;font-size:.875rem;margin-bottom:6px;transition:color .2s ease}.n-users-list-item:last-child{margin-bottom:0}.n-users-icon{font-weight:700;margin-right:8px;min-width:16px;text-align:center}.n-users-text{flex:1}.n-users-list ul{list-style:none}.n-users-login-section form,.n-users-register-section form,.n-users-reset-password-container form,.n-users-user-form form,form.n-users-form{display:flex;flex-direction:column;gap:1.5rem}.n-users-login-section{background:linear-gradient(135deg,var(--nu-color-bg-primary) 0,var(--nu-color-bg-secondary) 100%);border:1px solid var(--nu-color-border);border-radius:.75em;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);max-width:25rem}.n-users-login-header{margin-bottom:1em;text-align:center}.n-users-login-title{color:var(--nu-color-gray-700);font-size:1.875rem;font-weight:700;line-height:1.2;margin:0 0 .5em}.n-users-login-subtitle{color:var(--nu-color-gray-700);font-size:.875rem;line-height:1.5;margin:0}.n-users-remember-me{align-items:center;display:flex;gap:.5rem}.n-users-remember-me label{color:var(--nu-color-gray-700);font-size:.875rem;margin:0}.n-users-login-footer{margin-top:1em;text-align:center}.n-users-forgot-password{margin:0}.n-users-forgot-link{align-items:center;color:var(--nu-color-primary);display:inline-flex;font-size:.875rem;gap:.5rem;text-decoration:none;transition:color .2s ease-in-out}.n-users-forgot-link:hover:not(.loading){color:var(--nu-color-primary-dark);text-decoration:underline}.n-users-forgot-link.loading{cursor:not-allowed;opacity:.6;pointer-events:none}.n-users-password-strength{margin-top:8px}.n-users-validation-rules{margin-top:12px}.n-users-rules-title{margin-bottom:8px}.n-users-rules-list{padding-left:0}.n-users-rule-item{margin-bottom:6px}.n-users-rule-item:last-child{margin-bottom:0}.n-users-rule-passed{color:var(--nu-color-validation-passed,#28a745)}.n-users-rule-failed{color:var(--nu-color-validation-failed,#dc3545)}.n-users-rule-icon{margin-right:8px}.n-users-rule-text{flex:1}.n-users-validation-errors{margin-top:8px}.n-users-error-text:last-child{margin-bottom:0}.n-users-password-hints{margin-top:8px}.n-users-hint-title{margin-bottom:8px}.n-users-hint-list{padding-left:16px}.n-users-hint-item{color:var(--nu-color-validation-hint,#6c757d);margin-bottom:4px}.n-users-hint-item:last-child{margin-bottom:0}.n-users-logout-link{background:var(--nu-color-error);border:2px solid transparent;border-color:var(--nu-color-error-dark);border-radius:.5em;color:#fff;padding:.5em 1em;text-decoration:none}.n-users-logout-link:hover{border-color:var(--nu-color-primary)}.n-users-user-card dd{margin:0}.n-users-user-card-actions{display:flex;gap:.5rem;margin-top:1rem}.n-users-user-form{margin:0 auto;max-width:500px}.n-users-form-group input.error{border-color:#dc3545}.n-users-profile-info{background-color:var(--nu-color-bg-primary);border-top-left-radius:.5em;border-top-right-radius:.5em}.n-users-profile-details{font-size:1rem;list-style:none;margin:0;padding:0}.n-users-reset-password-container{background-color:var(--nu-color-bg-primary);border-bottom-left-radius:.5em;border-bottom-right-radius:.5em}@media (max-width:480px){.n-users-login-title{font-size:1.5rem}}.n-users-list-enter-active,.n-users-list-leave-active,.n-users-list-move{transition:all .3s ease}.n-users-list-enter-from,.n-users-list-leave-to{opacity:0;transform:translateX(2rem)}.n-users-list-leave-active{position:absolute}.n-users-list-move{transition-timing-function:ease}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
successTitle?: string;
|
|
3
|
+
errorTitle?: string;
|
|
4
|
+
loginButtonText?: string;
|
|
5
|
+
loginUrl?: string;
|
|
6
|
+
showLoginButton?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_11: {}, __VLS_13: {};
|
|
9
|
+
type __VLS_Slots = {} & {
|
|
10
|
+
'success-icon'?: (props: typeof __VLS_1) => any;
|
|
11
|
+
} & {
|
|
12
|
+
'success-content'?: (props: typeof __VLS_3) => any;
|
|
13
|
+
} & {
|
|
14
|
+
'success-actions'?: (props: typeof __VLS_5) => any;
|
|
15
|
+
} & {
|
|
16
|
+
'error-icon'?: (props: typeof __VLS_7) => any;
|
|
17
|
+
} & {
|
|
18
|
+
'error-content'?: (props: typeof __VLS_9) => any;
|
|
19
|
+
} & {
|
|
20
|
+
'error-actions'?: (props: typeof __VLS_11) => any;
|
|
21
|
+
} & {
|
|
22
|
+
'loading-content'?: (props: typeof __VLS_13) => any;
|
|
23
|
+
};
|
|
24
|
+
declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
25
|
+
successTitle: string;
|
|
26
|
+
errorTitle: string;
|
|
27
|
+
loginButtonText: string;
|
|
28
|
+
loginUrl: string;
|
|
29
|
+
showLoginButton: boolean;
|
|
30
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
31
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
32
|
+
declare const _default: typeof __VLS_export;
|
|
33
|
+
export default _default;
|
|
34
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
35
|
+
new (): {
|
|
36
|
+
$slots: S;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
@@ -21,14 +21,15 @@ type __VLS_Slots = {} & {
|
|
|
21
21
|
} & {
|
|
22
22
|
'loading-content'?: (props: typeof __VLS_13) => any;
|
|
23
23
|
};
|
|
24
|
-
declare const
|
|
24
|
+
declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
25
25
|
successTitle: string;
|
|
26
26
|
errorTitle: string;
|
|
27
27
|
loginButtonText: string;
|
|
28
28
|
loginUrl: string;
|
|
29
29
|
showLoginButton: boolean;
|
|
30
30
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
31
|
-
declare const
|
|
31
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
32
|
+
declare const _default: typeof __VLS_export;
|
|
32
33
|
export default _default;
|
|
33
34
|
type __VLS_WithSlots<T, S> = T & {
|
|
34
35
|
new (): {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/**
|
|
3
|
+
* Custom redirect endpoint for Google OAuth
|
|
4
|
+
* @default '/api/nuxt-users/auth/google/redirect'
|
|
5
|
+
*/
|
|
6
|
+
redirectEndpoint?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Button text
|
|
9
|
+
* @default 'Continue with Google'
|
|
10
|
+
*/
|
|
11
|
+
buttonText?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Show Google logo in button
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
showLogo?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Custom CSS class for button
|
|
19
|
+
*/
|
|
20
|
+
class?: string;
|
|
21
|
+
}
|
|
22
|
+
declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
23
|
+
click: () => any;
|
|
24
|
+
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
25
|
+
onClick?: (() => any) | undefined;
|
|
26
|
+
}>, {
|
|
27
|
+
buttonText: string;
|
|
28
|
+
showLogo: boolean;
|
|
29
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed } from "vue";
|
|
3
|
+
import { useRuntimeConfig, navigateTo } from "#imports";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
redirectEndpoint: { type: String, required: false },
|
|
6
|
+
buttonText: { type: String, required: false, default: "Continue with Google" },
|
|
7
|
+
showLogo: { type: Boolean, required: false, default: true },
|
|
8
|
+
class: { type: String, required: false }
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["click"]);
|
|
11
|
+
const { public: { nuxtUsers } } = useRuntimeConfig();
|
|
12
|
+
const { apiBasePath } = nuxtUsers;
|
|
13
|
+
const isLoading = ref(false);
|
|
14
|
+
const redirectEndpoint = computed(
|
|
15
|
+
() => props.redirectEndpoint || `${apiBasePath}/auth/google/redirect`
|
|
16
|
+
);
|
|
17
|
+
const handleGoogleLogin = async () => {
|
|
18
|
+
isLoading.value = true;
|
|
19
|
+
emit("click");
|
|
20
|
+
try {
|
|
21
|
+
await navigateTo(redirectEndpoint.value, { external: true });
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error("[Nuxt Users] Google OAuth redirect failed:", error);
|
|
24
|
+
} finally {
|
|
25
|
+
isLoading.value = false;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<button
|
|
32
|
+
type="button"
|
|
33
|
+
class="n-users-google-btn"
|
|
34
|
+
:class="[{ loading: isLoading }, props.class]"
|
|
35
|
+
:disabled="isLoading"
|
|
36
|
+
@click="handleGoogleLogin"
|
|
37
|
+
>
|
|
38
|
+
<!-- Loading spinner -->
|
|
39
|
+
<span
|
|
40
|
+
v-if="isLoading"
|
|
41
|
+
class="n-users-loading-spinner"
|
|
42
|
+
/>
|
|
43
|
+
|
|
44
|
+
<!-- Google logo SVG -->
|
|
45
|
+
<svg
|
|
46
|
+
v-if="showLogo && !isLoading"
|
|
47
|
+
class="n-users-google-logo"
|
|
48
|
+
viewBox="0 0 24 24"
|
|
49
|
+
width="18"
|
|
50
|
+
height="18"
|
|
51
|
+
>
|
|
52
|
+
<path
|
|
53
|
+
fill="#4285F4"
|
|
54
|
+
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
|
55
|
+
/>
|
|
56
|
+
<path
|
|
57
|
+
fill="#34A853"
|
|
58
|
+
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
|
59
|
+
/>
|
|
60
|
+
<path
|
|
61
|
+
fill="#FBBC05"
|
|
62
|
+
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
|
63
|
+
/>
|
|
64
|
+
<path
|
|
65
|
+
fill="#EA4335"
|
|
66
|
+
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
|
67
|
+
/>
|
|
68
|
+
</svg>
|
|
69
|
+
|
|
70
|
+
<!-- Button text -->
|
|
71
|
+
<span class="n-users-google-text">
|
|
72
|
+
{{ isLoading ? "Redirecting..." : buttonText }}
|
|
73
|
+
</span>
|
|
74
|
+
</button>
|
|
75
|
+
</template>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/**
|
|
3
|
+
* Custom redirect endpoint for Google OAuth
|
|
4
|
+
* @default '/api/nuxt-users/auth/google/redirect'
|
|
5
|
+
*/
|
|
6
|
+
redirectEndpoint?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Button text
|
|
9
|
+
* @default 'Continue with Google'
|
|
10
|
+
*/
|
|
11
|
+
buttonText?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Show Google logo in button
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
showLogo?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Custom CSS class for button
|
|
19
|
+
*/
|
|
20
|
+
class?: string;
|
|
21
|
+
}
|
|
22
|
+
declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
23
|
+
click: () => any;
|
|
24
|
+
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
25
|
+
onClick?: (() => any) | undefined;
|
|
26
|
+
}>, {
|
|
27
|
+
buttonText: string;
|
|
28
|
+
showLogo: boolean;
|
|
29
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
apiEndpoint?: string;
|
|
3
|
+
forgotPasswordEndpoint?: string;
|
|
4
|
+
redirectTo?: string;
|
|
5
|
+
}
|
|
6
|
+
declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_11: {}, __VLS_13: {
|
|
7
|
+
message: string;
|
|
8
|
+
}, __VLS_15: {
|
|
9
|
+
error: string;
|
|
10
|
+
};
|
|
11
|
+
type __VLS_Slots = {} & {
|
|
12
|
+
header?: (props: typeof __VLS_1) => any;
|
|
13
|
+
} & {
|
|
14
|
+
'email-field'?: (props: typeof __VLS_3) => any;
|
|
15
|
+
} & {
|
|
16
|
+
'password-field'?: (props: typeof __VLS_5) => any;
|
|
17
|
+
} & {
|
|
18
|
+
'remember-me'?: (props: typeof __VLS_7) => any;
|
|
19
|
+
} & {
|
|
20
|
+
'submit-button'?: (props: typeof __VLS_9) => any;
|
|
21
|
+
} & {
|
|
22
|
+
footer?: (props: typeof __VLS_11) => any;
|
|
23
|
+
} & {
|
|
24
|
+
'success-message'?: (props: typeof __VLS_13) => any;
|
|
25
|
+
} & {
|
|
26
|
+
'error-message'?: (props: typeof __VLS_15) => any;
|
|
27
|
+
};
|
|
28
|
+
declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
29
|
+
error: (error: string) => any;
|
|
30
|
+
success: (user: UserWithoutPassword, rememberMe: boolean) => any;
|
|
31
|
+
submit: (data: LoginFormData) => any;
|
|
32
|
+
"forgot-password-error": (error: string) => any;
|
|
33
|
+
"forgot-password-success": () => any;
|
|
34
|
+
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
35
|
+
onError?: ((error: string) => any) | undefined;
|
|
36
|
+
onSuccess?: ((user: UserWithoutPassword, rememberMe: boolean) => any) | undefined;
|
|
37
|
+
onSubmit?: ((data: LoginFormData) => any) | undefined;
|
|
38
|
+
"onForgot-password-error"?: ((error: string) => any) | undefined;
|
|
39
|
+
"onForgot-password-success"?: (() => any) | undefined;
|
|
40
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
41
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
42
|
+
declare const _default: typeof __VLS_export;
|
|
43
|
+
export default _default;
|
|
44
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
45
|
+
new (): {
|
|
46
|
+
$slots: S;
|
|
47
|
+
};
|
|
48
|
+
};
|