fix(ui): redirect app root to lobby/login; evict stale root service worker
Tests · UI / test (push) Has been cancelled
Build · Site / build (push) Successful in 8s
Tests · Integration / integration (pull_request) Successful in 1m42s
Build · Site / build (pull_request) Successful in 6s
Tests · UI / test (pull_request) Successful in 2m23s
Tests · Go / test (pull_request) Successful in 1m56s
Tests · UI / test (push) Has been cancelled
Build · Site / build (push) Successful in 8s
Tests · Integration / integration (pull_request) Successful in 1m42s
Build · Site / build (pull_request) Successful in 6s
Tests · UI / test (pull_request) Successful in 2m23s
Tests · Go / test (pull_request) Successful in 1m56s
- The app root ("/", i.e. /game/) rendered a dev "workspace skeleton"
stub, and the layout guard only redirected anonymous users off it, so
an authenticated visitor stayed on the stub. Redirect "/" to /lobby
(authenticated) and /login (anonymous), and replace the stub with a
minimal loading placeholder. Drop the obsolete landing-stub unit test
(root redirect is covered by the auth-flow e2e).
- Ship a tombstone /service-worker.js on the project site so any old
root-scoped PWA worker (from when the game lived at the origin root)
unregisters itself instead of serving a stale cached page at the
site origin. The game now registers its worker only under /game/.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
// Tombstone service worker for the site origin's root scope (`/`).
|
||||||
|
//
|
||||||
|
// The game UI used to be served at this origin's root with a
|
||||||
|
// root-scoped service worker. It now lives under `/game/` (its own
|
||||||
|
// scoped worker), and the project site served at `/` ships no service
|
||||||
|
// worker of its own. This file exists only so any lingering old
|
||||||
|
// root-scoped worker, on its next update check, replaces itself with
|
||||||
|
// this one — which unregisters itself and reloads its controlled pages
|
||||||
|
// so they fall through to the live network (the site) instead of a
|
||||||
|
// stale cache. New visitors never register it; nothing here calls
|
||||||
|
// `register`.
|
||||||
|
self.addEventListener("install", () => self.skipWaiting());
|
||||||
|
|
||||||
|
self.addEventListener("activate", (event) => {
|
||||||
|
event.waitUntil(
|
||||||
|
(async () => {
|
||||||
|
await self.registration.unregister();
|
||||||
|
const clients = await self.clients.matchAll({ type: "window" });
|
||||||
|
for (const client of clients) {
|
||||||
|
client.navigate(client.url);
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -90,7 +90,10 @@
|
|||||||
}
|
}
|
||||||
if (session.status === "anonymous" && pathname !== "/login") {
|
if (session.status === "anonymous" && pathname !== "/login") {
|
||||||
void goto(withBase("/login"), { replaceState: true });
|
void goto(withBase("/login"), { replaceState: true });
|
||||||
} else if (session.status === "authenticated" && pathname === "/login") {
|
} else if (
|
||||||
|
session.status === "authenticated" &&
|
||||||
|
(pathname === "/login" || pathname === "/")
|
||||||
|
) {
|
||||||
void goto(withBase("/lobby"), { replaceState: true });
|
void goto(withBase("/lobby"), { replaceState: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { APP_VERSION } from "$lib/version";
|
// The app root renders no content of its own. The root layout's auth
|
||||||
|
// guard redirects "/" to /lobby (authenticated) or /login
|
||||||
|
// (anonymous); this placeholder only shows for the brief moment
|
||||||
|
// before that client-side redirect resolves.
|
||||||
|
import { i18n } from "$lib/i18n/index.svelte";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main class="status">
|
||||||
<h1>Galaxy</h1>
|
<p>{i18n.t("common.loading")}</p>
|
||||||
<p>Cross-platform UI client — workspace skeleton.</p>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer data-testid="app-version">version {APP_VERSION}</footer>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
main {
|
.status {
|
||||||
padding: 2rem;
|
padding: var(--space-6);
|
||||||
font-family: system-ui, sans-serif;
|
font-family: var(--font-sans);
|
||||||
}
|
|
||||||
footer {
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
opacity: 0.6;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { render } from "@testing-library/svelte";
|
|
||||||
import { describe, expect, it } from "vitest";
|
|
||||||
import Page from "../src/routes/+page.svelte";
|
|
||||||
|
|
||||||
describe("landing page", () => {
|
|
||||||
it("renders a non-empty version string in the footer", () => {
|
|
||||||
const { getByTestId } = render(Page);
|
|
||||||
const footer = getByTestId("app-version");
|
|
||||||
expect(footer).toBeInTheDocument();
|
|
||||||
expect(footer.textContent?.trim()).not.toBe("");
|
|
||||||
expect(footer.textContent).toMatch(/version\s+\S+/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user