nuxt-users 1.38.0 → 1.40.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 (94) hide show
  1. package/README.md +13 -1
  2. package/dist/cli.mjs +57 -27
  3. package/dist/module.d.mts +2 -2
  4. package/dist/module.d.ts +2 -2
  5. package/dist/module.json +4 -1
  6. package/dist/module.mjs +29 -7
  7. package/dist/runtime/assets/nuxt-users.css +1 -1
  8. package/dist/runtime/components/NUsersEmailConfirmation.d.vue.ts +5 -3
  9. package/dist/runtime/components/NUsersEmailConfirmation.vue +22 -15
  10. package/dist/runtime/components/NUsersEmailConfirmation.vue.d.ts +5 -3
  11. package/dist/runtime/components/NUsersGoogleLoginButton.d.vue.ts +4 -2
  12. package/dist/runtime/components/NUsersGoogleLoginButton.vue +5 -2
  13. package/dist/runtime/components/NUsersGoogleLoginButton.vue.d.ts +4 -2
  14. package/dist/runtime/components/NUsersList.vue +25 -11
  15. package/dist/runtime/components/NUsersLoginForm.d.vue.ts +13 -2
  16. package/dist/runtime/components/NUsersLoginForm.vue +35 -13
  17. package/dist/runtime/components/NUsersLoginForm.vue.d.ts +13 -2
  18. package/dist/runtime/components/NUsersLogoutLink.d.vue.ts +3 -4
  19. package/dist/runtime/components/NUsersLogoutLink.vue +8 -5
  20. package/dist/runtime/components/NUsersLogoutLink.vue.d.ts +3 -4
  21. package/dist/runtime/components/NUsersPasswordStrengthIndicator.d.vue.ts +6 -0
  22. package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue +17 -9
  23. package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue.d.ts +6 -0
  24. package/dist/runtime/components/NUsersProfileInfo.d.vue.ts +13 -1
  25. package/dist/runtime/components/NUsersProfileInfo.vue +23 -9
  26. package/dist/runtime/components/NUsersProfileInfo.vue.d.ts +13 -1
  27. package/dist/runtime/components/NUsersRegisterForm.d.vue.ts +26 -11
  28. package/dist/runtime/components/NUsersRegisterForm.vue +34 -16
  29. package/dist/runtime/components/NUsersRegisterForm.vue.d.ts +26 -11
  30. package/dist/runtime/components/NUsersResetPasswordForm.d.vue.ts +11 -2
  31. package/dist/runtime/components/NUsersResetPasswordForm.vue +25 -12
  32. package/dist/runtime/components/NUsersResetPasswordForm.vue.d.ts +11 -2
  33. package/dist/runtime/components/NUsersUserCard.d.vue.ts +2 -0
  34. package/dist/runtime/components/NUsersUserCard.vue +8 -4
  35. package/dist/runtime/components/NUsersUserCard.vue.d.ts +2 -0
  36. package/dist/runtime/components/NUsersUserForm.d.vue.ts +2 -2
  37. package/dist/runtime/components/NUsersUserForm.vue +5 -4
  38. package/dist/runtime/components/NUsersUserForm.vue.d.ts +2 -2
  39. package/dist/runtime/composables/useAuthentication.js +14 -0
  40. package/dist/runtime/composables/useNuxtUsersLocale.d.ts +15 -0
  41. package/dist/runtime/composables/useNuxtUsersLocale.js +27 -0
  42. package/dist/runtime/composables/usePasswordValidation.d.ts +1 -1
  43. package/dist/runtime/composables/usePublicPaths.js +2 -1
  44. package/dist/runtime/locales/en.d.ts +2 -0
  45. package/dist/runtime/locales/en.js +130 -0
  46. package/dist/runtime/locales/hu.d.ts +3 -0
  47. package/dist/runtime/locales/hu.js +188 -0
  48. package/dist/runtime/locales/index.d.ts +5 -0
  49. package/dist/runtime/locales/index.js +8 -0
  50. package/dist/runtime/server/api/nuxt-users/[id].delete.js +1 -1
  51. package/dist/runtime/server/api/nuxt-users/[id].get.js +1 -1
  52. package/dist/runtime/server/api/nuxt-users/[id].patch.js +1 -1
  53. package/dist/runtime/server/api/nuxt-users/auth/google/callback.get.js +1 -1
  54. package/dist/runtime/server/api/nuxt-users/auth/google/redirect.get.js +1 -1
  55. package/dist/runtime/server/api/nuxt-users/confirm-email.get.js +3 -3
  56. package/dist/runtime/server/api/nuxt-users/inactive.get.js +1 -2
  57. package/dist/runtime/server/api/nuxt-users/index.get.js +1 -2
  58. package/dist/runtime/server/api/nuxt-users/index.post.js +1 -1
  59. package/dist/runtime/server/api/nuxt-users/me.get.js +20 -13
  60. package/dist/runtime/server/api/nuxt-users/me.patch.js +1 -1
  61. package/dist/runtime/server/api/nuxt-users/password/forgot.post.js +2 -1
  62. package/dist/runtime/server/api/nuxt-users/password/index.patch.js +1 -1
  63. package/dist/runtime/server/api/nuxt-users/password/reset.post.d.ts +1 -1
  64. package/dist/runtime/server/api/nuxt-users/password/reset.post.js +4 -2
  65. package/dist/runtime/server/api/nuxt-users/session/index.delete.js +1 -1
  66. package/dist/runtime/server/api/nuxt-users/session/index.post.js +5 -3
  67. package/dist/runtime/server/composables/useServerAuth.js +1 -1
  68. package/dist/runtime/server/internal/index.d.ts +1 -7
  69. package/dist/runtime/server/internal/index.js +23 -7
  70. package/dist/runtime/server/middleware/authorization.server.js +22 -5
  71. package/dist/runtime/server/tasks/cleanup-tokens.d.ts +1 -1
  72. package/dist/runtime/server/utils/add-indexes.d.ts +3 -0
  73. package/dist/runtime/server/utils/add-indexes.js +17 -0
  74. package/dist/runtime/server/utils/google-oauth.js +2 -1
  75. package/dist/runtime/server/utils/index.d.ts +2 -2
  76. package/dist/runtime/server/utils/index.js +2 -2
  77. package/dist/runtime/server/utils/migrate.d.ts +6 -0
  78. package/dist/runtime/server/utils/migrate.js +10 -1
  79. package/dist/runtime/utils/deep-merge.d.ts +8 -0
  80. package/dist/runtime/utils/deep-merge.js +17 -0
  81. package/dist/runtime/utils/locale.d.ts +14 -0
  82. package/dist/runtime/utils/locale.js +38 -0
  83. package/dist/shared/{nuxt-users.BnOQs2LI.mjs → nuxt-users.DfZ7bc_P.mjs} +16 -8
  84. package/dist/shared/{nuxt-users.SXaMnaEL.d.mts → nuxt-users.XW6DYM7t.d.mts} +46 -2
  85. package/dist/shared/{nuxt-users.SXaMnaEL.d.ts → nuxt-users.XW6DYM7t.d.ts} +46 -2
  86. package/dist/utils.d.mts +4 -1
  87. package/dist/utils.d.ts +4 -1
  88. package/dist/utils.mjs +4 -1
  89. package/package.json +11 -6
  90. package/scripts/check-locale-consistency.ts +156 -0
  91. package/scripts/check-peer-dependencies.js +5 -5
  92. package/scripts/check-translations.ts +255 -0
  93. package/scripts/post-build.js +1 -1
  94. package/scripts/test-nuxt3.sh +78 -0
