@lenne.tech/nuxt-extensions 1.11.1 → 1.11.2
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.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import { LtExtensionsModuleOptions } from '../dist/runtime/types/index.js';
|
|
|
3
3
|
export * from '../dist/runtime/types/index.js';
|
|
4
4
|
|
|
5
5
|
declare const name = "@lenne.tech/nuxt-extensions";
|
|
6
|
-
declare const version = "1.11.
|
|
6
|
+
declare const version = "1.11.2";
|
|
7
7
|
declare const configKey = "ltExtensions";
|
|
8
8
|
declare const DEFAULT_LT_AUTH_STATE_COOKIE = "lt-auth-state";
|
|
9
9
|
declare const DEFAULT_LT_JWT_TOKEN_COOKIE = "lt-jwt-token";
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineNuxtModule, createResolver, tryResolveModule, addImports, addComponent, addPlugin, addRouteMiddleware } from '@nuxt/kit';
|
|
2
2
|
|
|
3
3
|
const name = "@lenne.tech/nuxt-extensions";
|
|
4
|
-
const version = "1.11.
|
|
4
|
+
const version = "1.11.2";
|
|
5
5
|
const configKey = "ltExtensions";
|
|
6
6
|
const DEFAULT_LT_AUTH_STATE_COOKIE = "lt-auth-state";
|
|
7
7
|
const DEFAULT_LT_JWT_TOKEN_COOKIE = "lt-jwt-token";
|
|
@@ -110,7 +110,7 @@ export function useLtAuth() {
|
|
|
110
110
|
if (!isJwtMode.value || !jwtToken.value) return false;
|
|
111
111
|
return switchToJwtMode();
|
|
112
112
|
}
|
|
113
|
-
const PATHS_REQUIRING_COOKIES = ["/passkey/", "/two-factor/", "/2fa/"];
|
|
113
|
+
const PATHS_REQUIRING_COOKIES = ["/passkey/", "/two-factor/", "/2fa/", "/get-session"];
|
|
114
114
|
function urlRequiresCookies(url) {
|
|
115
115
|
return PATHS_REQUIRING_COOKIES.some((path) => url.includes(path));
|
|
116
116
|
}
|
|
@@ -39,7 +39,8 @@ export function getOrCreateLtAuthClient(config) {
|
|
|
39
39
|
}
|
|
40
40
|
export function createLtAuthClient(config = {}) {
|
|
41
41
|
const useProxy = isLocalDevApiProxy();
|
|
42
|
-
const
|
|
42
|
+
const envApiUrl = typeof import.meta.env?.VITE_API_URL === "string" ? import.meta.env.VITE_API_URL : void 0;
|
|
43
|
+
const defaultBaseURL = useProxy ? "" : envApiUrl || process.env.API_URL || "";
|
|
43
44
|
const defaultBasePath = useProxy ? "/api/iam" : "/iam";
|
|
44
45
|
const {
|
|
45
46
|
baseURL = defaultBaseURL,
|
|
@@ -29,7 +29,17 @@ export default (nuxtApp) => {
|
|
|
29
29
|
"/forgot-password",
|
|
30
30
|
"/reset-password",
|
|
31
31
|
"/verify-email",
|
|
32
|
-
|
|
32
|
+
// Better Auth's session routes, spelled out. A generic '/session' entry
|
|
33
|
+
// used to stand here and never matched anything: the routes are
|
|
34
|
+
// `get-session`, `list-sessions`, `revoke-session`, … — in every one of
|
|
35
|
+
// them the character before `session` is `-`, not `/`, so `url.includes`
|
|
36
|
+
// returned false. `/get-session` matters most: it is the URL the session
|
|
37
|
+
// probe below calls, and exempting it is what keeps a 401 from the probe
|
|
38
|
+
// out of this handler.
|
|
39
|
+
"/get-session",
|
|
40
|
+
"/list-sessions",
|
|
41
|
+
"/revoke-session",
|
|
42
|
+
"/revoke-other-sessions",
|
|
33
43
|
"/token",
|
|
34
44
|
// Passkey endpoints - handled by authFetch with JWT fallback
|
|
35
45
|
"/passkey/",
|
|
@@ -43,19 +53,38 @@ export default (nuxtApp) => {
|
|
|
43
53
|
];
|
|
44
54
|
return authEndpoints.some((endpoint) => url.includes(endpoint));
|
|
45
55
|
}
|
|
56
|
+
const ALIVE_VERDICT_TTL_MS = 1e3;
|
|
57
|
+
let aliveVerdictValidUntil = 0;
|
|
46
58
|
async function isSessionStillAlive() {
|
|
47
59
|
try {
|
|
48
|
-
const { fetchWithAuth } = getAuth();
|
|
60
|
+
const { fetchWithAuth, isJwtMode, switchToJwtMode } = getAuth();
|
|
49
61
|
const response = await fetchWithAuth(`${getLtApiBase()}/get-session`, { method: "GET" });
|
|
50
|
-
if (
|
|
62
|
+
if (response.status === 401 || response.status === 403) {
|
|
51
63
|
return false;
|
|
52
64
|
}
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
53
68
|
const data = await response.json().catch(() => null);
|
|
54
|
-
|
|
69
|
+
const alive = Boolean(data && (data.user || data.session));
|
|
70
|
+
if (alive && isJwtMode.value) {
|
|
71
|
+
await switchToJwtMode().catch(() => false);
|
|
72
|
+
}
|
|
73
|
+
return alive;
|
|
55
74
|
} catch {
|
|
56
75
|
return null;
|
|
57
76
|
}
|
|
58
77
|
}
|
|
78
|
+
async function probeSessionAlive() {
|
|
79
|
+
if (Date.now() < aliveVerdictValidUntil) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
const verdict = await isSessionStillAlive();
|
|
83
|
+
if (verdict === true) {
|
|
84
|
+
aliveVerdictValidUntil = Date.now() + ALIVE_VERDICT_TTL_MS;
|
|
85
|
+
}
|
|
86
|
+
return verdict;
|
|
87
|
+
}
|
|
59
88
|
async function handleUnauthorized(requestUrl) {
|
|
60
89
|
if (isHandling401) {
|
|
61
90
|
return;
|
|
@@ -66,28 +95,35 @@ export default (nuxtApp) => {
|
|
|
66
95
|
if (isPublicAuthRoute()) {
|
|
67
96
|
return;
|
|
68
97
|
}
|
|
98
|
+
const { clearUser, isAuthenticated } = getAuth();
|
|
99
|
+
if (!isAuthenticated.value) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
69
102
|
isHandling401 = true;
|
|
103
|
+
let loggingOut = false;
|
|
70
104
|
try {
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
console.debug("[LtAuth Interceptor] Session expired, logging out...");
|
|
81
|
-
clearUser();
|
|
82
|
-
const router = nuxtApp.$router;
|
|
83
|
-
const currentPath = router?.currentRoute?.value?.fullPath;
|
|
84
|
-
const redirectQuery = currentPath && currentPath !== loginPath ? `?redirect=${encodeURIComponent(currentPath)}` : "";
|
|
85
|
-
window.location.href = loginPath + redirectQuery;
|
|
105
|
+
const sessionAlive = await probeSessionAlive();
|
|
106
|
+
if (sessionAlive !== false) {
|
|
107
|
+
console.debug(
|
|
108
|
+
sessionAlive ? `[LtAuth Interceptor] 401 from ${requestUrl ?? "unknown URL"} but session is still valid \u2014 treating it as a permission error, not logging out` : "[LtAuth Interceptor] 401 received but session state could not be verified \u2014 not logging out"
|
|
109
|
+
);
|
|
110
|
+
return;
|
|
86
111
|
}
|
|
112
|
+
console.debug("[LtAuth Interceptor] Session expired, logging out...");
|
|
113
|
+
loggingOut = true;
|
|
114
|
+
clearUser();
|
|
115
|
+
const router = nuxtApp.$router;
|
|
116
|
+
const currentPath = router?.currentRoute?.value?.fullPath;
|
|
117
|
+
const redirectQuery = currentPath && currentPath !== loginPath ? `?redirect=${encodeURIComponent(currentPath)}` : "";
|
|
118
|
+
window.location.href = loginPath + redirectQuery;
|
|
87
119
|
} finally {
|
|
88
|
-
|
|
120
|
+
if (loggingOut) {
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
isHandling401 = false;
|
|
123
|
+
}, 1e3);
|
|
124
|
+
} else {
|
|
89
125
|
isHandling401 = false;
|
|
90
|
-
}
|
|
126
|
+
}
|
|
91
127
|
}
|
|
92
128
|
}
|
|
93
129
|
const wrapMarker = "__ltAuthFetchWrapped";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nuxt-extensions",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.2",
|
|
4
4
|
"description": "Reusable Nuxt 4 composables, components, and Better-Auth integration for lenne.tech projects",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -101,13 +101,13 @@
|
|
|
101
101
|
"devDependencies": {
|
|
102
102
|
"@better-auth/passkey": "1.6.23",
|
|
103
103
|
"@nuxt/module-builder": "1.0.2",
|
|
104
|
-
"@nuxt/schema": "4.
|
|
104
|
+
"@nuxt/schema": "4.5.2",
|
|
105
105
|
"@playwright/test": "1.61.1",
|
|
106
106
|
"@types/node": "26.1.1",
|
|
107
107
|
"@vitest/coverage-v8": "4.1.10",
|
|
108
108
|
"better-auth": "1.6.23",
|
|
109
109
|
"happy-dom": "20.10.6",
|
|
110
|
-
"nuxt": "4.
|
|
110
|
+
"nuxt": "4.5.2",
|
|
111
111
|
"oxfmt": "0.59.0",
|
|
112
112
|
"oxlint": "1.74.0",
|
|
113
113
|
"tus-js-client": "4.3.1",
|