nuxt-users 1.40.3 → 1.41.1

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/dist/cli.mjs CHANGED
@@ -5,7 +5,7 @@ import { defaultOptions } from './module.mjs';
5
5
  import { loadNuxt } from '@nuxt/kit';
6
6
  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, 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';
8
+ import { g as getPasswordValidationOptions, v as validatePassword } from './shared/nuxt-users.Cvjgn5KJ.mjs';
9
9
  import '../dist/runtime/locales/index.js';
10
10
  import '../dist/runtime/utils/locale.js';
11
11
  import '../dist/runtime/utils/deep-merge.js';
package/dist/module.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
- import { M as ModuleOptions } from './shared/nuxt-users.XW6DYM7t.mjs';
2
+ import { M as ModuleOptions } from './shared/nuxt-users.DUmdxjpk.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 { M as ModuleOptions } from './shared/nuxt-users.XW6DYM7t.js';
2
+ import { M as ModuleOptions } from './shared/nuxt-users.DUmdxjpk.js';
3
3
  export * from '../dist/runtime/server/internal/index.js';
4
4
 
5
5
  declare const defaultOptions: ModuleOptions;
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "1.40.3",
7
+ "version": "1.41.1",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -56,8 +56,11 @@ const defaultOptions = {
56
56
  fallbackLocale: "en",
57
57
  texts: {}
58
58
  },
59
- tokenCleanupSchedule: "0 2 * * *"
59
+ tokenCleanupSchedule: "0 2 * * *",
60
60
  // Daily at 2 AM
61
+ theme: {
62
+ enabled: true
63
+ }
61
64
  };