package/README.md CHANGED
@@ -1,4 +1,12 @@
1
1
  # Nuxt Users
2
+ [![Context7](https://img.shields.io/badge/Context7-Indexed-blue)](https://context7.com/rrd108/nuxt-users)
3
+ [![npm version](https://img.shields.io/npm/v/nuxt-users/latest.svg)](https://www.npmjs.com/package/nuxt-users)
4
+ [![npm downloads](https://img.shields.io/npm/dm/nuxt-users.svg)](https://www.npmjs.com/package/nuxt-users)
5
+ [![License](https://img.shields.io/npm/l/nuxt-users.svg)](https://github.com/rrd108/nuxt-users/blob/main/LICENSE)
6
+ [![ci](https://github.com/rrd108/nuxt-users/actions/workflows/ci.yml/badge.svg)](https://github.com/rrd108/nuxt-users/actions/workflows/ci.yml)
7
+ [![Nuxt 3](https://img.shields.io/badge/Nuxt-3-00DC82.svg?logo=nuxt.js&logoColor=white)](https://nuxt.com)
8
+ [![Nuxt 4](https://img.shields.io/badge/Nuxt-4-00DC82.svg?logo=nuxt.js&logoColor=white)](https://nuxt.com)
9
+
2
10
 
3
11
  A user authentication module for Nuxt 3 and Nuxt 4 with database support for SQLite, MySQL, and PostgreSQL.
4
12
 
@@ -39,7 +47,7 @@ A user authentication module for Nuxt 3 and Nuxt 4 with database support for SQL
39
47
 
40
48
  MIT
41
49
 
42
- ## Dev misc
50
+ ## Dev Misc
43
51
 
44
52
  ### Using yalc
45
53
 
@@ -49,4 +57,8 @@ yalc publish
49
57
 
50
58
  # Install the module in the consumer app
51
59
  yalc add nuxt-users
60
+
61
+ # Clean up consumer app
62
+ yalc remove nuxt-users
63
+ yarn add nuxt-users
52
64
  ```
package/dist/cli.mjs CHANGED
@@ -4,11 +4,12 @@ import { readFileSync } from 'node:fs';
4
4
  import { defaultOptions } from './module.mjs';
5
5
  import { loadNuxt } from '@nuxt/kit';
6
6
  import { defu } from 'defu';
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
- import { g as getPasswordValidationOptions, v as validatePassword } from './shared/nuxt-users.BnOQs2LI.mjs';
7
+ import { runMigrations, createUser as createUser$1, createUsersTable as createUsersTable$1, createPersonalAccessTokensTable as createPersonalAccessTokensTable$1, createPasswordResetTokensTable as createPasswordResetTokensTable$1, createMigrationsTable as createMigrationsTable$1, useDb, checkTableExists, getAppliedMigrations } from '../dist/runtime/server/utils/index.js';
8
+ import { g as getPasswordValidationOptions, v as validatePassword } from './shared/nuxt-users.DfZ7bc_P.mjs';
9
+ import '../dist/runtime/locales/index.js';
10
+ import '../dist/runtime/utils/locale.js';
11
+ import '../dist/runtime/utils/deep-merge.js';
9
12
  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';
12
13
  import '../dist/runtime/server/internal/index.js';
13
14
 
14
15
  const getOptionsFromEnv = () => {
@@ -52,33 +53,58 @@ const getOptionsFromEnv = () => {
52
53
  const loadOptions = async () => {
53
54
  try {
54
55
  console.log("[Nuxt Users] Loading Nuxt project...");
56
+ console.log("[Nuxt Users] \u2139\uFE0F Note: CLI commands read .env files. If you use .env.local in development, export variables first:");
57
+ console.log("[Nuxt Users] set -a; source .env.local; set +a; npx nuxt-users <command>");
58
+ console.log("[Nuxt Users] In production, environment variables are set directly in the deployment environment.");
55
59
  const nuxt = await loadNuxt({ cwd: process.cwd(), ready: false });
56
60
  const topLevelConfig = nuxt.options.nuxtUsers;
57
- const originalRuntimeConfig = await (async () => {
58
- try {
59
- const configPath = await import('node:path').then((p) => p.resolve(process.cwd(), "nuxt.config.ts"));
60
- const config = await import(configPath).then((m) => m.default);
61
- return config?.runtimeConfig?.nuxtUsers;
62
- } catch {
63
- return nuxt.options.runtimeConfig?.nuxtUsers;
64
- }
65
- })();
61
+ const processedRuntimeConfig = nuxt.options.runtimeConfig?.nuxtUsers;
66
62
  await nuxt.close();
67
- if (topLevelConfig || originalRuntimeConfig) {
63
+ if (topLevelConfig || processedRuntimeConfig) {
68
64
  console.log("[Nuxt Users] Using configuration from nuxt.config");
69
- let mergedConfig = defu(topLevelConfig, originalRuntimeConfig, defaultOptions);
70
- const configuredConnector = topLevelConfig?.connector || originalRuntimeConfig?.connector;
71
- if (configuredConnector) {
72
- mergedConfig = {
73
- ...mergedConfig,
74
- connector: configuredConnector
75
- };
65
+ const { connector: _defaultConnector, ...defaultsWithoutConnector } = defaultOptions;
66
+ const mergedConfig = defu(topLevelConfig, processedRuntimeConfig, defaultsWithoutConnector);
67
+ const configuredConnector = topLevelConfig?.connector || processedRuntimeConfig?.connector;
68
+ mergedConfig.connector = configuredConnector || defaultOptions.connector;
69
+ if (mergedConfig.connector.name === "mysql" || mergedConfig.connector.name === "postgresql") {
70
+ const options = mergedConfig.connector.options;
71
+ const envOptions = {};
72
+ if (!options.user && process.env.DB_USER) {
73
+ envOptions.user = process.env.DB_USER;
74
+ }
75
+ if (!options.password && process.env.DB_PASSWORD) {
76
+ envOptions.password = process.env.DB_PASSWORD;
77
+ }
78
+ if (!options.host && process.env.DB_HOST) {
79
+ envOptions.host = process.env.DB_HOST;
80
+ }
81
+ if (!options.database && process.env.DB_NAME) {
82
+ envOptions.database = process.env.DB_NAME;
83
+ }
84
+ if (!options.port && process.env.DB_PORT) {
85
+ envOptions.port = Number.parseInt(process.env.DB_PORT);
86
+ }
87
+ if (Object.keys(envOptions).length > 0) {
88
+ mergedConfig.connector.options = { ...options, ...envOptions };
89
+ console.log("[Nuxt Users] Filled in missing connector options from environment variables");
90
+ }
91
+ const finalOptions = mergedConfig.connector.options;
92
+ if (!finalOptions.user || !finalOptions.password || !finalOptions.host || !finalOptions.database) {
93
+ console.warn("[Nuxt Users] Warning: MySQL/PostgreSQL connector options are incomplete.");
94
+ console.warn("[Nuxt Users] Required: user, password, host, database");
95
+ console.warn("[Nuxt Users] Found:", {
96
+ user: finalOptions.user || "(missing)",
97
+ password: finalOptions.password ? "***" : "(missing)",
98
+ host: finalOptions.host || "(missing)",
99
+ database: finalOptions.database || "(missing)"
100
+ });
101
+ console.warn("[Nuxt Users] Please set these in nuxt.config.ts or as environment variables (DB_USER, DB_PASSWORD, DB_HOST, DB_NAME)");
102
+ }
76
103
  }
77
104
  return mergedConfig;
78
- } else {
79
- console.log("[Nuxt Users] No nuxt-users configuration found, using environment variables");
80
- return getOptionsFromEnv();
81
105
  }
106
+ console.log("[Nuxt Users] No nuxt-users configuration found, using environment variables");
107
+ return getOptionsFromEnv();
82
108
  } catch (error) {
83
109
  console.log("[Nuxt Users] Could not load Nuxt project, using environment variables");
84
110
  console.error("[Nuxt Users] Error:", error);
@@ -327,7 +353,9 @@ const projectInfo = defineCommand({
327
353
  async run() {
328
354
  try {
329
355
  console.log("[Nuxt Users] Loading Nuxt project...");
330
- console.log("[Nuxt Users] \u2139\uFE0F Note: This command only reads .env files. If you use .env.local or other env files, export those variables first.");
356
+ console.log("[Nuxt Users] \u2139\uFE0F Note: CLI commands read .env files. If you use .env.local in development, export variables first:");
357
+ console.log("[Nuxt Users] set -a; source .env.local; set +a; npx nuxt-users <command>");
358
+ console.log("[Nuxt Users] In production, environment variables are set directly in the deployment environment.");
331
359
  const nuxt = await loadNuxt({ cwd: process.cwd() });
332
360
  console.log("[Nuxt Users] \u2705 Nuxt project loaded successfully!");
333
361
  console.log("[Nuxt Users] \u{1F4C1} Source directory:", nuxt.options.srcDir);
@@ -369,14 +397,16 @@ const projectInfo = defineCommand({
369
397
  console.log("[Nuxt Users] -", migration);
370
398
  });
371
399
  }
372
- } else {
400
+ }
401
+ if (!migrationsTableExists) {
373
402
  console.log("[Nuxt Users] Table exists: no \u274C");
374
403
  console.log('[Nuxt Users] \u27A1\uFE0F Run "npx nuxt-users migrate" to set up the database');
375
404
  }
376
405
  } catch (error) {
377
406
  console.log("[Nuxt Users] Status: \u26A0\uFE0F Error -", error instanceof Error ? error.message : "Unknown error");
378
407
  }
379
- } else {
408
+ }
409
+ if (!nuxtUsersConfig) {
380
410
  console.log("[Nuxt Users] \u26A0\uFE0F Nuxt Users module not configured in runtime config");
381
411
  }
382
412
  } catch (error) {
package/dist/module.d.mts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
- import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.SXaMnaEL.mjs';
2
+ import { M as ModuleOptions } from './shared/nuxt-users.XW6DYM7t.mjs';
3
3
  export * from '../dist/runtime/server/internal/index.js';
4
4
 
5
5
  declare const defaultOptions: ModuleOptions;
6
- declare const _default: _nuxt_schema.NuxtModule<RuntimeModuleOptions, RuntimeModuleOptions, false>;
6
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
7
7
 
8
8
  export { _default as default, defaultOptions };
package/dist/module.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
- import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.SXaMnaEL.js';
2
+ import { M as ModuleOptions } from './shared/nuxt-users.XW6DYM7t.js';
3
3
  export * from '../dist/runtime/server/internal/index.js';
4
4
 
5
5
  declare const defaultOptions: ModuleOptions;
6
- declare const _default: _nuxt_schema.NuxtModule<RuntimeModuleOptions, RuntimeModuleOptions, false>;
6
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
7
7
 
8
8
  export { _default as default, defaultOptions };
package/dist/module.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "nuxt-users",
3
3
  "configKey": "nuxtUsers",
4
- "version": "1.38.0",
4
+ "compatibility": {
5
+ "nuxt": ">=3.0.0"
6
+ },
7
+ "version": "1.40.0",
5
8
  "builder": {
6
9
  "@nuxt/module-builder": "1.0.2",
7
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { defineNuxtModule, createResolver, addPlugin, addImportsDir, addServerImportsDir, addServerHandler, addRouteMiddleware, addComponentsDir } from '@nuxt/kit';
1
+ import { defineNuxtModule, createResolver, addPlugin, addImportsDir, addServerImportsDir, addServerScanDir, addServerHandler, addRouteMiddleware, addComponentsDir } from '@nuxt/kit';
2
2
  import { defu } from 'defu';
3
3
  export * from '../dist/runtime/server/internal/index.js';
4
4
 
@@ -50,12 +50,22 @@ const defaultOptions = {
50
50
  requireSpecialChars: true,
51
51
  preventCommonPasswords: true
52
52
  },
53
- hardDelete: false
53
+ hardDelete: false,
54
+ locale: {
55
+ default: "en",
56
+ fallbackLocale: "en",
57
+ texts: {}
58
+ },
59
+ tokenCleanupSchedule: "0 2 * * *"
60
+ // Daily at 2 AM
54
61
  };
55
62
  const module$1 = defineNuxtModule({
56
63
  meta: {
57
64
  name: "nuxt-users",
58
- configKey: "nuxtUsers"
65
+ configKey: "nuxtUsers",
66
+ compatibility: {
67
+ nuxt: ">=3.0.0"
68
+ }
59
69
  },
60
70
  // Default configuration options of the Nuxt module
61
71
  defaults: defaultOptions,
@@ -63,6 +73,9 @@ const module$1 = defineNuxtModule({
63
73
  const resolver = createResolver(import.meta.url);
64
74
  const { connector: _defaultConnector, ...defaultsWithoutConnector } = defaultOptions;
65
75
  const runtimeConfigOptions = defu(nuxt.options.runtimeConfig.nuxtUsers || {}, options, defaultsWithoutConnector);
76
+ if (!runtimeConfigOptions.locale) {
77
+ runtimeConfigOptions.locale = defaultOptions.locale;
78
+ }
66
79
  const configuredConnector = nuxt.options.runtimeConfig.nuxtUsers?.connector || options.connector;
67
80
  runtimeConfigOptions.connector = configuredConnector || defaultOptions.connector;
68
81
  nuxt.options.runtimeConfig.nuxtUsers = {
@@ -108,6 +121,7 @@ const module$1 = defineNuxtModule({
108
121
  nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
109
122
  nuxt.options.runtimeConfig.public.nuxtUsers = {
110
123
  passwordValidation: runtimeConfigOptions.passwordValidation,
124
+ locale: runtimeConfigOptions.locale,
111
125
  auth: {
112
126
  whitelist: (() => {
113
127
  const combinedWhitelist = [...defaultOptions.auth?.whitelist || [], ...runtimeConfigOptions.auth?.whitelist || []];
@@ -154,6 +168,7 @@ const module$1 = defineNuxtModule({
154
168
  });
155
169
  addImportsDir(resolver.resolve("./runtime/composables"));
156
170
  addServerImportsDir(resolver.resolve("./runtime/server/composables"));
171
+ addServerScanDir(resolver.resolve("./runtime/server"));
157
172
  addServerHandler({
158
173
  middleware: true,
159
174
  handler: resolver.resolve("./runtime/server/middleware/authorization.server")
@@ -163,7 +178,7 @@ const module$1 = defineNuxtModule({
163
178
  path: resolver.resolve("./runtime/middleware/authorization.client"),
164
179
  global: true
165
180
  });
166
- const base = nuxt.options.runtimeConfig.nuxtUsers.apiBasePath || defaultOptions.apiBasePath;
181
+ const base = runtimeConfigOptions.apiBasePath || defaultOptions.apiBasePath;
167
182
  addServerHandler({
168
183
  route: `${base}/session`,
169
184
  method: "post",
@@ -248,11 +263,18 @@ const module$1 = defineNuxtModule({
248
263
  nitroConfig.experimental = nitroConfig.experimental || {};
249
264
  nitroConfig.experimental.database = true;
250
265
  nitroConfig.experimental.tasks = true;
251
- nitroConfig.scanDirs = nitroConfig.scanDirs || [];
252
- nitroConfig.scanDirs.push(resolver.resolve("./runtime/server/tasks"));
266
+ const cleanupSchedule = runtimeConfigOptions.tokenCleanupSchedule ?? defaultOptions.tokenCleanupSchedule;
267
+ if (cleanupSchedule) {
268
+ nitroConfig.scheduledTasks = nitroConfig.scheduledTasks || {};
269
+ nitroConfig.scheduledTasks[cleanupSchedule] = [
270
+ ...nitroConfig.scheduledTasks[cleanupSchedule] || [],
271
+ "nuxt-users:cleanup-tokens"
272
+ ];
273
+ console.log(`[Nuxt Users] \u{1F504} Token cleanup scheduled: ${cleanupSchedule}`);
274
+ }
253
275
  nitroConfig.prerender = nitroConfig.prerender || {};
254
276
  nitroConfig.prerender.ignore = nitroConfig.prerender.ignore || [];
255
- const apiBasePath = nuxt.options.runtimeConfig.nuxtUsers.apiBasePath || defaultOptions.apiBasePath;
277
+ const apiBasePath = runtimeConfigOptions.apiBasePath || defaultOptions.apiBasePath;
256
278
  const ignorePattern = `${apiBasePath}/**`;
257
279
  if (!nitroConfig.prerender.ignore.includes(ignorePattern)) {
258
280
  nitroConfig.prerender.ignore.push(ignorePattern);
@@ -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-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}
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-success-text:#047857;--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:#15803d;--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-success-text:#6ee7b7;--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;border:none;border-radius:.25rem;cursor:pointer;display:inline-flex;font-size:1rem;font-weight:500;gap:8px;justify-content:center;padding:.5rem 1rem;text-decoration:none;transition:background-color .2s,transform .1s}.n-users-google-logo{flex-shrink:0}.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-600,#4b5563);color:#fff}.n-users-cancel-btn:hover{background-color:var(--nu-color-gray-700,#374151)}.n-users-delete-btn{background-color:var(--nu-color-error-dark,#b91c1c);color:#fff}.n-users-delete-btn:hover{background-color:#991b1b}.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-dark,#b91c1c);font-size:.875rem;margin-top:.5rem;padding:.75rem 1rem}.n-users-success-message{background-color:var(--nu-color-success-light,#f0fdf4);border:1px solid var(--nu-color-success-border,#9ae6b4);border-radius:.5rem;color:var(--nu-color-success-text,#047857);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,#15803d)}.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-dark,#b91c1c);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}
@@ -2,6 +2,11 @@ interface Props {
2
2
  successTitle?: string;
3
3
  errorTitle?: string;
4
4
  loginButtonText?: string;
5
+ backToLoginText?: string;
6
+ processingTitle?: string;
7
+ processingMessage?: string;
8
+ successMessage?: string;
9
+ errorMessage?: string;
5
10
  loginUrl?: string;
6
11
  showLoginButton?: boolean;
7
12
  }
@@ -22,9 +27,6 @@ type __VLS_Slots = {} & {
22
27
  'loading-content'?: (props: typeof __VLS_13) => any;
23
28
  };
24
29
  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
30
  loginUrl: string;
29
31
  showLoginButton: boolean;
30
32
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -1,15 +1,22 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
3
  import { useRoute } from "#app";
4
+ import { useNuxtUsersLocale } from "../composables/useNuxtUsersLocale";
5
+ const { t } = useNuxtUsersLocale();
4
6
  const route = useRoute();
5
7
  const status = computed(() => route.query.status);
6
8
  const message = computed(() => route.query.message);
7
9
  const isSuccess = computed(() => status.value === "success");
8
10
  const isError = computed(() => status.value === "error");
9
11
  const _props = defineProps({
10
- successTitle: { type: String, required: false, default: "Email Confirmed!" },
11
- errorTitle: { type: String, required: false, default: "Confirmation Failed" },
12
- loginButtonText: { type: String, required: false, default: "Continue to Login" },
12
+ successTitle: { type: String, required: false },
13
+ errorTitle: { type: String, required: false },
14
+ loginButtonText: { type: String, required: false },
15
+ backToLoginText: { type: String, required: false },
16
+ processingTitle: { type: String, required: false },
17
+ processingMessage: { type: String, required: false },
18
+ successMessage: { type: String, required: false },
19
+ errorMessage: { type: String, required: false },
13
20
  loginUrl: { type: String, required: false, default: "/login" },
14
21
  showLoginButton: { type: Boolean, required: false, default: true }
15
22
  });
@@ -44,10 +51,10 @@ const _props = defineProps({
44
51
  <div class="n-users-section-header">
45
52
  <slot name="success-content">
46
53
  <h1 class="n-users-login-title">
47
- {{ successTitle }}
54
+ {{ _props.successTitle || t("emailConfirmation.successTitle") }}
48
55
  </h1>
49
56
  <div class="n-users-success-message">
50
- {{ message || "Your email has been confirmed and your account is now active." }}
57
+ {{ message || _props.successMessage || t("emailConfirmation.successMessage") }}
51
58
  </div>
52
59
  </slot>
53
60
  </div>
@@ -58,10 +65,10 @@ const _props = defineProps({
58
65
  class="n-users-form-actions"
59
66
  >
60
67
  <a
61
- :href="loginUrl"
68
+ :href="_props.loginUrl"
62
69
  class="n-users-btn n-users-btn-primary"
63
70
  >
64
- {{ loginButtonText }}
71
+ {{ _props.loginButtonText || t("emailConfirmation.loginButton") }}
65
72
  </a>
66
73
  </div>
67
74
  </slot>
@@ -69,7 +76,7 @@ const _props = defineProps({
69
76
 
70
77
  <!-- Error state -->
71
78
  <div
72
- v-else-if="isError"
79
+ v-if="isError"
73
80
  class="n-users-confirmation-content"
74
81
  >
75
82
  <slot name="error-icon">
@@ -104,10 +111,10 @@ const _props = defineProps({
104
111
  <div class="n-users-section-header">
105
112
  <slot name="error-content">
106
113
  <h1 class="n-users-login-title">
107
- {{ errorTitle }}
114
+ {{ _props.errorTitle || t("emailConfirmation.errorTitle") }}
108
115
  </h1>
109
116
  <div class="n-users-error-message">
110
- {{ message || "The confirmation link is invalid or has expired. Please try registering again or contact support." }}
117
+ {{ message || _props.errorMessage || t("emailConfirmation.errorMessage") }}
111
118
  </div>
112
119
  </slot>
113
120
  </div>
@@ -115,10 +122,10 @@ const _props = defineProps({
115
122
  <slot name="error-actions">
116
123
  <div class="n-users-form-actions">
117
124
  <a
118
- :href="loginUrl"
125
+ :href="_props.loginUrl"
119
126
  class="n-users-btn n-users-btn-secondary"
120
127
  >
121
- Back to Login
128
+ {{ _props.backToLoginText || t("emailConfirmation.backToLogin") }}
122
129
  </a>
123
130
  </div>
124
131
  </slot>
@@ -126,7 +133,7 @@ const _props = defineProps({
126
133
 
127
134
  <!-- Loading/unknown state -->
128
135
  <div
129
- v-else
136
+ v-if="!isError"
130
137
  class="n-users-confirmation-content"
131
138
  >
132
139
  <slot name="loading-content">
@@ -135,10 +142,10 @@ const _props = defineProps({
135
142
  </div>
136
143
  <div class="n-users-section-header">
137
144
  <h1 class="n-users-login-title">
138
- Processing...
145
+ {{ _props.processingTitle || t("emailConfirmation.processing") }}
139
146
  </h1>
140
147
  <div class="n-users-form-help">
141
- Please wait while we process your email confirmation.
148
+ {{ _props.processingMessage || t("emailConfirmation.processingMessage") }}
142
149
  </div>
143
150
  </div>
144
151
  </slot>
@@ -2,6 +2,11 @@ interface Props {
2
2
  successTitle?: string;
3
3
  errorTitle?: string;
4
4
  loginButtonText?: string;
5
+ backToLoginText?: string;
6
+ processingTitle?: string;
7
+ processingMessage?: string;
8
+ successMessage?: string;
9
+ errorMessage?: string;
5
10
  loginUrl?: string;
6
11
  showLoginButton?: boolean;
7
12
  }
@@ -22,9 +27,6 @@ type __VLS_Slots = {} & {
22
27
  'loading-content'?: (props: typeof __VLS_13) => any;
23
28
  };
24
29
  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
30
  loginUrl: string;
29
31
  showLoginButton: boolean;
30
32
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -6,9 +6,12 @@ interface Props {
6
6
  redirectEndpoint?: string;
7
7
  /**
8
8
  * Button text
9
- * @default 'Continue with Google'
10
9
  */
11
10
  buttonText?: string;
11
+ /**
12
+ * Redirecting text
13
+ */
14
+ redirectingText?: string;
12
15
  /**
13
16
  * Show Google logo in button
14
17
  * @default true
@@ -24,7 +27,6 @@ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {},
24
27
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
25
28
  onClick?: (() => any) | undefined;
26
29
  }>, {
27
- buttonText: string;
28
30
  showLogo: boolean;
29
31
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
32
  declare const _default: typeof __VLS_export;
@@ -1,9 +1,12 @@
1
1
  <script setup>
2
2
  import { ref, computed } from "vue";
3
3
  import { useRuntimeConfig, navigateTo } from "#imports";
4
+ import { useNuxtUsersLocale } from "../composables/useNuxtUsersLocale";
5
+ const { t } = useNuxtUsersLocale();
4
6
  const props = defineProps({
5
7
  redirectEndpoint: { type: String, required: false },
6
- buttonText: { type: String, required: false, default: "Continue with Google" },
8
+ buttonText: { type: String, required: false },
9
+ redirectingText: { type: String, required: false },
7
10
  showLogo: { type: Boolean, required: false, default: true },
8
11
  class: { type: String, required: false }
9
12
  });
@@ -69,7 +72,7 @@ const handleGoogleLogin = async () => {
69
72
 
70
73
  <!-- Button text -->
71
74
  <span class="n-users-google-text">
72
- {{ isLoading ? "Redirecting..." : buttonText }}
75
+ {{ isLoading ? props.redirectingText || t("googleLogin.redirecting") : props.buttonText || t("googleLogin.buttonText") }}
73
76
  </span>
74
77
  </button>
75
78
  </template>
@@ -6,9 +6,12 @@ interface Props {
6
6
  redirectEndpoint?: string;
7
7
  /**
8
8
  * Button text
9
- * @default 'Continue with Google'
10
9
  */
11
10
  buttonText?: string;
11
+ /**
12
+ * Redirecting text
13
+ */
14
+ redirectingText?: string;
12
15
  /**
13
16
  * Show Google logo in button
14
17
  * @default true
@@ -24,7 +27,6 @@ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {},
24
27
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
25
28
  onClick?: (() => any) | undefined;
26
29
  }>, {
27
- buttonText: string;
28
30
  showLogo: boolean;
29
31
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
32
  declare const _default: typeof __VLS_export;