@mundogamernetwork/shared-ui 1.16.3 → 1.16.5
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/composables/useLogout.ts +38 -23
- package/nuxt.config.ts +12 -20
- package/package.json +1 -1
- package/plugins/echo.client.ts +26 -3
package/composables/useLogout.ts
CHANGED
|
@@ -1,41 +1,56 @@
|
|
|
1
|
-
import { default as AuthService } from "../services/authService";
|
|
2
|
-
|
|
3
1
|
export function useLogout() {
|
|
4
2
|
const authStore = useAuthStore();
|
|
5
3
|
const runtimeConfig = useRuntimeConfig();
|
|
6
4
|
const accountsBaseUrl = runtimeConfig.public.mgSharedUi?.accountsBaseUrl || runtimeConfig.public.accountsBaseUrl;
|
|
5
|
+
// Same host login uses (see MgLoginRegisterMenu's goLogin) — the platform's
|
|
6
|
+
// own API, not accountsBaseUrl. That's where OAuthLogoutController's real
|
|
7
|
+
// /logout route lives.
|
|
8
|
+
const apiBase = (
|
|
9
|
+
(runtimeConfig.public.mgSharedUi?.apiBaseURL as string) ||
|
|
10
|
+
(runtimeConfig.public.apiBaseURL as string) ||
|
|
11
|
+
(import.meta.env.VITE_API_BASE_URL as string) ||
|
|
12
|
+
""
|
|
13
|
+
).replace(/\/api\/v1\/?$/, "");
|
|
7
14
|
|
|
8
15
|
const performLogout = async (redirectTo?: string) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} catch {
|
|
12
|
-
// continue with cleanup even if server call fails
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Clear auth state
|
|
16
|
+
// Clear client-visible auth state immediately so the UI doesn't sit in
|
|
17
|
+
// a signed-in state while the real server-side logout below completes.
|
|
16
18
|
authStore.clearUser();
|
|
17
19
|
authStore.$reset();
|
|
18
|
-
|
|
19
|
-
// Clear cookies client-side
|
|
20
|
-
if (typeof document !== "undefined") {
|
|
21
|
-
const cookiesToClear = ["oauth_token", "browser_id", "mundo_gamer_network_session", "XSRF-TOKEN"];
|
|
22
|
-
cookiesToClear.forEach((name) => {
|
|
23
|
-
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
|
24
|
-
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${window.location.hostname};`;
|
|
25
|
-
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.${window.location.hostname};`;
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Clear localStorage auth data
|
|
30
20
|
if (typeof localStorage !== "undefined") {
|
|
31
21
|
["accessToken", "userData", "userAbility"].forEach((key) => {
|
|
32
22
|
localStorage.removeItem(key);
|
|
33
23
|
});
|
|
34
24
|
}
|
|
35
25
|
|
|
36
|
-
// Redirect
|
|
37
26
|
const target = redirectTo || `${accountsBaseUrl}/login`;
|
|
38
|
-
|
|
27
|
+
|
|
28
|
+
if (typeof document === "undefined" || !apiBase) {
|
|
29
|
+
if (typeof window !== "undefined") window.location.href = target;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// The real session is an httpOnly `oauth_token` cookie set by the
|
|
34
|
+
// platform's own API — document.cookie can never read or clear an
|
|
35
|
+
// httpOnly cookie, on any domain. Only a real server response can clear
|
|
36
|
+
// it (a Set-Cookie header the browser actually honors), which means a
|
|
37
|
+
// genuine top-level POST navigation to that API's own /logout route,
|
|
38
|
+
// not an axios/fetch call whose response body a script merely inspects.
|
|
39
|
+
// POST is required (the route isn't registered for GET) and CSRF is
|
|
40
|
+
// already exempted server-side for exactly this cross-origin case.
|
|
41
|
+
const form = document.createElement("form");
|
|
42
|
+
form.method = "POST";
|
|
43
|
+
form.action = `${apiBase}/logout`;
|
|
44
|
+
form.style.display = "none";
|
|
45
|
+
|
|
46
|
+
const redirectField = document.createElement("input");
|
|
47
|
+
redirectField.type = "hidden";
|
|
48
|
+
redirectField.name = "redirect_to";
|
|
49
|
+
redirectField.value = target;
|
|
50
|
+
form.appendChild(redirectField);
|
|
51
|
+
|
|
52
|
+
document.body.appendChild(form);
|
|
53
|
+
form.submit();
|
|
39
54
|
};
|
|
40
55
|
|
|
41
56
|
return { performLogout };
|
package/nuxt.config.ts
CHANGED
|
@@ -72,28 +72,20 @@ export default defineNuxtConfig({
|
|
|
72
72
|
build: {
|
|
73
73
|
transpile: ['@vue-leaflet/vue-leaflet'],
|
|
74
74
|
},
|
|
75
|
-
// pusher-js's browser build is a webpack-bundled UMD file
|
|
76
|
-
// = factory()
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
// evaluation time — before the plugin's own pusherKey guard ever runs, so
|
|
87
|
-
// it takes the whole plugin down, and on hosts where that happens during
|
|
88
|
-
// app bootstrap it silently breaks ALL click handling on the page (every
|
|
89
|
-
// header dropdown, the sidebar toggle, everything — not just this
|
|
90
|
-
// plugin's own WebSocket setup). needsInterop forces Vite to always
|
|
91
|
-
// treat it as CJS needing the default-export wrapper, which is the fix
|
|
92
|
-
// Vite ships for exactly this class of mismatch.
|
|
75
|
+
// pusher-js's browser build is a webpack-bundled UMD file
|
|
76
|
+
// (module.exports = factory(), no real ESM default export). needsInterop
|
|
77
|
+
// here was an earlier attempt at fixing plugins/echo.client.ts's import of
|
|
78
|
+
// it — proven unreliable across consuming hosts (still crashed on a real,
|
|
79
|
+
// non-symlinked install even with this exact config). The actual fix now
|
|
80
|
+
// lives in echo.client.ts itself: it no longer imports pusher-js as a
|
|
81
|
+
// module at all, instead pulling its source in as a plain string
|
|
82
|
+
// (`?raw`) and executing it directly, letting the UMD wrapper's own
|
|
83
|
+
// browser-global fallback (`root["Pusher"] = factory()`) self-register
|
|
84
|
+
// window.Pusher. laravel-echo is still a real, safely-interoppable
|
|
85
|
+
// dynamic import, so it stays here.
|
|
93
86
|
vite: {
|
|
94
87
|
optimizeDeps: {
|
|
95
|
-
include: ["
|
|
96
|
-
needsInterop: ["pusher-js"],
|
|
88
|
+
include: ["laravel-echo"],
|
|
97
89
|
},
|
|
98
90
|
},
|
|
99
91
|
components: [
|
package/package.json
CHANGED
package/plugins/echo.client.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import Echo from "laravel-echo";
|
|
2
|
-
import Pusher from "pusher-js";
|
|
3
1
|
import axios from "axios";
|
|
2
|
+
// Raw source, not a real import: pusher-js ships only a webpack-UMD bundle
|
|
3
|
+
// (module.exports = factory(), no ESM default export), and Vite's CJS
|
|
4
|
+
// interop for it doesn't reliably kick in across every consuming host —
|
|
5
|
+
// including as a dynamic import, which still surfaced as an empty/unusable
|
|
6
|
+
// module namespace object in testing (`Pusher is not a constructor`). The
|
|
7
|
+
// UMD wrapper itself already knows how to self-register on `window` when no
|
|
8
|
+
// module system is present (`else root["Pusher"] = factory()`, with `root`
|
|
9
|
+
// passed in as `window` directly) — so instead of asking Vite/ESM to
|
|
10
|
+
// understand this file at all, its source is pulled in as a plain string
|
|
11
|
+
// and executed directly, letting that fallback branch do the work.
|
|
12
|
+
import pusherSrc from "pusher-js/dist/web/pusher.js?raw";
|
|
4
13
|
|
|
5
14
|
declare global {
|
|
6
15
|
interface Window {
|
|
@@ -13,7 +22,7 @@ export default defineNuxtPlugin({
|
|
|
13
22
|
name: "shared-ui-echo",
|
|
14
23
|
enforce: "post",
|
|
15
24
|
parallel: true,
|
|
16
|
-
setup(nuxtApp) {
|
|
25
|
+
async setup(nuxtApp) {
|
|
17
26
|
// Skip if already provided by the extending frontend's own Echo plugin
|
|
18
27
|
if (nuxtApp.$echo || window.Echo) {
|
|
19
28
|
return;
|
|
@@ -28,6 +37,20 @@ export default defineNuxtPlugin({
|
|
|
28
37
|
return;
|
|
29
38
|
}
|
|
30
39
|
|
|
40
|
+
// laravel-echo is a real ESM/CJS-interoppable package; a plain dynamic
|
|
41
|
+
// import is enough (and, unlike the static import this plugin used to
|
|
42
|
+
// have, confines any future interop failure to this plugin instead of
|
|
43
|
+
// crashing the whole client bundle before Vue mounts).
|
|
44
|
+
const EchoModule = await import("laravel-echo");
|
|
45
|
+
const Echo = (EchoModule as any).default ?? EchoModule;
|
|
46
|
+
|
|
47
|
+
// See the pusherSrc import comment above — self-registers window.Pusher.
|
|
48
|
+
if (!window.Pusher) {
|
|
49
|
+
// eslint-disable-next-line no-new-func
|
|
50
|
+
new Function(pusherSrc)();
|
|
51
|
+
}
|
|
52
|
+
const Pusher = window.Pusher;
|
|
53
|
+
|
|
31
54
|
const headers: Record<string, string> = {
|
|
32
55
|
Accept: "application/json",
|
|
33
56
|
};
|