nuxt-users 1.37.3 → 1.39.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/README.md +5 -1
- package/dist/cli.mjs +10 -6
- package/dist/module.d.mts +1 -1
- package/dist/module.d.ts +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +16 -3
- package/dist/runtime/components/NUsersEmailConfirmation.d.vue.ts +5 -3
- package/dist/runtime/components/NUsersEmailConfirmation.vue +22 -15
- package/dist/runtime/components/NUsersEmailConfirmation.vue.d.ts +5 -3
- package/dist/runtime/components/NUsersGoogleLoginButton.d.vue.ts +4 -2
- package/dist/runtime/components/NUsersGoogleLoginButton.vue +5 -2
- package/dist/runtime/components/NUsersGoogleLoginButton.vue.d.ts +4 -2
- package/dist/runtime/components/NUsersList.vue +25 -11
- package/dist/runtime/components/NUsersLoginForm.d.vue.ts +13 -2
- package/dist/runtime/components/NUsersLoginForm.vue +35 -13
- package/dist/runtime/components/NUsersLoginForm.vue.d.ts +13 -2
- package/dist/runtime/components/NUsersLogoutLink.d.vue.ts +3 -4
- package/dist/runtime/components/NUsersLogoutLink.vue +8 -5
- package/dist/runtime/components/NUsersLogoutLink.vue.d.ts +3 -4
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.d.vue.ts +6 -0
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue +17 -9
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue.d.ts +6 -0
- package/dist/runtime/components/NUsersProfileInfo.d.vue.ts +13 -1
- package/dist/runtime/components/NUsersProfileInfo.vue +23 -9
- package/dist/runtime/components/NUsersProfileInfo.vue.d.ts +13 -1
- package/dist/runtime/components/NUsersRegisterForm.d.vue.ts +26 -11
- package/dist/runtime/components/NUsersRegisterForm.vue +34 -16
- package/dist/runtime/components/NUsersRegisterForm.vue.d.ts +26 -11
- package/dist/runtime/components/NUsersResetPasswordForm.d.vue.ts +11 -2
- package/dist/runtime/components/NUsersResetPasswordForm.vue +25 -12
- package/dist/runtime/components/NUsersResetPasswordForm.vue.d.ts +11 -2
- package/dist/runtime/components/NUsersUserCard.d.vue.ts +2 -0
- package/dist/runtime/components/NUsersUserCard.vue +8 -4
- package/dist/runtime/components/NUsersUserCard.vue.d.ts +2 -0
- package/dist/runtime/components/NUsersUserForm.d.vue.ts +2 -2
- package/dist/runtime/components/NUsersUserForm.vue +5 -4
- package/dist/runtime/components/NUsersUserForm.vue.d.ts +2 -2
- package/dist/runtime/composables/useNuxtUsersLocale.d.ts +15 -0
- package/dist/runtime/composables/useNuxtUsersLocale.js +27 -0
- package/dist/runtime/composables/usePasswordValidation.d.ts +1 -1
- package/dist/runtime/composables/usePublicPaths.js +2 -1
- package/dist/runtime/locales/en.d.ts +2 -0
- package/dist/runtime/locales/en.js +130 -0
- package/dist/runtime/locales/hu.d.ts +3 -0
- package/dist/runtime/locales/hu.js +188 -0
- package/dist/runtime/locales/index.d.ts +5 -0
- package/dist/runtime/locales/index.js +8 -0
- package/dist/runtime/middleware/authorization.client.js +4 -1
- package/dist/runtime/plugin.auth-init.d.ts +9 -0
- package/dist/runtime/plugin.auth-init.js +16 -0
- package/dist/runtime/server/api/nuxt-users/confirm-email.get.js +3 -3
- package/dist/runtime/server/api/nuxt-users/password/forgot.post.js +2 -1
- package/dist/runtime/server/api/nuxt-users/password/reset.post.d.ts +1 -1
- package/dist/runtime/server/api/nuxt-users/password/reset.post.js +4 -2
- package/dist/runtime/server/api/nuxt-users/session/index.post.js +4 -2
- package/dist/runtime/server/middleware/authorization.server.js +6 -3
- package/dist/runtime/server/utils/google-oauth.js +2 -1
- package/dist/runtime/utils/deep-merge.d.ts +8 -0
- package/dist/runtime/utils/deep-merge.js +17 -0
- package/dist/runtime/utils/locale.d.ts +14 -0
- package/dist/runtime/utils/locale.js +38 -0
- package/dist/shared/{nuxt-users.BnOQs2LI.mjs → nuxt-users.DfZ7bc_P.mjs} +16 -8
- package/dist/shared/{nuxt-users.SXaMnaEL.d.ts → nuxt-users.FiQjvlZl.d.mts} +40 -2
- package/dist/shared/{nuxt-users.SXaMnaEL.d.mts → nuxt-users.FiQjvlZl.d.ts} +40 -2
- package/dist/utils.d.mts +4 -1
- package/dist/utils.d.ts +4 -1
- package/dist/utils.mjs +4 -1
- package/package.json +5 -3
- package/scripts/check-locale-consistency.ts +156 -0
- package/scripts/check-peer-dependencies.js +5 -5
- package/scripts/check-translations.ts +255 -0
- package/scripts/post-build.js +1 -1
- package/dist/runtime/plugin.client.d.ts +0 -2
- package/dist/runtime/plugin.client.js +0 -6
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { deepMerge } from "../utils/deep-merge.js";
|
|
2
|
+
const huBase = {
|
|
3
|
+
common: {
|
|
4
|
+
email: "E-mail",
|
|
5
|
+
password: "Jelsz\xF3",
|
|
6
|
+
name: "N\xE9v",
|
|
7
|
+
fullName: "Teljes n\xE9v",
|
|
8
|
+
role: "Szerepk\xF6r",
|
|
9
|
+
active: "Akt\xEDv",
|
|
10
|
+
yes: "Igen",
|
|
11
|
+
no: "Nem",
|
|
12
|
+
id: "ID",
|
|
13
|
+
created: "L\xE9trehozva",
|
|
14
|
+
updated: "Friss\xEDtve",
|
|
15
|
+
lastLogin: "Utols\xF3 bel\xE9p\xE9s",
|
|
16
|
+
registered: "Regisztr\xE1lva",
|
|
17
|
+
lastUpdated: "Utolj\xE1ra friss\xEDtve",
|
|
18
|
+
edit: "Szerkeszt\xE9s",
|
|
19
|
+
delete: "T\xF6rl\xE9s",
|
|
20
|
+
loading: "Bet\xF6lt\xE9s...",
|
|
21
|
+
error: "Hiba"
|
|
22
|
+
},
|
|
23
|
+
login: {
|
|
24
|
+
passwordLabel: "Jelsz\xF3",
|
|
25
|
+
submit: "Bejelentkez\xE9s",
|
|
26
|
+
submitting: "Bejelentkez\xE9s...",
|
|
27
|
+
forgotPasswordSending: "K\xFCld\xE9s...",
|
|
28
|
+
loginFailed: "Bejelentkez\xE9s sikertelen",
|
|
29
|
+
forgotPasswordFailed: "A jelsz\xF3 vissza\xE1ll\xEDt\xF3 e-mail k\xFCld\xE9se sikertelen"
|
|
30
|
+
},
|
|
31
|
+
register: {
|
|
32
|
+
title: "Regisztr\xE1ci\xF3",
|
|
33
|
+
nameLabel: "Teljes n\xE9v",
|
|
34
|
+
passwordLabel: "Jelsz\xF3",
|
|
35
|
+
confirmPasswordLabel: "Jelsz\xF3 meger\u0151s\xEDt\xE9s",
|
|
36
|
+
passwordMismatch: "A jelszavak nem egyeznek",
|
|
37
|
+
submit: "Regisztr\xE1ci\xF3",
|
|
38
|
+
submitting: "Fi\xF3k l\xE9trehoz\xE1sa..."
|
|
39
|
+
},
|
|
40
|
+
resetPassword: {
|
|
41
|
+
titleReset: "Jelsz\xF3 vissza\xE1ll\xEDt\xE1s",
|
|
42
|
+
titleChange: "Jelsz\xF3 megv\xE1ltoztat\xE1sa",
|
|
43
|
+
currentPasswordLabel: "Jelenlegi jelsz\xF3",
|
|
44
|
+
newPasswordLabel: "\xDAj jelsz\xF3",
|
|
45
|
+
confirmPasswordLabel: "\xDAj jelsz\xF3 meger\u0151s\xEDt\xE9se",
|
|
46
|
+
submitReset: "Jelsz\xF3 vissza\xE1ll\xEDt\xE1s",
|
|
47
|
+
submitUpdate: "Jelsz\xF3 friss\xEDt\xE9se",
|
|
48
|
+
submittingReset: "Vissza\xE1ll\xEDt\xE1s...",
|
|
49
|
+
submittingUpdate: "Friss\xEDt\xE9s...",
|
|
50
|
+
passwordHelpText: "A jelsz\xF3nak tartalmaznia kell legal\xE1bb",
|
|
51
|
+
secureResetInfo: "Biztons\xE1gos linket haszn\xE1lva \xE1ll\xEDthatod vissza a jelszavad."
|
|
52
|
+
},
|
|
53
|
+
passwordStrength: {
|
|
54
|
+
label: "Jelsz\xF3 k\xF6vetelm\xE9nyek",
|
|
55
|
+
strength: {
|
|
56
|
+
weak: "Gyenge",
|
|
57
|
+
medium: "K\xF6zepes",
|
|
58
|
+
strong: "Er\u0151s",
|
|
59
|
+
veryStrong: "Nagyon er\u0151s",
|
|
60
|
+
unknown: "Ismeretlen"
|
|
61
|
+
},
|
|
62
|
+
requirements: {
|
|
63
|
+
minLength: "Legal\xE1bb {0} karakter",
|
|
64
|
+
uppercase: "Tartalmaz nagybet\u0171t",
|
|
65
|
+
lowercase: "Tartalmaz kisbet\u0171t",
|
|
66
|
+
numbers: "Tartalmaz sz\xE1mot",
|
|
67
|
+
specialChars: "Tartalmaz speci\xE1lis karaktert"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
profile: {
|
|
71
|
+
title: "Profil inform\xE1ci\xF3k",
|
|
72
|
+
name: "N\xE9v",
|
|
73
|
+
email: "E-mail",
|
|
74
|
+
role: "Jogosults\xE1g",
|
|
75
|
+
registered: "Regisztr\xE1lva",
|
|
76
|
+
lastUpdated: "Utolj\xE1ra friss\xEDtve",
|
|
77
|
+
active: "Akt\xEDv",
|
|
78
|
+
id: "ID"
|
|
79
|
+
},
|
|
80
|
+
emailConfirmation: {
|
|
81
|
+
successTitle: "E-mail meger\u0151s\xEDtve!",
|
|
82
|
+
errorTitle: "Meger\u0151s\xEDt\xE9s sikertelen",
|
|
83
|
+
loginButton: "Tov\xE1bb a bejelentkez\xE9shez",
|
|
84
|
+
backToLogin: "Vissza a bejelentkez\xE9shez",
|
|
85
|
+
processing: "Feldolgoz\xE1s..."
|
|
86
|
+
},
|
|
87
|
+
logout: {
|
|
88
|
+
linkText: "Kijelentkez\xE9s",
|
|
89
|
+
loggingOut: "Kijelentkez\xE9s...",
|
|
90
|
+
confirmMessage: "Biztosan ki szeretn\xE9l jelentkezni?"
|
|
91
|
+
},
|
|
92
|
+
userCard: {
|
|
93
|
+
edit: "Szerkeszt\xE9s",
|
|
94
|
+
delete: "T\xF6rl\xE9s"
|
|
95
|
+
},
|
|
96
|
+
googleLogin: {
|
|
97
|
+
buttonText: "Folytat\xE1s Google-lel",
|
|
98
|
+
redirecting: "\xC1tir\xE1ny\xEDt\xE1s..."
|
|
99
|
+
},
|
|
100
|
+
usersList: {
|
|
101
|
+
title: "Felhaszn\xE1l\xF3k list\xE1ja",
|
|
102
|
+
loading: "Felhaszn\xE1l\xF3k bet\xF6lt\xE9se...",
|
|
103
|
+
noUsers: "Nem tal\xE1lhat\xF3 felhaszn\xE1l\xF3",
|
|
104
|
+
error: "Hiba",
|
|
105
|
+
page: "Oldal",
|
|
106
|
+
of: "/",
|
|
107
|
+
total: "\xD6sszesen",
|
|
108
|
+
users: "felhaszn\xE1l\xF3",
|
|
109
|
+
previous: "El\u0151z\u0151",
|
|
110
|
+
next: "K\xF6vetkez\u0151"
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const huInformalOverrides = {
|
|
114
|
+
login: {
|
|
115
|
+
title: "Hell\xF3!",
|
|
116
|
+
subtitle: "Jelentkezz be a fi\xF3kodba",
|
|
117
|
+
emailPlaceholder: "Add meg az e-mail c\xEDmed",
|
|
118
|
+
passwordPlaceholder: "Add meg a jelszavad",
|
|
119
|
+
forgotPassword: "Elfelejtetted a jelszavad?",
|
|
120
|
+
rememberMe: "Eml\xE9kezz r\xE1m",
|
|
121
|
+
emailRequiredForForgotPassword: "K\xE9rj\xFCk, el\u0151sz\xF6r add meg az e-mail c\xEDmed",
|
|
122
|
+
loginFailed: "Bejelentkez\xE9s sikertelen",
|
|
123
|
+
forgotPasswordFailed: "A jelsz\xF3 vissza\xE1ll\xEDt\xF3 e-mail k\xFCld\xE9se sikertelen"
|
|
124
|
+
},
|
|
125
|
+
register: {
|
|
126
|
+
subtitle: "Hozz l\xE9tre egy \xFAj fi\xF3kot",
|
|
127
|
+
namePlaceholder: "Add meg a teljes neved",
|
|
128
|
+
emailPlaceholder: "Add meg az e-mail c\xEDmed",
|
|
129
|
+
passwordPlaceholder: "Add meg a jelszavad",
|
|
130
|
+
confirmPasswordPlaceholder: "Er\u0151s\xEDtsd meg a jelszavad",
|
|
131
|
+
alreadyHaveAccount: "M\xE1r van fi\xF3kod?",
|
|
132
|
+
signInLink: "Jelentkezz be itt",
|
|
133
|
+
submit: "Regisztr\xE1lj"
|
|
134
|
+
},
|
|
135
|
+
passwordStrength: {
|
|
136
|
+
hintsTitle: "Hogyan tedd er\u0151sebb\xE9 a jelszavad"
|
|
137
|
+
},
|
|
138
|
+
logout: {
|
|
139
|
+
confirmMessage: "Biztosan ki szeretn\xE9l jelentkezni?"
|
|
140
|
+
},
|
|
141
|
+
userCard: {
|
|
142
|
+
deleteConfirm: "Biztosan t\xF6rl\xF6d {0} felhaszn\xE1l\xF3t?"
|
|
143
|
+
},
|
|
144
|
+
emailConfirmation: {
|
|
145
|
+
processingMessage: "K\xE9rj\xFCk, v\xE1rj, am\xEDg feldolgozzuk az e-mail meger\u0151s\xEDt\xE9s\xE9t.",
|
|
146
|
+
successMessage: "Az e-mail c\xEDmed meger\u0151s\xEDt\xE9sre ker\xFClt \xE9s a fi\xF3kod akt\xEDv.",
|
|
147
|
+
errorMessage: "A meger\u0151s\xEDt\u0151 link \xE9rv\xE9nytelen vagy lej\xE1rt. K\xE9rj\xFCk, pr\xF3b\xE1ld \xFAjra regisztr\xE1lni vagy l\xE9pj kapcsolatba az \xFCgyf\xE9lszolg\xE1lattal."
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const huFormalOverrides = {
|
|
151
|
+
login: {
|
|
152
|
+
title: "\xDCdv\xF6z\xF6lj\xFCk",
|
|
153
|
+
subtitle: "Jelentkezzen be fi\xF3kj\xE1ba",
|
|
154
|
+
emailPlaceholder: "Adja meg az e-mail c\xEDm\xE9t",
|
|
155
|
+
passwordPlaceholder: "Adja meg a jelszav\xE1t",
|
|
156
|
+
forgotPassword: "Elfelejtette a jelszav\xE1t?",
|
|
157
|
+
rememberMe: "Bejelentkezve maradok",
|
|
158
|
+
emailRequiredForForgotPassword: "K\xE9rj\xFCk, el\u0151sz\xF6r adja meg az e-mail c\xEDm\xE9t",
|
|
159
|
+
loginFailed: "Bejelentkez\xE9s sikertelen",
|
|
160
|
+
forgotPasswordFailed: "A jelsz\xF3 vissza\xE1ll\xEDt\xF3 e-mail k\xFCld\xE9se sikertelen"
|
|
161
|
+
},
|
|
162
|
+
register: {
|
|
163
|
+
subtitle: "Hozzon l\xE9tre egy \xFAj fi\xF3kot",
|
|
164
|
+
namePlaceholder: "Adja meg a teljes nev\xE9t",
|
|
165
|
+
emailPlaceholder: "Adja meg az e-mail c\xEDm\xE9t",
|
|
166
|
+
passwordPlaceholder: "Adja meg a jelszav\xE1t",
|
|
167
|
+
confirmPasswordPlaceholder: "Er\u0151s\xEDtse meg a jelszav\xE1t",
|
|
168
|
+
alreadyHaveAccount: "M\xE1r van fi\xF3kja?",
|
|
169
|
+
signInLink: "Jelentkezzen be itt",
|
|
170
|
+
submit: "Regisztr\xE1ljon"
|
|
171
|
+
},
|
|
172
|
+
passwordStrength: {
|
|
173
|
+
hintsTitle: "Hogyan tegye er\u0151sebb\xE9 a jelszav\xE1t?"
|
|
174
|
+
},
|
|
175
|
+
logout: {
|
|
176
|
+
confirmMessage: "Biztosan ki szeretne jelentkezni?"
|
|
177
|
+
},
|
|
178
|
+
userCard: {
|
|
179
|
+
deleteConfirm: "Biztosan t\xF6rli {0} felhaszn\xE1l\xF3t?"
|
|
180
|
+
},
|
|
181
|
+
emailConfirmation: {
|
|
182
|
+
processingMessage: "K\xE9rj\xFCk, v\xE1rjon, am\xEDg feldolgozzuk az e-mail meger\u0151s\xEDt\xE9s\xE9t.",
|
|
183
|
+
successMessage: "Az e-mail c\xEDme meger\u0151s\xEDt\xE9sre ker\xFClt \xE9s a fi\xF3kja akt\xEDv.",
|
|
184
|
+
errorMessage: "A meger\u0151s\xEDt\u0151 link \xE9rv\xE9nytelen vagy lej\xE1rt. K\xE9rj\xFCk, pr\xF3b\xE1ljon meg \xFAjra regisztr\xE1lni vagy l\xE9pjen kapcsolatba az \xFCgyf\xE9lszolg\xE1lattal."
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
export const hu = deepMerge(huBase, huInformalOverrides);
|
|
188
|
+
export const huFormal = deepMerge(huBase, huFormalOverrides);
|
|
@@ -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
|
+
});
|
|
@@ -20,7 +20,8 @@ export default defineEventHandler(async (event) => {
|
|
|
20
20
|
redirectUrl.searchParams.set("status", "success");
|
|
21
21
|
redirectUrl.searchParams.set("message", "Email confirmed successfully! Your account is now active. You can now log in.");
|
|
22
22
|
return sendRedirect(event, redirectUrl.pathname + redirectUrl.search, 302);
|
|
23
|
-
}
|
|
23
|
+
}
|
|
24
|
+
if (!success) {
|
|
24
25
|
const redirectUrl = new URL(options.emailConfirmationUrl, "http://localhost");
|
|
25
26
|
redirectUrl.searchParams.set("status", "error");
|
|
26
27
|
redirectUrl.searchParams.set("message", "Invalid or expired confirmation token");
|
|
@@ -32,10 +33,9 @@ export default defineEventHandler(async (event) => {
|
|
|
32
33
|
const options = nuxtUsers;
|
|
33
34
|
const redirectUrl = new URL(options.emailConfirmationUrl, "http://localhost");
|
|
34
35
|
redirectUrl.searchParams.set("status", "error");
|
|
36
|
+
redirectUrl.searchParams.set("message", "Email confirmation failed");
|
|
35
37
|
if (error instanceof Error) {
|
|
36
38
|
redirectUrl.searchParams.set("message", error.message);
|
|
37
|
-
} else {
|
|
38
|
-
redirectUrl.searchParams.set("message", "Email confirmation failed");
|
|
39
39
|
}
|
|
40
40
|
return sendRedirect(event, redirectUrl.pathname + redirectUrl.search, 302);
|
|
41
41
|
}
|
|
@@ -21,7 +21,8 @@ export default defineEventHandler(async (event) => {
|
|
|
21
21
|
} catch (error) {
|
|
22
22
|
if (error instanceof Error) {
|
|
23
23
|
console.error("[Nuxt Users] Error in forgot-password endpoint:", error.message);
|
|
24
|
-
}
|
|
24
|
+
}
|
|
25
|
+
if (!(error instanceof Error)) {
|
|
25
26
|
console.error("[Nuxt Users] Error in forgot-password endpoint:", error);
|
|
26
27
|
}
|
|
27
28
|
throw createError({
|
|
@@ -27,7 +27,8 @@ export default defineEventHandler(async (event) => {
|
|
|
27
27
|
const success = await resetPassword(token, email, password, options);
|
|
28
28
|
if (success) {
|
|
29
29
|
return { message: "Password has been reset successfully. You can now log in with your new password." };
|
|
30
|
-
}
|
|
30
|
+
}
|
|
31
|
+
if (!success) {
|
|
31
32
|
throw createError({
|
|
32
33
|
statusCode: 400,
|
|
33
34
|
// Or 422 if you prefer for semantic validation errors
|
|
@@ -37,7 +38,8 @@ export default defineEventHandler(async (event) => {
|
|
|
37
38
|
} catch (error) {
|
|
38
39
|
if (error instanceof Error) {
|
|
39
40
|
console.error("[Nuxt Users] Error in reset-password endpoint:", error.message);
|
|
40
|
-
}
|
|
41
|
+
}
|
|
42
|
+
if (!(error instanceof Error)) {
|
|
41
43
|
console.error("[Nuxt Users] Error in reset-password endpoint:", error);
|
|
42
44
|
}
|
|
43
45
|
if (error instanceof H3Error) {
|
|
@@ -51,7 +51,8 @@ export default defineEventHandler(async (event) => {
|
|
|
51
51
|
if (rememberMe) {
|
|
52
52
|
const longTermDays = options.auth.rememberMeExpiration || 30;
|
|
53
53
|
expiresAt.setDate(expiresAt.getDate() + longTermDays);
|
|
54
|
-
}
|
|
54
|
+
}
|
|
55
|
+
if (!rememberMe) {
|
|
55
56
|
expiresAt.setMinutes(expiresAt.getMinutes() + options.auth.tokenExpiration);
|
|
56
57
|
}
|
|
57
58
|
await db.sql`
|
|
@@ -69,7 +70,8 @@ export default defineEventHandler(async (event) => {
|
|
|
69
70
|
if (rememberMe) {
|
|
70
71
|
const longTermDays = options.auth.rememberMeExpiration || 30;
|
|
71
72
|
cookieOptions.maxAge = 60 * 60 * 24 * longTermDays;
|
|
72
|
-
}
|
|
73
|
+
}
|
|
74
|
+
if (!rememberMe) {
|
|
73
75
|
}
|
|
74
76
|
setCookie(event, "auth_token", token, cookieOptions);
|
|
75
77
|
const { password: _, ...userWithoutPassword } = user;
|
|
@@ -32,7 +32,8 @@ export default defineEventHandler(async (event) => {
|
|
|
32
32
|
if (event.path.startsWith("/api/")) {
|
|
33
33
|
console.warn(`[Nuxt Users] authorization: ${event.path} No token found - API request rejected`);
|
|
34
34
|
throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
|
|
35
|
-
}
|
|
35
|
+
}
|
|
36
|
+
if (!event.path.startsWith("/api/")) {
|
|
36
37
|
console.debug(`[Nuxt Users] authorization: ${event.path} No token found - letting client handle page redirect`);
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
@@ -42,7 +43,8 @@ export default defineEventHandler(async (event) => {
|
|
|
42
43
|
if (event.path.startsWith("/api/")) {
|
|
43
44
|
console.warn(`[Nuxt Users] authorization: ${event.path} Invalid token - API request rejected`);
|
|
44
45
|
throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
|
|
45
|
-
}
|
|
46
|
+
}
|
|
47
|
+
if (!event.path.startsWith("/api/")) {
|
|
46
48
|
console.debug(`[Nuxt Users] authorization: ${event.path} Invalid token - letting client handle page redirect`);
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
@@ -55,7 +57,8 @@ export default defineEventHandler(async (event) => {
|
|
|
55
57
|
if (event.path.startsWith("/api/")) {
|
|
56
58
|
console.warn(`[Nuxt Users] authorization: ${event.path} User ${user.id} with role ${user.role} denied access - API request rejected`);
|
|
57
59
|
throw createError({ statusCode: 403, statusMessage: "Forbidden" });
|
|
58
|
-
}
|
|
60
|
+
}
|
|
61
|
+
if (!event.path.startsWith("/api/")) {
|
|
59
62
|
console.debug(`[Nuxt Users] authorization: ${event.path} User ${user.id} with role ${user.role} denied access - letting client handle page redirect`);
|
|
60
63
|
return;
|
|
61
64
|
}
|
|
@@ -122,7 +122,8 @@ export async function createAuthTokenForUser(user, moduleOptions, rememberMe = f
|
|
|
122
122
|
if (rememberMe) {
|
|
123
123
|
const longTermDays = moduleOptions.auth.rememberMeExpiration || 30;
|
|
124
124
|
expiresAt.setDate(expiresAt.getDate() + longTermDays);
|
|
125
|
-
}
|
|
125
|
+
}
|
|
126
|
+
if (!rememberMe) {
|
|
126
127
|
expiresAt.setMinutes(expiresAt.getMinutes() + moduleOptions.auth.tokenExpiration);
|
|
127
128
|
}
|
|
128
129
|
await db.sql`
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LocaleMessages } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Deep merge two objects
|
|
4
|
+
* @param target - Base object
|
|
5
|
+
* @param source - Object to merge into target
|
|
6
|
+
* @returns Merged object
|
|
7
|
+
*/
|
|
8
|
+
export declare const deepMerge: (target: LocaleMessages, source: LocaleMessages) => LocaleMessages;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const deepMerge = (target, source) => {
|
|
2
|
+
const result = { ...target };
|
|
3
|
+
for (const key in source) {
|
|
4
|
+
const sourceValue = source[key];
|
|
5
|
+
if (!sourceValue) {
|
|
6
|
+
result[key] = sourceValue;
|
|
7
|
+
} else if (typeof sourceValue === "object" && !Array.isArray(sourceValue)) {
|
|
8
|
+
result[key] = deepMerge(
|
|
9
|
+
result[key] || {},
|
|
10
|
+
sourceValue
|
|
11
|
+
);
|
|
12
|
+
} else {
|
|
13
|
+
result[key] = sourceValue;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LocaleMessages } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get a nested value from an object using dot notation
|
|
4
|
+
*/
|
|
5
|
+
export declare const getNestedValue: (obj: LocaleMessages, path: string) => string | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Get translation for a key
|
|
8
|
+
* @param key - Translation key (e.g., 'login.title')
|
|
9
|
+
* @param locale - Current locale
|
|
10
|
+
* @param customTexts - Custom texts from config
|
|
11
|
+
* @param fallbackLocale - Fallback locale
|
|
12
|
+
* @param params - Parameters to replace in the translation (e.g., {0}, {1})
|
|
13
|
+
*/
|
|
14
|
+
export declare const getTranslation: (key: string, locale?: string, customTexts?: Record<string, LocaleMessages>, fallbackLocale?: string, params?: (string | number)[]) => string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { defaultLocaleMessages } from "../locales/index.js";
|
|
2
|
+
import { deepMerge } from "./deep-merge.js";
|
|
3
|
+
export const getNestedValue = (obj, path) => {
|
|
4
|
+
const keys = path.split(".");
|
|
5
|
+
let value = obj;
|
|
6
|
+
for (const key of keys) {
|
|
7
|
+
if (value && typeof value === "object") {
|
|
8
|
+
value = value[key];
|
|
9
|
+
} else {
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return typeof value === "string" ? value : void 0;
|
|
14
|
+
};
|
|
15
|
+
export const getTranslation = (key, locale = "en", customTexts, fallbackLocale = "en", params) => {
|
|
16
|
+
const localeMessages = customTexts?.[locale] ? deepMerge(defaultLocaleMessages[locale] || {}, customTexts[locale]) : defaultLocaleMessages[locale];
|
|
17
|
+
let translation = localeMessages ? getNestedValue(localeMessages, key) : void 0;
|
|
18
|
+
if (!translation && fallbackLocale !== locale) {
|
|
19
|
+
const fallbackMessages = customTexts?.[fallbackLocale] ? deepMerge(defaultLocaleMessages[fallbackLocale] || {}, customTexts[fallbackLocale]) : defaultLocaleMessages[fallbackLocale];
|
|
20
|
+
translation = fallbackMessages ? getNestedValue(fallbackMessages, key) : void 0;
|
|
21
|
+
}
|
|
22
|
+
if (!translation && locale !== "en" && fallbackLocale !== "en" && defaultLocaleMessages.en) {
|
|
23
|
+
translation = getNestedValue(defaultLocaleMessages.en, key);
|
|
24
|
+
}
|
|
25
|
+
if (translation && params && params.length > 0) {
|
|
26
|
+
const placeholderMatches = translation.match(/\{\d+\}/g);
|
|
27
|
+
const expectedParamCount = placeholderMatches ? placeholderMatches.length : 0;
|
|
28
|
+
if (expectedParamCount !== params.length && process.env.NODE_ENV !== "production") {
|
|
29
|
+
console.warn(
|
|
30
|
+
`[nuxt-users locale] Parameter count mismatch for key "${key}": expected ${expectedParamCount} parameter(s), but received ${params.length}`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
params.forEach((param, index) => {
|
|
34
|
+
translation = translation.replace(`{${index}}`, String(param));
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return translation || key;
|
|
38
|
+
};
|
|
@@ -69,7 +69,8 @@ const validatePassword = (password, options = {}) => {
|
|
|
69
69
|
if (password.length < config.minLength) {
|
|
70
70
|
errors.push(`Password must be at least ${config.minLength} characters long`);
|
|
71
71
|
hints.push(`Use at least ${config.minLength} characters`);
|
|
72
|
-
}
|
|
72
|
+
}
|
|
73
|
+
if (password.length >= config.minLength) {
|
|
73
74
|
score += 20;
|
|
74
75
|
if (password.length < 12) {
|
|
75
76
|
hints.push("Use 12 or more characters for extra security");
|
|
@@ -78,25 +79,29 @@ const validatePassword = (password, options = {}) => {
|
|
|
78
79
|
if (config.requireUppercase && !/[A-Z]/.test(password)) {
|
|
79
80
|
errors.push("Password must contain at least one uppercase letter");
|
|
80
81
|
hints.push("Add an uppercase letter (A-Z)");
|
|
81
|
-
}
|
|
82
|
+
}
|
|
83
|
+
if (/[A-Z]/.test(password)) {
|
|
82
84
|
score += 15;
|
|
83
85
|
}
|
|
84
86
|
if (config.requireLowercase && !/[a-z]/.test(password)) {
|
|
85
87
|
errors.push("Password must contain at least one lowercase letter");
|
|
86
88
|
hints.push("Add a lowercase letter (a-z)");
|
|
87
|
-
}
|
|
89
|
+
}
|
|
90
|
+
if (/[a-z]/.test(password)) {
|
|
88
91
|
score += 15;
|
|
89
92
|
}
|
|
90
93
|
if (config.requireNumbers && !/\d/.test(password)) {
|
|
91
94
|
errors.push("Password must contain at least one number");
|
|
92
95
|
hints.push("Add a number (0-9)");
|
|
93
|
-
}
|
|
96
|
+
}
|
|
97
|
+
if (/\d/.test(password)) {
|
|
94
98
|
score += 15;
|
|
95
99
|
}
|
|
96
100
|
if (config.requireSpecialChars && !/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
|
|
97
101
|
errors.push("Password must contain at least one special character");
|
|
98
102
|
hints.push("Add a special character (e.g. !@#$%)");
|
|
99
|
-
}
|
|
103
|
+
}
|
|
104
|
+
if (/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
|
|
100
105
|
score += 15;
|
|
101
106
|
}
|
|
102
107
|
if (config.preventCommonPasswords && COMMON_PASSWORDS.includes(password.toLowerCase())) {
|
|
@@ -105,7 +110,8 @@ const validatePassword = (password, options = {}) => {
|
|
|
105
110
|
}
|
|
106
111
|
if (password.length >= 12) {
|
|
107
112
|
score += 10;
|
|
108
|
-
}
|
|
113
|
+
}
|
|
114
|
+
if (password.length >= 10 && password.length < 12) {
|
|
109
115
|
score += 5;
|
|
110
116
|
}
|
|
111
117
|
const hasUppercase = /[A-Z]/.test(password);
|
|
@@ -115,14 +121,16 @@ const validatePassword = (password, options = {}) => {
|
|
|
115
121
|
const complexityTypes = [hasUppercase, hasLowercase, hasNumbers, hasSpecial].filter(Boolean).length;
|
|
116
122
|
if (complexityTypes >= 4) {
|
|
117
123
|
score += 10;
|
|
118
|
-
}
|
|
124
|
+
}
|
|
125
|
+
if (complexityTypes >= 3 && complexityTypes < 4) {
|
|
119
126
|
score += 5;
|
|
120
127
|
hints.push("Use a mix of uppercase, lowercase, numbers, and special characters");
|
|
121
128
|
}
|
|
122
129
|
let strength = "weak";
|
|
123
130
|
if (score >= 80) {
|
|
124
131
|
strength = "strong";
|
|
125
|
-
}
|
|
132
|
+
}
|
|
133
|
+
if (score >= 60 && score < 80) {
|
|
126
134
|
strength = "medium";
|
|
127
135
|
}
|
|
128
136
|
return {
|
|
@@ -12,6 +12,35 @@ type DatabaseConfig = {
|
|
|
12
12
|
password?: string;
|
|
13
13
|
database?: string;
|
|
14
14
|
};
|
|
15
|
+
interface LocaleMessages {
|
|
16
|
+
[key: string]: string | LocaleMessages;
|
|
17
|
+
}
|
|
18
|
+
interface LocaleOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Default locale code
|
|
21
|
+
* @default 'en'
|
|
22
|
+
*/
|
|
23
|
+
default?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Custom messages to override or extend default translations
|
|
26
|
+
* Use nested object structure for organizing translations
|
|
27
|
+
* @example
|
|
28
|
+
* {
|
|
29
|
+
* en: {
|
|
30
|
+
* login: { title: 'Welcome', submit: 'Sign In' }
|
|
31
|
+
* },
|
|
32
|
+
* hu: {
|
|
33
|
+
* login: { title: 'Üdvözöljük', submit: 'Bejelentkezés' }
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
*/
|
|
37
|
+
texts?: Record<string, LocaleMessages>;
|
|
38
|
+
/**
|
|
39
|
+
* Fallback locale when translation is missing
|
|
40
|
+
* @default 'en'
|
|
41
|
+
*/
|
|
42
|
+
fallbackLocale?: string;
|
|
43
|
+
}
|
|
15
44
|
interface GoogleOAuthOptions {
|
|
16
45
|
/**
|
|
17
46
|
* Google OAuth client ID from Google Cloud Console
|
|
@@ -159,6 +188,10 @@ interface RuntimeModuleOptions {
|
|
|
159
188
|
* @default false
|
|
160
189
|
*/
|
|
161
190
|
hardDelete?: boolean;
|
|
191
|
+
/**
|
|
192
|
+
* Locale configuration for component labels and messages
|
|
193
|
+
*/
|
|
194
|
+
locale?: LocaleOptions;
|
|
162
195
|
}
|
|
163
196
|
interface ModuleOptions {
|
|
164
197
|
connector: {
|
|
@@ -191,6 +224,11 @@ interface ModuleOptions {
|
|
|
191
224
|
preventCommonPasswords: boolean;
|
|
192
225
|
};
|
|
193
226
|
hardDelete: boolean;
|
|
227
|
+
locale?: {
|
|
228
|
+
default: string;
|
|
229
|
+
fallbackLocale?: string;
|
|
230
|
+
texts?: Record<string, LocaleMessages>;
|
|
231
|
+
};
|
|
194
232
|
}
|
|
195
233
|
interface MailerOptions {
|
|
196
234
|
host: string;
|
|
@@ -268,5 +306,5 @@ declare const defaultFieldLabels: {
|
|
|
268
306
|
last_login_at: string;
|
|
269
307
|
};
|
|
270
308
|
|
|
271
|
-
export { defaultDisplayFields as
|
|
272
|
-
export type { DisplayFieldsProps as D, GoogleOAuthOptions as G, LoginFormData as L, ModuleOptions as M, PersonalAccessToken as P, RuntimeModuleOptions as R, User as U, UserWithoutPassword as a, PasswordResetToken as b, LoginFormProps as c, ResetPasswordFormProps as d, Permission as e, DatabaseType as f, DatabaseConfig as g };
|
|
309
|
+
export { defaultDisplayFields as j, defaultFieldLabels as k };
|
|
310
|
+
export type { DisplayFieldsProps as D, GoogleOAuthOptions as G, LoginFormData as L, ModuleOptions as M, PersonalAccessToken as P, RuntimeModuleOptions as R, User as U, UserWithoutPassword as a, PasswordResetToken as b, LoginFormProps as c, ResetPasswordFormProps as d, Permission as e, DatabaseType as f, DatabaseConfig as g, LocaleOptions as h, LocaleMessages as i };
|
|
@@ -12,6 +12,35 @@ type DatabaseConfig = {
|
|
|
12
12
|
password?: string;
|
|
13
13
|
database?: string;
|
|
14
14
|
};
|
|
15
|
+
interface LocaleMessages {
|
|
16
|
+
[key: string]: string | LocaleMessages;
|
|
17
|
+
}
|
|
18
|
+
interface LocaleOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Default locale code
|
|
21
|
+
* @default 'en'
|
|
22
|
+
*/
|
|
23
|
+
default?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Custom messages to override or extend default translations
|
|
26
|
+
* Use nested object structure for organizing translations
|
|
27
|
+
* @example
|
|
28
|
+
* {
|
|
29
|
+
* en: {
|
|
30
|
+
* login: { title: 'Welcome', submit: 'Sign In' }
|
|
31
|
+
* },
|
|
32
|
+
* hu: {
|
|
33
|
+
* login: { title: 'Üdvözöljük', submit: 'Bejelentkezés' }
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
*/
|
|
37
|
+
texts?: Record<string, LocaleMessages>;
|
|
38
|
+
/**
|
|
39
|
+
* Fallback locale when translation is missing
|
|
40
|
+
* @default 'en'
|
|
41
|
+
*/
|
|
42
|
+
fallbackLocale?: string;
|
|
43
|
+
}
|
|
15
44
|
interface GoogleOAuthOptions {
|
|
16
45
|
/**
|
|
17
46
|
* Google OAuth client ID from Google Cloud Console
|
|
@@ -159,6 +188,10 @@ interface RuntimeModuleOptions {
|
|
|
159
188
|
* @default false
|
|
160
189
|
*/
|
|
161
190
|
hardDelete?: boolean;
|
|
191
|
+
/**
|
|
192
|
+
* Locale configuration for component labels and messages
|
|
193
|
+
*/
|
|
194
|
+
locale?: LocaleOptions;
|
|
162
195
|
}
|
|
163
196
|
interface ModuleOptions {
|
|
164
197
|
connector: {
|
|
@@ -191,6 +224,11 @@ interface ModuleOptions {
|
|
|
191
224
|
preventCommonPasswords: boolean;
|
|
192
225
|
};
|
|
193
226
|
hardDelete: boolean;
|
|
227
|
+
locale?: {
|
|
228
|
+
default: string;
|
|
229
|
+
fallbackLocale?: string;
|
|
230
|
+
texts?: Record<string, LocaleMessages>;
|
|
231
|
+
};
|
|
194
232
|
}
|
|
195
233
|
interface MailerOptions {
|
|
196
234
|
host: string;
|
|
@@ -268,5 +306,5 @@ declare const defaultFieldLabels: {
|
|
|
268
306
|
last_login_at: string;
|
|
269
307
|
};
|
|
270
308
|
|
|
271
|
-
export { defaultDisplayFields as
|
|
272
|
-
export type { DisplayFieldsProps as D, GoogleOAuthOptions as G, LoginFormData as L, ModuleOptions as M, PersonalAccessToken as P, RuntimeModuleOptions as R, User as U, UserWithoutPassword as a, PasswordResetToken as b, LoginFormProps as c, ResetPasswordFormProps as d, Permission as e, DatabaseType as f, DatabaseConfig as g };
|
|
309
|
+
export { defaultDisplayFields as j, defaultFieldLabels as k };
|
|
310
|
+
export type { DisplayFieldsProps as D, GoogleOAuthOptions as G, LoginFormData as L, ModuleOptions as M, PersonalAccessToken as P, RuntimeModuleOptions as R, User as U, UserWithoutPassword as a, PasswordResetToken as b, LoginFormProps as c, ResetPasswordFormProps as d, Permission as e, DatabaseType as f, DatabaseConfig as g, LocaleOptions as h, LocaleMessages as i };
|
package/dist/utils.d.mts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { defaultLocaleMessages, en, hu, huFormal } from '../dist/runtime/locales/index.js';
|
|
2
|
+
export { getNestedValue, getTranslation } from '../dist/runtime/utils/locale.js';
|
|
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.FiQjvlZl.mjs';
|
|
2
5
|
|
|
3
6
|
interface PasswordValidationResult {
|
|
4
7
|
isValid: boolean;
|