62
65
  const module$1 = defineNuxtModule({
63
66
  meta: {
@@ -122,6 +125,7 @@ const module$1 = defineNuxtModule({
122
125
  nuxt.options.runtimeConfig.public.nuxtUsers = {
123
126
  passwordValidation: runtimeConfigOptions.passwordValidation,
124
127
  locale: runtimeConfigOptions.locale,
128
+ theme: runtimeConfigOptions.theme,
125
129
  auth: {
126
130
  whitelist: (() => {
127
131
  const combinedWhitelist = [...defaultOptions.auth?.whitelist || [], ...runtimeConfigOptions.auth?.whitelist || []];
@@ -162,6 +166,10 @@ const module$1 = defineNuxtModule({
162
166
  src: resolver.resolve("./runtime/plugin.auth-init"),
163
167
  name: "0-auth-init-nuxt-users"
164
168
  });
169
+ addPlugin({
170
+ src: resolver.resolve("./runtime/plugin.theme"),
171
+ mode: "client"
172
+ });
165
173
  addPlugin({
166
174
  src: resolver.resolve("./runtime/plugin"),
167
175
  mode: "server"
@@ -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-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}
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}@media (prefers-color-scheme: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}}:root.dark{--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-link{color:var(--nu-color-primary);font-size:.875rem;text-decoration:none;transition:color .2s ease-in-out}.n-users-link:hover{color:var(--nu-color-primary-dark);text-decoration:underline}.n-users-link:visited{color:var(--nu-color-primary)}.n-users-link:visited:hover{color:var(--nu-color-primary-dark)}.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}
@@ -26,40 +26,49 @@ const validationRules = computed(() => {
26
26
  if (moduleOptions.passwordValidation?.minLength) {
27
27
  const hasMinLength = props.password.length >= moduleOptions.passwordValidation.minLength;
28
28
  rules.push({
29
- text: t("passwordStrength.minLength", [moduleOptions.passwordValidation.minLength]),
29
+ text: t("passwordStrength.requirements.minLength", [moduleOptions.passwordValidation.minLength]),
30
30
  passed: hasMinLength
31
31
  });
32
32
  }
33
33
  if (moduleOptions.passwordValidation?.requireUppercase) {
34
34
  const hasUppercase = /[A-Z]/.test(props.password);
35
35
  rules.push({
36
- text: t("passwordStrength.uppercase"),
36
+ text: t("passwordStrength.requirements.uppercase"),
37
37
  passed: hasUppercase
38
38
  });
39
39
  }
40
40
  if (moduleOptions.passwordValidation?.requireLowercase) {
41
41
  const hasLowercase = /[a-z]/.test(props.password);
42
42
  rules.push({
43
- text: t("passwordStrength.lowercase"),
43
+ text: t("passwordStrength.requirements.lowercase"),
44
44
  passed: hasLowercase
45
45
  });
46
46
  }
47
47
  if (moduleOptions.passwordValidation?.requireNumbers) {
48
48
  const hasNumbers = /\d/.test(props.password);
49
49
  rules.push({
50
- text: t("passwordStrength.number"),
50
+ text: t("passwordStrength.requirements.numbers"),
51
51
  passed: hasNumbers
52
52
  });
53
53
  }
54
54
  if (moduleOptions.passwordValidation?.requireSpecialChars) {
55
55
  const hasSpecialChars = /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(props.password);
56
56
  rules.push({
57
- text: t("passwordStrength.specialChar"),
57
+ text: t("passwordStrength.requirements.specialChars"),
58
58
  passed: hasSpecialChars
59
59
  });
60
60
  }
61
61
  return rules;
62
62
  });
63
+ const resolveTranslation = (message) => {
64
+ if (!message) return "";
65
+ if (message.includes("|")) {
66
+ const [key = "", paramStr] = message.split("|");
67
+ const params = paramStr ? paramStr.split(",") : [];
68
+ return t(key, params);
69
+ }
70
+ return t(message);
71
+ };
63
72
  </script>
64
73
 
65
74
  <template>
@@ -82,7 +91,7 @@ const validationRules = computed(() => {
82
91
  color: validationResult?.strength === 'weak' ? '#dc3545' : validationResult?.strength === 'medium' ? '#ffc107' : validationResult?.strength === 'strong' ? '#28a745' : '#6c757d'
83
92
  }"
84
93
  >
85
- {{ validationResult?.strength === "weak" ? props.weakLabel || t("passwordStrength.weak") : validationResult?.strength === "medium" ? props.mediumLabel || t("passwordStrength.medium") : validationResult?.strength === "strong" ? props.strongLabel || t("passwordStrength.strong") : props.unknownLabel || t("passwordStrength.unknown") }}
94
+ {{ validationResult?.strength === "weak" ? props.weakLabel || t("passwordStrength.strength.weak") : validationResult?.strength === "medium" ? props.mediumLabel || t("passwordStrength.strength.medium") : validationResult?.strength === "strong" ? props.strongLabel || t("passwordStrength.strength.strong") : props.unknownLabel || t("passwordStrength.strength.unknown") }}
86
95
  ({{ validationResult?.score || 0 }}%)
87
96
  </span>
88
97
  </div>
@@ -122,7 +131,7 @@ const validationRules = computed(() => {
122
131
  :key="String(error)"
123
132
  class="n-users-error-text"
124
133
  >
125
- {{ error }}
134
+ {{ resolveTranslation(error) }}
126
135
  </small>
127
136
  </div>
128
137
 
@@ -140,7 +149,7 @@ const validationRules = computed(() => {
140
149
  :key="'hint-' + hint"
141
150
  class="n-users-hint-item n-users-list-item"
142
151
  >
143
- {{ hint }}
152
+ {{ resolveTranslation(hint) }}
144
153
  </li>
145
154
  </ul>
146
155
  </div>
@@ -0,0 +1,40 @@
1
+ import type { Ref } from 'vue';
2
+ export type ThemeMode = 'light' | 'dark' | 'system';
3
+ export interface UseThemeReturn {
4
+ /**
5
+ * Current theme mode
6
+ */
7
+ theme: Ref<ThemeMode>;
8
+ /**
9
+ * Current resolved theme (system resolved to actual light/dark)
10
+ */
11
+ resolvedTheme: Ref<'light' | 'dark'>;
12
+ /**
13
+ * Set the theme mode
14
+ */
15
+ setTheme: (mode: ThemeMode) => void;
16
+ /**
17
+ * Toggle between light and dark themes
18
+ */
19
+ toggleTheme: () => void;
20
+ }
21
+ /**
22
+ * Composable for managing theme state in nuxt-users module
23
+ *
24
+ * This composable provides a reactive theme state that can be shared
25
+ * between the module and consumer applications.
26
+ *
27
+ * @example
28
+ * ```vue
29
+ * <script setup>
30
+ * const { theme, setTheme, toggleTheme } = useTheme()
31
+ * </script>
32
+ *
33
+ * <template>
34
+ * <button @click="toggleTheme">
35
+ * Current: {{ theme }}
36
+ * </button>
37
+ * </template>
38
+ * ```
39
+ */
40
+ export declare const useTheme: () => UseThemeReturn;
@@ -0,0 +1,47 @@
1
+ import { useState } from "#app";
2
+ export const useTheme = () => {
3
+ const theme = useState("nuxt-users-theme", () => "system");
4
+ const resolvedTheme = useState("nuxt-users-resolved-theme", () => "light");
5
+ const resolveTheme = () => {
6
+ if (theme.value === "system") {
7
+ if (typeof window === "undefined") {
8
+ return "light";
9
+ }
10
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
11
+ }
12
+ return theme.value;
13
+ };
14
+ const applyTheme = (resolved) => {
15
+ if (typeof document === "undefined") {
16
+ return;
17
+ }
18
+ if (resolved === "dark") {
19
+ document.documentElement.classList.add("dark");
20
+ }
21
+ if (resolved === "light") {
22
+ document.documentElement.classList.remove("dark");
23
+ }
24
+ resolvedTheme.value = resolved;
25
+ };
26
+ const setTheme = (mode) => {
27
+ theme.value = mode;
28
+ const resolved = resolveTheme();
29
+ applyTheme(resolved);
30
+ if (typeof window !== "undefined") {
31
+ window.dispatchEvent(new CustomEvent("nuxt-users:theme-change", {
32
+ detail: { mode, resolved }
33
+ }));
34
+ }
35
+ };
36
+ const toggleTheme = () => {
37
+ const current = resolveTheme();
38
+ const newMode = current === "dark" ? "light" : "dark";
39
+ setTheme(newMode);
40
+ };
41
+ return {
42
+ theme,
43
+ resolvedTheme,
44
+ setTheme,
45
+ toggleTheme
46
+ };
47
+ };
@@ -79,6 +79,24 @@ export const en = {
79
79
  numbers: "Contains number",
80
80
  specialChars: "Contains special character"
81
81
  },
82
+ errors: {
83
+ minLength: "Password must be at least {0} characters long",
84
+ uppercase: "Password must contain at least one uppercase letter",
85
+ lowercase: "Password must contain at least one lowercase letter",
86
+ numbers: "Password must contain at least one number",
87
+ specialChars: "Password must contain at least one special character",
88
+ common: "Password is too common. Please choose a more unique password"
89
+ },
90
+ hints: {
91
+ minLength: "Use at least {0} characters",
92
+ length12: "Use 12 or more characters for extra security",
93
+ uppercase: "Add an uppercase letter (A-Z)",
94
+ lowercase: "Add a lowercase letter (a-z)",
95
+ numbers: "Add a number (0-9)",
96
+ specialChars: "Add a special character (e.g. !@#$%)",
97
+ common: "Avoid common passwords or names",
98
+ mix: "Use a mix of uppercase, lowercase, numbers, and special characters"
99
+ },
82
100
  hintsTitle: "How to make your password stronger?"
83
101
  },
84
102
  profile: {
@@ -65,6 +65,24 @@ const huBase = {
65
65
  lowercase: "Tartalmaz kisbet\u0171t",
66
66
  numbers: "Tartalmaz sz\xE1mot",
67
67
  specialChars: "Tartalmaz speci\xE1lis karaktert"
68
+ },
69
+ errors: {
70
+ minLength: "A jelsz\xF3nak legal\xE1bb {0} karakter hossz\xFAnak kell lennie",
71
+ uppercase: "A jelsz\xF3nak tartalmaznia kell legal\xE1bb egy nagybet\u0171t",
72
+ lowercase: "A jelsz\xF3nak tartalmaznia kell legal\xE1bb egy kisbet\u0171t",
73
+ numbers: "A jelsz\xF3nak tartalmaznia kell legal\xE1bb egy sz\xE1mot",
74
+ specialChars: "A jelsz\xF3nak tartalmaznia kell legal\xE1bb egy speci\xE1lis karaktert",
75
+ common: "Ez a jelsz\xF3 t\xFAl gyakori. K\xE9rj\xFCk, v\xE1lassz egyedibbet"
76
+ },
77
+ hints: {
78
+ minLength: "Haszn\xE1lj legal\xE1bb {0} karaktert",
79
+ length12: "Haszn\xE1lj 12 vagy t\xF6bb karaktert a nagyobb biztons\xE1g \xE9rdek\xE9ben",
80
+ uppercase: "Adj hozz\xE1 egy nagybet\u0171t (A-Z)",
81
+ lowercase: "Adj hozz\xE1 egy kisbet\u0171t (a-z)",
82
+ numbers: "Adj hozz\xE1 egy sz\xE1mot (0-9)",
83
+ specialChars: "Adj hozz\xE1 egy speci\xE1lis karaktert (pl. !@#$%)",
84
+ common: "Ker\xFCld a gyakori jelszavakat \xE9s neveket",
85
+ mix: "Haszn\xE1lj vegyesen nagybet\u0171ket, kisbet\u0171ket, sz\xE1mokat \xE9s speci\xE1lis karaktereket"
68
86
  }
69
87
  },
70
88
  profile: {
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Theme detection plugin with hybrid detection support
3
+ *
4
+ * This plugin provides flexible theme management that works seamlessly
5
+ * with consumer applications that have their own theme systems.
6
+ *
7
+ * Detection methods:
8
+ * 1. System preference changes (prefers-color-scheme)
9
+ * 2. DOM class changes via MutationObserver (consumer app control)
10
+ * 3. Custom events (consumer app notification)
11
+ * 4. Shared state via useTheme composable
12
+ *
13
+ * The plugin respects consumer app theme changes and won't conflict
14
+ * with external theme management systems.
15
+ */
16
+ declare const _default: import("#app").Plugin<{
17
+ nuxtUsersTheme: import("./composables/useTheme.js").UseThemeReturn;
18
+ }> & import("#app").ObjectPlugin<{
19
+ nuxtUsersTheme: import("./composables/useTheme.js").UseThemeReturn;
20
+ }>;
21
+ export default _default;
@@ -0,0 +1,92 @@
1
+ import { defineNuxtPlugin, useRuntimeConfig } from "#app";
2
+ import { useTheme } from "./composables/useTheme.js";
3
+ export default defineNuxtPlugin(() => {
4
+ if (import.meta.server) {
5
+ return;
6
+ }
7
+ const config = useRuntimeConfig();
8
+ const themeConfig = config.public?.nuxtUsers?.theme;
9
+ if (themeConfig?.enabled === false) {
10
+ return;
11
+ }
12
+ const { setTheme, theme } = useTheme();
13
+ let isInternalChange = false;
14
+ const syncThemeFromDOM = () => {
15
+ if (isInternalChange) {
16
+ return;
17
+ }
18
+ if (typeof document === "undefined") {
19
+ return;
20
+ }
21
+ const isDark = document.documentElement.classList.contains("dark");
22
+ const currentResolved = window.matchMedia("(prefers-color-scheme: dark)").matches;
23
+ if (isDark) {
24
+ theme.value = "dark";
25
+ }
26
+ if (!isDark && !currentResolved) {
27
+ theme.value = "light";
28
+ }
29
+ if (!isDark && currentResolved) {
30
+ theme.value = "light";
31
+ }
32
+ };
33
+ const handleSystemThemeChange = () => {
34
+ if (theme.value === "system") {
35
+ isInternalChange = true;
36
+ setTheme("system");
37
+ isInternalChange = false;
38
+ }
39
+ };
40
+ if (typeof window !== "undefined" && window.matchMedia) {
41
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
42
+ if (mediaQuery.addEventListener) {
43
+ mediaQuery.addEventListener("change", handleSystemThemeChange);
44
+ }
45
+ if (mediaQuery.addListener) {
46
+ mediaQuery.addListener(handleSystemThemeChange);
47
+ }
48
+ }
49
+ if (typeof window !== "undefined" && typeof MutationObserver !== "undefined") {
50
+ const observer = new MutationObserver(() => {
51
+ syncThemeFromDOM();
52
+ });
53
+ observer.observe(document.documentElement, {
54
+ attributes: true,
55
+ attributeFilter: ["class"]
56
+ });
57
+ }
58
+ if (typeof window !== "undefined") {
59
+ window.addEventListener("theme-change", (event) => {
60
+ const customEvent = event;
61
+ const newTheme = customEvent.detail?.theme;
62
+ if (newTheme === "light" || newTheme === "dark") {
63
+ isInternalChange = true;
64
+ setTheme(newTheme);
65
+ isInternalChange = false;
66
+ }
67
+ });
68
+ window.addEventListener("color-scheme-change", (event) => {
69
+ const customEvent = event;
70
+ const newTheme = customEvent.detail?.colorScheme || customEvent.detail?.theme;
71
+ if (newTheme === "light" || newTheme === "dark") {
72
+ isInternalChange = true;
73
+ setTheme(newTheme);
74
+ isInternalChange = false;
75
+ }
76
+ });
77
+ }
78
+ if (typeof document !== "undefined") {
79
+ const hasExistingDarkClass = document.documentElement.classList.contains("dark");
80
+ if (hasExistingDarkClass) {
81
+ theme.value = "dark";
82
+ }
83
+ if (!hasExistingDarkClass) {
84
+ setTheme("system");
85
+ }
86
+ }
87
+ return {
88
+ provide: {
89
+ nuxtUsersTheme: useTheme()
90
+ }
91
+ };
92
+ });
@@ -67,46 +67,46 @@ const validatePassword = (password, options = {}) => {
67
67
  const hints = [];
68
68
  let score = 0;
69
69
  if (password.length < config.minLength) {
70
- errors.push(`Password must be at least ${config.minLength} characters long`);
71
- hints.push(`Use at least ${config.minLength} characters`);
70
+ errors.push(`passwordStrength.errors.minLength|${config.minLength}`);
71
+ hints.push(`passwordStrength.hints.minLength|${config.minLength}`);
72
72
  }
73
73
  if (password.length >= config.minLength) {
74
74
  score += 20;
75
75
  if (password.length < 12) {
76
- hints.push("Use 12 or more characters for extra security");
76
+ hints.push("passwordStrength.hints.length12");
77
77
  }
78
78
  }
79
79
  if (config.requireUppercase && !/[A-Z]/.test(password)) {
80
- errors.push("Password must contain at least one uppercase letter");
81
- hints.push("Add an uppercase letter (A-Z)");
80
+ errors.push("passwordStrength.errors.uppercase");
81
+ hints.push("passwordStrength.hints.uppercase");
82
82
  }
83
83
  if (/[A-Z]/.test(password)) {
84
84
  score += 15;
85
85
  }
86
86
  if (config.requireLowercase && !/[a-z]/.test(password)) {
87
- errors.push("Password must contain at least one lowercase letter");
88
- hints.push("Add a lowercase letter (a-z)");
87
+ errors.push("passwordStrength.errors.lowercase");
88
+ hints.push("passwordStrength.hints.lowercase");
89
89
  }
90
90
  if (/[a-z]/.test(password)) {
91
91
  score += 15;
92
92
  }
93
93
  if (config.requireNumbers && !/\d/.test(password)) {
94
- errors.push("Password must contain at least one number");
95
- hints.push("Add a number (0-9)");
94
+ errors.push("passwordStrength.errors.numbers");
95
+ hints.push("passwordStrength.hints.numbers");
96
96
  }
97
97
  if (/\d/.test(password)) {
98
98
  score += 15;
99
99
  }
100
100
  if (config.requireSpecialChars && !/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
101
- errors.push("Password must contain at least one special character");
102
- hints.push("Add a special character (e.g. !@#$%)");
101
+ errors.push("passwordStrength.errors.specialChars");
102
+ hints.push("passwordStrength.hints.specialChars");
103
103
  }
104
104
  if (/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
105
105
  score += 15;
106
106
  }
107
107
  if (config.preventCommonPasswords && COMMON_PASSWORDS.includes(password.toLowerCase())) {
108
- errors.push("Password is too common. Please choose a more unique password");
109
- hints.push("Avoid common passwords or names");
108
+ errors.push("passwordStrength.errors.common");
109
+ hints.push("passwordStrength.hints.common");
110
110
  }
111
111
  if (password.length >= 12) {
112
112
  score += 10;
@@ -124,7 +124,7 @@ const validatePassword = (password, options = {}) => {
124
124
  }
125
125
  if (complexityTypes >= 3 && complexityTypes < 4) {
126
126
  score += 5;
127
- hints.push("Use a mix of uppercase, lowercase, numbers, and special characters");
127
+ hints.push("passwordStrength.hints.mix");
128
128
  }
129
129
  let strength = "weak";
130
130
  if (score >= 80) {
@@ -192,6 +192,18 @@ interface RuntimeModuleOptions {
192
192
  * Locale configuration for component labels and messages
193
193
  */
194
194
  locale?: LocaleOptions;
195
+ /**
196
+ * Theme configuration for color scheme management
197
+ */
198
+ theme?: {
199
+ /**
200
+ * Enable the automatic theme plugin
201
+ * When disabled, the module won't manage themes automatically,
202
+ * allowing consumer apps full control over theme management
203
+ * @default true
204
+ */
205
+ enabled?: boolean;
206
+ };
195
207
  }
196
208
  interface ModuleOptions {
197
209
  connector: {
@@ -235,6 +247,18 @@ interface ModuleOptions {
235
247
  * Default: '0 2 * * *' (daily at 2 AM)
236
248
  */
237
249
  tokenCleanupSchedule?: string | false | null;
250
+ /**
251
+ * Theme configuration for color scheme management
252
+ */
253
+ theme?: {
254
+ /**
255
+ * Enable the automatic theme plugin
256
+ * When disabled, the module won't manage themes automatically,
257
+ * allowing consumer apps full control over theme management
258
+ * @default true
259
+ */
260
+ enabled?: boolean;
261
+ };
238
262
  }
239
263
  interface MailerOptions {
240
264
  host: string;
@@ -192,6 +192,18 @@ interface RuntimeModuleOptions {
192
192
  * Locale configuration for component labels and messages
193
193
  */
194
194
  locale?: LocaleOptions;
195
+ /**
196
+ * Theme configuration for color scheme management
197
+ */
198
+ theme?: {
199
+ /**
200
+ * Enable the automatic theme plugin
201
+ * When disabled, the module won't manage themes automatically,
202
+ * allowing consumer apps full control over theme management
203
+ * @default true
204
+ */
205
+ enabled?: boolean;
206
+ };
195
207
  }
196
208
  interface ModuleOptions {
197
209
  connector: {
@@ -235,6 +247,18 @@ interface ModuleOptions {
235
247
  * Default: '0 2 * * *' (daily at 2 AM)
236
248
  */
237
249
  tokenCleanupSchedule?: string | false | null;
250
+ /**
251
+ * Theme configuration for color scheme management
252
+ */
253
+ theme?: {
254
+ /**
255
+ * Enable the automatic theme plugin
256
+ * When disabled, the module won't manage themes automatically,
257
+ * allowing consumer apps full control over theme management
258
+ * @default true
259
+ */
260
+ enabled?: boolean;
261
+ };
238
262
  }
239
263
  interface MailerOptions {
240
264
  host: string;
package/dist/utils.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { defaultLocaleMessages, en, hu, huFormal } from '../dist/runtime/locales/index.js';
2
2
  export { getNestedValue, getTranslation } from '../dist/runtime/utils/locale.js';
3
3
  export { deepMerge } from '../dist/runtime/utils/deep-merge.js';
4
- export { g as DatabaseConfig, f as DatabaseType, D as DisplayFieldsProps, G as GoogleOAuthOptions, i as LocaleMessages, h as LocaleOptions, L as LoginFormData, c as LoginFormProps, M as ModuleOptions, b as PasswordResetToken, e as Permission, P as PersonalAccessToken, d as ResetPasswordFormProps, R as RuntimeModuleOptions, U as User, a as UserWithoutPassword, j as defaultDisplayFields, k as defaultFieldLabels } from './shared/nuxt-users.XW6DYM7t.mjs';
4
+ export { g as DatabaseConfig, f as DatabaseType, D as DisplayFieldsProps, G as GoogleOAuthOptions, i as LocaleMessages, h as LocaleOptions, L as LoginFormData, c as LoginFormProps, M as ModuleOptions, b as PasswordResetToken, e as Permission, P as PersonalAccessToken, d as ResetPasswordFormProps, R as RuntimeModuleOptions, U as User, a as UserWithoutPassword, j as defaultDisplayFields, k as defaultFieldLabels } from './shared/nuxt-users.DUmdxjpk.mjs';
5
5
 
6
6
  interface PasswordValidationResult {
7
7
  isValid: boolean;
package/dist/utils.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { defaultLocaleMessages, en, hu, huFormal } from '../dist/runtime/locales/index.js';
2
2
  export { getNestedValue, getTranslation } from '../dist/runtime/utils/locale.js';
3
3
  export { deepMerge } from '../dist/runtime/utils/deep-merge.js';
4
- export { g as DatabaseConfig, f as DatabaseType, D as DisplayFieldsProps, G as GoogleOAuthOptions, i as LocaleMessages, h as LocaleOptions, L as LoginFormData, c as LoginFormProps, M as ModuleOptions, b as PasswordResetToken, e as Permission, P as PersonalAccessToken, d as ResetPasswordFormProps, R as RuntimeModuleOptions, U as User, a as UserWithoutPassword, j as defaultDisplayFields, k as defaultFieldLabels } from './shared/nuxt-users.XW6DYM7t.js';
4
+ export { g as DatabaseConfig, f as DatabaseType, D as DisplayFieldsProps, G as GoogleOAuthOptions, i as LocaleMessages, h as LocaleOptions, L as LoginFormData, c as LoginFormProps, M as ModuleOptions, b as PasswordResetToken, e as Permission, P as PersonalAccessToken, d as ResetPasswordFormProps, R as RuntimeModuleOptions, U as User, a as UserWithoutPassword, j as defaultDisplayFields, k as defaultFieldLabels } from './shared/nuxt-users.DUmdxjpk.js';
5
5
 
6
6
  interface PasswordValidationResult {
7
7
  isValid: boolean;
package/dist/utils.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { a as getPasswordStrengthColor, b as getPasswordStrengthText, g as getPasswordValidationOptions, v as validatePassword } from './shared/nuxt-users.DfZ7bc_P.mjs';
1
+ export { a as getPasswordStrengthColor, b as getPasswordStrengthText, g as getPasswordValidationOptions, v as validatePassword } from './shared/nuxt-users.Cvjgn5KJ.mjs';
2
2
  export { defaultLocaleMessages, en, hu, huFormal } from '../dist/runtime/locales/index.js';
3
3
  export { getNestedValue, getTranslation } from '../dist/runtime/utils/locale.js';
4
4
  export { deepMerge } from '../dist/runtime/utils/deep-merge.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-users",
3
- "version": "1.40.3",
3
+ "version": "1.41.1",
4
4
  "description": "A comprehensive user management module for Nuxt 3 and Nuxt 4 applications with authentication, authorization, database support, and CLI tools",
5
5
  "keywords": [
6
6
  "nuxt",
@@ -64,9 +64,9 @@
64
64
  "postbuild": "node scripts/post-build.js",
65
65
  "check:translations": "tsx scripts/check-translations.ts",
66
66
  "check:locale-consistency": "tsx scripts/check-locale-consistency.ts",
67
- "check:npm_token": "if [ -z \"$NPM_TOKEN\" ]; then echo '❌ NPM_TOKEN environment variable is not set. Please set it to your npm token.'; exit 1; fi",
67
+ "check:npm_token": "dotenv -- sh -c 'if [ -z \"$NPM_TOKEN\" ]; then echo \"❌ NPM_TOKEN environment variable is not set in .env file. Please set it to your npm token.\"; exit 1; fi'",
68
68
  "prerelease": "node -v | grep -q 'v22' || (echo 'Please use Node.js v22 for deployment' && exit 1)",
69
- "release": "yarn check:npm_token && yarn lint && yarn check:translations && yarn check:locale-consistency && yarn test && yarn prepack && dotenv -- changelogen --release && dotenv -- npm publish --registry https://registry.npmjs.org/ && git push --follow-tags",
69
+ "release": "yarn check:npm_token && yarn lint && yarn check:translations && yarn check:locale-consistency && yarn test && yarn prepack && dotenv -- changelogen --release && dotenv -- sh -c 'npm publish --//registry.npmjs.org/:_authToken=$NPM_TOKEN --registry https://registry.npmjs.org/' && git push --follow-tags",
70
70
  "lint": "eslint .",
71
71
  "lint:fix": "eslint . --fix",
72
72
  "pretest": "node -v | grep -q 'v22' || (echo 'Please use Node.js v22 for testing' && exit 1)",