实现账号绑定、持久登录与跨设备对局恢复
CI / test (ubuntu-latest, node 22) (push) Failing after 33m10s
CI / test (ubuntu-latest, node 24) (push) Failing after 34m41s
CI / tooling (lint, imports, typecheck) (push) Failing after 36m11s
CI / test (windows-latest, node 22) (push) Canceled after 0s
CI / test (windows-latest, node 24) (push) Canceled after 0s

This commit is contained in:
herryyun committed 2026-10-14 23:22:50 +08:00
1 parent 488db49f11
commit 7c25c89992
62 files changed
+6855 -1005

No files matched your search

+11 -2
View File
@@ -2,6 +2,8 @@
// (i18n-ignore-file: the error pages are bilingual by design, 中文 · English — docs/I18N.md)
//
// * a URL longer than 4096 characters → 414; one that does not parse → 400;
// * /skland/* → the Skland module's own listener when it is enabled (server/skland/http.js; SP_SKLAND=1). It owns
// its methods (POST), so it runs before the GET/HEAD gate below;
// * any method but GET / HEAD → 405 with `Allow: GET, HEAD`;
// * GET /healthz → JSON status (protocol `version`, release `app`, uptime, the served `build`, sockets, sessions,
// rooms, matches), never cached; `?traffic=1` adds the traffic counters (traffic.js: bytes by category since the
@@ -48,16 +50,23 @@ const wantsTraffic = (query) => /(?:^|&)traffic(?:=(?:1|true|yes))?(?:&|$)/i.tes
* The request listener for `http.createServer`.
* @param {{ serveStatic: (req: import('node:http').IncomingMessage, res: import('node:http').ServerResponse,
* rawPath: string, query: string) => Promise<void>,
* health: Parameters<typeof healthReport>[0], log: object, trustProxy?: 'auto' | boolean }} deps
* health: Parameters<typeof healthReport>[0], log: object, trustProxy?: 'auto' | boolean,
* skland?: ((req: import('node:http').IncomingMessage, res: import('node:http').ServerResponse,
* parts: { rawPath: string, query: string }) => Promise<boolean>) | null }} deps
* trustProxy: whose forwarding headers name the client (net.js clientAddress; the server's TRUST_PROXY)
* skland: the /skland/* handler when the module is enabled (server/skland/http.js; SP_SKLAND=1). It owns its paths
* and its methods (POST), so it runs before the GET/HEAD method gate.
* @returns {(req: import('node:http').IncomingMessage, res: import('node:http').ServerResponse) => void}
*/
export function createRequestHandler({ serveStatic, health, log, trustProxy = 'auto' }) {
export function createRequestHandler({ serveStatic, health, log, trustProxy = 'auto', skland = null }) {
async function handleRequest(req, res) {
const url = req.url || '/';
if (url.length > MAX_URL_LENGTH) { sendError(req, res, 414, '请求地址过长 · URI too long'); return; }
const parts = splitUrl(url);
if (!parts) { sendError(req, res, 400, '请求地址无效 · Bad request'); return; }
if (skland && (parts.rawPath === '/skland' || parts.rawPath.startsWith('/skland/'))) {
if (await skland(req, res, parts)) return;
}
if (req.method !== 'GET' && req.method !== 'HEAD') {
res.setHeader('Allow', 'GET, HEAD');
sendError(req, res, 405, '不支持的请求方法 · Method not allowed');