nuxt-users 1.1.6 → 1.3.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 (32) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +5 -2
  3. package/dist/cli.mjs +30 -24
  4. package/dist/module.d.mts +1 -1
  5. package/dist/module.d.ts +1 -1
  6. package/dist/module.json +1 -1
  7. package/dist/module.mjs +21 -5
  8. package/dist/runtime/assets/colors.css +1 -1
  9. package/dist/runtime/components/ForgotPasswordForm.vue +1 -1
  10. package/dist/runtime/components/LoginForm.vue +6 -4
  11. package/dist/runtime/components/LogoutLink.vue +62 -0
  12. package/dist/runtime/components/LogoutLink.vue.d.ts +20 -0
  13. package/dist/runtime/components/ResetPasswordForm.vue +1 -1
  14. package/dist/runtime/composables/useAuth.d.ts +5 -0
  15. package/dist/runtime/composables/useAuth.js +19 -0
  16. package/dist/runtime/middleware/auth.global.d.ts +2 -0
  17. package/dist/runtime/middleware/auth.global.js +12 -0
  18. package/dist/runtime/plugin.js +0 -1
  19. package/dist/runtime/server/api/auth/forgot-password.post.js +2 -2
  20. package/dist/runtime/server/api/auth/reset-password.post.js +2 -2
  21. package/dist/runtime/server/api/login.post.d.ts +1 -0
  22. package/dist/runtime/server/api/login.post.js +1 -1
  23. package/dist/runtime/server/api/logout.get.d.ts +4 -0
  24. package/dist/runtime/server/api/logout.get.js +21 -0
  25. package/dist/runtime/server/services/password.js +9 -9
  26. package/dist/shared/{nuxt-users.Dtq4WcpY.d.mts → nuxt-users.DGRKT2Tq.d.mts} +9 -1
  27. package/dist/shared/{nuxt-users.Dtq4WcpY.d.ts → nuxt-users.DGRKT2Tq.d.ts} +9 -1
  28. package/dist/shared/{nuxt-users.eSQUrS6l.mjs → nuxt-users.DZkU2AbH.mjs} +19 -13
  29. package/dist/utils.d.mts +2 -1
  30. package/dist/utils.d.ts +2 -1
  31. package/dist/utils.mjs +1 -1
  32. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,53 @@
1
1
  # Changelog
2
2
 
3
3
 
