nuxt-users 1.37.2 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-users",
3
3
  "configKey": "nuxtUsers",
4
- "version": "1.37.2",
4
+ "version": "1.38.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -52,7 +52,7 @@ const defaultOptions = {
52
52
  },
53
53
  hardDelete: false
54
54
  };
55
- const module = defineNuxtModule({
55
+ const module$1 = defineNuxtModule({
56
56
  meta: {
57
57
  name: "nuxt-users",
58
58
  configKey: "nuxtUsers"
@@ -144,6 +144,10 @@ const module = defineNuxtModule({
144
144
  },
145
145
  apiBasePath: runtimeConfigOptions.apiBasePath || defaultOptions.apiBasePath
146
146
  };
147
+ addPlugin({
148
+ src: resolver.resolve("./runtime/plugin.auth-init"),
149
+ name: "0-auth-init-nuxt-users"
150
+ });
147
151
  addPlugin({
148
152
  src: resolver.resolve("./runtime/plugin"),
149
153
  mode: "server"
@@ -266,4 +270,4 @@ const module = defineNuxtModule({
266
270
  }
267
271
  });
268
272
 
269
- export { module as default, defaultOptions };
273
+ export { module$1 as default, defaultOptions };
@@ -26,14 +26,14 @@ type __VLS_Slots = {} & {
26
26
  'error-message'?: (props: typeof __VLS_15) => any;
27
27
  };
28
28
  declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
29
- error: (error: string) => any;
30
29
  success: (user: UserWithoutPassword, rememberMe: boolean) => any;
30
+ error: (error: string) => any;
31
31
  submit: (data: LoginFormData) => any;
32
32
  "forgot-password-error": (error: string) => any;
33
33
  "forgot-password-success": () => any;
34
34
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
35
- onError?: ((error: string) => any) | undefined;
36
35
  onSuccess?: ((user: UserWithoutPassword, rememberMe: boolean) => any) | undefined;
36
+ onError?: ((error: string) => any) | undefined;
37
37
  onSubmit?: ((data: LoginFormData) => any) | undefined;
38
38
  "onForgot-password-error"?: ((error: string) => any) | undefined;
39
39
  "onForgot-password-success"?: (() => any) | undefined;
@@ -26,14 +26,14 @@ type __VLS_Slots = {} & {
26
26
  'error-message'?: (props: typeof __VLS_15) => any;
27
27
  };
28
28
  declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
29
- error: (error: string) => any;
30
29
  success: (user: UserWithoutPassword, rememberMe: boolean) => any;
30
+ error: (error: string) => any;
31
31
  submit: (data: LoginFormData) => any;
32
32
  "forgot-password-error": (error: string) => any;
33
33
  "forgot-password-success": () => any;
34
34
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
35
- onError?: ((error: string) => any) | undefined;
36
35
  onSuccess?: ((user: UserWithoutPassword, rememberMe: boolean) => any) | undefined;
36
+ onError?: ((error: string) => any) | undefined;
37
37
  onSubmit?: ((data: LoginFormData) => any) | undefined;
38
38
  "onForgot-password-error"?: ((error: string) => any) | undefined;
39
39
  "onForgot-password-success"?: (() => any) | undefined;
@@ -16,12 +16,12 @@ type __VLS_Slots = {} & {
16
16
  default?: (props: typeof __VLS_1) => any;
17
17
  };
18
18
  declare const __VLS_base: import("vue").DefineComponent<LogoutLinkProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
19
- error: (error: string) => any;
20
19
  success: () => any;
20
+ error: (error: string) => any;
21
21
  click: () => any;
22
22
  }, string, import("vue").PublicProps, Readonly<LogoutLinkProps> & Readonly<{
23
- onError?: ((error: string) => any) | undefined;
24
23
  onSuccess?: (() => any) | undefined;
24
+ onError?: ((error: string) => any) | undefined;
25
25
  onClick?: (() => any) | undefined;
26
26
  }>, {
27
27
  redirectTo: string;
@@ -16,12 +16,12 @@ type __VLS_Slots = {} & {
16
16
  default?: (props: typeof __VLS_1) => any;
17
17
  };
18
18
  declare const __VLS_base: import("vue").DefineComponent<LogoutLinkProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
19
- error: (error: string) => any;
20
19
  success: () => any;
20
+ error: (error: string) => any;
21
21
  click: () => any;
22
22
  }, string, import("vue").PublicProps, Readonly<LogoutLinkProps> & Readonly<{
23
- onError?: ((error: string) => any) | undefined;
24
23
  onSuccess?: (() => any) | undefined;
24
+ onError?: ((error: string) => any) | undefined;
25
25
  onClick?: (() => any) | undefined;
26
26
  }>, {
27
27
  redirectTo: string;
@@ -10,9 +10,9 @@ interface RegistrationFormData {
10
10
  password: string;
11
11
  confirmPassword: string;
12
12
  }
13
- declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_16: {}, __VLS_18: {}, __VLS_20: {}, __VLS_22: {
13
+ declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_17: {}, __VLS_19: {}, __VLS_21: {}, __VLS_23: {
14
14
  message: string;
15
- }, __VLS_24: {
15
+ }, __VLS_25: {
16
16
  error: string;
17
17
  };
18
18
  type __VLS_Slots = {} & {
@@ -26,29 +26,29 @@ type __VLS_Slots = {} & {
26
26
  } & {
27
27
  'password-strength'?: (props: typeof __VLS_9) => any;
28
28
  } & {
29
- 'confirm-password-field'?: (props: typeof __VLS_16) => any;
29
+ 'confirm-password-field'?: (props: typeof __VLS_17) => any;
30
30
  } & {
31
- 'submit-button'?: (props: typeof __VLS_18) => any;
31
+ 'submit-button'?: (props: typeof __VLS_19) => any;
32
32
  } & {
33
- footer?: (props: typeof __VLS_20) => any;
33
+ footer?: (props: typeof __VLS_21) => any;
34
34
  } & {
35
- 'success-message'?: (props: typeof __VLS_22) => any;
35
+ 'success-message'?: (props: typeof __VLS_23) => any;
36
36
  } & {
37
- 'error-message'?: (props: typeof __VLS_24) => any;
37
+ 'error-message'?: (props: typeof __VLS_25) => any;
38
38
  };
39
39
  declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
40
- error: (error: string) => any;
41
40
  success: (data: {
42
41
  user: Omit<UserWithoutPassword, "active">;
43
42
  message: string;
44
43
  }) => any;
44
+ error: (error: string) => any;
45
45
  submit: (data: RegistrationFormData) => any;
46
46
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
47
- onError?: ((error: string) => any) | undefined;
48
47
  onSuccess?: ((data: {
49
48
  user: Omit<UserWithoutPassword, "active">;
50
49
  message: string;
51
50
  }) => any) | undefined;
51
+ onError?: ((error: string) => any) | undefined;
52
52
  onSubmit?: ((data: RegistrationFormData) => any) | undefined;
53
53
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
54
54
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -10,9 +10,9 @@ interface RegistrationFormData {
10
10
  password: string;
11
11
  confirmPassword: string;
12
12
  }
13
- declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_16: {}, __VLS_18: {}, __VLS_20: {}, __VLS_22: {
13
+ declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_17: {}, __VLS_19: {}, __VLS_21: {}, __VLS_23: {
14
14
  message: string;
15
- }, __VLS_24: {
15
+ }, __VLS_25: {
16
16
  error: string;
17
17
  };
18
18
  type __VLS_Slots = {} & {
@@ -26,29 +26,29 @@ type __VLS_Slots = {} & {
26
26
  } & {
27
27
  'password-strength'?: (props: typeof __VLS_9) => any;
28
28
  } & {
29
- 'confirm-password-field'?: (props: typeof __VLS_16) => any;
29
+ 'confirm-password-field'?: (props: typeof __VLS_17) => any;
30
30
  } & {
31
- 'submit-button'?: (props: typeof __VLS_18) => any;
31
+ 'submit-button'?: (props: typeof __VLS_19) => any;
32
32
  } & {
33
- footer?: (props: typeof __VLS_20) => any;
33
+ footer?: (props: typeof __VLS_21) => any;
34
34
  } & {
35
- 'success-message'?: (props: typeof __VLS_22) => any;
35
+ 'success-message'?: (props: typeof __VLS_23) => any;
36
36
  } & {
37
- 'error-message'?: (props: typeof __VLS_24) => any;
37
+ 'error-message'?: (props: typeof __VLS_25) => any;
38
38
  };
39
39
  declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
40
- error: (error: string) => any;
41
40
  success: (data: {
42
41
  user: Omit<UserWithoutPassword, "active">;
43
42
  message: string;
44
43
  }) => any;
44
+ error: (error: string) => any;
45
45
  submit: (data: RegistrationFormData) => any;
46
46
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
47
- onError?: ((error: string) => any) | undefined;
48
47
  onSuccess?: ((data: {
49
48
  user: Omit<UserWithoutPassword, "active">;
50
49
  message: string;
51
50
  }) => any) | undefined;
51
+ onError?: ((error: string) => any) | undefined;
52
52
  onSubmit?: ((data: RegistrationFormData) => any) | undefined;
53
53
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
54
54
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -4,13 +4,13 @@ interface Props {
4
4
  redirectTo?: string;
5
5
  }
6
6
  declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
7
- error: (error: string) => any;
8
7
  success: (user: UserWithoutPassword) => any;
8
+ error: (error: string) => any;
9
9
  "password-error": (error: string) => any;
10
10
  "password-updated": () => any;
11
11
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
12
- onError?: ((error: string) => any) | undefined;
13
12
  onSuccess?: ((user: UserWithoutPassword) => any) | undefined;
13
+ onError?: ((error: string) => any) | undefined;
14
14
  "onPassword-error"?: ((error: string) => any) | undefined;
15
15
  "onPassword-updated"?: (() => any) | undefined;
16
16
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -4,13 +4,13 @@ interface Props {
4
4
  redirectTo?: string;
5
5
  }
6
6
  declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
7
- error: (error: string) => any;
8
7
  success: (user: UserWithoutPassword) => any;
8
+ error: (error: string) => any;
9
9
  "password-error": (error: string) => any;
10
10
  "password-updated": () => any;
11
11
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
12
- onError?: ((error: string) => any) | undefined;
13
12
  onSuccess?: ((user: UserWithoutPassword) => any) | undefined;
13
+ onError?: ((error: string) => any) | undefined;
14
14
  "onPassword-error"?: ((error: string) => any) | undefined;
15
15
  "onPassword-updated"?: (() => any) | undefined;
16
16
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -6,16 +6,16 @@ interface Props {
6
6
  fieldLabels?: Record<string, string>;
7
7
  }
8
8
  declare var __VLS_1: {
9
- user: User;
9
+ user: any;
10
10
  index: number;
11
11
  }, __VLS_3: {
12
12
  canEdit: any;
13
13
  editUser: () => Promise<void>;
14
- user: User;
14
+ user: any;
15
15
  }, __VLS_5: {
16
16
  canDelete: any;
17
17
  deleteUser: () => Promise<void>;
18
- user: User;
18
+ user: any;
19
19
  };
20
20
  type __VLS_Slots = {} & {
21
21
  userCard?: (props: typeof __VLS_1) => any;
@@ -6,16 +6,16 @@ interface Props {
6
6
  fieldLabels?: Record<string, string>;
7
7
  }
8
8
  declare var __VLS_1: {
9
- user: User;
9
+ user: any;
10
10
  index: number;
11
11
  }, __VLS_3: {
12
12
  canEdit: any;
13
13
  editUser: () => Promise<void>;
14
- user: User;
14
+ user: any;
15
15
  }, __VLS_5: {
16
16
  canDelete: any;
17
17
  deleteUser: () => Promise<void>;
18
- user: User;
18
+ user: any;
19
19
  };
20
20
  type __VLS_Slots = {} & {
21
21
  userCard?: (props: typeof __VLS_1) => any;
@@ -14,9 +14,9 @@ export const useAuthentication = () => {
14
14
  sessionStorage.removeItem("user");
15
15
  if (rememberMe) {
16
16
  localStorage.setItem("user", JSON.stringify(userWithoutPassword));
17
- } else {
18
- sessionStorage.setItem("user", JSON.stringify(userWithoutPassword));
17
+ return;
19
18
  }
19
+ sessionStorage.setItem("user", JSON.stringify(userWithoutPassword));
20
20
  }
21
21
  };
22
22
  const logout = async () => {
@@ -48,7 +48,8 @@ export const useAuthentication = () => {
48
48
  throw new Error(error.value.message || "Failed to fetch user");
49
49
  }
50
50
  userData = data.value?.user || null;
51
- } else {
51
+ }
52
+ if (!useSSR) {
52
53
  const response = await $fetch(`${apiBasePath}/me`, {
53
54
  method: "GET"
54
55
  });
@@ -63,9 +64,11 @@ export const useAuthentication = () => {
63
64
  const wasInSessionStorage = sessionStorage.getItem("user") !== null;
64
65
  if (wasInLocalStorage) {
65
66
  localStorage.setItem("user", JSON.stringify(userData));
66
- } else if (wasInSessionStorage) {
67
+ }
68
+ if (wasInSessionStorage) {
67
69
  sessionStorage.setItem("user", JSON.stringify(userData));
68
- } else {
70
+ }
71
+ if (!wasInLocalStorage && !wasInSessionStorage) {
69
72
  sessionStorage.setItem("user", JSON.stringify(userData));
70
73
  }
71
74
  }
@@ -84,24 +87,35 @@ export const useAuthentication = () => {
84
87
  if (!import.meta.client) {
85
88
  return;
86
89
  }
87
- const storedUserLocal = localStorage.getItem("user");
88
- const storedUserSession = sessionStorage.getItem("user");
89
- const storedUser = storedUserLocal || storedUserSession;
90
- if (storedUser) {
90
+ if (initializationPromise) {
91
+ return initializationPromise;
92
+ }
93
+ initializationPromise = (async () => {
94
+ const storedUserLocal = localStorage.getItem("user");
95
+ const storedUserSession = sessionStorage.getItem("user");
96
+ const storedUser = storedUserLocal || storedUserSession;
97
+ if (storedUser) {
98
+ try {
99
+ user.value = JSON.parse(storedUser);
100
+ await fetchUser();
101
+ } catch (error) {
102
+ console.error("Failed to parse stored user:", error);
103
+ localStorage.removeItem("user");
104
+ sessionStorage.removeItem("user");
105
+ user.value = null;
106
+ }
107
+ return;
108
+ }
91
109
  try {
92
- user.value = JSON.parse(storedUser);
93
110
  await fetchUser();
94
- } catch (error) {
95
- console.error("Failed to parse stored user:", error);
96
- localStorage.removeItem("user");
97
- sessionStorage.removeItem("user");
98
- user.value = null;
111
+ } catch {
99
112
  }
100
- }
113
+ })().catch((_error) => {
114
+ });
115
+ return initializationPromise;
101
116
  };
102
117
  if (import.meta.client && !initializationPromise) {
103
- initializationPromise = initializeUser().catch(() => {
104
- });
118
+ initializeUser();
105
119
  }
106
120
  return {
107
121
  user: readonly(user),
@@ -18,7 +18,10 @@ export default defineNuxtRouteMiddleware(async (to) => {
18
18
  console.log(`[Nuxt Users] client.middleware.auth.global: Whitelisted: ${to.path}`);
19
19
  return;
20
20
  }
21
- const { isAuthenticated, user, fetchUser } = useAuthentication();
21
+ const { isAuthenticated, user, fetchUser, initializeUser } = useAuthentication();
22
+ if (!isAuthenticated.value) {
23
+ await initializeUser();
24
+ }
22
25
  if (!isAuthenticated.value && to.query?.oauth_success === "true") {
23
26
  try {
24
27
  await fetchUser(true);
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Early authentication initialization plugin
3
+ *
4
+ * This plugin runs early (name starts with '0') to ensure authentication state
5
+ * is initialized from cookies before middleware runs. This prevents redirects
6
+ * to login page when opening new tabs with valid session cookies.
7
+ */
8
+ declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
9
+ export default _default;
@@ -0,0 +1,16 @@
1
+ import { defineNuxtPlugin } from "#app";
2
+ import { useAuthentication } from "./composables/useAuthentication.js";
3
+ export default defineNuxtPlugin(async () => {
4
+ if (import.meta.server) {
5
+ const { fetchUser } = useAuthentication();
6
+ try {
7
+ await fetchUser(true);
8
+ } catch {
9
+ }
10
+ return;
11
+ }
12
+ if (import.meta.client) {
13
+ const { initializeUser } = useAuthentication();
14
+ await initializeUser();
15
+ }
16
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-users",
3
- "version": "1.37.2",
3
+ "version": "1.38.0",
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",
@@ -63,7 +63,7 @@
63
63
  "build": "nuxt-module-build build",
64
64
  "postbuild": "node scripts/post-build.js",
65
65
  "prerelease": "node -v | grep -q 'v22' || (echo 'Please use Node.js v22 for deployment' && exit 1)",
66
- "release": "yarn lint && yarn test && yarn prepack && changelogen --release && yarn publish && git push --follow-tags",
66
+ "release": "yarn lint && yarn test && yarn prepack && changelogen --release && npm publish && git push --follow-tags",
67
67
  "lint": "eslint .",
68
68
  "lint:fix": "eslint . --fix",
69
69
  "pretest": "node -v | grep -q 'v22' || (echo 'Please use Node.js v22 for testing' && exit 1)",
@@ -1,18 +0,0 @@
1
- {
2
- "eslint.experimental.useFlatConfig": true,
3
- "editor.formatOnSave": true,
4
- "editor.defaultFormatter": "dbaeumer.vscode-eslint",
5
- "editor.codeActionsOnSave": {
6
- "source.fixAll.eslint": "explicit"
7
- },
8
- "[javascript]": {
9
- "editor.defaultFormatter": "dbaeumer.vscode-eslint"
10
- },
11
- "[typescript]": {
12
- "editor.defaultFormatter": "dbaeumer.vscode-eslint"
13
- },
14
- "[vue]": {
15
- "editor.defaultFormatter": "dbaeumer.vscode-eslint"
16
- },
17
- "eslint.validate": ["javascript", "typescript", "vue"]
18
- }