security update + make easter egg optional.

This commit is contained in:
KingKDot
2026-08-01 01:54:07 -05:00
parent bd7b3ea6f4
commit 34158ba673
22 changed files with 534 additions and 90 deletions
+21
View File
@@ -0,0 +1,21 @@
# Browser TypeScript
Browser source lives here and is bundled into `public/assets/generated/` by
`bun run build:web`. Generated assets are ignored by Git and must not be edited
directly.
The development supervisor runs the browser build once and watches this folder.
Production and E2E preparation also run the build before serving assets.
Migrate existing `public/assets/*.js` modules incrementally:
1. Move one leaf/shared module into this directory and add it as a browser
entrypoint in `package.json`.
2. Keep its public export names stable and update consumers to import from
`/assets/generated/` (or the equivalent relative path).
3. Add runtime schemas for data crossing HTTP, WebSocket, storage, or plugin
boundaries; TypeScript types alone do not validate external data.
4. Run `bun run typecheck`, `bun run build:web`, and the affected browser tests.
Do not duplicate or replace the generated wire-protocol types here. Wire changes
must continue through `protocol/wire-contract.json` and its generator.
@@ -0,0 +1,72 @@
import { object, record, safeParse, string, unknown } from "valibot";
export type SharedUiSettings = Record<string, unknown>;
const sharedUiSettingsResponseSchema = object({
settings: record(string(), unknown()),
});
export async function loadSharedUiSettings(scope: string): Promise<SharedUiSettings> {
try {
const res = await fetch(`/api/ui-settings/${encodeURIComponent(scope)}`, {
credentials: "include",
});
if (!res.ok) return {};
const input: unknown = await res.json().catch(() => null);
const result = safeParse(sharedUiSettingsResponseSchema, input);
return result.success ? result.output.settings : {};
} catch (err) {
console.warn(`ui-settings: failed to load ${scope}`, err);
return {};
}
}
export function createSharedUiSettingsSaver(
scope: string,
readSettings: () => SharedUiSettings | null | undefined,
delayMs = 350,
) {
let timer: ReturnType<typeof setTimeout> | null = null;
let lastPayload = "";
async function saveNow(): Promise<void> {
if (timer) {
clearTimeout(timer);
timer = null;
}
let settings: SharedUiSettings;
try {
settings = readSettings() ?? {};
} catch (err) {
console.warn(`ui-settings: failed to read ${scope}`, err);
return;
}
const payload = JSON.stringify(settings);
if (payload === lastPayload) return;
lastPayload = payload;
try {
const res = await fetch(`/api/ui-settings/${encodeURIComponent(scope)}`, {
method: "PUT",
credentials: "include",
keepalive: true,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ settings }),
});
if (!res.ok) lastPayload = "";
} catch (err) {
lastPayload = "";
console.warn(`ui-settings: failed to save ${scope}`, err);
}
}
function scheduleSave(): void {
if (timer) clearTimeout(timer);
timer = setTimeout(saveNow, delayMs);
}
return { scheduleSave, saveNow };
}