4
+ ## v1.3.0
5
+
6
+ [compare changes](https://github.com/rrd108/nuxt-users/compare/v1.2.0...v1.3.0)
7
+
8
+ ### 🚀 Enhancements
9
+
10
+ - Adds theme support with light/dark mode ([005ea87](https://github.com/rrd108/nuxt-users/commit/005ea87))
11
+ - Adds logout functionality ([a61b4e8](https://github.com/rrd108/nuxt-users/commit/a61b4e8))
12
+
13
+ ### 💅 Refactors
14
+
15
+ - Restyles login form for better UX closes #51 ([#51](https://github.com/rrd108/nuxt-users/issues/51))
16
+
17
+ ### 🏡 Chore
18
+
19
+ - **release:** V1.2.0 ([54fd5c8](https://github.com/rrd108/nuxt-users/commit/54fd5c8))
20
+
21
+ ### ❤️ Contributors
22
+
23
+ - Rrd108 ([@rrd108](https://github.com/rrd108))
24
+
25
+ ## v1.2.0
26
+
27
+ [compare changes](https://github.com/rrd108/nuxt-users/compare/v1.1.6...v1.2.0)
28
+
29
+ ### 🚀 Enhancements
30
+
31
+ - Adds user role functionality closes #25 ([#25](https://github.com/rrd108/nuxt-users/issues/25))
32
+ - Adds authentication middleware and route whitelisting closes #52 ([#52](https://github.com/rrd108/nuxt-users/issues/52))
33
+
34
+ ### 🩹 Fixes
35
+
36
+ - **ci:** Adds playground preparation step to CI ([cf9af1f](https://github.com/rrd108/nuxt-users/commit/cf9af1f))
37
+
38
+ ### 💅 Refactors
39
+
40
+ - Uses default table names as fallback ([dcee2ee](https://github.com/rrd108/nuxt-users/commit/dcee2ee))
41
+
42
+ ### 🏡 Chore
43
+
44
+ - **release:** V1.1.6 ([1222bcd](https://github.com/rrd108/nuxt-users/commit/1222bcd))
45
+ - Consistently prefixes logs with "[Nuxt Users]" ([9ed1df1](https://github.com/rrd108/nuxt-users/commit/9ed1df1))
46
+
47
+ ### ❤️ Contributors
48
+
49
+ - Rrd108 ([@rrd108](https://github.com/rrd108))
50
+
4
51
  ## v1.1.6
5
52
 
6
53
  [compare changes](https://github.com/rrd108/nuxt-users/compare/v1.1.5...v1.1.6)
package/README.md CHANGED
@@ -1,15 +1,16 @@
1
1
  # Nuxt Users
2
2
 
3
- A user authentication module for Nuxt 3 with database support for SQLite and MySQL.
3
+ A user authentication module for Nuxt 3 and Nuxt 4 with database support for SQLite, MySQL, and PostgreSQL.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - 🔐 User authentication with bcrypt password hashing
8
- - 🗄️ Database support (SQLite, MySQL)
8
+ - 🗄️ Database support (SQLite, MySQL, PostgreSQL)
9
9
  - 🛠️ CLI commands for database management
10
10
  - 🔑 Password Reset Functionality
11
11
  - 📦 Zero-config setup with sensible defaults
12
12
  - 🔧 TypeScript support
13
+ - 🚀 Nuxt 3 & 4 compatibility
13
14
 
14
15
  ## Quick Start
15
16
 
@@ -35,6 +36,8 @@ npx nuxt-users migrate
35
36
 
36
37
  # Create your first user
37
38
  npx nuxt-users create-user user@example.com "John Doe" password123
39
+ # Create an admin user
40
+ npx nuxt-users create-user admin@example.com "Admin User" adminpass123 admin
38
41
  ```
39
42
 
40
43
  ## Documentation
package/dist/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { defineCommand, runMain } from 'citty';
3
3
  import 'db0';
4
4
  import 'bcrypt';
5
- import { r as runMigrations, a as createUser$1, d as createUsersTable$1, e as createPersonalAccessTokensTable$1, g as createPasswordResetTokensTable$1, h as createMigrationsTable$1 } from './shared/nuxt-users.eSQUrS6l.mjs';
5
+ import { r as runMigrations, a as createUser$1, d as createUsersTable$1, e as createPersonalAccessTokensTable$1, g as createPasswordResetTokensTable$1, h as createMigrationsTable$1 } from './shared/nuxt-users.DZkU2AbH.mjs';
6
6
  import { loadNuxt } from '@nuxt/kit';
7
7
 
8
8
  const defaultOptions = {
@@ -85,7 +85,7 @@ const loadOptions = async () => {
85
85
  }
86
86
  } catch (error) {
87
87
  console.log("[Nuxt Users] Could not load Nuxt project, using environment variables");
88
- console.error(error);
88
+ console.error("[Nuxt Users] Error:", error);
89
89
  return getOptionsFromEnv();
90
90
  }
91
91
  };
@@ -132,17 +132,23 @@ const createUser = defineCommand({
132
132
  type: "string",
133
133
  description: "User password",
134
134
  required: true
135
+ },
136
+ role: {
137
+ alias: "r",
138
+ type: "string",
139
+ description: 'User role (defaults to "user")',
140
+ default: "user"
135
141
  }
136
142
  },
137
143
  async run({ args }) {
138
- const { email, name, password } = args;
144
+ const { email, name, password, role } = args;
139
145
  const options = await loadOptions();
140
146
  try {
141
- const user = await createUser$1({ email, name, password }, options);
142
- console.log(`[DB:Create User] User created successfully: ${user.email}`);
147
+ const user = await createUser$1({ email, name, password, role }, options);
148
+ console.log(`[Nuxt Users] User created successfully: ${user.email} (role: ${user.role})`);
143
149
  process.exit(0);
144
150
  } catch (error) {
145
- console.error("[DB:Create User] Error:", error);
151
+ console.error("[Nuxt Users] Error:", error);
146
152
  process.exit(1);
147
153
  }
148
154
  }
@@ -160,7 +166,7 @@ const createUsersTable = defineCommand({
160
166
  await createUsersTable$1(options);
161
167
  console.log("[Nuxt Users] Users table created successfully!");
162
168
  } catch (error) {
163
- console.error("[DB:Create Users Table] Error:", error);
169
+ console.error("[Nuxt Users] DB:Create Users Table Error:", error);
164
170
  process.exit(1);
165
171
  }
166
172
  }
@@ -178,7 +184,7 @@ const createPersonalAccessTokensTable = defineCommand({
178
184
  await createPersonalAccessTokensTable$1(options);
179
185
  console.log("[Nuxt Users] Personal access tokens table created successfully!");
180
186
  } catch (error) {
181
- console.error("[DB:Create Personal Access Tokens Table] Error:", error);
187
+ console.error("[Nuxt Users] DB:Create Personal Access Tokens Table Error:", error);
182
188
  process.exit(1);
183
189
  }
184
190
  }
@@ -196,7 +202,7 @@ const createPasswordResetTokensTable = defineCommand({
196
202
  await createPasswordResetTokensTable$1(options);
197
203
  console.log("[Nuxt Users] Password reset tokens table created successfully!");
198
204
  } catch (error) {
199
- console.error("[DB:Create Password Reset Tokens Table] Error:", error);
205
+ console.error("[Nuxt Users] DB:Create Password Reset Tokens Table Error:", error);
200
206
  process.exit(1);
201
207
  }
202
208
  }
@@ -214,7 +220,7 @@ const createMigrationsTable = defineCommand({
214
220
  await createMigrationsTable$1(options);
215
221
  console.log("[Nuxt Users] Migrations table created successfully!");
216
222
  } catch (error) {
217
- console.error("[DB:Create Migrations Table] Error:", error);
223
+ console.error("[Nuxt Users] DB:Create Migrations Table Error:", error);
218
224
  process.exit(1);
219
225
  }
220
226
  }
@@ -229,28 +235,28 @@ const projectInfo = defineCommand({
229
235
  try {
230
236
  console.log("[Nuxt Users] Loading Nuxt project...");
231
237
  const nuxt = await loadNuxt({ cwd: process.cwd() });
232
- console.log("\u2705 Nuxt project loaded successfully!");
233
- console.log("\u{1F4C1} Source directory:", nuxt.options.srcDir);
234
- console.log("\u{1F310} Base URL:", nuxt.options.app?.baseURL || "/");
238
+ console.log("[Nuxt Users] \u2705 Nuxt project loaded successfully!");
239
+ console.log("[Nuxt Users] \u{1F4C1} Source directory:", nuxt.options.srcDir);
240
+ console.log("[Nuxt Users] \u{1F310} Base URL:", nuxt.options.app?.baseURL || "/");
235
241
  const nuxtUsersConfig = nuxt.options.runtimeConfig?.nuxtUsers;
236
242
  if (nuxtUsersConfig) {
237
- console.log("\u{1F527} Nuxt Users module configuration:");
238
- console.log(" Database connector:", nuxtUsersConfig.connector?.name);
239
- console.log(" Users table:", nuxtUsersConfig.tables?.users);
240
- console.log(" Personal access tokens table:", nuxtUsersConfig.tables?.personalAccessTokens);
241
- console.log(" Password reset tokens table:", nuxtUsersConfig.tables?.passwordResetTokens);
243
+ console.log("[Nuxt Users] \u{1F527} Nuxt Users module configuration:");
244
+ console.log("[Nuxt Users] Database connector:", nuxtUsersConfig.connector?.name);
245
+ console.log("[Nuxt Users] Users table:", nuxtUsersConfig.tables?.users);
246
+ console.log("[Nuxt Users] Personal access tokens table:", nuxtUsersConfig.tables?.personalAccessTokens);
247
+ console.log("[Nuxt Users] Password reset tokens table:", nuxtUsersConfig.tables?.passwordResetTokens);
242
248
  } else {
243
- console.log("\u26A0\uFE0F Nuxt Users module not configured in runtime config");
249
+ console.log("[Nuxt Users] \u26A0\uFE0F Nuxt Users module not configured in runtime config");
244
250
  }
245
251
  const publicConfig = nuxt.options.runtimeConfig?.public?.nuxtUsers;
246
252
  if (publicConfig) {
247
- console.log("\u{1F30D} Public runtime config:");
248
- console.log(" Users table exists:", publicConfig.tables?.users);
249
- console.log(" Personal access tokens table exists:", publicConfig.tables?.personalAccessTokens);
250
- console.log(" Password reset tokens table exists:", publicConfig.tables?.passwordResetTokens);
253
+ console.log("[Nuxt Users] \u{1F30D} Public runtime config:");
254
+ console.log("[Nuxt Users] Users table exists:", publicConfig.tables?.users);
255
+ console.log("[Nuxt Users] Personal access tokens table exists:", publicConfig.tables?.personalAccessTokens);
256
+ console.log("[Nuxt Users] Password reset tokens table exists:", publicConfig.tables?.passwordResetTokens);
251
257
  }
252
258
  } catch (error) {
253
- console.error("\u274C Could not load Nuxt project:", error);
259
+ console.error("[Nuxt Users] \u274C Could not load Nuxt project:", error);
254
260
  process.exit(1);
255
261
  }
256
262
  }
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.Dtq4WcpY.mjs';
2
+ import { M as ModuleOptions } from './shared/nuxt-users.DGRKT2Tq.mjs';
3
3
 
4
4
  declare const defaultOptions: ModuleOptions;
5
5
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
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.Dtq4WcpY.js';
2
+ import { M as ModuleOptions } from './shared/nuxt-users.DGRKT2Tq.js';
3
3
 
4
4
  declare const defaultOptions: ModuleOptions;
5
5
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-users",
3
3
  "configKey": "nuxtUsers",
4
- "version": "1.1.6",
4
+ "version": "1.3.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.1",
7
7
  "unbuild": "3.6.0"
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { defineNuxtModule, createResolver, addPlugin, addServerHandler, addComponent } from '@nuxt/kit';
1
+ import { defineNuxtModule, createResolver, addPlugin, addImportsDir, addServerHandler, addComponent } from '@nuxt/kit';
2
2
  import { defu } from 'defu';
3
3
 
4
4
  const defaultOptions = {
@@ -28,6 +28,9 @@ const defaultOptions = {
28
28
  defaults: {
29
29
  from: '"Nuxt Users Module" <noreply@example.com>'
30
30
  }
31
+ },
32
+ auth: {
33
+ whitelist: ["/login"]
31
34
  }
32
35
  };
33
36
  const module = defineNuxtModule({
@@ -43,16 +46,20 @@ const module = defineNuxtModule({
43
46
  nuxt.options.runtimeConfig.nuxtUsers = {
44
47
  ...runtimeConfigOptions,
45
48
  tables: {
46
- migrations: options.tables?.migrations || "migrations",
47
- users: options.tables?.users || "users",
48
- personalAccessTokens: options.tables?.personalAccessTokens || "personal_access_tokens",
49
- passwordResetTokens: options.tables?.passwordResetTokens || "password_reset_tokens"
49
+ migrations: options.tables?.migrations || defaultOptions.tables.migrations,
50
+ users: options.tables?.users || defaultOptions.tables.users,
51
+ personalAccessTokens: options.tables?.personalAccessTokens || defaultOptions.tables.personalAccessTokens,
52
+ passwordResetTokens: options.tables?.passwordResetTokens || defaultOptions.tables.passwordResetTokens
53
+ },
54
+ auth: {
55
+ whitelist: options.auth?.whitelist || defaultOptions.auth?.whitelist || ["/login"]
50
56
  }
51
57
  };
52
58
  addPlugin({
53
59
  src: resolver.resolve("./runtime/plugin"),
54
60
  mode: "server"
55
61
  });
62
+ addImportsDir(resolver.resolve("./runtime/composables"));
56
63
  addServerHandler({
57
64
  route: "/api/login",
58
65
  method: "post",
@@ -68,6 +75,11 @@ const module = defineNuxtModule({
68
75
  method: "post",
69
76
  handler: resolver.resolve("./runtime/server/api/auth/reset-password.post")
70
77
  });
78
+ addServerHandler({
79
+ route: "/api/logout",
80
+ method: "get",
81
+ handler: resolver.resolve("./runtime/server/api/logout.get")
82
+ });
71
83
  addComponent({
72
84
  name: "LoginForm",
73
85
  filePath: resolver.resolve("./runtime/components/LoginForm.vue")
@@ -80,6 +92,10 @@ const module = defineNuxtModule({
80
92
  name: "ResetPasswordForm",
81
93
  filePath: resolver.resolve("./runtime/components/ResetPasswordForm.vue")
82
94
  });
95
+ addComponent({
96
+ name: "LogoutLink",
97
+ filePath: resolver.resolve("./runtime/components/LogoutLink.vue")
98
+ });
83
99
  nuxt.options.css = nuxt.options.css || [];
84
100
  nuxt.options.css.push(resolver.resolve("./runtime/assets/colors.css"));
85
101
  }
@@ -1 +1 @@
1
- :root{--color-primary:#3b82f6;--color-primary-dark:#2563eb;--color-primary-light:#60a5fa;--color-secondary:#059669;--color-secondary-dark:#047857;--color-secondary-light:#10b981;--color-white:#fff;--color-black:#000;--color-gray-50:#f9fafb;--color-gray-100:#f3f4f6;--color-gray-200:#e5e7eb;--color-gray-300:#d1d5db;--color-gray-400:#9ca3af;--color-gray-500:#6b7280;--color-gray-600:#4b5563;--color-gray-700:#374151;--color-gray-800:#1f2937;--color-gray-900:#111827;--color-success:#059669;--color-success-light:#f0fdf4;--color-warning:#f59e0b;--color-warning-light:#fef3c7;--color-warning-text:#92400e;--color-error:#dc2626;--color-error-light:#fef2f2;--color-error-border:#fecaca;--color-error-alt:#db5050;--color-border:#e5e7eb;--color-border-light:#d1d5db;--color-border-dark:#ccc;--color-bg-primary:#fff;--color-bg-secondary:#f9fafb;--color-bg-tertiary:#f3f4f6}
1
+ :root{--color-primary:#60a5fa;--color-primary-dark:#3b82f6;--color-primary-light:#93c5fd;--color-secondary:#10b981;--color-secondary-dark:#059669;--color-secondary-light:#34d399;--color-white:#000;--color-black:#fff;--color-gray-50:#111827;--color-gray-100:#1f2937;--color-gray-200:#374151;--color-gray-300:#4b5563;--color-gray-400:#6b7280;--color-gray-500:#9ca3af;--color-gray-600:#d1d5db;--color-gray-700:#e5e7eb;--color-gray-800:#f3f4f6;--color-gray-900:#f9fafb;--color-success:#10b981;--color-success-light:#064e3b;--color-warning:#fbbf24;--color-warning-light:#451a03;--color-warning-text:#fef3c7;--color-error:#ef4444;--color-error-light:#450a0a;--color-error-border:#7f1d1d;--color-error-alt:#f87171;--color-border:#374151;--color-border-light:#4b5563;--color-border-dark:#6b7280;--color-bg-primary:#111827;--color-bg-secondary:#1f2937;--color-bg-tertiary:#374151}@media (prefers-color-scheme:light){.light,:root{--color-primary:#3b82f6;--color-primary-dark:#2563eb;--color-primary-light:#60a5fa;--color-secondary:#059669;--color-secondary-dark:#047857;--color-secondary-light:#10b981;--color-white:#fff;--color-black:#000;--color-gray-50:#f9fafb;--color-gray-100:#f3f4f6;--color-gray-200:#e5e7eb;--color-gray-300:#d1d5db;--color-gray-400:#9ca3af;--color-gray-500:#6b7280;--color-gray-600:#4b5563;--color-gray-700:#374151;--color-gray-800:#1f2937;--color-gray-900:#111827;--color-success:#059669;--color-success-light:#f0fdf4;--color-warning:#f59e0b;--color-warning-light:#fef3c7;--color-warning-text:#92400e;--color-error:#dc2626;--color-error-light:#fef2f2;--color-error-border:#fecaca;--color-error-alt:#db5050;--color-border:#e5e7eb;--color-border-light:#d1d5db;--color-border-dark:#ccc;--color-bg-primary:#fff;--color-bg-secondary:#f9fafb;--color-bg-tertiary:#f3f4f6}}
@@ -32,7 +32,7 @@ const handleForgotPassword = async () => {
32
32
  } else {
33
33
  message.value = "Failed to send password reset link.";
34
34
  }
35
- console.error(err);
35
+ console.error("[Nuxt Users] Forgot Password Form Error:", err);
36
36
  isError.value = true;
37
37
  } finally {
38
38
  loading.value = false;
@@ -40,7 +40,7 @@ const handleSubmit = async () => {
40
40
  </script>
41
41
 
42
42
  <template>
43
- <div class="login-form-container">
43
+ <section>
44
44
  <form @submit.prevent="handleSubmit">
45
45
  <!-- Header slot -->
46
46
  <slot name="header">
@@ -119,7 +119,9 @@ const handleSubmit = async () => {
119
119
  <a
120
120
  href="#"
121
121
  class="forgot-link"
122
- >Forgot your password?</a>
122
+ >
123
+ Forgot your password?
124
+ </a>
123
125
  </p>
124
126
  </div>
125
127
  </slot>
@@ -137,9 +139,9 @@ const handleSubmit = async () => {
137
139
  </div>
138
140
  </slot>
139
141
  </form>
140
- </div>
142
+ </section>
141
143
  </template>
142
144
 
143
145
  <style scoped>
144
- .login-form-container{background:var(--color-bg-primary);border:1px solid var(--color-border);border-radius:12px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);margin:0 auto;max-width:400px;padding:2em;width:100%}form{gap:1.5rem}.form-group,form{display:flex;flex-direction:column}label{display:block;font-weight:500;margin-bottom:.5em}input[type=email],input[type=password],label{color:var(--color-gray-700);font-size:.875rem}input[type=email],input[type=password]{background-color:var(--color-bg-secondary);border:1px solid var(--color-border-light);border-radius:8px;box-sizing:border-box;padding:.75em 1em;transition:all .2s ease-in-out;width:100%}input[type=email]:focus,input[type=password]:focus{background-color:var(--color-bg-primary);border-color:var(--color-primary);box-shadow:0 0 0 3px rgba(59,130,246,.1);outline:none}.login-header{margin-bottom:1em;text-align:center}.login-title{color:var(--color-gray-800);font-size:1.875rem;font-weight:700;line-height:1.2;margin:0 0 .5em}.login-subtitle{color:var(--color-gray-500);font-size:.875rem;line-height:1.5;margin:0}.remember-me{align-items:center;display:flex;gap:.5rem}input[type=checkbox]{margin:0;width:auto}.remember-me label{color:var(--color-gray-700);font-size:.875rem;margin:0}button[type=submit]{align-items:center;background-color:var(--color-primary);border:1px solid var(--color-primary);border-radius:8px;color:var(--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%}button[type=submit]:hover:not(:disabled){background-color:var(--color-primary-dark);border-color:var(--color-primary-dark)}button[type=submit]:disabled{cursor:not-allowed;opacity:.6}.loading-spinner{animation:spin 1s linear infinite;border:2px solid var(--color-white);border-radius:50%;border-top:2px solid transparent;height:16px;width:16px}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.login-footer{margin-top:1em;text-align:center}.forgot-password{margin:0}.forgot-link{color:var(--color-primary);font-size:.875rem;text-decoration:none;transition:color .2s ease-in-out}.forgot-link:hover{color:var(--color-primary-dark);text-decoration:underline}.error-message{background-color:var(--color-error-light);border:1px solid var(--color-error-border);border-radius:8px;color:var(--color-error);font-size:.875rem;margin-top:1em;padding:.75em 1em;text-align:center}@media (max-width:480px){.login-form-container{margin:1em;padding:1.5em}.login-title{font-size:1.5rem}}
146
+ section{background:var(--color-bg-primary);border:1px solid var(--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);margin:0 auto;max-width:25rem;padding:1em}form{gap:1.5rem}.form-group,form{display:flex;flex-direction:column}label{display:block;font-weight:500;margin-bottom:.5em}input[type=email],input[type=password],label{color:var(--color-gray-700);font-size:.875rem}input[type=email],input[type=password]{background-color:var(--color-bg-secondary);border:1px solid var(--color-border-light);border-radius:8px;box-sizing:border-box;padding:.75em 1em;transition:all .2s ease-in-out;width:100%}input[type=email]:focus,input[type=password]:focus{background-color:var(--color-bg-primary);border-color:var(--color-primary);box-shadow:0 0 0 3px rgba(59,130,246,.1);outline:none}.login-header{margin-bottom:1em;text-align:center}.login-title{color:var(--color-gray-800);font-size:1.875rem;font-weight:700;line-height:1.2;margin:0 0 .5em}.login-subtitle{color:var(--color-gray-500);font-size:.875rem;line-height:1.5;margin:0}.remember-me{align-items:center;display:flex;gap:.5rem}input[type=checkbox]{margin:0;width:auto}.remember-me label{color:var(--color-gray-700);font-size:.875rem;margin:0}button[type=submit]{align-items:center;background-color:var(--color-primary);border:1px solid var(--color-primary);border-radius:8px;color:var(--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%}button[type=submit]:hover:not(:disabled){background-color:var(--color-primary-dark);border-color:var(--color-primary-dark)}button[type=submit]:disabled{cursor:not-allowed;opacity:.6}.loading-spinner{animation:spin 1s linear infinite;border:2px solid var(--color-white);border-radius:50%;border-top:2px solid transparent;height:16px;width:16px}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.login-footer{margin-top:1em;text-align:center}.forgot-password{margin:0}.forgot-link{color:var(--color-primary);font-size:.875rem;text-decoration:none;transition:color .2s ease-in-out}.forgot-link:hover{color:var(--color-primary-dark);text-decoration:underline}.error-message{background-color:var(--color-error-light);border:1px solid var(--color-error-border);border-radius:8px;color:var(--color-error);font-size:.875rem;margin-top:1em;padding:.75em 1em;text-align:center}@media (max-width:480px){.login-form-container{margin:1em;padding:1.5em}.login-title{font-size:1.5rem}}
145
147
  </style>
@@ -0,0 +1,62 @@
1
+ <script setup>
2
+ import { ref } from "vue";
3
+ import { navigateTo } from "#app";
4
+ import { useAuth } from "../composables/useAuth";
5
+ const props = defineProps({
6
+ redirectTo: { type: String, required: false, default: "/login" },
7
+ linkText: { type: String, required: false, default: "Logout" },
8
+ confirmMessage: { type: String, required: false, default: "Are you sure you want to logout?" },
9
+ class: { type: String, required: false }
10
+ });
11
+ const emit = defineEmits(["success", "click", "error"]);
12
+ const { logout } = useAuth();
13
+ const isLoading = ref(false);
14
+ const error = ref("");
15
+ const handleLogout = async (event) => {
16
+ event.preventDefault();
17
+ if (!confirm(props.confirmMessage)) {
18
+ return;
19
+ }
20
+ isLoading.value = true;
21
+ error.value = "";
22
+ try {
23
+ emit("click");
24
+ await logout();
25
+ emit("success");
26
+ if (props.redirectTo) {
27
+ await navigateTo(props.redirectTo);
28
+ }
29
+ } catch (err) {
30
+ const errorMessage = err instanceof Error ? err.message : "Logout failed";
31
+ error.value = errorMessage;
32
+ emit("error", errorMessage);
33
+ } finally {
34
+ isLoading.value = false;
35
+ }
36
+ };
37
+ </script>
38
+
39
+ <template>
40
+ <div>
41
+ <div
42
+ v-if="error"
43
+ class="error-message"
44
+ >
45
+ {{ error }}
46
+ </div>
47
+
48
+ <a
49
+ href="#"
50
+ :class="['logout-link', { loading: isLoading }, props.class]"
51
+ :disabled="isLoading"
52
+ @click="handleLogout"
53
+ >
54
+ <span v-if="isLoading">Logging out...</span>
55
+ <span v-else>{{ linkText }}</span>
56
+ </a>
57
+ </div>
58
+ </template>
59
+
60
+ <style scoped>
61
+ .logout-link{color:#dc3545;cursor:pointer;font-size:.875rem;font-weight:500;text-decoration:none;transition:color .2s}.logout-link:hover:not(.loading){color:#c82333;text-decoration:underline}.logout-link.loading{cursor:not-allowed;opacity:.6;pointer-events:none}.error-message{color:#dc3545;font-size:.875rem;margin-bottom:.5rem}
62
+ </style>
@@ -0,0 +1,20 @@
1
+ interface LogoutLinkProps {
2
+ redirectTo?: string;
3
+ linkText?: string;
4
+ confirmMessage?: string;
5
+ class?: string;
6
+ }
7
+ declare const _default: import("vue").DefineComponent<LogoutLinkProps, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
8
+ click: () => any;
9
+ error: (error: string) => any;
10
+ success: () => any;
11
+ }, string, import("vue").PublicProps, Readonly<LogoutLinkProps> & Readonly<{
12
+ onClick?: (() => any) | undefined;
13
+ onError?: ((error: string) => any) | undefined;
14
+ onSuccess?: (() => any) | undefined;
15
+ }>, {
16
+ redirectTo: string;
17
+ linkText: string;
18
+ confirmMessage: string;
19
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
+ export default _default;
@@ -72,7 +72,7 @@ const handleResetPassword = async () => {
72
72
  } else {
73
73
  message.value = "Failed to reset password.";
74
74
  }
75
- console.error(err);
75
+ console.error("[Nuxt Users] Reset Password Form Error:", err);
76
76
  isError.value = true;
77
77
  } finally {
78
78
  loading.value = false;
@@ -0,0 +1,5 @@
1
+ import type { User } from '../../types.js';
2
+ export declare const useAuth: () => {
3
+ user: import("vue").Ref<User | null, User | null>;
4
+ logout: () => Promise<void>;
5
+ };
@@ -0,0 +1,19 @@
1
+ import { useState } from "#app";
2
+ export const useAuth = () => {
3
+ const user = useState("user", () => null);
4
+ const logout = async () => {
5
+ try {
6
+ await $fetch("/api/logout", {
7
+ method: "GET"
8
+ });
9
+ user.value = null;
10
+ } catch (error) {
11
+ console.error("Logout failed:", error);
12
+ user.value = null;
13
+ }
14
+ };
15
+ return {
16
+ user,
17
+ logout
18
+ };
19
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: import("#app").RouteMiddleware;
2
+ export default _default;
@@ -0,0 +1,12 @@
1
+ import { defineNuxtRouteMiddleware, useRuntimeConfig, navigateTo } from "#app";
2
+ import { useAuth } from "../composables/useAuth.js";
3
+ export default defineNuxtRouteMiddleware((to, _from) => {
4
+ const { nuxtUsers } = useRuntimeConfig();
5
+ const { user } = useAuth();
6
+ if (to.path === "/login") {
7
+ return;
8
+ }
9
+ if (!user.value && !nuxtUsers.auth?.whitelist?.includes(to.path)) {
10
+ return navigateTo("/login");
11
+ }
12
+ });
@@ -3,7 +3,6 @@ import { checkTableExists } from "../utils";
3
3
  export default defineNuxtPlugin(async (_nuxtApp) => {
4
4
  const { nuxtUsers } = useRuntimeConfig();
5
5
  const options = nuxtUsers;
6
- console.log({ nuxtUsers });
7
6
  const hasMigrationsTable = await checkTableExists(options, options.tables.migrations);
8
7
  if (!hasMigrationsTable) {
9
8
  console.warn("[Nuxt Users] \u26A0\uFE0F Migrations table does not exist, you should run the migration script to create it by running: npx nuxt-users migrate");
@@ -14,9 +14,9 @@ export default defineEventHandler(async (event) => {
14
14
  return { message: "If a user with that email exists, a password reset link has been sent." };
15
15
  } catch (error) {
16
16
  if (error instanceof Error) {
17
- console.error("Error in forgot-password endpoint:", error.message);
17
+ console.error("[Nuxt Users] Error in forgot-password endpoint:", error.message);
18
18
  } else {
19
- console.error("Error in forgot-password endpoint:", error);
19
+ console.error("[Nuxt Users] Error in forgot-password endpoint:", error);
20
20
  }
21
21
  throw createError({
22
22
  statusCode: 500,
@@ -33,9 +33,9 @@ export default defineEventHandler(async (event) => {
33
33
  }
34
34
  } catch (error) {
35
35
  if (error instanceof Error) {
36
- console.error("Error in reset-password endpoint:", error.message);
36
+ console.error("[Nuxt Users] Error in reset-password endpoint:", error.message);
37
37
  } else {
38
- console.error("Error in reset-password endpoint:", error);
38
+ console.error("[Nuxt Users] Error in reset-password endpoint:", error);
39
39
  }
40
40
  if (error instanceof H3Error) {
41
41
  throw error;
@@ -3,6 +3,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
3
3
  id: number;
4
4
  email: string;
5
5
  name: string;
6
+ role: string;
6
7
  created_at: string;
7
8
  updated_at: string;
8
9
  };
@@ -46,7 +46,7 @@ export default defineEventHandler(async (event) => {
46
46
  sameSite: "lax",
47
47
  // Adjust as needed
48
48
  maxAge: 60 * 60 * 24 * 7,
49
- // Example: 7 days
49
+ // 7 days
50
50
  path: "/"
51
51
  });
52
52
  const { password: _, ...userWithoutPassword } = user;
@@ -0,0 +1,4 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
2
+ message: string;
3
+ }>>;
4
+ export default _default;
@@ -0,0 +1,21 @@
1
+ import { defineEventHandler, getCookie, setCookie } from "h3";
2
+ import { useRuntimeConfig } from "#imports";
3
+ import { useDb } from "../../../utils";
4
+ export default defineEventHandler(async (event) => {
5
+ const { nuxtUsers } = useRuntimeConfig();
6
+ const options = nuxtUsers;
7
+ const db = await useDb(options);
8
+ const personalAccessTokensTable = options.tables.personalAccessTokens;
9
+ const token = getCookie(event, "auth_token");
10
+ if (token) {
11
+ await db.sql`DELETE FROM {${personalAccessTokensTable}} WHERE token = ${token}`;
12
+ }
13
+ setCookie(event, "auth_token", "", {
14
+ httpOnly: true,
15
+ secure: process.env.NODE_ENV === "production",
16
+ sameSite: "lax",
17
+ maxAge: 0,
18
+ path: "/"
19
+ });
20
+ return { message: "Logged out successfully" };
21
+ });
@@ -6,7 +6,7 @@ const TOKEN_EXPIRATION_HOURS = 1;
6
6
  export const sendPasswordResetLink = async (email, options) => {
7
7
  const user = await findUserByEmail(email, options);
8
8
  if (!user) {
9
- console.log(`Password reset requested for non-existent email: ${email}`);
9
+ console.log(`[Nuxt Users] Password reset requested for non-existent email: ${email}`);
10
10
  return;
11
11
  }
12
12
  const db = await useDb(options);
@@ -18,7 +18,7 @@ export const sendPasswordResetLink = async (email, options) => {
18
18
  VALUES (${email}, ${hashedToken}, CURRENT_TIMESTAMP)
19
19
  `;
20
20
  if (!options.mailer) {
21
- console.error("Mailer configuration is missing. Cannot send password reset email.");
21
+ console.error("[Nuxt Users] Mailer configuration is missing. Cannot send password reset email.");
22
22
  return;
23
23
  }
24
24
  const transporter = createTransport({
@@ -38,9 +38,9 @@ export const sendPasswordResetLink = async (email, options) => {
38
38
  text: `Please click the following link to reset your password: ${options.passwordResetBaseUrl}`,
39
39
  html: `<p>Please click the following link to reset your password:</p><p><a href="${options.passwordResetBaseUrl}">${options.passwordResetBaseUrl}</a></p><p>This link will expire in ${TOKEN_EXPIRATION_HOURS} hour(s).</p>`
40
40
  });
41
- console.log(`Password reset email sent to ${email}`);
41
+ console.log(`[Nuxt Users] Password reset email sent to ${email}`);
42
42
  } catch (error) {
43
- console.error(`Failed to send password reset email to ${email}:`, error);
43
+ console.error(`[Nuxt Users] Failed to send password reset email to ${email}:`, error);
44
44
  }
45
45
  };
46
46
  export const resetPassword = async (token, email, newPassword, options) => {
@@ -52,7 +52,7 @@ export const resetPassword = async (token, email, newPassword, options) => {
52
52
  ORDER BY created_at DESC
53
53
  `;
54
54
  if (tokenRecords.rows.length === 0) {
55
- console.log(`No password reset tokens found for email: ${email}`);
55
+ console.log(`[Nuxt Users] No password reset tokens found for email: ${email}`);
56
56
  return false;
57
57
  }
58
58
  let validTokenRecord = null;
@@ -64,7 +64,7 @@ export const resetPassword = async (token, email, newPassword, options) => {
64
64
  }
65
65
  }
66
66
  if (!validTokenRecord || !validTokenRecord.created_at) {
67
- console.log(`Invalid password reset token provided for email: ${email}`);
67
+ console.log(`[Nuxt Users] Invalid password reset token provided for email: ${email}`);
68
68
  return false;
69
69
  }
70
70
  const now = /* @__PURE__ */ new Date();
@@ -82,13 +82,13 @@ export const resetPassword = async (token, email, newPassword, options) => {
82
82
  }
83
83
  const expirationTimeString = `${expirationYear.toString().padStart(4, "0")}-${expirationMonth.toString().padStart(2, "0")}-${expirationDay.toString().padStart(2, "0")} ${expirationHour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}:${second.toString().padStart(2, "0")}`;
84
84
  if (currentTimeString > expirationTimeString) {
85
- console.log(`Expired password reset token for email: ${email}`);
85
+ console.log(`[Nuxt Users] Expired password reset token for email: ${email}`);
86
86
  await db.sql`DELETE FROM {${passwordResetTokensTable}} WHERE id = ${validTokenRecord.id}`;
87
87
  return false;
88
88
  }
89
89
  await updateUserPassword(email, newPassword, options);
90
90
  await db.sql`DELETE FROM {${passwordResetTokensTable}} WHERE email = ${email}`;
91
- console.log(`Password reset successful for email: ${email}`);
91
+ console.log(`[Nuxt Users] Password reset successful for email: ${email}`);
92
92
  return true;
93
93
  };
94
94
  export const deleteExpiredPasswordResetTokens = async (options) => {
@@ -101,5 +101,5 @@ export const deleteExpiredPasswordResetTokens = async (options) => {
101
101
  DELETE FROM {${passwordResetTokensTable}}
102
102
  WHERE created_at < ${expirationDateString}
103
103
  `;
104
- console.log(`Expired password reset tokens older than ${expirationDateString} deleted.`);
104
+ console.log(`[Nuxt Users] Expired password reset tokens older than ${expirationDateString} deleted.`);
105
105
  };
@@ -32,7 +32,14 @@ interface ModuleOptions {
32
32
  * Skip database checks during module setup to prevent hanging
33
33
  * @default false
34
34
  */
35
- skipDatabaseChecks?: boolean;
35
+ auth?: {
36
+ /**
37
+ * Whitelisted routes that do not require authentication
38
+ * @default ['/login']
39
+ * @example ['/login', '/register']
40
+ */
41
+ whitelist: string[];
42
+ };
36
43
  }
37
44
  interface MailerOptions {
38
45
  host: string;
@@ -51,6 +58,7 @@ interface User {
51
58
  email: string;
52
59
  name: string;
53
60
  password: string;
61
+ role: string;
54
62
  created_at: string;
55
63
  updated_at: string;
56
64
  }
@@ -32,7 +32,14 @@ interface ModuleOptions {
32
32
  * Skip database checks during module setup to prevent hanging
33
33
  * @default false
34
34
  */
35
- skipDatabaseChecks?: boolean;
35
+ auth?: {
36
+ /**
37
+ * Whitelisted routes that do not require authentication
38
+ * @default ['/login']
39
+ * @example ['/login', '/register']
40
+ */
41
+ whitelist: string[];
42
+ };
36
43
  }
37
44
  interface MailerOptions {
38
45
  host: string;
@@ -51,6 +58,7 @@ interface User {
51
58
  email: string;
52
59
  name: string;
53
60
  password: string;
61
+ role: string;
54
62
  created_at: string;
55
63
  updated_at: string;
56
64
  }
@@ -33,7 +33,7 @@ const useDb = async (options) => {
33
33
  try {
34
34
  return createDatabase(connector(connectorOptions));
35
35
  } catch (error) {
36
- console.warn(`[Nuxt Users DB] \u26A0\uFE0F Failed to connect to ${connectorName} database:`, error instanceof Error ? error.message : "Unknown error");
36
+ console.warn(`[Nuxt Users] \u26A0\uFE0F Failed to connect to ${connectorName} database:`, error instanceof Error ? error.message : "Unknown error");
37
37
  throw error;
38
38
  }
39
39
  };
@@ -51,11 +51,12 @@ const createUser = async (userData, options) => {
51
51
  const db = await useDb(options);
52
52
  const usersTable = options.tables.users;
53
53
  const hashedPassword = await bcrypt.hash(userData.password, 10);
54
+ const role = userData.role || "user";
54
55
  await db.sql`
55
- INSERT INTO {${usersTable}} (email, name, password, created_at, updated_at)
56
- VALUES (${userData.email}, ${userData.name}, ${hashedPassword}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
56
+ INSERT INTO {${usersTable}} (email, name, password, role, created_at, updated_at)
57
+ VALUES (${userData.email}, ${userData.name}, ${hashedPassword}, ${role}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
57
58
  `;
58
- const result = await db.sql`SELECT id, email, name, created_at, updated_at FROM {${usersTable}} WHERE email = ${userData.email}`;
59
+ const result = await db.sql`SELECT id, email, name, role, created_at, updated_at FROM {${usersTable}} WHERE email = ${userData.email}`;
59
60
  if (result.rows.length === 0) {
60
61
  throw new Error("Failed to retrieve created user.");
61
62
  }
@@ -64,6 +65,7 @@ const createUser = async (userData, options) => {
64
65
  id: user.id,
65
66
  email: user.email,
66
67
  name: user.name,
68
+ role: user.role,
67
69
  created_at: user.created_at instanceof Date ? user.created_at.toISOString() : user.created_at,
68
70
  updated_at: user.updated_at instanceof Date ? user.updated_at.toISOString() : user.updated_at
69
71
  };
@@ -81,6 +83,7 @@ const findUserByEmail = async (email, options) => {
81
83
  email: user.email,
82
84
  name: user.name,
83
85
  password: user.password,
86
+ role: user.role,
84
87
  created_at: user.created_at instanceof Date ? user.created_at.toISOString() : user.created_at,
85
88
  updated_at: user.updated_at instanceof Date ? user.updated_at.toISOString() : user.updated_at
86
89
  };
@@ -100,7 +103,7 @@ const createUsersTable = async (options) => {
100
103
  const connectorName = options.connector.name;
101
104
  const db = await useDb(options);
102
105
  const tableName = options.tables.users;
103
- console.log(`[DB:Create ${connectorName} Users Table] Creating ${tableName}...`);
106
+ console.log(`[Nuxt Users] DB:Create ${connectorName} Users Table Creating ${tableName}...`);
104
107
  if (connectorName === "sqlite") {
105
108
  await db.sql`
106
109
  CREATE TABLE IF NOT EXISTS {${tableName}} (
@@ -108,6 +111,7 @@ const createUsersTable = async (options) => {
108
111
  email TEXT NOT NULL UNIQUE,
109
112
  name TEXT NOT NULL,
110
113
  password TEXT NOT NULL,
114
+ role TEXT NOT NULL DEFAULT 'user',
111
115
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
112
116
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
113
117
  )
@@ -120,6 +124,7 @@ const createUsersTable = async (options) => {
120
124
  email VARCHAR(255) NOT NULL UNIQUE,
121
125
  name VARCHAR(255) NOT NULL,
122
126
  password VARCHAR(255) NOT NULL,
127
+ role VARCHAR(32) NOT NULL DEFAULT 'user',
123
128
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
124
129
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
125
130
  )
@@ -132,19 +137,20 @@ const createUsersTable = async (options) => {
132
137
  email VARCHAR(255) NOT NULL UNIQUE,
133
138
  name VARCHAR(255) NOT NULL,
134
139
  password VARCHAR(255) NOT NULL,
140
+ role VARCHAR(32) NOT NULL DEFAULT 'user',
135
141
  created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
136
142
  updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
137
143
  )
138
144
  `;
139
145
  }
140
- console.log(`[DB:Create ${connectorName} Users Table] Fields: id, email, name, password, created_at, updated_at \u2705`);
146
+ console.log(`[Nuxt Users] DB:Create ${connectorName} Users Table Fields: id, email, name, password, role, created_at, updated_at \u2705`);
141
147
  };
142
148
 
143
149
  const createPersonalAccessTokensTable = async (options) => {
144
150
  const connectorName = options.connector.name;
145
151
  const db = await useDb(options);
146
152
  const tableName = options.tables.personalAccessTokens;
147
- console.log(`[DB:Create Personal Access Tokens ${connectorName} Table] Creating ${tableName} table with ${connectorName} connector...`);
153
+ console.log(`[Nuxt Users] DB:Create Personal Access Tokens ${connectorName} Table Creating ${tableName} table with ${connectorName} connector...`);
148
154
  if (connectorName === "sqlite") {
149
155
  await db.sql`
150
156
  CREATE TABLE IF NOT EXISTS {${tableName}} (
@@ -193,14 +199,14 @@ const createPersonalAccessTokensTable = async (options) => {
193
199
  )
194
200
  `;
195
201
  }
196
- console.log(`[DB:Create Personal Access Tokens ${connectorName} Table] Fields: id, tokenable_type, tokenable_id, name, token, abilities, last_used_at, expires_at, created_at, updated_at \u2705`);
202
+ console.log(`[Nuxt Users] DB:Create Personal Access Tokens ${connectorName} Table Fields: id, tokenable_type, tokenable_id, name, token, abilities, last_used_at, expires_at, created_at, updated_at \u2705`);
197
203
  };
198
204
 
199
205
  const createPasswordResetTokensTable = async (options) => {
200
206
  const connectorName = options.connector.name;
201
207
  const db = await useDb(options);
202
208
  const tableName = options.tables.passwordResetTokens;
203
- console.log(`[DB:Create Password Reset Tokens ${connectorName} Table] Creating ${tableName} table with ${connectorName} connector...`);
209
+ console.log(`[Nuxt Users] DB:Create Password Reset Tokens ${connectorName} Table Creating ${tableName} table with ${connectorName} connector...`);
204
210
  if (connectorName === "sqlite") {
205
211
  await db.sql`
206
212
  CREATE TABLE IF NOT EXISTS {${tableName}} (
@@ -233,14 +239,14 @@ const createPasswordResetTokensTable = async (options) => {
233
239
  }
234
240
  await db.sql`CREATE INDEX IF NOT EXISTS idx_password_reset_tokens_email ON {${tableName}} (email)`;
235
241
  await db.sql`CREATE INDEX IF NOT EXISTS idx_password_reset_tokens_token ON {${tableName}} (token)`;
236
- console.log(`[DB:Create Password Reset Tokens ${connectorName} Table] Fields: id, email, token, created_at \u2705`);
242
+ console.log(`[Nuxt Users] DB:Create Password Reset Tokens ${connectorName} Table Fields: id, email, token, created_at \u2705`);
237
243
  };
238
244
 
239
245
  const createMigrationsTable = async (options) => {
240
246
  const connectorName = options.connector.name;
241
247
  const db = await useDb(options);
242
248
  const tableName = "migrations";
243
- console.log(`[DB:Create Migrations ${connectorName} Table] Creating ${tableName} table with ${connectorName} connector...`);
249
+ console.log(`[Nuxt Users] DB:Create Migrations ${connectorName} Table Creating ${tableName} table with ${connectorName} connector...`);
244
250
  if (connectorName === "sqlite") {
245
251
  await db.sql`
246
252
  CREATE TABLE IF NOT EXISTS {${tableName}} (
@@ -268,7 +274,7 @@ const createMigrationsTable = async (options) => {
268
274
  )
269
275
  `;
270
276
  }
271
- console.log(`[DB:Create Migrations ${connectorName} Table] successfull \u2705`);
277
+ console.log(`[Nuxt Users] DB:Create Migrations ${connectorName} Table successfull \u2705`);
272
278
  };
273
279
 
274
280
  const migrations = [
@@ -314,7 +320,7 @@ const runMigrations = async (options) => {
314
320
  }
315
321
  console.log(`[Nuxt Users] Found ${pendingMigrations.length} pending migrations:`);
316
322
  pendingMigrations.forEach((migration) => {
317
- console.log(` - ${migration.name}`);
323
+ console.log(`[Nuxt Users] - ${migration.name}`);
318
324
  });
319
325
  for (const migration of pendingMigrations) {
320
326
  console.log(`[Nuxt Users] Running migration: ${migration.name}`);
package/dist/utils.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as db0 from 'db0';
2
- import { M as ModuleOptions, U as User } from './shared/nuxt-users.Dtq4WcpY.mjs';
2
+ import { M as ModuleOptions, U as User } from './shared/nuxt-users.DGRKT2Tq.mjs';
3
3
 
4
4
  declare const useDb: (options: ModuleOptions) => Promise<db0.Database<db0.Connector<Database.Database>>>;
5
5
  declare const checkTableExists: (options: ModuleOptions, tableName: string) => Promise<boolean>;
@@ -8,6 +8,7 @@ interface CreateUserParams {
8
8
  email: string;
9
9
  name: string;
10
10
  password: string;
11
+ role?: string;
11
12
  }
12
13
  /**
13
14
  * Creates a new user in the database.
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as db0 from 'db0';
2
- import { M as ModuleOptions, U as User } from './shared/nuxt-users.Dtq4WcpY.js';
2
+ import { M as ModuleOptions, U as User } from './shared/nuxt-users.DGRKT2Tq.js';
3
3
 
4
4
  declare const useDb: (options: ModuleOptions) => Promise<db0.Database<db0.Connector<Database.Database>>>;
5
5
  declare const checkTableExists: (options: ModuleOptions, tableName: string) => Promise<boolean>;
@@ -8,6 +8,7 @@ interface CreateUserParams {
8
8
  email: string;
9
9
  name: string;
10
10
  password: string;
11
+ role?: string;
11
12
  }
12
13
  /**
13
14
  * Creates a new user in the database.
package/dist/utils.mjs CHANGED
@@ -1,3 +1,3 @@
1
- export { c as checkTableExists, h as createMigrationsTable, g as createPasswordResetTokensTable, e as createPersonalAccessTokensTable, a as createUser, d as createUsersTable, f as findUserByEmail, r as runMigrations, b as updateUserPassword, u as useDb } from './shared/nuxt-users.eSQUrS6l.mjs';
1
+ export { c as checkTableExists, h as createMigrationsTable, g as createPasswordResetTokensTable, e as createPersonalAccessTokensTable, a as createUser, d as createUsersTable, f as findUserByEmail, r as runMigrations, b as updateUserPassword, u as useDb } from './shared/nuxt-users.DZkU2AbH.mjs';
2
2
  import 'bcrypt';
3
3
  import 'db0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-users",
3
- "version": "1.1.6",
3
+ "version": "1.3.0",
4
4
  "description": "A comprehensive user management module for Nuxt 3 applications with authentication, database support, and CLI tools",
5
5
  "keywords": [
6
6
  "nuxt",