0.2.6-dev: /data/assets.json and /data/local-assets.json are served with content-hashed URLs (/assets/~<hash>/…, one hash per Spine model, the committed files unchanged); the ~hash routes of /assets/ /fonts/ /media/ answer immutable when the hash names the file and the current file with no-cache otherwise; content ETags — host bandwidth layer 1.2; golden: unchanged

This commit is contained in:
sganggs committed 2026-10-12 16:24:03 +08:00
1 parent 521dd984e7
commit 893d17e725
12 files changed
+571 -34

No files matched your search

+9 -5
View File
@@ -11,6 +11,8 @@
// http/files.js one file → response: MIME, gzip + memory cache, ETag / Last-Modified / 304, Cache-Control, ranges
// http/assetIndex.js the content hashes of public/assets and public/fonts (built in the background, cached in
// .cache/asset-hashes.json by path + size + mtime; Spine models share one hash)
// http/assetViews.js the served /data/assets.json and /data/local-assets.json: every art URL with its hash segment
// (/assets/~<hash>/…, immutable when the hash matches); the committed files stay unchanged
// http/buildTag.js the build tag of the served browser runtime (/healthz `build`, public/js/ui/buildGuard.js)
// http/routes.js the request listener: security headers, 414 / 400 / 405, GET /healthz → JSON status, else static
// http/traffic.js the traffic counters: bytes sent per category (assets / audio / code / data) and on the
@@ -37,6 +39,7 @@ import { BUILD_INPUTS, computeBuildTag, buildTag, resetBuildTag } from './http/b
import { createRequestHandler } from './http/routes.js';
import { createTrafficCounter } from './http/traffic.js';
import { createAssetIndex } from './http/assetIndex.js';
import { createManifestViews } from './http/assetViews.js';
import { answerClientError } from './http/common.js';
import { lanUrls, displayHost, isProcessEntry, runMain } from './http/boot.js';
@@ -63,7 +66,7 @@ export {
* lobby: import('./lobby.js').Lobby, network: import('./net.js').Network,
* registry: import('./net.js').SessionRegistry, packs: ReturnType<typeof createPackRegistry>,
* traffic: ReturnType<typeof createTrafficCounter>, assetIndex: ReturnType<typeof createAssetIndex> | null,
* close: () => Promise<void> }>}
* views: ReturnType<typeof createManifestViews> | null, close: () => Promise<void> }>}
*/
export async function startServer(opts = {}) {
const { port, host } = listenAddress(opts);
@@ -76,17 +79,18 @@ export async function startServer(opts = {}) {
// content packs (docs/PACKS.md): scanned now — the start log names them — and again whenever their folders change
const packs = createPackRegistry({ publicDir, dataDir, packsDir }, { log });
packs.refresh(true);
// the content hashes of the art (built in the background once listening)
// the content hashes of the art (built in the background once listening) and the manifests served with them
const indexOptions = assetIndexOptionsFrom(opts, publicDir);
const assetIndex = indexOptions ? createAssetIndex({ publicDir, log, ...indexOptions }) : null;
const serveStatic = createStaticHandler({ publicDir, dataDir, sharedDir, packsDir, packs, log });
const views = assetIndex ? createManifestViews({ dataDir, index: assetIndex, log }) : null;
const serveStatic = createStaticHandler({ publicDir, dataDir, sharedDir, packsDir, packs, log, assetIndex, views });
const startedAt = Date.now();
// The tag is per process (see buildTag): read the browser runtime once, here, not on every /healthz.
resetBuildTag();
buildTag();
const traffic = createTrafficCounter();
const server = http.createServer(createRequestHandler({ serveStatic, health: { startedAt, network, registry, lobby, traffic, assetIndex }, log }));
const server = http.createServer(createRequestHandler({ serveStatic, health: { startedAt, network, registry, lobby, traffic, assetIndex, views }, log }));
server.on('clientError', answerClientError);
const wss = attachWebSocket(server, { network, log, traffic });
@@ -148,7 +152,7 @@ export async function startServer(opts = {}) {
return closing;
}
return { port: actualPort, host: boundHost, url, server, wss, lobby, network, registry, packs, traffic, assetIndex, close };
return { port: actualPort, host: boundHost, url, server, wss, lobby, network, registry, packs, traffic, assetIndex, views, close };
}
// `node server/index.js` / npm start: listen, print the banner, stop on SIGINT / SIGTERM (http/boot.js).