feedback5 R1: startServer and main become wiring — PORT / HOST / TRUST_PROXY and the option picks go to http/config.js, the session stack and the /ws upgrade to http/websocket.js, the request listener and /healthz to http/routes.js (new), the security headers and the clientError 400 to http/common.js, the banner, signals and entry check to http/boot.js
Same order of construction, listeners and headers as before; a scripted fingerprint (export list, 51 HTTP requests' status / header order / body hash, raw upgrade and malformed-request replies) and the process run (banner, port in use, SIGINT) match the pre-split server exactly. test/version.test.js reads the banner and /healthz from their new files; module headers describe each piece.
This commit is contained in:
1 parent
b48a67caec
commit
1b38e30819
11 files changed
+323
-202
No files matched your search
+22
-19
@@ -1,16 +1,19 @@
|
||||
// server/http/static.js — the static file server (moved from server/index.js):
|
||||
// * node:http static server: / → public/ (index.html for directories)
|
||||
// /data/ → data/ (generated game data)
|
||||
// /shared/ → shared/ (ESM shared with the browser)
|
||||
// /sim/ → server/sim/ (the battle simulation, read-only, `.js` only — client-side
|
||||
// combat, DESIGN §14; the Node-only loader nodeData.js is not served)
|
||||
// /data.js → a generated browser stand-in of server/data.js (the sim's content modules
|
||||
// import `../../../data.js`; in the browser it serves the data injected with
|
||||
// /sim/simdata.js setSimData). No other server file is ever served.
|
||||
// /media/bgm/act1 → public/assets/audio/bgm/act1.mp3 — the same audio files, addressed
|
||||
// **without** an extension so download managers (IDM / 迅雷 …) stop popping a
|
||||
// "下载文件信息" dialog for every BGM track (shared/media.js, public/js/media.js)
|
||||
// traversal & dotfile protection; 404 page. Files go out through files.js serveFile.
|
||||
// server/http/static.js — the static file server (routes.js hands it every GET / HEAD that is not an API route):
|
||||
//
|
||||
// / → public/ (index.html for directories)
|
||||
// /data/ → data/ (generated game data)
|
||||
// /shared/ → shared/ (ESM shared with the browser)
|
||||
// /sim/ → server/sim/ (the battle simulation, read-only, `.js` only — client-side
|
||||
// combat, DESIGN §14; the Node-only loader nodeData.js is not served)
|
||||
// /data.js → a generated browser stand-in of server/data.js (the sim's content modules
|
||||
// import `../../../data.js`; in the browser it serves the data injected with
|
||||
// /sim/simdata.js setSimData). No other server file is ever served.
|
||||
// /media/bgm/act1 → public/assets/audio/bgm/act1.mp3 — the same audio files, addressed
|
||||
// **without** an extension so download managers (IDM / 迅雷 …) stop popping a
|
||||
// "下载文件信息" dialog for every BGM track (media.js, shared/media.js, public/js/media.js)
|
||||
//
|
||||
// Traversal & dotfile protection, a directory without its trailing slash → 301, 404 page; an absent
|
||||
// data/local-assets.json is answered with an empty manifest. Files go out through files.js serveFile.
|
||||
|
||||
import fsp from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
@@ -20,7 +23,7 @@ import { sendError } from './common.js';
|
||||
import { MIME, GzipCache, isNotModified, serveFile } from './files.js';
|
||||
import { serveMedia } from './media.js';
|
||||
|
||||
/** Browser stand-in of server/data.js, served at /data.js (see the header). */
|
||||
/** Browser stand-in of server/data.js, served at /data.js (see the header). Served byte for byte: its first line names the entry, server/index.js. */
|
||||
export const DATA_SHIM_JS = `// Generated by server/index.js — browser stand-in for server/data.js (DESIGN §14 client-side combat).
|
||||
// The simulation's content modules (/sim/content/support/index.js) import getData() from here; it returns the game data
|
||||
// the page injected with /sim/simdata.js setSimData(data).
|
||||
@@ -35,15 +38,15 @@ const SIM_PRIVATE = new Set(['nodedata.js']); // lower-case (compared case-insen
|
||||
// Static file handler
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create the static request handler.
|
||||
* @param {{ publicDir: string, dataDir: string, sharedDir: string, simDir?: string, log?: object }} dirs
|
||||
* @returns {(req: http.IncomingMessage, res: http.ServerResponse, rawPath: string, query: string) => Promise<void>}
|
||||
*/
|
||||
/** Optional per-machine art manifest (tools/local-extract) and the empty stand-in served when it is absent. */
|
||||
const LOCAL_ART_MANIFEST = 'local-assets.json';
|
||||
const EMPTY_LOCAL_ART = Buffer.from(JSON.stringify({ version: 1, source: 'none', count: 0, groups: {} }));
|
||||
|
||||
/**
|
||||
* Create the static request handler.
|
||||
* @param {{ publicDir: string, dataDir: string, sharedDir: string, simDir?: string, log?: object }} dirs
|
||||
* @returns {(req: import('node:http').IncomingMessage, res: import('node:http').ServerResponse, rawPath: string, query: string) => Promise<void>}
|
||||
*/
|
||||
export function createStaticHandler({ publicDir, dataDir, sharedDir, simDir = path.join(ROOT, 'server', 'sim'), log = noopLog }) {
|
||||
const mounts = [
|
||||
{ prefix: '/data/', name: 'data', dir: path.resolve(dataDir) },
|
||||
|
||||
Reference in new issue
Block a user