una-nuxt-module 3.0.36 → 3.0.38

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 (28) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +179 -9
  3. package/dist/runtime/auth/middleware/authentication.d.ts +3 -3
  4. package/dist/runtime/auth/middleware/authentication.js +22 -27
  5. package/dist/runtime/auth/middleware/authorization.js +7 -1
  6. package/dist/runtime/auth/pages/login.d.vue.ts +1 -11
  7. package/dist/runtime/auth/pages/login.vue +2 -10
  8. package/dist/runtime/auth/pages/login.vue.d.ts +1 -11
  9. package/dist/runtime/auth/pages/logout.d.vue.ts +1 -11
  10. package/dist/runtime/auth/pages/logout.vue +4 -6
  11. package/dist/runtime/auth/pages/logout.vue.d.ts +1 -11
  12. package/dist/runtime/auth/plugins/auth.js +43 -26
  13. package/dist/runtime/auth/stores/auth.d.ts +38 -29
  14. package/dist/runtime/auth/stores/auth.js +20 -3
  15. package/dist/runtime/auth/utils/isAuthCallback.d.ts +3 -0
  16. package/dist/runtime/auth/utils/isAuthCallback.js +9 -0
  17. package/dist/runtime/auth/utils/parseCedulaFromSub.d.ts +1 -0
  18. package/dist/runtime/auth/utils/parseCedulaFromSub.js +4 -0
  19. package/dist/runtime/auth/utils/parseUserInfo.d.ts +6 -0
  20. package/dist/runtime/auth/utils/parseUserInfo.js +55 -0
  21. package/dist/runtime/auth/utils/postLoginRedirect.d.ts +3 -0
  22. package/dist/runtime/auth/utils/postLoginRedirect.js +36 -0
  23. package/dist/runtime/composables/useFonts.d.ts +3 -0
  24. package/dist/runtime/composables/useFonts.js +10 -0
  25. package/dist/runtime/repository-pattern/plugins/api-fetch.d.ts +2 -0
  26. package/dist/runtime/repository-pattern/plugins/api-fetch.js +5 -1
  27. package/dist/runtime/types/index.d.ts +9 -8
  28. package/package.json +1 -1
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "una-nuxt-module",
3
- "version": "3.0.36",
3
+ "version": "3.0.38",
4
4
  "configKey": "unaxt",
