Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .github/workflows/ootb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22.5'
# db-server imports `node:sqlite` at module scope. That builtin is
# gated behind --experimental-sqlite on 22.5.0-22.12.x and only
# became available unflagged from 22.13.0 onward — pinning to
# '22.5' here made db-server crash on import on every run.
node-version: '22.13'

- name: Install root deps
shell: pwsh
Expand All @@ -27,6 +31,15 @@ jobs:
shell: pwsh
run: npm run build --workspaces --if-present

- name: Seed configs/ from configs-default/
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path configs | Out-Null
Get-ChildItem -Path configs-default -Filter *.json | ForEach-Object {
$dest = Join-Path configs $_.Name
if (-not (Test-Path $dest)) { Copy-Item $_.FullName $dest }
}

- name: Run check-ootb
shell: pwsh
run: node tools/check-ootb.js
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
bds-tools/dist/
db-server/dist/
panel/dist/
qq-bridge/dist/
sfmc/dist/
modules/sdk/@sfmc-sdk/dist/
modules/sdk/@sfmc-sdk/node_modules/
shared/**/dist/
Expand Down
15 changes: 8 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ npm workspaces monorepo (root `package.json` has `workspaces`):

| Path | What | Runtime |
|------|------|---------|
| `db-server/` | SQLite HTTP REST backend (plain `node:http` + `node:sqlite`) | Node.js >=22.5 |
| `db-server/` | SQLite HTTP REST backend (plain `node:http` + `node:sqlite`) | Node.js >=22.13 |
| `qq-bridge/` | QQ bridge (LLBot OneBot 11, WS 3002) | Node.js |
| `bds-tools/` | BDS auto-updater + behavior-pack assembler | Node.js |
| `sfmc/` | CLI management tool (REPL + supervisor), assembles SAPI BP at deploy time | Node.js, can SEA-bundle |
Expand Down Expand Up @@ -215,14 +215,15 @@ node tools/lock.js drift # detect drifted files

## Cursor Cloud specific instructions

The Cloud VM is Linux; the repo primarily targets Windows, but the Node services run fine on Linux (Node ≥22.5 provides `node:sqlite`). The update script only runs `npm install`. Everything below is required each session before running/verifying services.
The Cloud VM is Linux; the repo primarily targets Windows, but the Node services run fine on Linux (Node ≥22.13 provides unflagged `node:sqlite`; 22.5–22.12 require the `--experimental-sqlite` CLI flag or db-server crashes on startup with `ERR_UNKNOWN_BUILTIN_MODULE`). The update script only runs `npm install`. Everything below is required each session before running/verifying services.

