starraid/star-raid/server/db.js
JOJO ab403f4cc7 后端化:账号系统+排行榜+图鉴收集同步+飞行员大厅(零依赖Node+SQLite)
- server/:node:http+node:sqlite 零依赖后端(users/sessions/user_stats/codex_unlocks/runs 五表)
- 安全:scrypt密码哈希/服务端session/全prepared statement/输入白名单/限流/CSP等安全头/静态白名单防穿越
- 前端:o-auth登陆注册 + o-home飞行员大厅(排行榜Top100三排序+图鉴展柜背景:随机3主3副2僚机+刷怪巡游)
- 图鉴改为收集点亮制(未收集=剪影+???),服务端codex_unlocks与本地并集同步
- 修复:回标题/大厅后背景卡在上场残影——render按battleUI门控+离场G=null;空闲=星空
- 结算上报:endRun/rush胜利两处submitRun,Boss击杀计数入排行榜
- playwright全流程验证通过(注册/登陆/游戏/结算/图鉴/安全注入/限流);游戏视觉未验收(用户亲自)
2026-08-06 04:20:25 +08:00

64 lines
2.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
/* ================= SQLitenode:sqlite 内置驱动,零依赖) ================= */
const { DatabaseSync } = require("node:sqlite");
const path = require("node:path");
const fs = require("node:fs");
const DATA_DIR = process.env.DATA_DIR || path.join(__dirname, "..", "data");
fs.mkdirSync(DATA_DIR, { recursive: true });
const db = new DatabaseSync(path.join(DATA_DIR, "starraid.db"));
db.exec("PRAGMA journal_mode=WAL;");
db.exec("PRAGMA foreign_keys=ON;");
db.exec(`
CREATE TABLE IF NOT EXISTS users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE COLLATE NOCASE,
email TEXT NOT NULL UNIQUE COLLATE NOCASE,
pass_hash TEXT NOT NULL,
created_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS sessions(
token TEXT PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id);
CREATE TABLE IF NOT EXISTS user_stats(
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
boss_kills INTEGER NOT NULL DEFAULT 0,
endless_high INTEGER NOT NULL DEFAULT 0,
runs INTEGER NOT NULL DEFAULT 0,
updated_at INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS codex_unlocks(
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
entry_key TEXT NOT NULL,
unlocked_at INTEGER NOT NULL,
PRIMARY KEY(user_id, entry_key)
);
CREATE TABLE IF NOT EXISTS runs(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
mode TEXT NOT NULL,
diff INTEGER NOT NULL,
score INTEGER NOT NULL,
wave INTEGER NOT NULL,
stage INTEGER NOT NULL,
time_sec INTEGER NOT NULL,
boss_kills INTEGER NOT NULL,
win INTEGER NOT NULL,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_runs_user ON runs(user_id);
`);
/* 定期清理过期 session */
setInterval(() => {
try { db.prepare("DELETE FROM sessions WHERE expires_at<?").run(Date.now()); } catch (e) { /* 忽略 */ }
}, 3600000).unref();
module.exports = db;