5
5
  "compatibility": {
6
6
  "nuxt": ">=4.0.0"
package/dist/module.mjs CHANGED
@@ -167,12 +167,165 @@ function addTemplates() {
167
167
  }
168
168
 
169
169
  const name = "una-nuxt-module";
170
- const version = "3.0.36";
170
+ const version = "3.0.38";
171
+ const description = "Módulo Nuxt para desarrollo CGI";
172
+ const repository = {
173
+ type: "git",
174
+ url: ""
175
+ };
176
+ const license = "MIT";
177
+ const type = "module";
178
+ const exports$1 = {
179
+ ".": {
180
+ types: "./dist/types.d.mts",
181
+ style: "./dist/runtime/styles/main.css",
182
+ "import": "./dist/module.mjs",
183
+ require: "./dist/module.mjs"
184
+ }
185
+ };
186
+ const main = "./dist/module.mjs";
187
+ const typesVersions = {
188
+ "*": {
189
+ ".": [
190
+ "./dist/types.d.mts"
191
+ ],
192
+ "runtime/*": [
193
+ "./dist/runtime/*"
194
+ ],
195
+ "components/*": [
196
+ "./dist/runtime/components/*"
197
+ ]
198
+ }
199
+ };
200
+ const imports = {
201
+ "#build/templates/*": "./.nuxt/templates/*.ts",
202
+ "#build/templates.css": "./.nuxt/templates.css"
203
+ };
204
+ const style = "./dist/runtime/styles/main.css";
205
+ const files = [
206
+ "README.md",
207
+ "LICENSE",
208
+ ".nuxt/templates",
209
+ ".nuxt/templates.css",
210
+ "dist"
211
+ ];
212
+ const scripts = {
213
+ prepack: "nuxt-module-build build",
214
+ dev: "pnpm run dev:prepare && nuxi dev playground",
215
+ "dev:https": "pnpm run dev:prepare && cd playground && pnpm run dev:https",
216
+ "dev:build": "nuxi build playground",
217
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
218
+ "release:prepare:major": "pnpm run test && pnpm run prepack && changelogen --release --major",
219
+ "release:prepare:minor": "pnpm run test && pnpm run prepack && changelogen --release --minor",
220
+ "release:prepare:patch": "pnpm run test && pnpm run prepack && changelogen --release --patch",
221
+ release: "pnpm publish && git push --follow-tags",
222
+ prepare: "husky",
223
+ format: "prettier --write .",
224
+ lint: "eslint .",
225
+ "lint:fix": "eslint . --fix",
226
+ test: "vitest run",
227
+ "test:watch": "vitest watch",
228
+ "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
229
+ };
230
+ const dependencies = {
231
+ "@asgardeo/auth-spa": "3.5.2",
232
+ "@nuxt/a11y": "1.0.0-alpha.1",
233
+ "@nuxt/fonts": "0.14.0",
234
+ "@nuxt/hints": "1.1.2",
235
+ "@nuxt/icon": "2.2.3",
236
+ "@nuxt/image": "2.0.0",
237
+ "@nuxt/kit": "4.4.7",
238
+ "@nuxtjs/i18n": "10.4.0",
239
+ "@pinia/nuxt": "0.5.5",
240
+ "@tailwindcss/vite": "4.3.0",
241
+ "@tanstack/vue-table": "8.21.3",
242
+ "@unovis/ts": "1.6.5",
243
+ "@unovis/vue": "1.6.5",
244
+ "@vee-validate/zod": "4.15.1",
245
+ "@vueuse/core": "14.3.0",
246
+ "class-variance-authority": "0.7.1",
247
+ clsx: "2.1.1",
248
+ colorette: "2.0.20",
249
+ defu: "6.1.7",
250
+ "embla-carousel-vue": "8.6.0",
251
+ "lucide-vue-next": "1.0.0",
252
+ "nuxt-security": "2.6.0",
253
+ pinia: "2.2.8",
254
+ "reka-ui": "2.9.9",
255
+ scule: "1.3.0",
256
+ "tailwind-merge": "3.6.0",
257
+ tailwindcss: "4.3.0",
258
+ "tw-animate-css": "1.4.0",
259
+ "vaul-vue": "0.4.1",
260
+ "vee-validate": "4.15.1",
261
+ "vue-input-otp": "0.3.2",
262
+ "vue-sonner": "2.0.9",
263
+ zod: "3.25.76"
264
+ };
265
+ const devDependencies = {
266
+ "@nuxt/devtools": "3.2.4",
267
+ "@nuxt/eslint-config": "1.15.2",
268
+ "@nuxt/module-builder": "1.0.2",
269
+ "@nuxt/schema": "4.4.7",
270
+ "@nuxt/test-utils": "4.0.3",
271
+ "@nuxtjs/color-mode": "4.0.0",
272
+ "@types/node": "24.3.1",
273
+ "@typescript-eslint/parser": "8.60.1",
274
+ changelogen: "0.6.2",
275
+ eslint: "9.39.1",
276
+ "eslint-plugin-security": "3.0.1",
277
+ husky: "9.1.7",
278
+ "lint-staged": "17.0.7",
279
+ nuxt: "4.4.7",
280
+ prettier: "3.8.3",
281
+ "prettier-plugin-tailwindcss": "0.8.0",
282
+ "shadcn-nuxt": "2.7.4",
283
+ typescript: "~5.9.2",
284
+ "unaxt-eslint-config": "0.0.3",
285
+ vitest: "4.1.8",
286
+ "vue-eslint-parser": "10.4.1",
287
+ "vue-tsc": "3.3.3"
288
+ };
289
+ const directories = {
290
+ test: "test"
291
+ };
292
+ const author = "Universidad Nacional - Centro de Gestion Informatica";
293
+ const bugs = {
294
+ url: "https://github.com/una-cgi/una-nuxt-module/issues"
295
+ };
296
+ const homepage = "https://github.com/una-cgi/una-nuxt-module#readme";
297
+ const pkg = {
298
+ name: name,
299
+ version: version,
300
+ description: description,
301
+ repository: repository,
302
+ license: license,
303
+ type: type,
304
+ exports: exports$1,
305
+ main: main,
306
+ typesVersions: typesVersions,
307
+ imports: imports,
308
+ style: style,
309
+ files: files,
310
+ scripts: scripts,
311
+ dependencies: dependencies,
312
+ devDependencies: devDependencies,
313
+ "lint-staged": {
314
+ "*.{js,ts,json,vue}": [
315
+ "prettier --write",
316
+ "eslint --fix"
317
+ ]
318
+ },
319
+ directories: directories,
320
+ author: author,
321
+ bugs: bugs,
322
+ homepage: homepage
323
+ };
171
324
 
172
325
  const module$1 = defineNuxtModule({
173
326
  meta: {
174
- name,
175
- version,
327
+ name: pkg.name,
328
+ version: pkg.version,
176
329
  configKey: "unaxt",
177
330
  compatibility: {
178
331
  nuxt: ">=4.0.0"
@@ -185,9 +338,9 @@ const module$1 = defineNuxtModule({
185
338
  enabled: true,
186
339
  sso: {
187
340
  automaticSignIn: true,
188
- postLoginRedirectUrl: "/",
189
341
  signInRedirectUrl: "/auth/sso/login",
190
- signOutRedirectUrl: "/auth/sso/logout"
342
+ signOutRedirectUrl: "/auth/sso/logout",
343
+ postLoginRedirect: "/"
191
344
  },
192
345
  middleware: {
193
346
  authentication: {
@@ -207,7 +360,7 @@ const module$1 = defineNuxtModule({
207
360
  },
208
361
  moduleDependencies: {
209
362
  "nuxt-security": {
210
- version: ">=2.0.0",
363
+ version: `>=${pkg.dependencies["nuxt-security"]}`,
211
364
  optional: true,
212
365
  defaults: {
213
366
  removeLoggers: true
@@ -231,11 +384,26 @@ const module$1 = defineNuxtModule({
231
384
  }
232
385
  },
233
386
  async setup(options, nuxt) {
234
- const logger = useLogger(name);
387
+ const logger = useLogger(pkg.name);
235
388
  const { resolve } = createResolver(import.meta.url);
236
389
  options = defu(nuxt.options.runtimeConfig.public.unaxt, options);
237
390
  nuxt.options.runtimeConfig.public.unaxt = options;
238
391
  nuxt.options.alias["#unaxt"] = resolve("./runtime");
392
+ function injectComponentsConfig() {
393
+ if (nuxt.options.components === false) {
394
+ return;
395
+ }
396
+ nuxt.options.components = {
397
+ dirs: [
398
+ { path: "~/components/global", global: true },
399
+ {
400
+ path: "~/components",
401
+ pattern: ["*/**", "**"],
402
+ pathPrefix: false
403
+ }
404
+ ]
405
+ };
406
+ }
239
407
  function setupAutoImports() {
240
408
  addImportsDir(
241
409
  ["composables", "constants", "enums", "types", "utils"].map(
@@ -303,12 +471,13 @@ const module$1 = defineNuxtModule({
303
471
  if (options.auth?.enabled) {
304
472
  logger.ready(green("Iniciando m\xF3dulo de autenticaci\xF3n"));
305
473
  addImportsDir(
306
- ["auth/stores", "auth/composables"].map(
474
+ ["auth/stores", "auth/composables", "auth/utils"].map(
307
475
  (dir) => resolve(`./runtime/${dir}`)
308
476
  )
309
477
  );
310
478
  logger.ready("\u251C\u2500\u2500 " + gray("Stores"));
311
479
  logger.ready("\u251C\u2500\u2500 " + gray("Composables"));
480
+ logger.ready("\u251C\u2500\u2500 " + gray("Utils"));
312
481
  addPlugin({
313
482
  name: "auth",
314
483
  src: resolve("./runtime/auth/plugins/auth"),
@@ -386,10 +555,11 @@ const module$1 = defineNuxtModule({
386
555
  }
387
556
  try {
388
557
  console.log(banner);
389
- console.log(yellow(bold(`\u279C v${version}
558
+ console.log(yellow(bold(`\u279C v${pkg.version}
390
559
  `)));
391
560
  logger.start(cyan(bold("Registro del m\xF3dulo iniciado...")));
392
561
  const startTime = Date.now();
562
+ injectComponentsConfig();
393
563
  setupAutoImports();
394
564
  setupAuth();
395
565
  setupComponents();
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Middleware encargado de sincronizar los datos de la sesión del usuario.
2
+ * Middleware encargado de sincronizar los datos de la sesion del usuario.
3
3
  *
4
- * En el flujo de inicio de sesión mediante SSO, en el cuál el usuario ingresa y hay una sesión activa en las cookies,
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 sesión estaran sincronizados en Pinia.
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, useRuntimeConfig } from "#app";
1
+ import { defineNuxtRouteMiddleware, useNuxtApp } from "#app";
2
2
  import { useAuthStore } from "../stores/auth.js";
3
- import { useAuthorization } from "../composables/useAuthorization.js";
4
- export default defineNuxtRouteMiddleware(async () => {
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
- const runtimeConfig = useRuntimeConfig();
14
- const authConfig = runtimeConfig.public.unaxt.auth;
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 resources = await authorization.getResources(token);
24
- let email = "";
25
- const getUserInfo = () => {
26
- if (authResponse?.email) {
27
- const rawEmail = Array.isArray(authResponse?.email) ? authResponse?.email[0] : authResponse?.email;
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
- ...getUserInfo(),
39
- cedula: authResponse?.displayName,
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 var __VLS_1: {};
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
- <slot />
2
+ <LoadingSessionScreen />
3
3
  </template>
4
4
 
5
5
  <script setup>
6
- import { useRuntimeConfig } from "#app";
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 var __VLS_1: {};
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 var __VLS_1: {};
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
- <slot />
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
- const runtimeConfig = useRuntimeConfig();
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 var __VLS_1: {};
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 { defineNuxtPlugin, useRuntimeConfig, useNuxtApp } from "#app";
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 { useAuthorization } from "../composables/useAuthorization.js";
8
- export default defineNuxtPlugin(() => {
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,47 @@ 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
- if (authConfig.sso?.automaticSignIn) {
26
- auth?.signIn();
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 authorization = useAuthorization();
32
- let email = "";
33
- const getUserInfo = () => {
34
- if (response?.email) {
35
- const rawEmail = Array.isArray(response?.email) ? response?.email[0] : response?.email;
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
- ...getUserInfo(),
47
- cedula: response.displayName,
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(getPostLoginRedirect());
71
+ } catch (error) {
72
+ console.error("Error procesando callback SSO:", error);
73
+ }
74
+ });
75
+ }
59
76
  return {
60
77
  provide: {
61
78
  /**
@@ -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: string;
7
+ cedula?: string | undefined;
8
8
  email: string;
9
9
  fullName?: string | undefined;
10
10
  name?: string | undefined;
11
- lastName?: string | undefined;
11
+ lastName1?: string | undefined;
12
+ lastName2?: string | undefined;
12
13
  } | null, IAuthenticatedUser | {
13
- cedula: string;
14
+ cedula?: string | undefined;
14
15
  email: string;
15
16
  fullName?: string | undefined;
16
17
  name?: string | undefined;
17
- lastName?: string | undefined;
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: string;
51
+ cedula?: string | undefined;
49
52
  email: string;
50
53
  fullName?: string | undefined;
51
54
  name?: string | undefined;
52
- lastName?: string | undefined;
55
+ lastName1?: string | undefined;
56
+ lastName2?: string | undefined;
53
57
  } | null, IAuthenticatedUser | {
54
- cedula: string;
58
+ cedula?: string | undefined;
55
59
  email: string;
56
60
  fullName?: string | undefined;
57
61
  name?: string | undefined;
58
- lastName?: string | undefined;
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: string;
95
+ cedula?: string | undefined;
90
96
  email: string;
91
97
  fullName?: string | undefined;
92
98
  name?: string | undefined;
93
- lastName?: string | undefined;
99
+ lastName1?: string | undefined;
100
+ lastName2?: string | undefined;
94
101
  } | null, IAuthenticatedUser | {
95
- cedula: string;
102
+ cedula?: string | undefined;
96
103
  email: string;
97
104
  fullName?: string | undefined;
98
105
  name?: string | undefined;
99
- lastName?: string | undefined;
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 = data;
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.find(
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,3 @@
1
+ export declare function isAuthCallback(path: string): boolean;
2
+ export declare function isSignInCallback(path: string): boolean;
3
+ export declare function isSignOutCallback(path: string): boolean;
@@ -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,4 @@
1
+ export function parseCedulaFromSub(sub) {
2
+ if (!sub) return void 0;
3
+ return /^\d{9}$/.test(sub) ? sub : void 0;
4
+ }
@@ -0,0 +1,6 @@
1
+ import type { IAuthenticatedUser } from '../../types/index.js';
2
+ export declare function parseUserInfo(claims: {
3
+ email?: string | string[];
4
+ givenName?: string;
5
+ familyName?: string;
6
+ }): Omit<IAuthenticatedUser, 'cedula'>;
@@ -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,3 @@
1
+ export declare function isSafePath(path: string): boolean;
2
+ export declare function savePostLoginRedirect(path: string): void;
3
+ export declare function getPostLoginRedirect(): string | undefined;
@@ -0,0 +1,36 @@
1
+ import { useRuntimeConfig } from "#app";
2
+ import { isAuthCallback } from "./isAuthCallback.js";
3
+ const STORAGE_KEY = "postLoginRedirect";
4
+ export function isSafePath(path) {
5
+ return Boolean(path?.startsWith("/") && !path.startsWith("//"));
6
+ }
7
+ export function savePostLoginRedirect(path) {
8
+ if (!import.meta.client) {
9
+ return;
10
+ }
11
+ const runtimeConfig = useRuntimeConfig();
12
+ const postLoginRedirect = runtimeConfig.public.unaxt.auth.sso?.postLoginRedirect;
13
+ if (postLoginRedirect !== true) {
14
+ return;
15
+ }
16
+ if (!isSafePath(path) || isAuthCallback(path)) {
17
+ return;
18
+ }
19
+ sessionStorage.setItem(STORAGE_KEY, path);
20
+ }
21
+ export function getPostLoginRedirect() {
22
+ if (!import.meta.client) {
23
+ return;
24
+ }
25
+ const runtimeConfig = useRuntimeConfig();
26
+ const postLoginRedirect = runtimeConfig.public.unaxt.auth.sso?.postLoginRedirect;
27
+ if (typeof postLoginRedirect === "string") {
28
+ return postLoginRedirect;
29
+ }
30
+ const stored = sessionStorage.getItem(STORAGE_KEY);
31
+ sessionStorage.removeItem(STORAGE_KEY);
32
+ if (postLoginRedirect === true && stored && isSafePath(stored)) {
33
+ return stored;
34
+ }
35
+ return "/";
36
+ }
@@ -0,0 +1,3 @@
1
+ export declare function useFonts(): {
2
+ fontsReady: import("vue").Ref<boolean, boolean>;
3
+ };
@@ -0,0 +1,10 @@
1
+ import { onMounted, ref } from "#imports";
2
+ export function useFonts() {
3
+ const fontsReady = ref(false);
4
+ onMounted(() => {
5
+ document.fonts.ready.then(() => {
6
+ fontsReady.value = true;
7
+ });
8
+ });
9
+ return { fontsReady };
10
+ }
@@ -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
  };
@@ -21,7 +21,7 @@ interface ISSOConfig {
21
21
  /**
22
22
  * URL de redirección final después de completar el login SSO.
23
23
  */
24
- postLoginRedirectUrl: string;
24
+ postLoginRedirect: boolean | string;
25
25
  /**
26
26
  * ID del cliente para la autenticación (OAuth Client Key del Service Provider).
27
27
  */
@@ -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} lastName - Primer apellido del usuario
225
- * @property {string} photoUrl - Url de la foto del usuario
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: string;
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
- lastName?: string;
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: IResource[];
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.36",
3
+ "version": "3.0.38",
4
4
  "description": "Módulo Nuxt para desarrollo CGI",
5
5
  "repository": {
6
6
  "type": "git",