Update Dev branch #11
@@ -212,7 +212,7 @@ Legacy `chats` migration is handled during startup. New code only reads the sess
|
|||||||
|
|
||||||
## Frontend Structure
|
## Frontend Structure
|
||||||
|
|
||||||
The browser UI remains framework-free and uses native ES modules. Shared behavior lives under `public/app/`:
|
The browser UI remains framework-free and uses native ES modules. Shared behavior lives under `public/js/`:
|
||||||
|
|
||||||
- `api.js`: JSON and streaming request helpers
|
- `api.js`: JSON and streaming request helpers
|
||||||
- `constants.js`: theme and onboarding metadata
|
- `constants.js`: theme and onboarding metadata
|
||||||
@@ -222,7 +222,7 @@ The browser UI remains framework-free and uses native ES modules. Shared behavio
|
|||||||
- `statusNotice.js`: shared status and error presentation
|
- `statusNotice.js`: shared status and error presentation
|
||||||
- `dom.js`: cached chat-page DOM references
|
- `dom.js`: cached chat-page DOM references
|
||||||
|
|
||||||
`public/style.css` is a self-contained design system rebuilt around semantic tokens, shared components, and deliberate responsive breakpoints. It contains the six visual identities and their dark variants without legacy imports or precedence layers. `public/legal.css` contains only the legal-page layout.
|
`public/css/style.css` is a self-contained design system rebuilt around semantic tokens, shared components, and deliberate responsive breakpoints. It contains the six visual identities and their dark variants without legacy imports or precedence layers. `public/css/legal.css` contains only the legal-page layout.
|
||||||
|
|
||||||
Pure chat message, retry, memory, summary, and persona-state formatting lives in `src/services/chatMessageHelpers.js`; `chatService.js` remains responsible for orchestration and persistence.
|
Pure chat message, retry, memory, summary, and persona-state formatting lives in `src/services/chatMessageHelpers.js`; `chatService.js` remains responsible for orchestration and persistence.
|
||||||
|
|
||||||
@@ -280,6 +280,6 @@ Run `node --test --test-isolation=none` and `npm run lint` to check the feature
|
|||||||
|
|
||||||
Protected pages redirect to sign-in with a local return destination. Public discovery only returns published persona summaries; using a persona requires an account.
|
Protected pages redirect to sign-in with a local return destination. Public discovery only returns published persona summaries; using a persona requires an account.
|
||||||
|
|
||||||
All page routes render the same navigation from `src/pageLayout.js` into the `<!-- site-header -->` placeholder. `public/shell.css` owns the shared header, page spacing, and mobile navigation; `public/app/workspaceNavigation.js` owns sign-out. Page-specific headers contain only local titles and actions. The chat sidebar is reserved for conversation history. Public and home content share `public/pages.css` and `public/pages.js`. Page routes run before static assets and authenticated API routers; rendered pages use private, non-cacheable responses.
|
All page routes render the same navigation from `src/pageLayout.js` into the `<!-- site-header -->` placeholder. `public/css/shell.css` owns the shared header, page spacing, and mobile navigation; `public/js/workspaceNavigation.js` owns sign-out. Page-specific headers contain only local titles and actions. The chat sidebar is reserved for conversation history. Public and home content share `public/css/pages.css` and `public/js/pages.js`. Page routes run before static assets and authenticated API routers; rendered pages use private, non-cacheable responses.
|
||||||
|
|
||||||
For environments that block child-process test workers, run `node --test --test-isolation=none`.
|
For environments that block child-process test workers, run `node --test --test-isolation=none`.
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Sign in · Elsewhere</title>
|
<title>Sign in · Elsewhere</title>
|
||||||
<link rel="icon" href="img/favicon.svg">
|
<link rel="icon" href="/img/favicon.svg">
|
||||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls">
|
<script src="/js/theme-bootstrap.js?v=20260909-account-controls">
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls">
|
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls">
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
<a href="/privacy.html">Privacy</a>
|
<a href="/privacy.html">Privacy</a>
|
||||||
<a href="/tos.html">Terms</a>
|
<a href="/tos.html">Terms</a>
|
||||||
</footer>
|
</footer>
|
||||||
<script type="module" src="js/pages.js?v=20260909-account-controls">
|
<script type="module" src="/js/pages.js?v=20260909-account-controls">
|
||||||
</script>
|
</script>
|
||||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="img/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg">
|
||||||
<title>Elsewhere</title>
|
<title>Elsewhere</title>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
|||||||
+3
-3
@@ -8,9 +8,9 @@
|
|||||||
<link rel="icon" href="/img/favicon.svg">
|
<link rel="icon" href="/img/favicon.svg">
|
||||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls">
|
<script src="/js/theme-bootstrap.js?v=20260909-account-controls">
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="/style.css?v=20260909-account-controls">
|
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls">
|
||||||
<link rel="stylesheet" href="/pages.css?v=20260909-account-controls">
|
<link rel="stylesheet" href="/css/pages.css?v=20260909-account-controls">
|
||||||
<link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
|
|||||||
@@ -1087,3 +1087,31 @@ test("frontend scripts and styles revalidate across deployments", async () => {
|
|||||||
}
|
}
|
||||||
} finally { await server.close(); }
|
} finally { await server.close(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("every served page references existing local assets", async () => {
|
||||||
|
const server = await startTestServer();
|
||||||
|
try {
|
||||||
|
const assetPattern = /(?:src|href)="([^"#]+\.(?:css|js|svg)(?:\?[^"#]*)?)"/g;
|
||||||
|
const assertPageAssets = async (route, headers = {}) => {
|
||||||
|
const response = await fetch(server.baseUrl + route, {headers});
|
||||||
|
assert.equal(response.status, 200, `${route} must render`);
|
||||||
|
const html = await response.text();
|
||||||
|
for (const [, reference] of html.matchAll(assetPattern)) {
|
||||||
|
if (/^https?:\/\//.test(reference)) continue;
|
||||||
|
const assetUrl = new URL(reference, server.baseUrl + route);
|
||||||
|
const assetResponse = await fetch(assetUrl, {headers});
|
||||||
|
assert.equal(assetResponse.status, 200, `${route} references missing asset ${assetUrl.pathname}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const route of ["/", "/login", "/register", "/market", "/privacy.html", "/tos.html"]) {
|
||||||
|
await assertPageAssets(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
const jar = new CookieJar();
|
||||||
|
await request(server.baseUrl, "/register", {method: "POST", body: {username: "assetchecker", password: "password123"}, jar});
|
||||||
|
for (const route of ["/app", "/app/chats/new", "/app/personas", "/app/settings", "/market"]) {
|
||||||
|
await assertPageAssets(route, jar.headers());
|
||||||
|
}
|
||||||
|
} finally { await server.close(); }
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user