una-nuxt-module 3.0.35 → 3.0.37
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 +1 -1
- package/dist/module.mjs +19 -3
- package/dist/runtime/auth/middleware/authentication.d.ts +3 -3
- package/dist/runtime/auth/middleware/authentication.js +22 -27
- package/dist/runtime/auth/middleware/authorization.js +7 -1
- package/dist/runtime/auth/pages/login.d.vue.ts +1 -11
- package/dist/runtime/auth/pages/login.vue +2 -10
- package/dist/runtime/auth/pages/login.vue.d.ts +1 -11
- package/dist/runtime/auth/pages/logout.d.vue.ts +1 -11
- package/dist/runtime/auth/pages/logout.vue +4 -6
- package/dist/runtime/auth/pages/logout.vue.d.ts +1 -11
- package/dist/runtime/auth/plugins/auth.js +45 -26
- package/dist/runtime/auth/stores/auth.d.ts +38 -29
- package/dist/runtime/auth/stores/auth.js +20 -3
- package/dist/runtime/auth/utils/isAuthCallback.d.ts +3 -0
- package/dist/runtime/auth/utils/isAuthCallback.js +9 -0
- package/dist/runtime/auth/utils/parseCedulaFromSub.d.ts +1 -0
- package/dist/runtime/auth/utils/parseCedulaFromSub.js +4 -0
- package/dist/runtime/auth/utils/parseUserInfo.d.ts +6 -0
- package/dist/runtime/auth/utils/parseUserInfo.js +55 -0
- package/dist/runtime/auth/utils/postLoginRedirect.d.ts +3 -0
- package/dist/runtime/auth/utils/postLoginRedirect.js +25 -0
- package/dist/runtime/components/ui/calendar/Calendar.vue +1 -1
- package/dist/runtime/composables/useFonts.d.ts +3 -0
- package/dist/runtime/composables/useFonts.js +10 -0
- package/dist/runtime/repository-pattern/plugins/api-fetch.d.ts +2 -0
- package/dist/runtime/repository-pattern/plugins/api-fetch.js +5 -1
- package/dist/runtime/types/index.d.ts +8 -7
- package/package.json +12 -12
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -167,7 +167,7 @@ function addTemplates() {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
const name = "una-nuxt-module";
|
|
170
|
-
const version = "3.0.
|
|
170
|
+
const version = "3.0.37";
|
|
171
171
|
|
|
172
172
|
const module$1 = defineNuxtModule({
|
|
173
173
|
meta: {
|
|
@@ -185,7 +185,6 @@ const module$1 = defineNuxtModule({
|
|
|
185
185
|
enabled: true,
|
|
186
186
|
sso: {
|
|
187
187
|
automaticSignIn: true,
|
|
188
|
-
postLoginRedirectUrl: "/",
|
|
189
188
|
signInRedirectUrl: "/auth/sso/login",
|
|
190
189
|
signOutRedirectUrl: "/auth/sso/logout"
|
|
191
190
|
},
|
|
@@ -236,6 +235,21 @@ const module$1 = defineNuxtModule({
|
|
|
236
235
|
options = defu(nuxt.options.runtimeConfig.public.unaxt, options);
|
|
237
236
|
nuxt.options.runtimeConfig.public.unaxt = options;
|
|
238
237
|
nuxt.options.alias["#unaxt"] = resolve("./runtime");
|
|
238
|
+
function injectComponentsConfig() {
|
|
239
|
+
if (nuxt.options.components === false) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
nuxt.options.components = {
|
|
243
|
+
dirs: [
|
|
244
|
+
{ path: "~/components/global", global: true },
|
|
245
|
+
{
|
|
246
|
+
path: "~/components",
|
|
247
|
+
pattern: ["*/**", "**"],
|
|
248
|
+
pathPrefix: false
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
};
|
|
252
|
+
}
|
|
239
253
|
function setupAutoImports() {
|
|
240
254
|
addImportsDir(
|
|
241
255
|
["composables", "constants", "enums", "types", "utils"].map(
|
|
@@ -303,12 +317,13 @@ const module$1 = defineNuxtModule({
|
|
|
303
317
|
if (options.auth?.enabled) {
|
|
304
318
|
logger.ready(green("Iniciando m\xF3dulo de autenticaci\xF3n"));
|
|
305
319
|
addImportsDir(
|
|
306
|
-
["auth/stores", "auth/composables"].map(
|
|
320
|
+
["auth/stores", "auth/composables", "auth/utils"].map(
|
|
307
321
|
(dir) => resolve(`./runtime/${dir}`)
|
|
308
322
|
)
|
|
309
323
|
);
|
|
310
324
|
logger.ready("\u251C\u2500\u2500 " + gray("Stores"));
|
|
311
325
|
logger.ready("\u251C\u2500\u2500 " + gray("Composables"));
|
|
326
|
+
logger.ready("\u251C\u2500\u2500 " + gray("Utils"));
|
|
312
327
|
addPlugin({
|
|
313
328
|
name: "auth",
|
|
314
329
|
src: resolve("./runtime/auth/plugins/auth"),
|
|
@@ -390,6 +405,7 @@ const module$1 = defineNuxtModule({
|
|
|
390
405
|
`)));
|
|
391
406
|
logger.start(cyan(bold("Registro del m\xF3dulo iniciado...")));
|
|
392
407
|
const startTime = Date.now();
|
|
408
|
+
injectComponentsConfig();
|
|
393
409
|
setupAutoImports();
|
|
394
410
|
setupAuth();
|
|
395
411
|
setupComponents();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Middleware encargado de sincronizar los datos de la
|
|
2
|
+
* Middleware encargado de sincronizar los datos de la sesion del usuario.
|
|
3
3
|
*
|
|
4
|
-
* En el flujo de inicio de
|
|
4
|
+
* En el flujo de inicio de sesion mediante SSO, en el cual el usuario ingresa y hay una sesion activa en las cookies,
|
|
5
5
|
* este middleware sincroniza esos datos en el store de pinia.
|
|
6
6
|
*
|
|
7
|
-
* Nota: solo se ejecuta una vez, debido a que posteriormente los datos de la
|
|
7
|
+
* Nota: solo se ejecuta una vez, debido a que posteriormente los datos de la sesion estaran sincronizados en Pinia.
|
|
8
8
|
*/
|
|
9
9
|
declare const _default: import("#app").RouteMiddleware;
|
|
10
10
|
export default _default;
|
|
@@ -1,48 +1,43 @@
|
|
|
1
|
-
import { defineNuxtRouteMiddleware, useNuxtApp
|
|
1
|
+
import { defineNuxtRouteMiddleware, useNuxtApp } from "#app";
|
|
2
2
|
import { useAuthStore } from "../stores/auth.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { savePostLoginRedirect } from "../utils/postLoginRedirect.js";
|
|
4
|
+
import { parseUserInfo } from "../utils/parseUserInfo.js";
|
|
5
|
+
import { parseCedulaFromSub } from "../utils/parseCedulaFromSub.js";
|
|
6
|
+
import { isAuthCallback } from "../utils/isAuthCallback.js";
|
|
7
|
+
export default defineNuxtRouteMiddleware(async (to) => {
|
|
5
8
|
if (!import.meta.client) {
|
|
6
9
|
return;
|
|
7
10
|
}
|
|
11
|
+
if (isAuthCallback(to.path)) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
8
14
|
const { $pinia, $signIn, $authData, $isAuthenticated, $accessToken } = useNuxtApp();
|
|
9
|
-
const authorization = useAuthorization();
|
|
10
15
|
const authStore = useAuthStore($pinia);
|
|
11
16
|
const isAuthenticated = await $isAuthenticated();
|
|
12
17
|
if (!isAuthenticated) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (!authConfig.sso?.automaticSignIn) {
|
|
16
|
-
await $signIn();
|
|
17
|
-
}
|
|
18
|
+
savePostLoginRedirect(to.fullPath);
|
|
19
|
+
await $signIn();
|
|
18
20
|
return;
|
|
19
21
|
}
|
|
20
22
|
if (!authStore.isAuthenticated) {
|
|
21
23
|
const authResponse = await $authData();
|
|
22
24
|
const token = await $accessToken();
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
email = rawEmail?.trim();
|
|
29
|
-
const [name, lastName] = email.toUpperCase().split(".");
|
|
30
|
-
return {
|
|
31
|
-
name,
|
|
32
|
-
lastName,
|
|
33
|
-
fullName: name + " " + lastName
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
};
|
|
25
|
+
const { email, name, lastName1, lastName2, fullName } = parseUserInfo({
|
|
26
|
+
email: authResponse?.email,
|
|
27
|
+
givenName: authResponse?.givenName,
|
|
28
|
+
familyName: authResponse?.familyName
|
|
29
|
+
});
|
|
37
30
|
const userInfo = {
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
name,
|
|
32
|
+
lastName1,
|
|
33
|
+
lastName2,
|
|
34
|
+
fullName,
|
|
35
|
+
cedula: parseCedulaFromSub(authResponse?.sub),
|
|
40
36
|
email
|
|
41
37
|
};
|
|
42
38
|
const authData = {
|
|
43
39
|
isAuthenticated,
|
|
44
|
-
accessToken: token
|
|
45
|
-
resources
|
|
40
|
+
accessToken: token
|
|
46
41
|
};
|
|
47
42
|
authStore.update(userInfo, authData);
|
|
48
43
|
}
|
|
@@ -11,7 +11,7 @@ const getPathWhitoutFormPart = (path) => {
|
|
|
11
11
|
parts.pop();
|
|
12
12
|
return parts?.join("/");
|
|
13
13
|
};
|
|
14
|
-
export default defineNuxtRouteMiddleware((to) => {
|
|
14
|
+
export default defineNuxtRouteMiddleware(async (to) => {
|
|
15
15
|
if (!import.meta.client) {
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
@@ -25,6 +25,12 @@ export default defineNuxtRouteMiddleware((to) => {
|
|
|
25
25
|
if (!authStore.isAuthenticated) {
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
+
if (!authStore.authData?.resources) {
|
|
29
|
+
const resources = await authorization.getResources(
|
|
30
|
+
authStore.token
|
|
31
|
+
);
|
|
32
|
+
authStore.setResources(resources);
|
|
33
|
+
}
|
|
28
34
|
if (isUserGoingToForm(resource)) {
|
|
29
35
|
const formModeTrackerStore = useFormModeTrackerStore($pinia);
|
|
30
36
|
const params = {
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
declare
|
|
2
|
-
type __VLS_Slots = {} & {
|
|
3
|
-
default?: (props: typeof __VLS_1) => any;
|
|
4
|
-
};
|
|
5
|
-
declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
6
|
-
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
7
2
|
declare const _default: typeof __VLS_export;
|
|
8
3
|
export default _default;
|
|
9
|
-
type __VLS_WithSlots<T, S> = T & {
|
|
10
|
-
new (): {
|
|
11
|
-
$slots: S;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<LoadingSessionScreen />
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script setup>
|
|
6
|
-
import
|
|
7
|
-
import { navigateTo } from "#imports";
|
|
8
|
-
import { onMounted } from "vue";
|
|
9
|
-
onMounted(async () => {
|
|
10
|
-
const runtimeConfig = useRuntimeConfig();
|
|
11
|
-
await navigateTo(
|
|
12
|
-
runtimeConfig.public.unaxt.auth.sso?.postLoginRedirectUrl ?? "/"
|
|
13
|
-
);
|
|
14
|
-
});
|
|
6
|
+
import LoadingSessionScreen from "../../components/shared/LoadingSessionScreen.vue";
|
|
15
7
|
</script>
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
declare
|
|
2
|
-
type __VLS_Slots = {} & {
|
|
3
|
-
default?: (props: typeof __VLS_1) => any;
|
|
4
|
-
};
|
|
5
|
-
declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
6
|
-
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
7
2
|
declare const _default: typeof __VLS_export;
|
|
8
3
|
export default _default;
|
|
9
|
-
type __VLS_WithSlots<T, S> = T & {
|
|
10
|
-
new (): {
|
|
11
|
-
$slots: S;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
declare
|
|
2
|
-
type __VLS_Slots = {} & {
|
|
3
|
-
default?: (props: typeof __VLS_1) => any;
|
|
4
|
-
};
|
|
5
|
-
declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
6
|
-
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
7
2
|
declare const _default: typeof __VLS_export;
|
|
8
3
|
export default _default;
|
|
9
|
-
type __VLS_WithSlots<T, S> = T & {
|
|
10
|
-
new (): {
|
|
11
|
-
$slots: S;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<LoadingScreen />
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script setup>
|
|
6
|
-
import { useRuntimeConfig } from "#app";
|
|
7
6
|
import { navigateTo } from "#imports";
|
|
8
7
|
import { onMounted } from "vue";
|
|
8
|
+
import LoadingScreen from "../../components/shared/LoadingScreen.vue";
|
|
9
|
+
import { getPostLoginRedirect } from "../utils/postLoginRedirect";
|
|
9
10
|
onMounted(async () => {
|
|
10
|
-
|
|
11
|
-
await navigateTo(
|
|
12
|
-
runtimeConfig.public.unaxt.auth.sso?.signInRedirectUrl ?? "/"
|
|
13
|
-
);
|
|
11
|
+
await navigateTo(getPostLoginRedirect());
|
|
14
12
|
});
|
|
15
13
|
</script>
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
declare
|
|
2
|
-
type __VLS_Slots = {} & {
|
|
3
|
-
default?: (props: typeof __VLS_1) => any;
|
|
4
|
-
};
|
|
5
|
-
declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
6
|
-
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
7
2
|
declare const _default: typeof __VLS_export;
|
|
8
3
|
export default _default;
|
|
9
|
-
type __VLS_WithSlots<T, S> = T & {
|
|
10
|
-
new (): {
|
|
11
|
-
$slots: S;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
defineNuxtPlugin,
|
|
3
|
+
navigateTo,
|
|
4
|
+
useRuntimeConfig,
|
|
5
|
+
useNuxtApp
|
|
6
|
+
} from "#app";
|
|
2
7
|
import {
|
|
3
8
|
AsgardeoSPAClient,
|
|
4
9
|
Hooks
|
|
5
10
|
} from "@asgardeo/auth-spa";
|
|
6
11
|
import { useAuthStore } from "../stores/auth.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
12
|
+
import {
|
|
13
|
+
getPostLoginRedirect,
|
|
14
|
+
savePostLoginRedirect
|
|
15
|
+
} from "../utils/postLoginRedirect.js";
|
|
16
|
+
import { isSignOutCallback } from "../utils/isAuthCallback.js";
|
|
17
|
+
import { parseUserInfo } from "../utils/parseUserInfo.js";
|
|
18
|
+
import { parseCedulaFromSub } from "../utils/parseCedulaFromSub.js";
|
|
19
|
+
export default defineNuxtPlugin(async (nuxtApp) => {
|
|
9
20
|
const auth = AsgardeoSPAClient.getInstance();
|
|
10
21
|
const runtimeConfig = useRuntimeConfig();
|
|
11
22
|
const authConfig = runtimeConfig.public.unaxt.auth;
|
|
@@ -21,41 +32,49 @@ export default defineNuxtPlugin(() => {
|
|
|
21
32
|
signOutRedirectURL: origin + (authConfig.sso?.signOutRedirectUrl ?? "/"),
|
|
22
33
|
scope: authConfig.sso?.scopes !== void 0 ? authConfig.sso?.scopes?.split("|") : FALLBACK_SCOPES
|
|
23
34
|
};
|
|
24
|
-
auth?.initialize(config);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
await auth?.initialize(config);
|
|
36
|
+
const signInRedirectUrl = authConfig.sso?.signInRedirectUrl;
|
|
37
|
+
const isSignInCallbackPath = window.location.pathname === signInRedirectUrl;
|
|
38
|
+
const isSignOutCallbackPath = isSignOutCallback(window.location.pathname);
|
|
28
39
|
auth?.on(Hooks.SignIn, async (response) => {
|
|
29
40
|
const { $pinia } = useNuxtApp();
|
|
30
41
|
const authStore = useAuthStore($pinia);
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
email = rawEmail?.trim();
|
|
37
|
-
const [name, lastName] = email.toUpperCase().split(".");
|
|
38
|
-
return {
|
|
39
|
-
name,
|
|
40
|
-
lastName,
|
|
41
|
-
fullName: name + " " + lastName
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
};
|
|
42
|
+
const { email, name, lastName1, lastName2, fullName } = parseUserInfo({
|
|
43
|
+
email: response?.email,
|
|
44
|
+
givenName: response?.givenName,
|
|
45
|
+
familyName: response?.familyName
|
|
46
|
+
});
|
|
45
47
|
const userInfo = {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
name,
|
|
49
|
+
lastName1,
|
|
50
|
+
lastName2,
|
|
51
|
+
fullName,
|
|
52
|
+
cedula: parseCedulaFromSub(response.sub),
|
|
48
53
|
email
|
|
49
54
|
};
|
|
50
55
|
const token = await auth?.getAccessToken();
|
|
51
|
-
const resources = await authorization.getResources(token);
|
|
52
56
|
const authData = {
|
|
53
57
|
isAuthenticated: true,
|
|
54
|
-
accessToken: token
|
|
55
|
-
resources
|
|
58
|
+
accessToken: token
|
|
56
59
|
};
|
|
57
60
|
authStore.update(userInfo, authData);
|
|
58
61
|
});
|
|
62
|
+
if (authConfig.sso?.automaticSignIn && !isSignInCallbackPath && !isSignOutCallbackPath) {
|
|
63
|
+
savePostLoginRedirect(window.location.pathname);
|
|
64
|
+
await auth?.signIn();
|
|
65
|
+
}
|
|
66
|
+
if (isSignInCallbackPath) {
|
|
67
|
+
nuxtApp.hook("app:created", async () => {
|
|
68
|
+
try {
|
|
69
|
+
await auth?.signIn();
|
|
70
|
+
await navigateTo(
|
|
71
|
+
getPostLoginRedirect(authConfig.sso?.postLoginRedirectUrl)
|
|
72
|
+
);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error("Error procesando callback SSO:", error);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
59
78
|
return {
|
|
60
79
|
provide: {
|
|
61
80
|
/**
|
|
@@ -1,128 +1,137 @@
|
|
|
1
|
-
import type { IAuthData, IAuthenticatedUser, IHasAuthorizationInResourceParams } from '../../types/index.js';
|
|
1
|
+
import type { IAuthData, IAuthenticatedUser, IHasAuthorizationInResourceParams, IResource } from '../../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Store encargado de almacenar y gestionar la autenticación y autorización del usuario.
|
|
4
4
|
*/
|
|
5
5
|
export declare const useAuthStore: import("pinia").StoreDefinition<"AuthStore", Pick<{
|
|
6
6
|
user: import("vue").Ref<{
|
|
7
|
-
cedula
|
|
7
|
+
cedula?: string | undefined;
|
|
8
8
|
email: string;
|
|
9
9
|
fullName?: string | undefined;
|
|
10
10
|
name?: string | undefined;
|
|
11
|
-
|
|
11
|
+
lastName1?: string | undefined;
|
|
12
|
+
lastName2?: string | undefined;
|
|
12
13
|
} | null, IAuthenticatedUser | {
|
|
13
|
-
cedula
|
|
14
|
+
cedula?: string | undefined;
|
|
14
15
|
email: string;
|
|
15
16
|
fullName?: string | undefined;
|
|
16
17
|
name?: string | undefined;
|
|
17
|
-
|
|
18
|
+
lastName1?: string | undefined;
|
|
19
|
+
lastName2?: string | undefined;
|
|
18
20
|
} | null>;
|
|
19
21
|
authData: import("vue").Ref<{
|
|
20
22
|
isAuthenticated: boolean;
|
|
21
23
|
accessToken: string;
|
|
22
|
-
resources
|
|
24
|
+
resources?: {
|
|
23
25
|
id: number;
|
|
24
26
|
nombre: string;
|
|
25
27
|
permisoInsertar: boolean;
|
|
26
28
|
permisoModificar: boolean;
|
|
27
29
|
permisoEliminar: boolean;
|
|
28
|
-
}[];
|
|
30
|
+
}[] | undefined;
|
|
29
31
|
} | null, IAuthData | {
|
|
30
32
|
isAuthenticated: boolean;
|
|
31
33
|
accessToken: string;
|
|
32
|
-
resources
|
|
34
|
+
resources?: {
|
|
33
35
|
id: number;
|
|
34
36
|
nombre: string;
|
|
35
37
|
permisoInsertar: boolean;
|
|
36
38
|
permisoModificar: boolean;
|
|
37
39
|
permisoEliminar: boolean;
|
|
38
|
-
}[];
|
|
40
|
+
}[] | undefined;
|
|
39
41
|
} | null>;
|
|
40
42
|
isAuthenticated: import("vue").ComputedRef<boolean>;
|
|
41
43
|
token: import("vue").ComputedRef<string | null>;
|
|
42
44
|
logout: () => Promise<void>;
|
|
43
|
-
update: (userInfo: IAuthenticatedUser, data: IAuthData) => void;
|
|
45
|
+
update: (userInfo: IAuthenticatedUser, data: Pick<IAuthData, "isAuthenticated" | "accessToken">) => void;
|
|
46
|
+
setResources: (resources: IResource[]) => void;
|
|
44
47
|
hasResource: (resource: string) => boolean;
|
|
45
48
|
hasAuthorizationInResource: ({ resource, authorization }: IHasAuthorizationInResourceParams) => boolean;
|
|
46
49
|
}, "user" | "authData">, Pick<{
|
|
47
50
|
user: import("vue").Ref<{
|
|
48
|
-
cedula
|
|
51
|
+
cedula?: string | undefined;
|
|
49
52
|
email: string;
|
|
50
53
|
fullName?: string | undefined;
|
|
51
54
|
name?: string | undefined;
|
|
52
|
-
|
|
55
|
+
lastName1?: string | undefined;
|
|
56
|
+
lastName2?: string | undefined;
|
|
53
57
|
} | null, IAuthenticatedUser | {
|
|
54
|
-
cedula
|
|
58
|
+
cedula?: string | undefined;
|
|
55
59
|
email: string;
|
|
56
60
|
fullName?: string | undefined;
|
|
57
61
|
name?: string | undefined;
|
|
58
|
-
|
|
62
|
+
lastName1?: string | undefined;
|
|
63
|
+
lastName2?: string | undefined;
|
|
59
64
|
} | null>;
|
|
60
65
|
authData: import("vue").Ref<{
|
|
61
66
|
isAuthenticated: boolean;
|
|
62
67
|
accessToken: string;
|
|
63
|
-
resources
|
|
68
|
+
resources?: {
|
|
64
69
|
id: number;
|
|
65
70
|
nombre: string;
|
|
66
71
|
permisoInsertar: boolean;
|
|
67
72
|
permisoModificar: boolean;
|
|
68
73
|
permisoEliminar: boolean;
|
|
69
|
-
}[];
|
|
74
|
+
}[] | undefined;
|
|
70
75
|
} | null, IAuthData | {
|
|
71
76
|
isAuthenticated: boolean;
|
|
72
77
|
accessToken: string;
|
|
73
|
-
resources
|
|
78
|
+
resources?: {
|
|
74
79
|
id: number;
|
|
75
80
|
nombre: string;
|
|
76
81
|
permisoInsertar: boolean;
|
|
77
82
|
permisoModificar: boolean;
|
|
78
83
|
permisoEliminar: boolean;
|
|
79
|
-
}[];
|
|
84
|
+
}[] | undefined;
|
|
80
85
|
} | null>;
|
|
81
86
|
isAuthenticated: import("vue").ComputedRef<boolean>;
|
|
82
87
|
token: import("vue").ComputedRef<string | null>;
|
|
83
88
|
logout: () => Promise<void>;
|
|
84
|
-
update: (userInfo: IAuthenticatedUser, data: IAuthData) => void;
|
|
89
|
+
update: (userInfo: IAuthenticatedUser, data: Pick<IAuthData, "isAuthenticated" | "accessToken">) => void;
|
|
90
|
+
setResources: (resources: IResource[]) => void;
|
|
85
91
|
hasResource: (resource: string) => boolean;
|
|
86
92
|
hasAuthorizationInResource: ({ resource, authorization }: IHasAuthorizationInResourceParams) => boolean;
|
|
87
93
|
}, "isAuthenticated" | "token">, Pick<{
|
|
88
94
|
user: import("vue").Ref<{
|
|
89
|
-
cedula
|
|
95
|
+
cedula?: string | undefined;
|
|
90
96
|
email: string;
|
|
91
97
|
fullName?: string | undefined;
|
|
92
98
|
name?: string | undefined;
|
|
93
|
-
|
|
99
|
+
lastName1?: string | undefined;
|
|
100
|
+
lastName2?: string | undefined;
|
|
94
101
|
} | null, IAuthenticatedUser | {
|
|
95
|
-
cedula
|
|
102
|
+
cedula?: string | undefined;
|
|
96
103
|
email: string;
|
|
97
104
|
fullName?: string | undefined;
|
|
98
105
|
name?: string | undefined;
|
|
99
|
-
|
|
106
|
+
lastName1?: string | undefined;
|
|
107
|
+
lastName2?: string | undefined;
|
|
100
108
|
} | null>;
|
|
101
109
|
authData: import("vue").Ref<{
|
|
102
110
|
isAuthenticated: boolean;
|
|
103
111
|
accessToken: string;
|
|
104
|
-
resources
|
|
112
|
+
resources?: {
|
|
105
113
|
id: number;
|
|
106
114
|
nombre: string;
|
|
107
115
|
permisoInsertar: boolean;
|
|
108
116
|
permisoModificar: boolean;
|
|
109
117
|
permisoEliminar: boolean;
|
|
110
|
-
}[];
|
|
118
|
+
}[] | undefined;
|
|
111
119
|
} | null, IAuthData | {
|
|
112
120
|
isAuthenticated: boolean;
|
|
113
121
|
accessToken: string;
|
|
114
|
-
resources
|
|
122
|
+
resources?: {
|
|
115
123
|
id: number;
|
|
116
124
|
nombre: string;
|
|
117
125
|
permisoInsertar: boolean;
|
|
118
126
|
permisoModificar: boolean;
|
|
119
127
|
permisoEliminar: boolean;
|
|
120
|
-
}[];
|
|
128
|
+
}[] | undefined;
|
|
121
129
|
} | null>;
|
|
122
130
|
isAuthenticated: import("vue").ComputedRef<boolean>;
|
|
123
131
|
token: import("vue").ComputedRef<string | null>;
|
|
124
132
|
logout: () => Promise<void>;
|
|
125
|
-
update: (userInfo: IAuthenticatedUser, data: IAuthData) => void;
|
|
133
|
+
update: (userInfo: IAuthenticatedUser, data: Pick<IAuthData, "isAuthenticated" | "accessToken">) => void;
|
|
134
|
+
setResources: (resources: IResource[]) => void;
|
|
126
135
|
hasResource: (resource: string) => boolean;
|
|
127
136
|
hasAuthorizationInResource: ({ resource, authorization }: IHasAuthorizationInResourceParams) => boolean;
|
|
128
|
-
}, "logout" | "update" | "hasResource" | "hasAuthorizationInResource">>;
|
|
137
|
+
}, "logout" | "update" | "setResources" | "hasResource" | "hasAuthorizationInResource">>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { computed, ref, useNuxtApp, useRuntimeConfig } from "#imports";
|
|
1
|
+
import { computed, ref, useNuxtApp, useRoute, useRuntimeConfig } from "#imports";
|
|
2
2
|
import { defineStore } from "pinia";
|
|
3
3
|
import { EAuthorization } from "../../enums/EAuthorization.js";
|
|
4
|
+
import { savePostLoginRedirect } from "../utils/postLoginRedirect.js";
|
|
4
5
|
const LOGOUT_ENDPOINT = "/api/usuario/logout";
|
|
5
6
|
export const useAuthStore = defineStore("AuthStore", () => {
|
|
6
7
|
const user = ref(null);
|
|
@@ -12,7 +13,9 @@ export const useAuthStore = defineStore("AuthStore", () => {
|
|
|
12
13
|
const logout = async () => {
|
|
13
14
|
const { $signOut } = useNuxtApp();
|
|
14
15
|
const runtimeConfig = useRuntimeConfig();
|
|
16
|
+
const route = useRoute();
|
|
15
17
|
const baseURL = runtimeConfig.public.apiBaseUrl;
|
|
18
|
+
savePostLoginRedirect(route.fullPath);
|
|
16
19
|
try {
|
|
17
20
|
await $fetch(LOGOUT_ENDPOINT, {
|
|
18
21
|
baseURL,
|
|
@@ -29,7 +32,20 @@ export const useAuthStore = defineStore("AuthStore", () => {
|
|
|
29
32
|
};
|
|
30
33
|
const update = (userInfo, data) => {
|
|
31
34
|
user.value = userInfo;
|
|
32
|
-
authData.value =
|
|
35
|
+
authData.value = {
|
|
36
|
+
isAuthenticated: data.isAuthenticated,
|
|
37
|
+
accessToken: data.accessToken,
|
|
38
|
+
resources: authData.value?.resources
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
const setResources = (resources) => {
|
|
42
|
+
if (!authData.value) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
authData.value = {
|
|
46
|
+
...authData.value,
|
|
47
|
+
resources
|
|
48
|
+
};
|
|
33
49
|
};
|
|
34
50
|
const hasResource = (resource) => {
|
|
35
51
|
return authData.value?.resources?.some(
|
|
@@ -40,7 +56,7 @@ export const useAuthStore = defineStore("AuthStore", () => {
|
|
|
40
56
|
resource,
|
|
41
57
|
authorization
|
|
42
58
|
}) => {
|
|
43
|
-
const resourceData = authData.value?.resources
|
|
59
|
+
const resourceData = authData.value?.resources?.find(
|
|
44
60
|
(currentResource) => currentResource.nombre === resource
|
|
45
61
|
);
|
|
46
62
|
if (!resourceData) return false;
|
|
@@ -58,6 +74,7 @@ export const useAuthStore = defineStore("AuthStore", () => {
|
|
|
58
74
|
token,
|
|
59
75
|
logout,
|
|
60
76
|
update,
|
|
77
|
+
setResources,
|
|
61
78
|
hasResource,
|
|
62
79
|
hasAuthorizationInResource
|
|
63
80
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function isAuthCallback(path) {
|
|
2
|
+
return Boolean(path?.startsWith("/auth/sso/"));
|
|
3
|
+
}
|
|
4
|
+
export function isSignInCallback(path) {
|
|
5
|
+
return Boolean(path?.startsWith("/auth/sso/login"));
|
|
6
|
+
}
|
|
7
|
+
export function isSignOutCallback(path) {
|
|
8
|
+
return Boolean(path?.startsWith("/auth/sso/logout"));
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseCedulaFromSub(sub: string | undefined): string | undefined;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const INSTITUTIONAL_EMAIL_DOMAINS = ["una.cr", "est.una.ac.cr"];
|
|
2
|
+
function getInstitutionalNameParts(localPart) {
|
|
3
|
+
const parts = localPart.toUpperCase().split(".").filter(Boolean);
|
|
4
|
+
return parts.length === 3 ? parts : null;
|
|
5
|
+
}
|
|
6
|
+
function isInstitutionalEmail(email) {
|
|
7
|
+
if (!email.includes("@")) {
|
|
8
|
+
return getInstitutionalNameParts(email) !== null;
|
|
9
|
+
}
|
|
10
|
+
const [localPart, domain] = email.split("@");
|
|
11
|
+
return !!domain && INSTITUTIONAL_EMAIL_DOMAINS.includes(domain.toLowerCase()) && getInstitutionalNameParts(localPart ?? "") !== null;
|
|
12
|
+
}
|
|
13
|
+
function parseNamesFromFamilyName(familyName) {
|
|
14
|
+
const family = familyName.trim().toUpperCase();
|
|
15
|
+
if (!family) return {};
|
|
16
|
+
const spaceIndex = family.indexOf(" ");
|
|
17
|
+
if (spaceIndex === -1) {
|
|
18
|
+
return { lastName1: family };
|
|
19
|
+
}
|
|
20
|
+
const lastName1 = family.slice(0, spaceIndex);
|
|
21
|
+
const lastName2 = family.slice(spaceIndex + 1).trim() || void 0;
|
|
22
|
+
return { lastName1, lastName2 };
|
|
23
|
+
}
|
|
24
|
+
function normalizeEmail(rawEmail) {
|
|
25
|
+
return (Array.isArray(rawEmail) ? rawEmail[0]?.trim() : rawEmail)?.trim() ?? "";
|
|
26
|
+
}
|
|
27
|
+
export function parseUserInfo(claims) {
|
|
28
|
+
const email = normalizeEmail(claims.email);
|
|
29
|
+
if (email && isInstitutionalEmail(email)) {
|
|
30
|
+
const localPart = email.includes("@") ? email.split("@")[0] ?? "" : email;
|
|
31
|
+
const parts = getInstitutionalNameParts(localPart);
|
|
32
|
+
if (parts) {
|
|
33
|
+
const [name2, lastName12, lastName22] = parts;
|
|
34
|
+
return {
|
|
35
|
+
email,
|
|
36
|
+
name: name2,
|
|
37
|
+
lastName1: lastName12,
|
|
38
|
+
lastName2: lastName22,
|
|
39
|
+
fullName: [name2, lastName12, lastName22].join(" ")
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const name = claims.givenName?.trim().toUpperCase() || void 0;
|
|
44
|
+
const { lastName1, lastName2 } = parseNamesFromFamilyName(
|
|
45
|
+
claims.familyName ?? ""
|
|
46
|
+
);
|
|
47
|
+
const fullName = [name, lastName1, lastName2].filter(Boolean).join(" ");
|
|
48
|
+
return {
|
|
49
|
+
email,
|
|
50
|
+
name,
|
|
51
|
+
lastName1,
|
|
52
|
+
lastName2,
|
|
53
|
+
fullName: fullName || void 0
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isAuthCallback } from "./isAuthCallback.js";
|
|
2
|
+
const STORAGE_KEY = "postLoginRedirect";
|
|
3
|
+
export function isSafePath(path) {
|
|
4
|
+
return Boolean(path?.startsWith("/") && !path.startsWith("//"));
|
|
5
|
+
}
|
|
6
|
+
export function savePostLoginRedirect(path) {
|
|
7
|
+
if (!import.meta.client) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (!isSafePath(path) || isAuthCallback(path)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
sessionStorage.setItem(STORAGE_KEY, path);
|
|
14
|
+
}
|
|
15
|
+
export function getPostLoginRedirect(fallback = "/") {
|
|
16
|
+
if (!import.meta.client) {
|
|
17
|
+
return fallback;
|
|
18
|
+
}
|
|
19
|
+
const stored = sessionStorage.getItem(STORAGE_KEY);
|
|
20
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
21
|
+
if (stored && isSafePath(stored)) {
|
|
22
|
+
return stored;
|
|
23
|
+
}
|
|
24
|
+
return fallback;
|
|
25
|
+
}
|
|
@@ -29,7 +29,7 @@ const props = defineProps({
|
|
|
29
29
|
dir: { type: String, required: false },
|
|
30
30
|
nextPage: { type: Function, required: false },
|
|
31
31
|
prevPage: { type: Function, required: false },
|
|
32
|
-
modelValue: { type: null, required: false, default: void 0 },
|
|
32
|
+
modelValue: { type: [Object, Array, null], required: false, default: void 0 },
|
|
33
33
|
multiple: { type: Boolean, required: false },
|
|
34
34
|
disableDaysOutsideCurrentView: { type: Boolean, required: false },
|
|
35
35
|
asChild: { type: Boolean, required: false },
|
|
@@ -2,10 +2,12 @@ import type { ApiFetch } from '../types/index.js';
|
|
|
2
2
|
declare const _default: import("#app").Plugin<{
|
|
3
3
|
api: {
|
|
4
4
|
fetch: ApiFetch;
|
|
5
|
+
publicFetch: ApiFetch;
|
|
5
6
|
};
|
|
6
7
|
}> & import("#app").ObjectPlugin<{
|
|
7
8
|
api: {
|
|
8
9
|
fetch: ApiFetch;
|
|
10
|
+
publicFetch: ApiFetch;
|
|
9
11
|
};
|
|
10
12
|
}>;
|
|
11
13
|
export default _default;
|
|
@@ -23,10 +23,14 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
|
+
const publicFetch = $fetch.create({
|
|
27
|
+
baseURL: nuxtApp.$config.public.apiBaseUrl
|
|
28
|
+
});
|
|
26
29
|
return {
|
|
27
30
|
provide: {
|
|
28
31
|
api: {
|
|
29
|
-
fetch
|
|
32
|
+
fetch,
|
|
33
|
+
publicFetch
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
36
|
};
|
|
@@ -221,13 +221,12 @@ export interface IBaseEntityLite extends IIdentifiedEntity, IVersionedEntity, IA
|
|
|
221
221
|
* @property {string} email - Email del usuario
|
|
222
222
|
* @property {string} fullName - Nombre completo del usuario
|
|
223
223
|
* @property {string} name - Nombre del usuario
|
|
224
|
-
* @property {string}
|
|
225
|
-
* @property {string}
|
|
226
|
-
* @property {string} mainRole - Rol del usuario
|
|
224
|
+
* @property {string} lastName1 - Primer apellido del usuario
|
|
225
|
+
* @property {string} lastName2 - Segundo apellido del usuario
|
|
227
226
|
*/
|
|
228
227
|
export interface IAuthenticatedUser {
|
|
229
228
|
/** Cédula del usuario */
|
|
230
|
-
cedula
|
|
229
|
+
cedula?: string;
|
|
231
230
|
/** Email del usuario */
|
|
232
231
|
email: string;
|
|
233
232
|
/** Nombre completo del usuario */
|
|
@@ -235,7 +234,9 @@ export interface IAuthenticatedUser {
|
|
|
235
234
|
/** Nombre del usuario */
|
|
236
235
|
name?: string;
|
|
237
236
|
/** Primer apellido del usuario */
|
|
238
|
-
|
|
237
|
+
lastName1?: string;
|
|
238
|
+
/** Segundo apellido del usuario */
|
|
239
|
+
lastName2?: string;
|
|
239
240
|
}
|
|
240
241
|
/**
|
|
241
242
|
* Interfaz para la información de los recursos del usuario autenticado.
|
|
@@ -267,7 +268,7 @@ export interface IResource {
|
|
|
267
268
|
*
|
|
268
269
|
* @property {boolean} isAuthenticated - Almacena si el usuario está autenticado
|
|
269
270
|
* @property {string} accessToken - Access Token del usuario generado al iniciar sesión en WSO2
|
|
270
|
-
* @property {IResource[]} resources - Recursos del usuario
|
|
271
|
+
* @property {IResource[]} resources - Recursos del usuario. Se cargan en el middleware de autorización.
|
|
271
272
|
*/
|
|
272
273
|
export interface IAuthData {
|
|
273
274
|
/** Almacena si el usuario esta autenticado */
|
|
@@ -275,7 +276,7 @@ export interface IAuthData {
|
|
|
275
276
|
/** Access Token del usuario generado al iniciar sesión en WSO2 */
|
|
276
277
|
accessToken: string;
|
|
277
278
|
/** Recursos del usuario */
|
|
278
|
-
resources
|
|
279
|
+
resources?: IResource[];
|
|
279
280
|
}
|
|
280
281
|
/**
|
|
281
282
|
* Interfaz para los parámetros de métodos de validación de permisos en recursos.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "una-nuxt-module",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.37",
|
|
4
4
|
"description": "Módulo Nuxt para desarrollo CGI",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -65,9 +65,9 @@
|
|
|
65
65
|
"@nuxt/a11y": "1.0.0-alpha.1",
|
|
66
66
|
"@nuxt/fonts": "0.14.0",
|
|
67
67
|
"@nuxt/hints": "1.1.2",
|
|
68
|
-
"@nuxt/icon": "2.2.
|
|
68
|
+
"@nuxt/icon": "2.2.3",
|
|
69
69
|
"@nuxt/image": "2.0.0",
|
|
70
|
-
"@nuxt/kit": "4.4.
|
|
70
|
+
"@nuxt/kit": "4.4.7",
|
|
71
71
|
"@nuxtjs/i18n": "10.4.0",
|
|
72
72
|
"@pinia/nuxt": "0.5.5",
|
|
73
73
|
"@tailwindcss/vite": "4.3.0",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"lucide-vue-next": "1.0.0",
|
|
85
85
|
"nuxt-security": "2.6.0",
|
|
86
86
|
"pinia": "2.2.8",
|
|
87
|
-
"reka-ui": "2.9.
|
|
87
|
+
"reka-ui": "2.9.9",
|
|
88
88
|
"scule": "1.3.0",
|
|
89
89
|
"tailwind-merge": "3.6.0",
|
|
90
90
|
"tailwindcss": "4.3.0",
|
|
@@ -99,25 +99,25 @@
|
|
|
99
99
|
"@nuxt/devtools": "3.2.4",
|
|
100
100
|
"@nuxt/eslint-config": "1.15.2",
|
|
101
101
|
"@nuxt/module-builder": "1.0.2",
|
|
102
|
-
"@nuxt/schema": "4.4.
|
|
102
|
+
"@nuxt/schema": "4.4.7",
|
|
103
103
|
"@nuxt/test-utils": "4.0.3",
|
|
104
104
|
"@nuxtjs/color-mode": "4.0.0",
|
|
105
105
|
"@types/node": "24.3.1",
|
|
106
|
-
"@typescript-eslint/parser": "8.
|
|
106
|
+
"@typescript-eslint/parser": "8.60.1",
|
|
107
107
|
"changelogen": "0.6.2",
|
|
108
108
|
"eslint": "9.39.1",
|
|
109
109
|
"eslint-plugin-security": "3.0.1",
|
|
110
110
|
"husky": "9.1.7",
|
|
111
|
-
"lint-staged": "17.0.
|
|
112
|
-
"nuxt": "4.4.
|
|
111
|
+
"lint-staged": "17.0.7",
|
|
112
|
+
"nuxt": "4.4.7",
|
|
113
113
|
"prettier": "3.8.3",
|
|
114
114
|
"prettier-plugin-tailwindcss": "0.8.0",
|
|
115
|
-
"shadcn-nuxt": "2.7.
|
|
115
|
+
"shadcn-nuxt": "2.7.4",
|
|
116
116
|
"typescript": "~5.9.2",
|
|
117
117
|
"unaxt-eslint-config": "0.0.3",
|
|
118
|
-
"vitest": "4.1.
|
|
119
|
-
"vue-eslint-parser": "10.4.
|
|
120
|
-
"vue-tsc": "3.3.
|
|
118
|
+
"vitest": "4.1.8",
|
|
119
|
+
"vue-eslint-parser": "10.4.1",
|
|
120
|
+
"vue-tsc": "3.3.3"
|
|
121
121
|
},
|
|
122
122
|
"lint-staged": {
|
|
123
123
|
"*.{js,ts,json,vue}": [
|