- **Build before running.** `dist/` is gitignored for `@sfmc/sdk`, `db-server`, `bds-tools`, etc., and services run from `dist/`. Run `npm run build --workspaces --if-present` (builds the SDK first, then the services) after `npm install`. Without it, imports like `@sfmc/sdk/node/config` fail.
- **`configs/` is gitignored** — populate it once from `configs-default/` (`mkdir -p configs && cp -n configs-default/*.json configs/`). db-server also runs with defaults if `configs/` is absent.
- **Gotcha — `modulesDir` in `configs/db_config.json`.** The default value copied from `configs-default/` is `"../modules"`, which resolves *relative to `PROJECT_ROOT` (= `SFMC_ROOT`, the repo root)* → `/modules` (outside the repo) → the module API returns an empty catalog. Set it to `"modules"` (or delete the key so it falls back to `<root>/modules`). When `configs/` is absent entirely, the fallback is already correct.
- **Fixed — `modulesDir` in `configs-default/db_config.json`.** Used to ship as `"../modules"`, which resolved *relative to `PROJECT_ROOT` (= `SFMC_ROOT`, the repo root)* → `/modules` (outside the repo) → the module API returned an empty catalog. It now ships as `"modules"` so `configs/db_config.json` copied from the default is correct out of the box. When `configs/` is absent entirely, the fallback (`<root>/modules`) was already correct.
- **Run db-server (main service, port 3001):** `SFMC_ROOT=$PWD node db-server/dist/index.js`. Health: `GET http://127.0.0.1:3001/api/health`. The module/config REST surface is JSON-backed and is the CI-tested core path (`GET /api/sfmc/modules/catalog`, `POST /api/sfmc/modules/:id/{enable|disable}`).
- **Pre-existing bugs (not environment issues), so don't chase them during setup:**
- `tools/smoke-modules.js` uses `spawnSync` without importing it from `node:child_process` → crashes immediately.
- `tools/sim-new-user.js` (and the start-order docs above) spawn `db-server/index.js`, which does not exist — the real entry is `db-server/dist/index.js`. This makes the `sim-new-user` check in `tools/check-ootb.js` time out, so a healthy env shows **check-ootb 5/6 pass**.
- The SQLite-backed gameplay routes (`economy`, `lands`, `coops`, `scoreboards`, …) return `near "?": syntax error` because table names are interpolated through `sql-template-strings` (`FROM ${TABLE}` → `FROM ?`). The JSON-backed module/config API and `/api/health` work.
- **`node:sqlite` needs Node ≥22.13, not just ≥22.5.** `db-server` imports `node:sqlite` at module scope. On 22.5.0–22.12.x the module is still gated behind `--experimental-sqlite`; importing it unflagged throws `ERR_UNKNOWN_BUILTIN_MODULE` and db-server exits immediately on startup. This is exactly what caused the `ootb` GitHub Actions workflow to fail repeatedly (`setup-node` was pinned to `node-version: '22.5'`, which resolves to `22.5.1`) — `check-ootb`'s "db-server 启动 + 模块接口" step timed out waiting for `/api/health`, and `sim-new-user`/`smoke-modules` cascaded into the same timeout. Fixed by pinning CI to `22.13`+.
- **Pre-existing bugs (not environment issues), fixed as of this note — kept here for history:**
- `tools/check-catalog.js` used top-level ESM `import` syntax while the repo root `package.json` has no `"type": "module"` → `SyntaxError: Cannot use import statement outside a module` under plain `node`. Converted to CommonJS `require()` to match every other `tools/*.js` script.
- `tools/check-ootb.js`, `tools/sim-new-user.js`, and `tools/test-db-api.js` spawned `db-server/index.js`, which does not exist — the real entry is `db-server/dist/index.js`. This made the `db-server 启动` and `sim-new-user` checks in `tools/check-ootb.js` time out, so a healthy env used to show **check-ootb 5/6 pass**; both are now fixed and should pass 6/6 given a built workspace + `--experimental-sqlite`-capable Node.
- The SQLite-backed gameplay routes (`economy`, `lands`, `coops`, `scoreboards`, …) return `near "?": syntax error` because table names are interpolated through `sql-template-strings` (`FROM ${TABLE}` → `FROM ?`). The JSON-backed module/config API and `/api/health` work. This one is still open.
- **`npm run lint` is broken out-of-the-box** — ESLint v10 needs a flat `eslint.config.js` and none exists in the repo. Use per-workspace `npm run typecheck` for static checking instead.
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ScriptsForMinecraftServer is a Minecraft Bedrock Script API (SAPI) plugin with f

| Path | Role | Runtime |
|------|------|---------|
| `db-server/` | SQLite HTTP REST API (port 3001) | Node.js 22.5+ |
| `db-server/` | SQLite HTTP REST API (port 3001) | Node.js 22.13+ |
| `qq-bridge/` | QQ bridge via LLBot OneBot 11 (WS 3002 only) | Node.js |
| `panel/` | TUI management dashboard | Node.js (Ink) |
| `BDSTools/` | BDS auto-updater + behavior-pack assembler | Node.js |
Expand Down Expand Up @@ -64,7 +64,7 @@ node tools/install-module.js uninstall <id> # uninstall module

### Build prerequisites

- Node.js 22.5+ for everything (db-server requires `node:sqlite`)
- Node.js 22.13+ for everything (db-server requires `node:sqlite`, which needs the `--experimental-sqlite` CLI flag on 22.5–22.12; unflagged from 22.13)
- Run `sfmc` (or `node sfmc/dist/main.js`) to fill `configs/*.json` via wizard

## Architecture
Expand Down
2 changes: 1 addition & 1 deletion HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Per the user's directives:
│ HTTP @ 127.0.0.1:3001
┌────────────────────────────────────────────────────────────┐
│ db-server (Node 22.5+)
│ db-server (Node 22.13+)
│ manifest-loader.ts ← v2 manifests │
│ schema-registry.ts ← collects db.defineTable calls │
│ tx-runner.ts ← /api/sfmc/db/tx POST │
Expand Down
4 changes: 2 additions & 2 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

