diff --git a/public/js/market.js b/public/js/market.js index 23b26d1..d40a808 100644 --- a/public/js/market.js +++ b/public/js/market.js @@ -1,7 +1,7 @@ -import { get, post, put } from "./js/api.js?v=20260909-account-controls"; -import { initializeAppearance } from "./js/themeController.js?v=20260909-account-controls"; -import { clearStatus, setStatus } from "./js/statusNotice.js?v=20260909-account-controls"; -import { populatePersonaForm, readPersonaForm } from "./js/personaForm.js?v=20260909-account-controls"; +import { get, post, put } from "./api.js?v=20260909-account-controls"; +import { initializeAppearance } from "./themeController.js?v=20260909-account-controls"; +import { clearStatus, setStatus } from "./statusNotice.js?v=20260909-account-controls"; +import { populatePersonaForm, readPersonaForm } from "./personaForm.js?v=20260909-account-controls"; const $ = (id) => document.getElementById(id); const marketPersonaList = $("marketPersonaList"); diff --git a/public/js/script.js b/public/js/script.js index 990cc42..e94ebd5 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -1,12 +1,12 @@ -import { del, get, post, put, stream } from "./js/api.js?v=20260909-account-controls"; -import { regenerateInline } from "./js/regeneration.js"; -import { appendSources, createWebSearchToggle } from "./js/webSearch.js"; -import { appendAttachments, createAttachmentComposer } from "./js/attachments.js"; -import { createReasoningToggle, finishReasoning, updateReasoning } from "./js/reasoning.js?v=20260921-reasoning-capability"; -import { closeChatDrawer, openChatDrawer } from "./js/chatDrawer.js?v=20260909-account-controls"; -import { onboardingPrompts, requestedChatId } from "./js/constants.js?v=20260909-account-controls"; -import { getModelProfile } from "./js/modelProfiles.js?v=20260909-account-controls"; -import { applyTheme as applySharedTheme, applyThemeMode as applySharedThemeMode, readStoredAppearance } from "./js/themeController.js?v=20260909-account-controls"; +import { del, get, post, put, stream } from "./api.js?v=20260909-account-controls"; +import { regenerateInline } from "./regeneration.js"; +import { appendSources, createWebSearchToggle } from "./webSearch.js"; +import { appendAttachments, createAttachmentComposer } from "./attachments.js"; +import { createReasoningToggle, finishReasoning, updateReasoning } from "./reasoning.js?v=20260921-reasoning-capability"; +import { closeChatDrawer, openChatDrawer } from "./chatDrawer.js?v=20260909-account-controls"; +import { onboardingPrompts, requestedChatId } from "./constants.js?v=20260909-account-controls"; +import { getModelProfile } from "./modelProfiles.js?v=20260909-account-controls"; +import { applyTheme as applySharedTheme, applyThemeMode as applySharedThemeMode, readStoredAppearance } from "./themeController.js?v=20260909-account-controls"; import { activeChatTitle, activeUserPersonaStatus, @@ -103,7 +103,7 @@ import { brandLogoTargets, brandNameTargets, userPersonaList -} from "./js/dom.js?v=20260909-account-controls"; +} from "./dom.js?v=20260909-account-controls"; const headerModelButton = document.getElementById("headerModelButton"); const webSearchButton = document.getElementById("webSearch"); diff --git a/public/js/settings.js b/public/js/settings.js index 488d9e6..279fed9 100644 --- a/public/js/settings.js +++ b/public/js/settings.js @@ -1,11 +1,11 @@ -import { del, get, post, put } from "./js/api.js?v=20260909-account-controls"; +import { del, get, post, put } from "./api.js?v=20260909-account-controls"; import { applyTheme as applySharedTheme, applyThemeMode as applySharedThemeMode, initializeAppearance -} from "./js/themeController.js?v=20260909-account-controls"; -import { clearStatus, setStatus } from "./js/statusNotice.js?v=20260909-account-controls"; -import { populatePersonaForm, readPersonaForm } from "./js/personaForm.js?v=20260909-account-controls"; +} from "./themeController.js?v=20260909-account-controls"; +import { clearStatus, setStatus } from "./statusNotice.js?v=20260909-account-controls"; +import { populatePersonaForm, readPersonaForm } from "./personaForm.js?v=20260909-account-controls"; const $ = (id) => document.getElementById(id); const settingsNotice = $("settingsNotice"); diff --git a/scripts/lint.mjs b/scripts/lint.mjs index 1f670c0..2d318f6 100644 --- a/scripts/lint.mjs +++ b/scripts/lint.mjs @@ -30,11 +30,11 @@ const files = [ "src/services/workspaceImportService.js", "src/services/modelService.js", "src/services/personaService.js", - "public/script.js", - "public/pages.js", + "public/js/script.js", + "public/js/pages.js", "public/js/workspaceNavigation.js", - "public/settings.js", - "public/market.js", + "public/js/settings.js", + "public/js/market.js", "public/js/api.js", "public/js/regeneration.js", "public/js/webSearch.js", diff --git a/test/app.test.js b/test/app.test.js index 59de1ff..b4152ef 100644 --- a/test/app.test.js +++ b/test/app.test.js @@ -1017,7 +1017,7 @@ test("public pages, workspace guards, and legacy chat links have distinct destin assert.match(await home.text(), /What would you like to do/); const chat = await fetch(server.baseUrl + "/app/chats/new", {headers: jar.headers()}); const html = await chat.text(); - assert.ok(html.includes('src="/script.js')); + assert.ok(html.includes('src="/js/script.js')); assert.ok(!html.includes('id="loginForm"')); assert.deepEqual((await request(server.baseUrl, "/chats", {jar})).json.chats, [], "home and chat pages do not create chats on GET"); await request(server.baseUrl, "/logout", {method: "POST", body: {}, jar}); @@ -1071,7 +1071,7 @@ test("page headers share navigation and keep session markup private", async () = test("frontend scripts and styles revalidate across deployments", async () => { const server = await startTestServer({config: {staticMaxAge: "1h"}}); try { - for (const asset of ["/script.js?v=20260909-account-controls", "/app/dom.js?v=20260909-account-controls", "/pages.css?v=20260909-account-controls"]) { + for (const asset of ["/js/script.js?v=20260909-account-controls", "/js/dom.js?v=20260909-account-controls", "/css/pages.css?v=20260909-account-controls"]) { const response = await fetch(server.baseUrl + asset); assert.equal(response.status, 200); assert.equal(response.headers.get("cache-control"), "no-cache"); @@ -1079,5 +1079,11 @@ test("frontend scripts and styles revalidate across deployments", async () => { assert.ok(etag); await response.text(); } + + for (const entrypoint of ["/js/script.js", "/js/settings.js", "/js/market.js"]) { + const response = await fetch(server.baseUrl + entrypoint); + assert.equal(response.status, 200); + assert.doesNotMatch(await response.text(), /from\s+["']\.\/js\//, `${entrypoint} must not resolve dependencies below /js/js`); + } } finally { await server.close(); } }); diff --git a/test/regenerationUi.test.js b/test/regenerationUi.test.js index 1c9749b..3895d57 100644 --- a/test/regenerationUi.test.js +++ b/test/regenerationUi.test.js @@ -1,7 +1,7 @@ import test from "node:test"; import assert from "node:assert/strict"; import {readFile} from "node:fs/promises"; -import {regenerateInline} from "../public/app/regeneration.js"; +import {regenerateInline} from "../public/js/regeneration.js"; class Element { constructor(tag = "div") { @@ -86,7 +86,7 @@ test("inline renderer streams in place, follows only nearby output, commits or r }); test("Regenerate uses inline activity and never reloads or appends a chat message", async () => { - const source = await readFile(new URL("../public/script.js", import.meta.url), "utf8"); + const source = await readFile(new URL("../public/js/script.js", import.meta.url), "utf8"); const regenerate = source.slice(source.indexOf("async function retryLatestAssistantMessage"), source.indexOf("async function switchResponseVersion")); assert.match(regenerate, /setLoadingState\(true, false\)/); assert.match(regenerate, /regenerateInline/);