[![version](https://img.shields.io/github/v/tag/DogeLakeDev/ScriptsForMinecraftServer?style=flat-square&label=version)](https://github.com/DogeLakeDev/ScriptsForMinecraftServer/tags)
[![license](https://img.shields.io/github/license/DogeLakeDev/ScriptsForMinecraftServer?style=flat-square)](./LICENSE)
[![node](https://img.shields.io/badge/node-22.5%2B-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
[![node](https://img.shields.io/badge/node-22.13%2B-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
[![typescript](https://img.shields.io/badge/TypeScript-6.x-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org)
[![sea](https://img.shields.io/badge/SEA-single--executable-FF6B6B?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org/api/single-executable-applications.html)
[![modules](https://img.shields.io/badge/modules-25-7B68EE?style=flat-square&logo=cube&logoColor=white)](./modules/catalog.json)
Expand Down Expand Up @@ -221,7 +221,7 @@ ScriptsForMinecraftServer/

| Component | Required |
|-----------|----------|
| Node.js | 22.5+ (db-server uses native `node:sqlite`) + 18+ (SAPI bundle) |
| Node.js | 22.13+ (db-server uses native `node:sqlite`, needs `--experimental-sqlite` before 22.13) + 18+ (SAPI bundle) |
| OS | Windows 10/11 (primary), Linux/macOS supported |
| BDS | Bedrock Dedicated Server 1.26.x |
| Disk | ~500 MB (BP + services + node_modules) |
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

[![version](https://img.shields.io/github/v/tag/DogeLakeDev/ScriptsForMinecraftServer?style=flat-square&label=version)](https://github.com/DogeLakeDev/ScriptsForMinecraftServer/tags)
[![license](https://img.shields.io/github/license/DogeLakeDev/ScriptsForMinecraftServer?style=flat-square)](./LICENSE)
[![node](https://img.shields.io/badge/node-22.5%2B-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
[![node](https://img.shields.io/badge/node-22.13%2B-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
[![typescript](https://img.shields.io/badge/TypeScript-6.x-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org)
[![sea](https://img.shields.io/badge/SEA-single--executable-FF6B6B?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org/api/single-executable-applications.html)
[![modules](https://img.shields.io/badge/modules-25-7B68EE?style=flat-square&logo=cube&logoColor=white)](./modules/catalog.json)
Expand Down Expand Up @@ -227,7 +227,7 @@ ScriptsForMinecraftServer/

| 组件 | 要求 |
|------|------|
| Node.js | 22.5+(db-server 原生 `node:sqlite`)+ 18+(SAPI 打包) |
| Node.js | 22.13+(db-server 原生 `node:sqlite`,22.13 前需 `--experimental-sqlite`)+ 18+(SAPI 打包) |
| OS | Windows 10/11(主要),Linux/macOS 也支持 |
| BDS | Bedrock Dedicated Server 1.26.x |
| 磁盘 | ~500 MB(含 BP + 服务 + node_modules) |
Expand Down
2 changes: 1 addition & 1 deletion configs-default/db_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"db_port": 3001,
"http_auth": "",
"dbDir": "./data/sfmc_data.db",
"modulesDir": "../modules"
"modulesDir": "modules"
}
2 changes: 1 addition & 1 deletion db-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"format": "prettier --write \"src/**/*.{ts,tsx,js,json}\""
},
"engines": {
"node": ">=22.5.0"
"node": ">=22.13.0"
},
"dependencies": {
"sql-template-strings": "^2.2.2",
Expand Down
2 changes: 1 addition & 1 deletion db-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import { readJsonFile, writeJsonFile } from "./lib/json.js";
import { isEnabled, loadModuleLock, updateModuleState } from "./lib/module-state.js";
import { body as sharedBody, json as sharedJson } from "./lib/http.js";

if (!assertNodeVersion(22, 5)) {
if (!assertNodeVersion(22, 13)) {
process.exit(2);
}

Expand Down
11 changes: 9 additions & 2 deletions db-server/src/lib/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@ export function parseNodeVersion(version: string = process.versions.node): {
}

/**
* 校验当前 Node.js 版本是否满足最低要求。
*
* 默认下限 22.13 —— `node:sqlite`(db-server 的核心依赖)在 22.5.0–22.12.x
* 仍需 `--experimental-sqlite` CLI 参数才能加载,未带参数时会在 import 阶段
* 直接抛出 `ERR_UNKNOWN_BUILTIN_MODULE`;该模块从 22.13.0 起默认可用(仍标记为
* experimental)。注意:由于 ESM 静态 import 会在本文件被调用之前完成解析,
* 这里的检查无法拦截 `./lib/sqlite.ts` 自身的 import 崩溃,只能作为其余场景
* 的兜底防线与版本要求的单一事实来源。
*
* @param {number} [minMajor=22]
* @param {number} [minMinor=5]
* @param {number} [minMinor=13]
* @return {*} {boolean}
*/
export function assertNodeVersion(minMajor: number = 22, minMinor: number = 5): boolean {
export function assertNodeVersion(minMajor: number = 22, minMinor: number = 13): boolean {
const actual = parseNodeVersion();
if (!actual || actual.major < minMajor || (actual.major === minMajor && actual.minor < minMinor)) {
log.error(`[Runtime] Node.js ${minMajor}.${minMinor}+ is required; found ${process.versions.node}`);
Expand Down
8 changes: 4 additions & 4 deletions docs/user-guide.en.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ScriptsForMinecraftServer User Guide

> End-to-end walkthrough from a fresh BDS install to daily ops. After reading this you can:
> 1. Set up the environment (Node 18+ / Node 22.5+ / Windows Loopback Exemption)
> 1. Set up the environment (Node 18+ / Node 22.13+ / Windows Loopback Exemption)
> 2. Initialize configs (`db_config.json` / `qq_config.json` / BP `.env`)
> 3. Start all five top-level services (db-server / qq-bridge / bds-tools / sfmc / BP)
> 4. Enable / disable modules in BDS
Expand All @@ -18,7 +18,7 @@
│ HTTP @ 127.0.0.1:3001
┌─────────────────────────────────────────────────────────┐
│ db-server (Node 22.5+)
│ db-server (Node 22.13+)
│ └─ SQLite @ ./data/sfmc_data.db │
│ REST API /api/sfmc/* │
│ manifest loader @ modules/_manifests/...json │
Expand Down Expand Up @@ -52,12 +52,12 @@

| Component | Required |
|-----------|----------|
| Node.js | 18.x (SAPI bundle) + 22.5+ (db-server) |
| Node.js | 18.x (SAPI bundle) + 22.13+ (db-server; `node:sqlite` needs `--experimental-sqlite` before 22.13) |
| OS | Windows 10/11 (primary), Linux/macOS also supported |
| BDS | Bedrock Dedicated Server 1.26.x (tested with preview.30) |
| Disk | ~500MB (BP + services + node_modules) |

**Install Node**: grab 22.5+ LTS from [nodejs.org](https://nodejs.org/). Then verify:
**Install Node**: grab 22.13+ LTS from [nodejs.org](https://nodejs.org/). Then verify:

```bash
node -v # should print v22.x.x
Expand Down
6 changes: 3 additions & 3 deletions docs/user-guide.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
│ HTTP @ 127.0.0.1:3001
┌─────────────────────────────────────────────────────────┐
│ db-server (Node 22.5+)
│ db-server (Node 22.13+)
│ └─ SQLite @ ./data/sfmc_data.db │
│ REST API /api/sfmc/* │
│ manifest loader @ modules/_manifests/...json │
Expand Down Expand Up @@ -54,12 +54,12 @@

| 组件 | 要求 |
|------|------|
| Node.js | 22.5+ |
| Node.js | 22.13+(db-server 依赖 `node:sqlite`,22.13 前该模块需 `--experimental-sqlite` 才能加载) |
| 操作系统 | Windows 10/11(主要平台),Linux/macOS 也支持 |
| BDS | Bedrock Dedicated Server 1.26.x |
| 磁盘 | ~500MB(含 BP + 服务 + node_modules) |

**Node 安装**:从 [nodejs.org](https://nodejs.org/) 拉 22.5+ LTS。装完后:
**Node 安装**:从 [nodejs.org](https://nodejs.org/) 拉 22.13+ LTS。装完后:

```bash
node -v # 应输出 v22.x.x
Expand Down
5 changes: 3 additions & 2 deletions sfmc/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import { resolveRuntimeRoot } from "@sfmc/sdk/node/config";
* 子服务进程通过 SFMC_ROOT + SFMC_PACKAGES_DIR env 拿到项目根 + 模块目录,
* db-server 据此定位 modules/packages/, 不依赖自身 __dirname(SEA-launched 时不可靠)。
*
* node:sea 在 Node 21.7+/22+ 可用;db-server 依赖 node:sqlite 已要求 Node 22.5+,
* 因此这里可直接顶层 import,无需降级。
* node:sea 在 Node 21.7+/22+ 可用;db-server 依赖 node:sqlite 要求 Node 22.13+
* (22.5–22.12 该模块仍需 --experimental-sqlite,否则 import 阶段直接抛出
* ERR_UNKNOWN_BUILTIN_MODULE),因此这里可直接顶层 import,无需降级。
*/

export const IS_SEA: boolean = typeof isSea === "function" && isSea();
Expand Down
12 changes: 7 additions & 5 deletions tools/check-catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
* - entry.init 仅在 sapi 类型可选
* - 不允许循环依赖(拓扑排序检测)
*/
import { accessSync, constants, readFileSync } from "node:fs";
import { resolve, join, dirname } from "node:path";
import { fileURLToPath } from 'node:url';
import path from "node:path";
// 仓库根 package.json 未声明 "type": "module",本文件按 CommonJS 解析;
// 与其余 tools/*.js 保持一致改用 require(),避免在未开启 ESM 探测的 Node
// 版本(例如 CI 固定的 node-version)上直接抛出 "Cannot use import
// statement outside a module" 而崩溃。
const { accessSync, constants, readFileSync } = require("node:fs");
const { resolve, join } = require("node:path");

const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const ROOT = resolve(__dirname, "..");
const CATALOG = join(ROOT, "modules", "catalog.json");
const SERVICES_CATALOG = join(ROOT, "services", "catalog.json");
/* SAPI modules no longer register through a single static entry.ts —
Expand Down
2 changes: 1 addition & 1 deletion tools/check-ootb.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function fileContains(p, needle) {
{
let dbProc = null;
try {
dbProc = spawn(process.execPath, [path.join(ROOT, "db-server", "index.js")], {
dbProc = spawn(process.execPath, [path.join(ROOT, "db-server", "dist", "index.js")], {
cwd: ROOT,
env: { ...process.env },
stdio: ["ignore", "pipe", "pipe"],
Expand Down
2 changes: 1 addition & 1 deletion tools/sim-new-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ let dbProc = null;

function startDb(simDir) {
const env = { ...process.env, SFMC_ROOT: simDir, DB_PORT: String(DB_PORT) };
dbProc = spawn(process.execPath, [path.join(ROOT, "db-server", "index.js")], {
dbProc = spawn(process.execPath, [path.join(ROOT, "db-server", "dist", "index.js")], {
cwd: ROOT,
env,
stdio: ["ignore", "pipe", "pipe"],
Expand Down
4 changes: 2 additions & 2 deletions tools/test-db-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ async function main() {
copy(path.join(ROOT, 'modules', 'module-lock.json'), path.join(workspace, 'modules', 'module-lock.json'));
fs.mkdirSync(path.join(workspace, 'data'), { recursive: true });
fs.mkdirSync(path.join(workspace, 'configs'), { recursive: true });
fs.writeFileSync(path.join(workspace, 'configs', 'db_config.json'), JSON.stringify({ db_port: PORT, dbDir: './data/sfmc_data.db', modulesDir: '../modules' }) + '\n');
fs.writeFileSync(path.join(workspace, 'configs', 'db_config.json'), JSON.stringify({ db_port: PORT, dbDir: './data/sfmc_data.db', modulesDir: 'modules' }) + '\n');
copy(path.join(ROOT, 'configs', 'qq_config.json'), path.join(workspace, 'configs', 'qq_config.json'));
copy(path.join(ROOT, 'configs', 'settings.json'), path.join(workspace, 'configs', 'settings.json'));

const child = spawn(process.execPath, [path.join(ROOT, 'db-server', 'index.js')], {
const child = spawn(process.execPath, [path.join(ROOT, 'db-server', 'dist', 'index.js')], {
cwd: ROOT,
env: { ...process.env, SFMC_ROOT: workspace, SFMC_DB_PATH: dbPath, SFMC_MODULES_DIR: path.join(workspace, 'modules'), DB_PORT: String(PORT) },
stdio: ['ignore', 'pipe', 'pipe'],
Expand Down
Loading