@sfmc-bds/cli 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * client.ts — CLI 侧守护进程客户端:ensureDaemon + RPC + 日志订阅
3
3
  *
4
- * 若 `.sfmc/daemon.json` 对应进程不在或管道不可连,则 spawn `sfmc --daemon`
5
- *(detached + windowsHide),再轮询直到 ping 成功。
4
+ * 若 `.sfmc/daemon.json` 对应进程不在或管道不可连,则在登录会话之外启动 `sfmc --daemon`,
5
+ * 再轮询直到 ping 成功。管理连接退出只断开管道,不停止守护进程。
6
6
  */
7
7
  import net from "node:net";
8
8
  import type { ServiceStateEvent, ServiceStatus } from "../services.js";
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/daemon/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,GAAG,MAAM,UAAU,CAAC;AAK3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAGV,YAAY,EACZ,YAAY,EAEZ,YAAY,EACb,MAAM,eAAe,CAAC;AAIvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAG9F;AACD,wBAAgB,sBAAsB,IAAI,IAAI,CAAgE;AAmB9G;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI,CAK1F;AAED,4BAA4B;AAC5B,cAAM,gBAAgB;IACpB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAGX;IACJ,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAA4B;IAC/C,MAAM,UAAS;IAEf,YAAY,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,EAO7C;IAED,OAAO,CAAC,MAAM;IA4Bd,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,OAAO;IAWf,0BAA0B;IAC1B,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,SAAS,SAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsBpG;IAED,8BAA8B;IACxB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ/B;IAED,mBAAmB;IACnB,UAAU,IAAI,IAAI,CAQjB;CACF;AAyED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAU9D;AA2CD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAInG;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,CAWpE;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAqBtD;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAItE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAK3D;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAKhG"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/daemon/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,GAAG,MAAM,UAAU,CAAC;AAK3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAGV,YAAY,EACZ,YAAY,EAEZ,YAAY,EACb,MAAM,eAAe,CAAC;AAKvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAG9F;AACD,wBAAgB,sBAAsB,IAAI,IAAI,CAAgE;AAmB9G;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI,CAK1F;AAED,4BAA4B;AAC5B,cAAM,gBAAgB;IACpB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAGX;IACJ,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAA4B;IAC/C,MAAM,UAAS;IAEf,YAAY,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,EAO7C;IAED,OAAO,CAAC,MAAM;IA4Bd,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,OAAO;IAWf,0BAA0B;IAC1B,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,SAAS,SAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsBpG;IAED,8BAA8B;IACxB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ/B;IAED,mBAAmB;IACnB,UAAU,IAAI,IAAI,CAQjB;CACF;AAiED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAU9D;AA2CD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAInG;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,CAWpE;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAqBtD;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAItE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAK3D;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAKhG"}
@@ -1,6 +1,4 @@
1
1
  import { isProcessAlive } from "@sfmc-bds/bds-tools/process-probe";
2
- import { logsDir } from "@sfmc-bds/sdk/node/config";
3
- import { spawn } from "node:child_process";
4
2
  import { randomBytes } from "node:crypto";
5
3
  import fs from "node:fs";
6
4
  import path from "node:path";
@@ -17,6 +15,7 @@ import {
17
15
  } from "./paths.js";
18
16
  import { isLogPayload } from "./protocol.js";
19
17
  import { isDaemonServer } from "./role.js";
18
+ import { launchDaemonHost } from "./host.js";
20
19
  import { fileURLToPath } from "node:url";
21
20
  import { lockOwnerAlive, maintenanceToken } from "@sfmc-bds/management/node";
22
21
  function onDaemonManagementEvent(callback) {
@@ -196,20 +195,13 @@ function spawnDaemonProcess() {
196
195
  }
197
196
  const entry = process.env.SFMC_DAEMON_ENTRY ?? fileURLToPath(new URL("../main.js", import.meta.url));
198
197
  if (!entry) throw new Error("cannot resolve sfmc entry for daemon spawn");
199
- fs.mkdirSync(logsDir(ROOT), { recursive: true });
200
- const logFd = fs.openSync(daemonLogPath(), "a");
201
- const child = spawn(process.env.SFMC_NODE_BINARY ?? process.execPath, [entry, "--daemon"], {
202
- detached: true,
203
- windowsHide: true,
204
- stdio: ["ignore", logFd, logFd],
205
- env: { ...process.env, SFMC_ROOT: ROOT },
206
- cwd: ROOT
198
+ launchDaemonHost({
199
+ node: process.env.SFMC_NODE_BINARY ?? process.execPath,
200
+ entry,
201
+ root: ROOT,
202
+ logPath: daemonLogPath(),
203
+ ...process.env.SFMC_PNPM_ENTRY ? { pnpm: process.env.SFMC_PNPM_ENTRY } : {}
207
204
  });
208
- child.unref();
209
- try {
210
- fs.closeSync(logFd);
211
- } catch {
212
- }
213
205
  }
214
206
  async function ensureDaemon() {
215
207
  if (isDaemonServer()) throw new Error("ensureDaemon must not run inside daemon server");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/daemon/client.ts"],
4
- "sourcesContent": ["/**\n * client.ts \u2014 CLI \u4FA7\u5B88\u62A4\u8FDB\u7A0B\u5BA2\u6237\u7AEF\uFF1AensureDaemon + RPC + \u65E5\u5FD7\u8BA2\u9605\n *\n * \u82E5 `.sfmc/daemon.json` \u5BF9\u5E94\u8FDB\u7A0B\u4E0D\u5728\u6216\u7BA1\u9053\u4E0D\u53EF\u8FDE\uFF0C\u5219 spawn `sfmc --daemon`\n *\uFF08detached + windowsHide\uFF09\uFF0C\u518D\u8F6E\u8BE2\u76F4\u5230 ping \u6210\u529F\u3002\n */\n\nimport { isProcessAlive } from \"@sfmc-bds/bds-tools/process-probe\";\nimport { logsDir } from \"@sfmc-bds/sdk/node/config\";\nimport { spawn } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport net from \"node:net\";\nimport process from \"node:process\";\nimport { EventEmitter } from \"node:events\";\nimport { ingestRemoteLog } from \"../logs.js\";\nimport { ROOT } from \"../runtime.js\";\nimport type { ServiceStateEvent, ServiceStatus } from \"../services.js\";\nimport {\n clearDaemonMeta,\n daemonLogPath,\n daemonMetaPath,\n readDaemonMeta,\n type DaemonMeta,\n} from \"./paths.js\";\nimport type {\n DaemonEvent,\n DaemonFrame,\n DaemonMethod,\n DaemonParams,\n DaemonRequest,\n DaemonResult,\n} from \"./protocol.js\";\nimport { isLogPayload } from \"./protocol.js\";\nimport { isDaemonServer } from \"./role.js\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ManagementEvent } from \"@sfmc-bds/management\";\nimport { lockOwnerAlive, maintenanceToken } from \"@sfmc-bds/management/node\";\n\nexport function onDaemonManagementEvent(callback: (event: ManagementEvent) => void): () => void {\n remoteStateBus.on(\"management\", callback);\n return () => { remoteStateBus.off(\"management\", callback); };\n}\nexport function disconnectDaemonClient(): void { subscriptionCount = 0; shared?.disconnect(); shared = null; }\n\n/** \u5355\u6B21 RPC \u9ED8\u8BA4\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09 */\nconst CALL_TIMEOUT_MS = 120_000;\n/** ensureDaemon \u7B49\u5F85\u5B88\u62A4\u8FDB\u7A0B\u5C31\u7EEA\u7684\u603B\u65F6\u957F */\nconst READY_TIMEOUT_MS = 15_000;\n/** \u8F6E\u8BE2\u95F4\u9694 */\nconst READY_POLL_MS = 150;\n\n/** \u5171\u4EAB\u8FDE\u63A5\uFF08\u540C\u4E00 CLI \u8FDB\u7A0B\u590D\u7528\uFF09 */\nlet shared: DaemonConnection | null = null;\n/** \u91CD\u8FDE\u671F\u95F4\u590D\u7528\u540C\u4E00\u6B21\u5EFA\u8FDE\uFF0C\u907F\u514D\u5E76\u884C\u72B6\u6001\u67E5\u8BE2\u8986\u76D6\u5DF2\u8BA2\u9605\u7684\u8FDE\u63A5\u3002 */\nlet connecting: Promise<DaemonConnection> | null = null;\n/** \u8BA2\u9605\u610F\u56FE\u5C5E\u4E8E\u5BA2\u6237\u7AEF\u4F1A\u8BDD\uFF0C\u4E0D\u80FD\u968F\u7740\u65E7 socket \u5173\u95ED\u800C\u4E22\u5931\u3002 */\nlet subscriptionCount = 0;\n\n/** \u672C\u5730\u72B6\u6001\u4E8B\u4EF6\u603B\u7EBF\uFF1A\u628A daemon \u63A8\u9001\u7684 state \u8F6C\u7ED9 CLI \u4FA7 onServiceStateChange \u8BA2\u9605\u8005 */\nconst remoteStateBus = new EventEmitter();\n\n/**\n * \u8BA2\u9605\u5B88\u62A4\u8FDB\u7A0B\u63A8\u9001\u7684\u670D\u52A1\u542F\u505C\u4E8B\u4EF6\uFF08CLI \u8FDB\u7A0B\u7528\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1AREPL \u6839\u636E running \u96C6\u5408\u5237\u65B0\u53D1\u9001\u76EE\u6807 / \u670D\u52A1\u7A97\uFF0C\u65E0\u9700\u672C\u5730\u6301\u6709 ChildProcess\u3002\n */\nexport function onRemoteServiceStateChange(fn: (ev: ServiceStateEvent) => void): () => void {\n remoteStateBus.on(\"state\", fn);\n return () => {\n remoteStateBus.off(\"state\", fn);\n };\n}\n\n/** \u5355\u6761\u8FDE\u63A5\uFF1A\u8BF7\u6C42/\u54CD\u5E94\u5339\u914D + \u53EF\u9009\u4E8B\u4EF6\u8BA2\u9605 */\nclass DaemonConnection {\n private sock: net.Socket;\n private meta: DaemonMeta;\n private buf = \"\";\n private pending = new Map<\n string,\n { resolve: (r: DaemonResult) => void; reject: (e: Error) => void; timer: ReturnType<typeof setTimeout> }\n >();\n private subscribed = false;\n private subscribing: Promise<void> | undefined;\n closed = false;\n\n constructor(sock: net.Socket, meta: DaemonMeta) {\n this.sock = sock;\n this.meta = meta;\n sock.setEncoding(\"utf8\");\n sock.on(\"data\", (chunk: string) => this.onData(chunk));\n sock.on(\"close\", () => this.onClose(new Error(\"daemon connection closed\")));\n sock.on(\"error\", (e) => this.onClose(e instanceof Error ? e : new Error(String(e))));\n }\n\n private onData(chunk: string): void {\n this.buf += chunk;\n let idx: number;\n while ((idx = this.buf.indexOf(\"\\n\")) >= 0) {\n const line = this.buf.slice(0, idx).trim();\n this.buf = this.buf.slice(idx + 1);\n if (!line) continue;\n let frame: DaemonFrame;\n try {\n frame = JSON.parse(line) as DaemonFrame;\n } catch {\n continue;\n }\n if (frame.type === \"event\") {\n this.handleEvent(frame);\n continue;\n }\n if (frame.type === \"res\") {\n const wait = this.pending.get(frame.id);\n if (!wait) continue;\n this.pending.delete(frame.id);\n clearTimeout(wait.timer);\n if (frame.ok && frame.result) wait.resolve(frame.result);\n else wait.reject(new Error(frame.error ?? \"daemon error\"));\n }\n }\n }\n\n private handleEvent(ev: DaemonEvent): void {\n if (ev.event === \"management\") { remoteStateBus.emit(\"management\", ev.payload); return; }\n if (ev.event === \"log\" && isLogPayload(ev.payload)) {\n ingestRemoteLog(ev.payload.text, ev.payload.source, ev.payload.level);\n return;\n }\n if (ev.event === \"state\") {\n remoteStateBus.emit(\"state\", ev.payload as ServiceStateEvent);\n }\n }\n\n private onClose(err: Error): void {\n if (this.closed) return;\n this.closed = true;\n for (const [, wait] of this.pending) {\n clearTimeout(wait.timer);\n wait.reject(err);\n }\n this.pending.clear();\n if (shared === this) shared = null;\n }\n\n /** \u53D1\u9001 RPC \u5E76\u7B49\u5F85\u5339\u914D id \u7684\u54CD\u5E94 */\n call(method: DaemonMethod, params?: DaemonParams, timeoutMs = CALL_TIMEOUT_MS): Promise<DaemonResult> {\n if (this.closed || this.sock.destroyed) {\n return Promise.reject(new Error(\"daemon not connected\"));\n }\n const id = randomBytes(8).toString(\"hex\");\n const req: DaemonRequest = params\n ? { id, token: this.meta.token, method, params }\n : { id, token: this.meta.token, method };\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`daemon call timeout: ${method}`));\n }, timeoutMs);\n this.pending.set(id, { resolve, reject, timer });\n try {\n this.sock.write(JSON.stringify(req) + \"\\n\");\n } catch (e) {\n this.pending.delete(id);\n clearTimeout(timer);\n reject(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n /** \u8BA2\u9605\u65E5\u5FD7\u4E0E\u72B6\u6001\u4E8B\u4EF6\uFF08\u540C\u4E00\u8FDE\u63A5\u4E0A\u7EE7\u7EED\u53D1 RPC\uFF09 */\n async subscribe(): Promise<void> {\n if (this.subscribed) return;\n if (!this.subscribing) {\n this.subscribing = this.call(\"subscribe\").then(() => {\n this.subscribed = true;\n }).finally(() => { this.subscribing = undefined; });\n }\n await this.subscribing;\n }\n\n /** \u65AD\u5F00\u8FDE\u63A5\uFF08\u4E0D\u505C\u5B88\u62A4\u8FDB\u7A0B\uFF09 */\n disconnect(): void {\n this.closed = true;\n try {\n this.sock.end();\n } catch {\n /* ignore */\n }\n if (shared === this) shared = null;\n }\n}\n\nfunction connectSocket(pipe: string, timeoutMs = 3000): Promise<net.Socket> {\n return new Promise((resolve, reject) => {\n const sock = net.createConnection(pipe);\n const timer = setTimeout(() => {\n sock.destroy();\n reject(new Error(\"connect timeout\"));\n }, timeoutMs);\n sock.once(\"connect\", () => {\n clearTimeout(timer);\n resolve(sock);\n });\n sock.once(\"error\", (e) => {\n clearTimeout(timer);\n reject(e);\n });\n });\n}\n\n/**\n * \u5C1D\u8BD5\u8FDE\u63A5\u5DF2\u6709 daemon\uFF1B\u6210\u529F\u5219\u8FD4\u56DE\u8FDE\u63A5\uFF0C\u5931\u8D25\u8FD4\u56DE null\u3002\n */\nasync function tryConnectExisting(): Promise<DaemonConnection | null> {\n const meta = readDaemonMeta();\n if (!meta) return null;\n if (!(await isProcessAlive(meta.pid))) {\n return null;\n }\n try {\n const sock = await connectSocket(meta.pipe);\n const conn = new DaemonConnection(sock, meta);\n await conn.call(\"ping\", undefined, 3000);\n return conn;\n } catch {\n return null;\n }\n}\n\n/**\n * \u62C9\u8D77\u5B88\u62A4\u8FDB\u7A0B\u5B50\u8FDB\u7A0B\uFF08detached\uFF0C\u65E5\u5FD7\u5199\u5165 daemon.log\uFF09\u3002\n * \u5165\u53E3\u811A\u672C\u590D\u7528\u5F53\u524D CLI \u7684 argv[1]\uFF08\u5373 sfmc \u4E3B\u5165\u53E3\uFF09\u3002\n */\nfunction spawnDaemonProcess(): void {\n const lockFile = path.join(ROOT, \".sfmc\", \"maintenance.lock\");\n if (fs.existsSync(lockFile)) {\n const owner = JSON.parse(fs.readFileSync(lockFile, \"utf8\")) as { pid?: number; nonce?: string };\n const token = maintenanceToken(ROOT) ?? process.env.SFMC_MAINTENANCE_TOKEN;\n const holder = token === owner.nonce;\n const pidKnown = Number.isSafeInteger(owner.pid) && (owner.pid ?? 0) > 0;\n // \u5F53\u524D\u7EF4\u62A4\u8FDB\u7A0B\u81EA\u5DF1\u62C9\u8D77\u66FF\u6362\u7528\u7684\u5B88\u62A4\u8FDB\u7A0B\u65F6 token \u76F8\u540C\uFF0C\u5141\u8BB8\u542F\u52A8\u3002\n // \u6301\u6709\u8005\u5DF2\u9000\u51FA\u5219\u4E0D\u518D\u6321\u4F4F\uFF1A\u5426\u5219\u754C\u9762\u65E0\u6CD5\u91CD\u8FDE\uFF0C\u4EFB\u52A1\u4F1A\u6C38\u8FDC\u505C\u5728\u300C\u8FDB\u884C\u4E2D\u300D\u3002\n if (!holder && (!pidKnown || lockOwnerAlive(owner.pid ?? 0))) throw new Error(\"\u5B9E\u4F8B\u6B63\u5728\u7EF4\u62A4\uFF1B\u540E\u53F0\u5207\u6362\u5B8C\u6210\u524D\u4E0D\u4F1A\u521B\u5EFA\u53E6\u4E00\u4E2A\u5B88\u62A4\u8FDB\u7A0B\");\n }\n const entry = process.env.SFMC_DAEMON_ENTRY ?? fileURLToPath(new URL(\"../main.js\", import.meta.url));\n if (!entry) throw new Error(\"cannot resolve sfmc entry for daemon spawn\");\n fs.mkdirSync(logsDir(ROOT), { recursive: true });\n const logFd = fs.openSync(daemonLogPath(), \"a\");\n const child = spawn(process.env.SFMC_NODE_BINARY ?? process.execPath, [entry, \"--daemon\"], {\n detached: true,\n windowsHide: true,\n stdio: [\"ignore\", logFd, logFd],\n env: { ...process.env, SFMC_ROOT: ROOT },\n cwd: ROOT,\n });\n child.unref();\n try {\n fs.closeSync(logFd);\n } catch {\n /* ignore */\n }\n}\n\n/**\n * \u786E\u4FDD\u5B88\u62A4\u8FDB\u7A0B\u53EF\u7528\u5E76\u8FD4\u56DE\u5171\u4EAB\u8FDE\u63A5\u3002\n * \u5B88\u62A4\u8FDB\u7A0B\u8FDB\u7A0B\u5185\u8C03\u7528\u4F1A\u629B\u9519\uFF08\u5E94\u76F4\u63A5\u8D70\u672C\u5730 cmd*\uFF09\u3002\n */\nexport async function ensureDaemon(): Promise<DaemonConnection> {\n if (isDaemonServer()) throw new Error(\"ensureDaemon must not run inside daemon server\");\n let conn = shared && !shared.closed ? shared : null;\n if (!conn) {\n connecting ??= connectDaemon().finally(() => { connecting = null; });\n conn = await connecting;\n }\n // \u7BA1\u7406\u8BF7\u6C42\u91CD\u8FDE\u6210\u529F\u540E\uFF0C\u5148\u6062\u590D\u65E5\u5FD7/\u72B6\u6001\u8BA2\u9605\uFF0C\u518D\u8FD4\u56DE\u65B0\u8FDE\u63A5\u3002\n if (subscriptionCount > 0) await conn.subscribe();\n return conn;\n}\n\nasync function connectDaemon(): Promise<DaemonConnection> {\n if (isDaemonServer()) {\n throw new Error(\"ensureDaemon must not run inside daemon server\");\n }\n if (shared && !shared.closed) return shared;\n\n let conn = await tryConnectExisting();\n if (conn) {\n shared = conn;\n return conn;\n }\n\n const existing = readDaemonMeta();\n if (existing && (await isProcessAlive(existing.pid))) {\n /* PID \u4ECD\u5728\u4F46\u6682\u65F6\u8FDE\u4E0D\u4E0A\uFF1A\u77ED\u6682\u91CD\u8BD5\uFF0C\u7981\u6B62\u518D spawn \u7B2C\u4E8C\u5957\u5B88\u62A4\u8FDB\u7A0B */\n const deadline = Date.now() + READY_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, READY_POLL_MS));\n conn = await tryConnectExisting();\n if (conn) {\n shared = conn;\n return conn;\n }\n }\n throw new Error(`daemon pid ${existing.pid} is alive but pipe is unreachable`);\n }\n\n spawnDaemonProcess();\n const deadline = Date.now() + READY_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, READY_POLL_MS));\n if (!fs.existsSync(daemonMetaPath())) continue;\n conn = await tryConnectExisting();\n if (conn) {\n shared = conn;\n return conn;\n }\n }\n throw new Error(\"failed to start or connect sfmc daemon\");\n}\n\n/**\n * \u8C03\u7528\u5B88\u62A4\u8FDB\u7A0B\u65B9\u6CD5\uFF1B\u81EA\u52A8 ensureDaemon\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1ACLI \u4FA7 status/start/stop/send/update \u7B49\u8FD0\u7EF4\u547D\u4EE4\u7684\u7EDF\u4E00\u51FA\u53E3\u3002\n */\nexport async function callDaemon(method: DaemonMethod, params?: DaemonParams): Promise<DaemonResult> {\n const conn = await ensureDaemon();\n const token = maintenanceToken(ROOT) ?? process.env.SFMC_MAINTENANCE_TOKEN;\n return conn.call(method, token ? { ...params, maintenanceToken: token } : params);\n}\n\n/**\n * \u786E\u4FDD\u5DF2\u8FDE\u63A5\u5E76\u8BA2\u9605\u8FDC\u7A0B\u65E5\u5FD7/\u72B6\u6001\uFF1B\u8FD4\u56DE\u65AD\u5F00\u51FD\u6570\uFF08\u4E0D\u505C\u5B88\u62A4\u8FDB\u7A0B\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1AREPL \u542F\u52A8\u65F6\u6302\u4E0A\u5B9E\u65F6\u65E5\u5FD7\u6D41\uFF0C\u9000\u51FA\u65F6\u53EA disconnect\u3002\n */\nexport async function ensureDaemonSubscription(): Promise<() => void> {\n subscriptionCount++;\n try { await ensureDaemon(); }\n catch (error) { subscriptionCount = Math.max(0, subscriptionCount - 1); throw error; }\n let disposed = false;\n return () => {\n if (disposed) return;\n disposed = true;\n subscriptionCount = Math.max(0, subscriptionCount - 1);\n if (subscriptionCount === 0) shared?.disconnect();\n };\n}\n\n/**\n * \u8BF7\u6C42\u5B88\u62A4\u8FDB\u7A0B stopAll \u540E\u9000\u51FA\uFF08`sfmc daemon stop`\uFF09\u3002\n */\nexport async function shutdownDaemon(): Promise<string> {\n try {\n const conn = await ensureDaemon();\n const token = maintenanceToken(ROOT) ?? process.env.SFMC_MAINTENANCE_TOKEN;\n await conn.call(\"shutdown\", token ? { maintenanceToken: token } : undefined);\n conn.disconnect();\n } catch (e) {\n const meta = readDaemonMeta();\n if (!meta || !await isProcessAlive(meta.pid)) { clearDaemonMeta(); return \"\u5B88\u62A4\u8FDB\u7A0B\u5DF2\u505C\u6B62\"; }\n throw e;\n }\n /* \u77ED\u6682\u7B49\u5F85 meta \u6E05\u7406 */\n const deadline = Date.now() + 5000;\n while (Date.now() < deadline) {\n if (!readDaemonMeta()) break;\n await new Promise((r) => setTimeout(r, 100));\n }\n const remaining = readDaemonMeta();\n if (remaining && await isProcessAlive(remaining.pid)) throw new Error(\"\u5B88\u62A4\u8FDB\u7A0B\u5C1A\u672A\u9000\u51FA\uFF0C\u4FDD\u7559\u8FDE\u63A5\u4FE1\u606F\");\n clearDaemonMeta();\n return \"\";\n}\n\n/**\n * \u4ECE\u5B88\u62A4\u8FDB\u7A0B\u62C9\u53D6\u8FD0\u884C\u6001\u884C\uFF1B\u5931\u8D25\u65F6\u8FD4\u56DE\u7A7A\u6570\u7EC4\u7531\u8C03\u7528\u65B9\u964D\u7EA7\u3002\n */\nexport async function queryRuntimeViaDaemon(): Promise<ServiceStatus[]> {\n const result = await callDaemon(\"status\");\n if (result.kind === \"status\") return result.rows;\n return [];\n}\n\n/**\n * \u4ECE\u5B88\u62A4\u8FDB\u7A0B\u62C9\u53D6\u683C\u5F0F\u5316 status \u6587\u672C\u3002\n */\nexport async function statusTextViaDaemon(): Promise<string> {\n const result = await callDaemon(\"status\");\n if (result.kind === \"status\") return result.text;\n if (result.kind === \"text\") return result.text;\n return \"\";\n}\n\n/**\n * \u901A\u7528\u300C\u8FD4\u56DE text\u300D\u7C7B RPC \u8F85\u52A9\u3002\n */\nexport async function textViaDaemon(method: DaemonMethod, params?: DaemonParams): Promise<string> {\n const result = await callDaemon(method, params);\n if (result.kind === \"text\") return result.text;\n if (result.kind === \"status\") return result.text;\n return \"\";\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * client.ts \u2014 CLI \u4FA7\u5B88\u62A4\u8FDB\u7A0B\u5BA2\u6237\u7AEF\uFF1AensureDaemon + RPC + \u65E5\u5FD7\u8BA2\u9605\n *\n * \u82E5 `.sfmc/daemon.json` \u5BF9\u5E94\u8FDB\u7A0B\u4E0D\u5728\u6216\u7BA1\u9053\u4E0D\u53EF\u8FDE\uFF0C\u5219\u5728\u767B\u5F55\u4F1A\u8BDD\u4E4B\u5916\u542F\u52A8 `sfmc --daemon`\uFF0C\n * \u518D\u8F6E\u8BE2\u76F4\u5230 ping \u6210\u529F\u3002\u7BA1\u7406\u8FDE\u63A5\u9000\u51FA\u53EA\u65AD\u5F00\u7BA1\u9053\uFF0C\u4E0D\u505C\u6B62\u5B88\u62A4\u8FDB\u7A0B\u3002\n */\n\nimport { isProcessAlive } from \"@sfmc-bds/bds-tools/process-probe\";\nimport { randomBytes } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport net from \"node:net\";\nimport process from \"node:process\";\nimport { EventEmitter } from \"node:events\";\nimport { ingestRemoteLog } from \"../logs.js\";\nimport { ROOT } from \"../runtime.js\";\nimport type { ServiceStateEvent, ServiceStatus } from \"../services.js\";\nimport {\n clearDaemonMeta,\n daemonLogPath,\n daemonMetaPath,\n readDaemonMeta,\n type DaemonMeta,\n} from \"./paths.js\";\nimport type {\n DaemonEvent,\n DaemonFrame,\n DaemonMethod,\n DaemonParams,\n DaemonRequest,\n DaemonResult,\n} from \"./protocol.js\";\nimport { isLogPayload } from \"./protocol.js\";\nimport { isDaemonServer } from \"./role.js\";\nimport { launchDaemonHost } from \"./host.js\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ManagementEvent } from \"@sfmc-bds/management\";\nimport { lockOwnerAlive, maintenanceToken } from \"@sfmc-bds/management/node\";\n\nexport function onDaemonManagementEvent(callback: (event: ManagementEvent) => void): () => void {\n remoteStateBus.on(\"management\", callback);\n return () => { remoteStateBus.off(\"management\", callback); };\n}\nexport function disconnectDaemonClient(): void { subscriptionCount = 0; shared?.disconnect(); shared = null; }\n\n/** \u5355\u6B21 RPC \u9ED8\u8BA4\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09 */\nconst CALL_TIMEOUT_MS = 120_000;\n/** ensureDaemon \u7B49\u5F85\u5B88\u62A4\u8FDB\u7A0B\u5C31\u7EEA\u7684\u603B\u65F6\u957F */\nconst READY_TIMEOUT_MS = 15_000;\n/** \u8F6E\u8BE2\u95F4\u9694 */\nconst READY_POLL_MS = 150;\n\n/** \u5171\u4EAB\u8FDE\u63A5\uFF08\u540C\u4E00 CLI \u8FDB\u7A0B\u590D\u7528\uFF09 */\nlet shared: DaemonConnection | null = null;\n/** \u91CD\u8FDE\u671F\u95F4\u590D\u7528\u540C\u4E00\u6B21\u5EFA\u8FDE\uFF0C\u907F\u514D\u5E76\u884C\u72B6\u6001\u67E5\u8BE2\u8986\u76D6\u5DF2\u8BA2\u9605\u7684\u8FDE\u63A5\u3002 */\nlet connecting: Promise<DaemonConnection> | null = null;\n/** \u8BA2\u9605\u610F\u56FE\u5C5E\u4E8E\u5BA2\u6237\u7AEF\u4F1A\u8BDD\uFF0C\u4E0D\u80FD\u968F\u7740\u65E7 socket \u5173\u95ED\u800C\u4E22\u5931\u3002 */\nlet subscriptionCount = 0;\n\n/** \u672C\u5730\u72B6\u6001\u4E8B\u4EF6\u603B\u7EBF\uFF1A\u628A daemon \u63A8\u9001\u7684 state \u8F6C\u7ED9 CLI \u4FA7 onServiceStateChange \u8BA2\u9605\u8005 */\nconst remoteStateBus = new EventEmitter();\n\n/**\n * \u8BA2\u9605\u5B88\u62A4\u8FDB\u7A0B\u63A8\u9001\u7684\u670D\u52A1\u542F\u505C\u4E8B\u4EF6\uFF08CLI \u8FDB\u7A0B\u7528\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1AREPL \u6839\u636E running \u96C6\u5408\u5237\u65B0\u53D1\u9001\u76EE\u6807 / \u670D\u52A1\u7A97\uFF0C\u65E0\u9700\u672C\u5730\u6301\u6709 ChildProcess\u3002\n */\nexport function onRemoteServiceStateChange(fn: (ev: ServiceStateEvent) => void): () => void {\n remoteStateBus.on(\"state\", fn);\n return () => {\n remoteStateBus.off(\"state\", fn);\n };\n}\n\n/** \u5355\u6761\u8FDE\u63A5\uFF1A\u8BF7\u6C42/\u54CD\u5E94\u5339\u914D + \u53EF\u9009\u4E8B\u4EF6\u8BA2\u9605 */\nclass DaemonConnection {\n private sock: net.Socket;\n private meta: DaemonMeta;\n private buf = \"\";\n private pending = new Map<\n string,\n { resolve: (r: DaemonResult) => void; reject: (e: Error) => void; timer: ReturnType<typeof setTimeout> }\n >();\n private subscribed = false;\n private subscribing: Promise<void> | undefined;\n closed = false;\n\n constructor(sock: net.Socket, meta: DaemonMeta) {\n this.sock = sock;\n this.meta = meta;\n sock.setEncoding(\"utf8\");\n sock.on(\"data\", (chunk: string) => this.onData(chunk));\n sock.on(\"close\", () => this.onClose(new Error(\"daemon connection closed\")));\n sock.on(\"error\", (e) => this.onClose(e instanceof Error ? e : new Error(String(e))));\n }\n\n private onData(chunk: string): void {\n this.buf += chunk;\n let idx: number;\n while ((idx = this.buf.indexOf(\"\\n\")) >= 0) {\n const line = this.buf.slice(0, idx).trim();\n this.buf = this.buf.slice(idx + 1);\n if (!line) continue;\n let frame: DaemonFrame;\n try {\n frame = JSON.parse(line) as DaemonFrame;\n } catch {\n continue;\n }\n if (frame.type === \"event\") {\n this.handleEvent(frame);\n continue;\n }\n if (frame.type === \"res\") {\n const wait = this.pending.get(frame.id);\n if (!wait) continue;\n this.pending.delete(frame.id);\n clearTimeout(wait.timer);\n if (frame.ok && frame.result) wait.resolve(frame.result);\n else wait.reject(new Error(frame.error ?? \"daemon error\"));\n }\n }\n }\n\n private handleEvent(ev: DaemonEvent): void {\n if (ev.event === \"management\") { remoteStateBus.emit(\"management\", ev.payload); return; }\n if (ev.event === \"log\" && isLogPayload(ev.payload)) {\n ingestRemoteLog(ev.payload.text, ev.payload.source, ev.payload.level);\n return;\n }\n if (ev.event === \"state\") {\n remoteStateBus.emit(\"state\", ev.payload as ServiceStateEvent);\n }\n }\n\n private onClose(err: Error): void {\n if (this.closed) return;\n this.closed = true;\n for (const [, wait] of this.pending) {\n clearTimeout(wait.timer);\n wait.reject(err);\n }\n this.pending.clear();\n if (shared === this) shared = null;\n }\n\n /** \u53D1\u9001 RPC \u5E76\u7B49\u5F85\u5339\u914D id \u7684\u54CD\u5E94 */\n call(method: DaemonMethod, params?: DaemonParams, timeoutMs = CALL_TIMEOUT_MS): Promise<DaemonResult> {\n if (this.closed || this.sock.destroyed) {\n return Promise.reject(new Error(\"daemon not connected\"));\n }\n const id = randomBytes(8).toString(\"hex\");\n const req: DaemonRequest = params\n ? { id, token: this.meta.token, method, params }\n : { id, token: this.meta.token, method };\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`daemon call timeout: ${method}`));\n }, timeoutMs);\n this.pending.set(id, { resolve, reject, timer });\n try {\n this.sock.write(JSON.stringify(req) + \"\\n\");\n } catch (e) {\n this.pending.delete(id);\n clearTimeout(timer);\n reject(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n /** \u8BA2\u9605\u65E5\u5FD7\u4E0E\u72B6\u6001\u4E8B\u4EF6\uFF08\u540C\u4E00\u8FDE\u63A5\u4E0A\u7EE7\u7EED\u53D1 RPC\uFF09 */\n async subscribe(): Promise<void> {\n if (this.subscribed) return;\n if (!this.subscribing) {\n this.subscribing = this.call(\"subscribe\").then(() => {\n this.subscribed = true;\n }).finally(() => { this.subscribing = undefined; });\n }\n await this.subscribing;\n }\n\n /** \u65AD\u5F00\u8FDE\u63A5\uFF08\u4E0D\u505C\u5B88\u62A4\u8FDB\u7A0B\uFF09 */\n disconnect(): void {\n this.closed = true;\n try {\n this.sock.end();\n } catch {\n /* ignore */\n }\n if (shared === this) shared = null;\n }\n}\n\nfunction connectSocket(pipe: string, timeoutMs = 3000): Promise<net.Socket> {\n return new Promise((resolve, reject) => {\n const sock = net.createConnection(pipe);\n const timer = setTimeout(() => {\n sock.destroy();\n reject(new Error(\"connect timeout\"));\n }, timeoutMs);\n sock.once(\"connect\", () => {\n clearTimeout(timer);\n resolve(sock);\n });\n sock.once(\"error\", (e) => {\n clearTimeout(timer);\n reject(e);\n });\n });\n}\n\n/**\n * \u5C1D\u8BD5\u8FDE\u63A5\u5DF2\u6709 daemon\uFF1B\u6210\u529F\u5219\u8FD4\u56DE\u8FDE\u63A5\uFF0C\u5931\u8D25\u8FD4\u56DE null\u3002\n */\nasync function tryConnectExisting(): Promise<DaemonConnection | null> {\n const meta = readDaemonMeta();\n if (!meta) return null;\n if (!(await isProcessAlive(meta.pid))) {\n return null;\n }\n try {\n const sock = await connectSocket(meta.pipe);\n const conn = new DaemonConnection(sock, meta);\n await conn.call(\"ping\", undefined, 3000);\n return conn;\n } catch {\n return null;\n }\n}\n\n/**\n * \u62C9\u8D77\u5B88\u62A4\u8FDB\u7A0B\u3002\u5165\u53E3\u811A\u672C\u590D\u7528\u5F53\u524D CLI \u7684 argv[1]\uFF08\u5373 sfmc \u4E3B\u5165\u53E3\uFF09\u3002\n * \u5B9E\u9645\u542F\u52A8\u4EA4\u7ED9 host\uFF1ASSH \u4F1A\u8BDD\u91CC\u4E0D\u4F1A\u628A\u5B88\u62A4\u8FDB\u7A0B\u7559\u5728\u8FD9\u6B21\u767B\u5F55\u4E2D\u3002\n */\nfunction spawnDaemonProcess(): void {\n const lockFile = path.join(ROOT, \".sfmc\", \"maintenance.lock\");\n if (fs.existsSync(lockFile)) {\n const owner = JSON.parse(fs.readFileSync(lockFile, \"utf8\")) as { pid?: number; nonce?: string };\n const token = maintenanceToken(ROOT) ?? process.env.SFMC_MAINTENANCE_TOKEN;\n const holder = token === owner.nonce;\n const pidKnown = Number.isSafeInteger(owner.pid) && (owner.pid ?? 0) > 0;\n // \u5F53\u524D\u7EF4\u62A4\u8FDB\u7A0B\u81EA\u5DF1\u62C9\u8D77\u66FF\u6362\u7528\u7684\u5B88\u62A4\u8FDB\u7A0B\u65F6 token \u76F8\u540C\uFF0C\u5141\u8BB8\u542F\u52A8\u3002\n // \u6301\u6709\u8005\u5DF2\u9000\u51FA\u5219\u4E0D\u518D\u6321\u4F4F\uFF1A\u5426\u5219\u754C\u9762\u65E0\u6CD5\u91CD\u8FDE\uFF0C\u4EFB\u52A1\u4F1A\u6C38\u8FDC\u505C\u5728\u300C\u8FDB\u884C\u4E2D\u300D\u3002\n if (!holder && (!pidKnown || lockOwnerAlive(owner.pid ?? 0))) throw new Error(\"\u5B9E\u4F8B\u6B63\u5728\u7EF4\u62A4\uFF1B\u540E\u53F0\u5207\u6362\u5B8C\u6210\u524D\u4E0D\u4F1A\u521B\u5EFA\u53E6\u4E00\u4E2A\u5B88\u62A4\u8FDB\u7A0B\");\n }\n const entry = process.env.SFMC_DAEMON_ENTRY ?? fileURLToPath(new URL(\"../main.js\", import.meta.url));\n if (!entry) throw new Error(\"cannot resolve sfmc entry for daemon spawn\");\n launchDaemonHost({\n node: process.env.SFMC_NODE_BINARY ?? process.execPath,\n entry,\n root: ROOT,\n logPath: daemonLogPath(),\n ...(process.env.SFMC_PNPM_ENTRY ? { pnpm: process.env.SFMC_PNPM_ENTRY } : {}),\n });\n}\n\n/**\n * \u786E\u4FDD\u5B88\u62A4\u8FDB\u7A0B\u53EF\u7528\u5E76\u8FD4\u56DE\u5171\u4EAB\u8FDE\u63A5\u3002\n * \u5B88\u62A4\u8FDB\u7A0B\u8FDB\u7A0B\u5185\u8C03\u7528\u4F1A\u629B\u9519\uFF08\u5E94\u76F4\u63A5\u8D70\u672C\u5730 cmd*\uFF09\u3002\n */\nexport async function ensureDaemon(): Promise<DaemonConnection> {\n if (isDaemonServer()) throw new Error(\"ensureDaemon must not run inside daemon server\");\n let conn = shared && !shared.closed ? shared : null;\n if (!conn) {\n connecting ??= connectDaemon().finally(() => { connecting = null; });\n conn = await connecting;\n }\n // \u7BA1\u7406\u8BF7\u6C42\u91CD\u8FDE\u6210\u529F\u540E\uFF0C\u5148\u6062\u590D\u65E5\u5FD7/\u72B6\u6001\u8BA2\u9605\uFF0C\u518D\u8FD4\u56DE\u65B0\u8FDE\u63A5\u3002\n if (subscriptionCount > 0) await conn.subscribe();\n return conn;\n}\n\nasync function connectDaemon(): Promise<DaemonConnection> {\n if (isDaemonServer()) {\n throw new Error(\"ensureDaemon must not run inside daemon server\");\n }\n if (shared && !shared.closed) return shared;\n\n let conn = await tryConnectExisting();\n if (conn) {\n shared = conn;\n return conn;\n }\n\n const existing = readDaemonMeta();\n if (existing && (await isProcessAlive(existing.pid))) {\n /* PID \u4ECD\u5728\u4F46\u6682\u65F6\u8FDE\u4E0D\u4E0A\uFF1A\u77ED\u6682\u91CD\u8BD5\uFF0C\u7981\u6B62\u518D spawn \u7B2C\u4E8C\u5957\u5B88\u62A4\u8FDB\u7A0B */\n const deadline = Date.now() + READY_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, READY_POLL_MS));\n conn = await tryConnectExisting();\n if (conn) {\n shared = conn;\n return conn;\n }\n }\n throw new Error(`daemon pid ${existing.pid} is alive but pipe is unreachable`);\n }\n\n spawnDaemonProcess();\n const deadline = Date.now() + READY_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, READY_POLL_MS));\n if (!fs.existsSync(daemonMetaPath())) continue;\n conn = await tryConnectExisting();\n if (conn) {\n shared = conn;\n return conn;\n }\n }\n throw new Error(\"failed to start or connect sfmc daemon\");\n}\n\n/**\n * \u8C03\u7528\u5B88\u62A4\u8FDB\u7A0B\u65B9\u6CD5\uFF1B\u81EA\u52A8 ensureDaemon\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1ACLI \u4FA7 status/start/stop/send/update \u7B49\u8FD0\u7EF4\u547D\u4EE4\u7684\u7EDF\u4E00\u51FA\u53E3\u3002\n */\nexport async function callDaemon(method: DaemonMethod, params?: DaemonParams): Promise<DaemonResult> {\n const conn = await ensureDaemon();\n const token = maintenanceToken(ROOT) ?? process.env.SFMC_MAINTENANCE_TOKEN;\n return conn.call(method, token ? { ...params, maintenanceToken: token } : params);\n}\n\n/**\n * \u786E\u4FDD\u5DF2\u8FDE\u63A5\u5E76\u8BA2\u9605\u8FDC\u7A0B\u65E5\u5FD7/\u72B6\u6001\uFF1B\u8FD4\u56DE\u65AD\u5F00\u51FD\u6570\uFF08\u4E0D\u505C\u5B88\u62A4\u8FDB\u7A0B\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1AREPL \u542F\u52A8\u65F6\u6302\u4E0A\u5B9E\u65F6\u65E5\u5FD7\u6D41\uFF0C\u9000\u51FA\u65F6\u53EA disconnect\u3002\n */\nexport async function ensureDaemonSubscription(): Promise<() => void> {\n subscriptionCount++;\n try { await ensureDaemon(); }\n catch (error) { subscriptionCount = Math.max(0, subscriptionCount - 1); throw error; }\n let disposed = false;\n return () => {\n if (disposed) return;\n disposed = true;\n subscriptionCount = Math.max(0, subscriptionCount - 1);\n if (subscriptionCount === 0) shared?.disconnect();\n };\n}\n\n/**\n * \u8BF7\u6C42\u5B88\u62A4\u8FDB\u7A0B stopAll \u540E\u9000\u51FA\uFF08`sfmc daemon stop`\uFF09\u3002\n */\nexport async function shutdownDaemon(): Promise<string> {\n try {\n const conn = await ensureDaemon();\n const token = maintenanceToken(ROOT) ?? process.env.SFMC_MAINTENANCE_TOKEN;\n await conn.call(\"shutdown\", token ? { maintenanceToken: token } : undefined);\n conn.disconnect();\n } catch (e) {\n const meta = readDaemonMeta();\n if (!meta || !await isProcessAlive(meta.pid)) { clearDaemonMeta(); return \"\u5B88\u62A4\u8FDB\u7A0B\u5DF2\u505C\u6B62\"; }\n throw e;\n }\n /* \u77ED\u6682\u7B49\u5F85 meta \u6E05\u7406 */\n const deadline = Date.now() + 5000;\n while (Date.now() < deadline) {\n if (!readDaemonMeta()) break;\n await new Promise((r) => setTimeout(r, 100));\n }\n const remaining = readDaemonMeta();\n if (remaining && await isProcessAlive(remaining.pid)) throw new Error(\"\u5B88\u62A4\u8FDB\u7A0B\u5C1A\u672A\u9000\u51FA\uFF0C\u4FDD\u7559\u8FDE\u63A5\u4FE1\u606F\");\n clearDaemonMeta();\n return \"\";\n}\n\n/**\n * \u4ECE\u5B88\u62A4\u8FDB\u7A0B\u62C9\u53D6\u8FD0\u884C\u6001\u884C\uFF1B\u5931\u8D25\u65F6\u8FD4\u56DE\u7A7A\u6570\u7EC4\u7531\u8C03\u7528\u65B9\u964D\u7EA7\u3002\n */\nexport async function queryRuntimeViaDaemon(): Promise<ServiceStatus[]> {\n const result = await callDaemon(\"status\");\n if (result.kind === \"status\") return result.rows;\n return [];\n}\n\n/**\n * \u4ECE\u5B88\u62A4\u8FDB\u7A0B\u62C9\u53D6\u683C\u5F0F\u5316 status \u6587\u672C\u3002\n */\nexport async function statusTextViaDaemon(): Promise<string> {\n const result = await callDaemon(\"status\");\n if (result.kind === \"status\") return result.text;\n if (result.kind === \"text\") return result.text;\n return \"\";\n}\n\n/**\n * \u901A\u7528\u300C\u8FD4\u56DE text\u300D\u7C7B RPC \u8F85\u52A9\u3002\n */\nexport async function textViaDaemon(method: DaemonMethod, params?: DaemonParams): Promise<string> {\n const result = await callDaemon(method, params);\n if (result.kind === \"text\") return result.text;\n if (result.kind === \"status\") return result.text;\n return \"\";\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["deadline"]
7
7
  }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * host.ts — 在登录会话之外启动守护进程
3
+ *
4
+ * 使用场景:桌面端通过 SSH 执行 `manage --stdio`,这条进程只是管理通道。
5
+ * Windows OpenSSH 会在会话结束时关掉作业里的全部进程;systemd 在登出时也会结束本次登录的进程。
6
+ * `detached` 仍留在该范围内,所以守护进程必须由会话外的服务创建(WMI 或 systemd --user)。
7
+ * 会话内启动只作为本机、且没有上述机制时的退路;SSH 会话里启动失败则直接报错,避免断开连接时停服。
8
+ */
9
+ /** 交给会话外宿主的启动参数。路径都来自当前管理进程已经解析好的运行时。 */
10
+ export interface DaemonHostSpec {
11
+ /** Node 可执行文件绝对路径 */
12
+ node: string;
13
+ /** 守护进程入口(launcher 或 sfmc 主文件) */
14
+ entry: string;
15
+ /** 实例根目录,同时作为工作目录 */
16
+ root: string;
17
+ /** 守护进程标准输出和标准错误追加到这个文件 */
18
+ logPath: string;
19
+ /** 可选的 pnpm 入口,供之后的维护任务使用 */
20
+ pnpm?: string;
21
+ }
22
+ /**
23
+ * 启动守护进程,并尽量让它活在当前登录会话之外。
24
+ * 使用场景:管理连接第一次发现没有守护进程时调用。已有守护进程不会走到这里。
25
+ */
26
+ export declare function launchDaemonHost(spec: DaemonHostSpec): void;
27
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/daemon/host.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,yCAAyC;AACzC,MAAM,WAAW,cAAc;IAC7B,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkLD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAe3D"}
@@ -0,0 +1,178 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { randomBytes, createHash } from "node:crypto";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ function insideSshSession() {
7
+ return Boolean(process.env.SSH_CONNECTION || process.env.SSH_CLIENT);
8
+ }
9
+ function currentUser() {
10
+ if (process.env.USER) return process.env.USER;
11
+ if (process.env.LOGNAME) return process.env.LOGNAME;
12
+ try {
13
+ return os.userInfo().username;
14
+ } catch {
15
+ return "";
16
+ }
17
+ }
18
+ function shellQuote(text) {
19
+ return `'${text.replace(/'/g, `'\\''`)}'`;
20
+ }
21
+ function psLiteral(text) {
22
+ return `'${text.replace(/'/g, "''")}'`;
23
+ }
24
+ function carriedEnv(spec, keys) {
25
+ const env = {
26
+ SFMC_ROOT: spec.root,
27
+ SFMC_NODE_BINARY: spec.node,
28
+ SFMC_DAEMON_ENTRY: spec.entry
29
+ };
30
+ if (spec.pnpm) env.SFMC_PNPM_ENTRY = spec.pnpm;
31
+ for (const key of keys) {
32
+ const value = process.env[key];
33
+ if (value) env[key] = value;
34
+ }
35
+ return env;
36
+ }
37
+ function failureText(result) {
38
+ const detail = `${result.stderr || ""}${result.stdout || ""}${result.error?.message || ""}`.trim();
39
+ return detail.slice(-500);
40
+ }
41
+ function launchDetached(spec) {
42
+ const logFd = fs.openSync(spec.logPath, "a");
43
+ const child = spawn(spec.node, [spec.entry, "--daemon"], {
44
+ detached: true,
45
+ windowsHide: true,
46
+ stdio: ["ignore", logFd, logFd],
47
+ cwd: spec.root,
48
+ env: { ...process.env, ...carriedEnv(spec, []) }
49
+ });
50
+ child.unref();
51
+ try {
52
+ fs.closeSync(logFd);
53
+ } catch {
54
+ }
55
+ }
56
+ function launchWindowsOutsideSession(spec) {
57
+ const env = carriedEnv(spec, ["PATH", "PATHEXT", "SystemRoot", "USERNAME", "USERPROFILE", "APPDATA", "LOCALAPPDATA", "TEMP", "TMP"]);
58
+ const assignments = Object.entries(env).map(([key, value]) => `$env:${key} = ${psLiteral(value)}`);
59
+ const log = psLiteral(spec.logPath);
60
+ const script = [
61
+ "$ErrorActionPreference = 'Stop'",
62
+ `$env:SFMC_DAEMON_LOG = ${log}`,
63
+ ...assignments,
64
+ "New-Item -ItemType Directory -Force -Path (Split-Path -Parent $env:SFMC_DAEMON_LOG) | Out-Null",
65
+ "Set-Location -LiteralPath $env:SFMC_ROOT",
66
+ // StreamWriter(path, append) 默认 FileShare.Read,会挡住下一次平台校验里的追加打开。
67
+ "$mode = [System.IO.FileMode]::Append",
68
+ "$access = [System.IO.FileAccess]::Write",
69
+ "$share = [System.IO.FileShare]::ReadWrite",
70
+ "$stream = New-Object System.IO.FileStream($env:SFMC_DAEMON_LOG, $mode, $access, $share)",
71
+ "$inner = New-Object System.IO.StreamWriter($stream)",
72
+ "$inner.AutoFlush = $true",
73
+ "$script:writer = [System.IO.TextWriter]::Synchronized($inner)",
74
+ "Remove-Item Env:SFMC_DAEMON_LOG",
75
+ "$psi = New-Object System.Diagnostics.ProcessStartInfo",
76
+ "$psi.FileName = $env:SFMC_NODE_BINARY",
77
+ "$psi.Arguments = ([char]34) + $env:SFMC_DAEMON_ENTRY + ([char]34) + ' --daemon'",
78
+ "$psi.WorkingDirectory = $env:SFMC_ROOT",
79
+ "$psi.UseShellExecute = $false",
80
+ "$psi.CreateNoWindow = $true",
81
+ "$psi.RedirectStandardOutput = $true",
82
+ "$psi.RedirectStandardError = $true",
83
+ "$proc = New-Object System.Diagnostics.Process",
84
+ "$proc.StartInfo = $psi",
85
+ "$onLine = { param($sender, $lineEvent) if ($null -ne $lineEvent.Data) { $script:writer.WriteLine($lineEvent.Data) } }",
86
+ "$proc.add_OutputDataReceived($onLine)",
87
+ "$proc.add_ErrorDataReceived({ param($sender, $lineEvent) if ($null -ne $lineEvent.Data) { $script:writer.WriteLine($lineEvent.Data) } })",
88
+ "[void]$proc.Start()",
89
+ "$proc.BeginOutputReadLine()",
90
+ "$proc.BeginErrorReadLine()",
91
+ "try { $proc.WaitForExit() } finally { if ($script:writer) { $script:writer.Dispose() } }"
92
+ ];
93
+ const commandLine = `powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand ${Buffer.from(script.join("\n"), "utf16le").toString("base64")}`;
94
+ const run = (hide) => {
95
+ const startup = hide ? "$startup = New-CimInstance -ClassName Win32_ProcessStartup -ClientOnly -Property @{ ShowWindow = 0 }\n" : "";
96
+ const invoke = [
97
+ "$ErrorActionPreference = 'Stop'",
98
+ startup.trimEnd(),
99
+ `$result = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = ${psLiteral(commandLine)}; CurrentDirectory = ${psLiteral(spec.root)}${hide ? "; ProcessStartupInformation = $startup" : ""} }`,
100
+ 'if ($result.ReturnValue -ne 0) { Write-Error "Win32_Process.Create $($result.ReturnValue)"; exit 1 }'
101
+ ].filter(Boolean).join("\n");
102
+ return spawnSync("powershell.exe", ["-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(invoke, "utf16le").toString("base64")], {
103
+ encoding: "utf8",
104
+ timeout: 3e4,
105
+ windowsHide: true
106
+ });
107
+ };
108
+ const hidden = run(true);
109
+ if (hidden.status === 0) return null;
110
+ const visible = run(false);
111
+ if (visible.status === 0) return null;
112
+ return failureText(visible) || failureText(hidden) || "Win32_Process.Create \u5931\u8D25";
113
+ }
114
+ function userBusEnv() {
115
+ const env = { ...process.env, SYSTEMD_ASK_PASSWORD: "0" };
116
+ const uid = process.getuid?.();
117
+ if (uid !== void 0 && !env.XDG_RUNTIME_DIR) env.XDG_RUNTIME_DIR = `/run/user/${uid}`;
118
+ if (env.XDG_RUNTIME_DIR && !env.DBUS_SESSION_BUS_ADDRESS && fs.existsSync(`${env.XDG_RUNTIME_DIR}/bus`)) {
119
+ env.DBUS_SESSION_BUS_ADDRESS = `unix:path=${env.XDG_RUNTIME_DIR}/bus`;
120
+ }
121
+ return env;
122
+ }
123
+ function writePosixHost(spec) {
124
+ const file = path.join(spec.root, ".sfmc", "daemon-host.sh");
125
+ fs.mkdirSync(path.dirname(file), { recursive: true });
126
+ const exports = Object.entries(carriedEnv(spec, ["PATH", "HOME", "USER", "LANG", "LC_ALL", "TMPDIR"])).map(([key, value]) => `export ${key}=${shellQuote(value)}`);
127
+ const body = [
128
+ "#!/bin/sh",
129
+ "set -eu",
130
+ `cd ${shellQuote(spec.root)}`,
131
+ ...exports,
132
+ `exec ${shellQuote(spec.node)} ${shellQuote(spec.entry)} --daemon >> ${shellQuote(spec.logPath)} 2>&1`,
133
+ ""
134
+ ].join("\n");
135
+ fs.writeFileSync(file, body, { encoding: "utf8", mode: 448 });
136
+ fs.chmodSync(file, 448);
137
+ return file;
138
+ }
139
+ function launchSystemdUser(spec) {
140
+ const user = currentUser();
141
+ if (!user) return "\u65E0\u6CD5\u786E\u5B9A\u5F53\u524D\u7528\u6237\uFF0C\u4E0D\u80FD\u653E\u5230 systemd \u7528\u6237\u670D\u52A1\u91CC";
142
+ const ask = { encoding: "utf8", timeout: 15e3, env: userBusEnv() };
143
+ const enable = spawnSync("loginctl", ["enable-linger", user], ask);
144
+ const show = spawnSync("loginctl", ["show-user", user, "-p", "Linger", "--value"], ask);
145
+ if (show.stdout?.trim() !== "yes") {
146
+ const detail = failureText(enable);
147
+ return `\u7528\u6237 ${user} \u6CA1\u6709 linger\uFF0C\u767B\u51FA\u65F6\u7CFB\u7EDF\u4F1A\u7ED3\u675F\u672C\u6B21\u767B\u5F55\u4E2D\u7684\u8FDB\u7A0B\u3002\u8BF7\u5148\u6267\u884C loginctl enable-linger ${user}\uFF0C\u6216\u5B89\u88C5\u5F00\u673A\u670D\u52A1\u3002${detail ? ` ${detail}` : ""}`;
148
+ }
149
+ const script = writePosixHost(spec);
150
+ const unit = `sfmc-${createHash("sha256").update(spec.root).digest("hex").slice(0, 8)}-${randomBytes(3).toString("hex")}`;
151
+ const result = spawnSync("systemd-run", ["--user", "--collect", `--unit=${unit}`, script], {
152
+ encoding: "utf8",
153
+ timeout: 2e4,
154
+ env: userBusEnv()
155
+ });
156
+ if (result.status === 0) return null;
157
+ return failureText(result) || "systemd-run --user \u5931\u8D25";
158
+ }
159
+ function launchDaemonHost(spec) {
160
+ fs.mkdirSync(path.dirname(spec.logPath), { recursive: true });
161
+ if (process.platform === "win32") {
162
+ const failure = launchWindowsOutsideSession(spec);
163
+ if (!failure) return;
164
+ if (insideSshSession()) throw new Error(`\u65E0\u6CD5\u5728 SSH \u4F1A\u8BDD\u4E4B\u5916\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B\uFF0C\u5DF2\u53D6\u6D88\u542F\u52A8\uFF0C\u907F\u514D\u65AD\u5F00\u8FDE\u63A5\u65F6\u505C\u670D\u3002${failure}`);
165
+ launchDetached(spec);
166
+ return;
167
+ }
168
+ if (fs.existsSync("/run/systemd/system")) {
169
+ const failure = launchSystemdUser(spec);
170
+ if (!failure) return;
171
+ if (insideSshSession()) throw new Error(`\u65E0\u6CD5\u5728 SSH \u4F1A\u8BDD\u4E4B\u5916\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B\uFF0C\u5DF2\u53D6\u6D88\u542F\u52A8\uFF0C\u907F\u514D\u65AD\u5F00\u8FDE\u63A5\u65F6\u505C\u670D\u3002${failure}`);
172
+ }
173
+ launchDetached(spec);
174
+ }
175
+ export {
176
+ launchDaemonHost
177
+ };
178
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/daemon/host.ts"],
4
+ "sourcesContent": ["/**\n * host.ts \u2014 \u5728\u767B\u5F55\u4F1A\u8BDD\u4E4B\u5916\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B\n *\n * \u4F7F\u7528\u573A\u666F\uFF1A\u684C\u9762\u7AEF\u901A\u8FC7 SSH \u6267\u884C `manage --stdio`\uFF0C\u8FD9\u6761\u8FDB\u7A0B\u53EA\u662F\u7BA1\u7406\u901A\u9053\u3002\n * Windows OpenSSH \u4F1A\u5728\u4F1A\u8BDD\u7ED3\u675F\u65F6\u5173\u6389\u4F5C\u4E1A\u91CC\u7684\u5168\u90E8\u8FDB\u7A0B\uFF1Bsystemd \u5728\u767B\u51FA\u65F6\u4E5F\u4F1A\u7ED3\u675F\u672C\u6B21\u767B\u5F55\u7684\u8FDB\u7A0B\u3002\n * `detached` \u4ECD\u7559\u5728\u8BE5\u8303\u56F4\u5185\uFF0C\u6240\u4EE5\u5B88\u62A4\u8FDB\u7A0B\u5FC5\u987B\u7531\u4F1A\u8BDD\u5916\u7684\u670D\u52A1\u521B\u5EFA\uFF08WMI \u6216 systemd --user\uFF09\u3002\n * \u4F1A\u8BDD\u5185\u542F\u52A8\u53EA\u4F5C\u4E3A\u672C\u673A\u3001\u4E14\u6CA1\u6709\u4E0A\u8FF0\u673A\u5236\u65F6\u7684\u9000\u8DEF\uFF1BSSH \u4F1A\u8BDD\u91CC\u542F\u52A8\u5931\u8D25\u5219\u76F4\u63A5\u62A5\u9519\uFF0C\u907F\u514D\u65AD\u5F00\u8FDE\u63A5\u65F6\u505C\u670D\u3002\n */\n\nimport { spawn, spawnSync } from \"node:child_process\";\nimport { randomBytes, createHash } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\n/** \u4EA4\u7ED9\u4F1A\u8BDD\u5916\u5BBF\u4E3B\u7684\u542F\u52A8\u53C2\u6570\u3002\u8DEF\u5F84\u90FD\u6765\u81EA\u5F53\u524D\u7BA1\u7406\u8FDB\u7A0B\u5DF2\u7ECF\u89E3\u6790\u597D\u7684\u8FD0\u884C\u65F6\u3002 */\nexport interface DaemonHostSpec {\n /** Node \u53EF\u6267\u884C\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84 */\n node: string;\n /** \u5B88\u62A4\u8FDB\u7A0B\u5165\u53E3\uFF08launcher \u6216 sfmc \u4E3B\u6587\u4EF6\uFF09 */\n entry: string;\n /** \u5B9E\u4F8B\u6839\u76EE\u5F55\uFF0C\u540C\u65F6\u4F5C\u4E3A\u5DE5\u4F5C\u76EE\u5F55 */\n root: string;\n /** \u5B88\u62A4\u8FDB\u7A0B\u6807\u51C6\u8F93\u51FA\u548C\u6807\u51C6\u9519\u8BEF\u8FFD\u52A0\u5230\u8FD9\u4E2A\u6587\u4EF6 */\n logPath: string;\n /** \u53EF\u9009\u7684 pnpm \u5165\u53E3\uFF0C\u4F9B\u4E4B\u540E\u7684\u7EF4\u62A4\u4EFB\u52A1\u4F7F\u7528 */\n pnpm?: string;\n}\n\n/** \u5F53\u524D\u8FDB\u7A0B\u662F\u5426\u7531 OpenSSH \u62C9\u8D77\u3002\u8FD9\u79CD\u4F1A\u8BDD\u7ED3\u675F\u65F6\uFF0C\u91CC\u9762\u7684\u8FDB\u7A0B\u4F1A\u88AB\u4E00\u8D77\u56DE\u6536\u3002 */\nfunction insideSshSession(): boolean {\n return Boolean(process.env.SSH_CONNECTION || process.env.SSH_CLIENT);\n}\n\nfunction currentUser(): string {\n if (process.env.USER) return process.env.USER;\n if (process.env.LOGNAME) return process.env.LOGNAME;\n try { return os.userInfo().username; } catch { return \"\"; }\n}\n\nfunction shellQuote(text: string): string {\n return `'${text.replace(/'/g, `'\\\\''`)}'`;\n}\n\nfunction psLiteral(text: string): string {\n return `'${text.replace(/'/g, \"''\")}'`;\n}\n\n/** \u4ECE\u5F53\u524D\u7BA1\u7406\u8FDB\u7A0B\u5E26\u4E0A\u7528\u6237\u73AF\u5883\uFF0C\u4E0D\u5E26 SSH_CONNECTION\uFF0C\u907F\u514D\u5B88\u62A4\u8FDB\u7A0B\u628A\u81EA\u5DF1\u5F53\u6210\u8FD9\u6B21\u767B\u5F55\u3002 */\nfunction carriedEnv(spec: DaemonHostSpec, keys: readonly string[]): Record<string, string> {\n const env: Record<string, string> = {\n SFMC_ROOT: spec.root,\n SFMC_NODE_BINARY: spec.node,\n SFMC_DAEMON_ENTRY: spec.entry,\n };\n if (spec.pnpm) env.SFMC_PNPM_ENTRY = spec.pnpm;\n for (const key of keys) {\n const value = process.env[key];\n if (value) env[key] = value;\n }\n return env;\n}\n\nfunction failureText(result: ReturnType<typeof spawnSync>): string {\n const detail = `${result.stderr || \"\"}${result.stdout || \"\"}${result.error?.message || \"\"}`.trim();\n return detail.slice(-500);\n}\n\n/**\n * \u672C\u673A\u9000\u8DEF\uFF1A\u7236\u8FDB\u7A0B\u9000\u51FA\u540E\u5B50\u8FDB\u7A0B\u8FD8\u80FD\u7559\u4E0B\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u6CA1\u6709 SSH \u4F1A\u8BDD\uFF0C\u4E14 WMI / systemd \u7528\u6237\u670D\u52A1\u4E0D\u53EF\u7528\u3002SSH \u91CC\u4E0D\u8D70\u8FD9\u91CC\u3002\n */\nfunction launchDetached(spec: DaemonHostSpec): void {\n const logFd = fs.openSync(spec.logPath, \"a\");\n const child = spawn(spec.node, [spec.entry, \"--daemon\"], {\n detached: true,\n windowsHide: true,\n stdio: [\"ignore\", logFd, logFd],\n cwd: spec.root,\n env: { ...process.env, ...carriedEnv(spec, []) },\n });\n child.unref();\n try { fs.closeSync(logFd); } catch { /* \u65E5\u5FD7\u53E5\u67C4\u5DF2\u4EA4\u7ED9\u5B50\u8FDB\u7A0B */ }\n}\n\n/**\n * \u7531 WMI \u521B\u5EFA\u8FDB\u7A0B\uFF0C\u4F7F\u5B88\u62A4\u8FDB\u7A0B\u4E0D\u5C5E\u4E8E OpenSSH \u7684\u4F5C\u4E1A\u5BF9\u8C61\u3002\n * \u8FD4\u56DE null \u8868\u793A\u5DF2\u7ECF\u542F\u52A8\uFF1B\u8FD4\u56DE\u5B57\u7B26\u4E32\u662F\u5931\u8D25\u539F\u56E0\u3002\n */\nfunction launchWindowsOutsideSession(spec: DaemonHostSpec): string | null {\n const env = carriedEnv(spec, [\"PATH\", \"PATHEXT\", \"SystemRoot\", \"USERNAME\", \"USERPROFILE\", \"APPDATA\", \"LOCALAPPDATA\", \"TEMP\", \"TMP\"]);\n const assignments = Object.entries(env).map(([key, value]) => `$env:${key} = ${psLiteral(value)}`);\n const log = psLiteral(spec.logPath);\n // \u4E8B\u4EF6\u56DE\u8C03\u8DD1\u5728\u522B\u7684\u7EBF\u7A0B\uFF0C\u7528\u811A\u672C\u4F5C\u7528\u57DF\u4FDD\u4F4F\u65E5\u5FD7\u5199\u5165\u5668\u3002\u5165\u53E3\u53C2\u6570\u7528\u5B57\u7B26\u7801\u62FC\u5F15\u53F7\uFF0C\u907F\u514D\u8F6C\u4E49\u628A\u8DEF\u5F84\u622A\u65AD\u3002\n const script = [\n \"$ErrorActionPreference = 'Stop'\",\n `$env:SFMC_DAEMON_LOG = ${log}`,\n ...assignments,\n \"New-Item -ItemType Directory -Force -Path (Split-Path -Parent $env:SFMC_DAEMON_LOG) | Out-Null\",\n \"Set-Location -LiteralPath $env:SFMC_ROOT\",\n // StreamWriter(path, append) \u9ED8\u8BA4 FileShare.Read\uFF0C\u4F1A\u6321\u4F4F\u4E0B\u4E00\u6B21\u5E73\u53F0\u6821\u9A8C\u91CC\u7684\u8FFD\u52A0\u6253\u5F00\u3002\n \"$mode = [System.IO.FileMode]::Append\",\n \"$access = [System.IO.FileAccess]::Write\",\n \"$share = [System.IO.FileShare]::ReadWrite\",\n \"$stream = New-Object System.IO.FileStream($env:SFMC_DAEMON_LOG, $mode, $access, $share)\",\n \"$inner = New-Object System.IO.StreamWriter($stream)\",\n \"$inner.AutoFlush = $true\",\n \"$script:writer = [System.IO.TextWriter]::Synchronized($inner)\",\n \"Remove-Item Env:SFMC_DAEMON_LOG\",\n \"$psi = New-Object System.Diagnostics.ProcessStartInfo\",\n \"$psi.FileName = $env:SFMC_NODE_BINARY\",\n \"$psi.Arguments = ([char]34) + $env:SFMC_DAEMON_ENTRY + ([char]34) + ' --daemon'\",\n \"$psi.WorkingDirectory = $env:SFMC_ROOT\",\n \"$psi.UseShellExecute = $false\",\n \"$psi.CreateNoWindow = $true\",\n \"$psi.RedirectStandardOutput = $true\",\n \"$psi.RedirectStandardError = $true\",\n \"$proc = New-Object System.Diagnostics.Process\",\n \"$proc.StartInfo = $psi\",\n \"$onLine = { param($sender, $lineEvent) if ($null -ne $lineEvent.Data) { $script:writer.WriteLine($lineEvent.Data) } }\",\n \"$proc.add_OutputDataReceived($onLine)\",\n \"$proc.add_ErrorDataReceived({ param($sender, $lineEvent) if ($null -ne $lineEvent.Data) { $script:writer.WriteLine($lineEvent.Data) } })\",\n \"[void]$proc.Start()\",\n \"$proc.BeginOutputReadLine()\",\n \"$proc.BeginErrorReadLine()\",\n \"try { $proc.WaitForExit() } finally { if ($script:writer) { $script:writer.Dispose() } }\",\n ];\n const commandLine = `powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand ${Buffer.from(script.join(\"\\n\"), \"utf16le\").toString(\"base64\")}`;\n const run = (hide: boolean) => {\n const startup = hide\n ? \"$startup = New-CimInstance -ClassName Win32_ProcessStartup -ClientOnly -Property @{ ShowWindow = 0 }\\n\"\n : \"\";\n const invoke = [\n \"$ErrorActionPreference = 'Stop'\",\n startup.trimEnd(),\n `$result = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = ${psLiteral(commandLine)}; CurrentDirectory = ${psLiteral(spec.root)}${hide ? \"; ProcessStartupInformation = $startup\" : \"\"} }`,\n \"if ($result.ReturnValue -ne 0) { Write-Error \\\"Win32_Process.Create $($result.ReturnValue)\\\"; exit 1 }\",\n ].filter(Boolean).join(\"\\n\");\n return spawnSync(\"powershell.exe\", [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-EncodedCommand\", Buffer.from(invoke, \"utf16le\").toString(\"base64\")], {\n encoding: \"utf8\",\n timeout: 30_000,\n windowsHide: true,\n });\n };\n const hidden = run(true);\n if (hidden.status === 0) return null;\n const visible = run(false);\n if (visible.status === 0) return null;\n return failureText(visible) || failureText(hidden) || \"Win32_Process.Create \u5931\u8D25\";\n}\n\nfunction userBusEnv(): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env, SYSTEMD_ASK_PASSWORD: \"0\" };\n const uid = process.getuid?.();\n if (uid !== undefined && !env.XDG_RUNTIME_DIR) env.XDG_RUNTIME_DIR = `/run/user/${uid}`;\n if (env.XDG_RUNTIME_DIR && !env.DBUS_SESSION_BUS_ADDRESS && fs.existsSync(`${env.XDG_RUNTIME_DIR}/bus`)) {\n env.DBUS_SESSION_BUS_ADDRESS = `unix:path=${env.XDG_RUNTIME_DIR}/bus`;\n }\n return env;\n}\n\n/** \u5199\u6210\u53EF\u6267\u884C\u811A\u672C\uFF0C\u4EA4\u7ED9 systemd --user\u3002\u811A\u672C\u91CC\u5E26\u4E0A\u542F\u52A8\u5F53\u65F6\u7684\u7528\u6237\u73AF\u5883\u3002 */\nfunction writePosixHost(spec: DaemonHostSpec): string {\n const file = path.join(spec.root, \".sfmc\", \"daemon-host.sh\");\n fs.mkdirSync(path.dirname(file), { recursive: true });\n const exports = Object.entries(carriedEnv(spec, [\"PATH\", \"HOME\", \"USER\", \"LANG\", \"LC_ALL\", \"TMPDIR\"]))\n .map(([key, value]) => `export ${key}=${shellQuote(value)}`);\n const body = [\n \"#!/bin/sh\",\n \"set -eu\",\n `cd ${shellQuote(spec.root)}`,\n ...exports,\n `exec ${shellQuote(spec.node)} ${shellQuote(spec.entry)} --daemon >> ${shellQuote(spec.logPath)} 2>&1`,\n \"\",\n ].join(\"\\n\");\n fs.writeFileSync(file, body, { encoding: \"utf8\", mode: 0o700 });\n fs.chmodSync(file, 0o700);\n return file;\n}\n\n/**\n * \u542F\u7528 linger \u540E\uFF0C\u7528 systemd \u7528\u6237\u670D\u52A1\u542F\u52A8\u3002\u7528\u6237\u670D\u52A1\u4E0D\u5C5E\u4E8E\u8FD9\u6B21 SSH \u4F1A\u8BDD\uFF0C\u767B\u51FA\u4E0D\u4F1A\u628A\u5B83\u505C\u6389\u3002\n * \u8FD4\u56DE null \u8868\u793A\u5DF2\u7ECF\u542F\u52A8\u3002\n */\nfunction launchSystemdUser(spec: DaemonHostSpec): string | null {\n const user = currentUser();\n if (!user) return \"\u65E0\u6CD5\u786E\u5B9A\u5F53\u524D\u7528\u6237\uFF0C\u4E0D\u80FD\u653E\u5230 systemd \u7528\u6237\u670D\u52A1\u91CC\";\n const ask = { encoding: \"utf8\" as const, timeout: 15_000, env: userBusEnv() };\n const enable = spawnSync(\"loginctl\", [\"enable-linger\", user], ask);\n const show = spawnSync(\"loginctl\", [\"show-user\", user, \"-p\", \"Linger\", \"--value\"], ask);\n if (show.stdout?.trim() !== \"yes\") {\n const detail = failureText(enable);\n return `\u7528\u6237 ${user} \u6CA1\u6709 linger\uFF0C\u767B\u51FA\u65F6\u7CFB\u7EDF\u4F1A\u7ED3\u675F\u672C\u6B21\u767B\u5F55\u4E2D\u7684\u8FDB\u7A0B\u3002\u8BF7\u5148\u6267\u884C loginctl enable-linger ${user}\uFF0C\u6216\u5B89\u88C5\u5F00\u673A\u670D\u52A1\u3002${detail ? ` ${detail}` : \"\"}`;\n }\n const script = writePosixHost(spec);\n const unit = `sfmc-${createHash(\"sha256\").update(spec.root).digest(\"hex\").slice(0, 8)}-${randomBytes(3).toString(\"hex\")}`;\n const result = spawnSync(\"systemd-run\", [\"--user\", \"--collect\", `--unit=${unit}`, script], {\n encoding: \"utf8\",\n timeout: 20_000,\n env: userBusEnv(),\n });\n if (result.status === 0) return null;\n return failureText(result) || \"systemd-run --user \u5931\u8D25\";\n}\n\n/**\n * \u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B\uFF0C\u5E76\u5C3D\u91CF\u8BA9\u5B83\u6D3B\u5728\u5F53\u524D\u767B\u5F55\u4F1A\u8BDD\u4E4B\u5916\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u7BA1\u7406\u8FDE\u63A5\u7B2C\u4E00\u6B21\u53D1\u73B0\u6CA1\u6709\u5B88\u62A4\u8FDB\u7A0B\u65F6\u8C03\u7528\u3002\u5DF2\u6709\u5B88\u62A4\u8FDB\u7A0B\u4E0D\u4F1A\u8D70\u5230\u8FD9\u91CC\u3002\n */\nexport function launchDaemonHost(spec: DaemonHostSpec): void {\n fs.mkdirSync(path.dirname(spec.logPath), { recursive: true });\n if (process.platform === \"win32\") {\n const failure = launchWindowsOutsideSession(spec);\n if (!failure) return;\n if (insideSshSession()) throw new Error(`\u65E0\u6CD5\u5728 SSH \u4F1A\u8BDD\u4E4B\u5916\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B\uFF0C\u5DF2\u53D6\u6D88\u542F\u52A8\uFF0C\u907F\u514D\u65AD\u5F00\u8FDE\u63A5\u65F6\u505C\u670D\u3002${failure}`);\n launchDetached(spec);\n return;\n }\n if (fs.existsSync(\"/run/systemd/system\")) {\n const failure = launchSystemdUser(spec);\n if (!failure) return;\n if (insideSshSession()) throw new Error(`\u65E0\u6CD5\u5728 SSH \u4F1A\u8BDD\u4E4B\u5916\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B\uFF0C\u5DF2\u53D6\u6D88\u542F\u52A8\uFF0C\u907F\u514D\u65AD\u5F00\u8FDE\u63A5\u65F6\u505C\u670D\u3002${failure}`);\n }\n launchDetached(spec);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2MH;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAwGrD"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2MH;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CA2GrD"}
@@ -293,6 +293,8 @@ async function runDaemonServer() {
293
293
  });
294
294
  process.on("SIGINT", () => {
295
295
  });
296
+ process.on("SIGHUP", () => {
297
+ });
296
298
  await new Promise(() => {
297
299
  });
298
300
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/daemon/server.ts"],
4
- "sourcesContent": ["/**\n * server.ts \u2014 \u5B88\u62A4\u8FDB\u7A0B\u670D\u52A1\u7AEF\uFF1A\u672C\u673A\u7BA1\u9053 listen + \u5C06 RPC \u5206\u53D1\u7ED9\u73B0\u6709\u76D1\u7BA1\u903B\u8F91\n *\n * \u4EC5\u5728 `sfmc --daemon` \u8FDB\u7A0B\u5185\u8FD0\u884C\uFF1B\u6301\u6709 Service \u5B50\u8FDB\u7A0B\u3001\u81EA\u52A8\u91CD\u542F\u4E0E BDS stdin\u3002\n * CLI \u9000\u51FA\u4E0D\u65AD\u5F00\u672C\u8FDB\u7A0B\uFF1B`shutdown` \u65B9\u6CD5\u4F1A\u5148 stopAll \u518D\u9000\u51FA\u3002\n */\n\nimport net from \"node:net\";\nimport process from \"node:process\";\nimport {\n cmdRestart,\n cmdSend,\n cmdStart,\n cmdStartAll,\n cmdStatus,\n cmdStop,\n cmdStopAll,\n cmdUpdate,\n} from \"../commands.js\";\nimport { onLog } from \"../logs.js\";\nimport { onServiceStateChange, queryServicesRuntimeLocal, stopAll } from \"../services.js\";\nimport { startAll } from \"../services.js\";\nimport {\n clearDaemonMeta,\n createDaemonToken,\n daemonPipePath,\n writeDaemonMeta,\n type DaemonMeta,\n} from \"./paths.js\";\nimport type { DaemonEvent, DaemonRequest, DaemonResponse, DaemonResult } from \"./protocol.js\";\nimport { toLogPayload } from \"./protocol.js\";\nimport { markDaemonServer } from \"./role.js\";\nimport { dispatchManagement, managementTasks, onManagementEvent } from \"../management/server.js\";\nimport { toManagementError } from \"@sfmc-bds/management\";\nimport { isMaintenanceLocked, withMaintenanceLock } from \"@sfmc-bds/management/node\";\nimport { ROOT } from \"../runtime.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { stopForMaintenance } from \"../management/maintenance.js\";\nimport { START_ORDER } from \"../services.js\";\nimport { readDaemonMeta } from \"./paths.js\";\nimport { isProcessAlive } from \"@sfmc-bds/bds-tools/process-probe\";\nimport { randomUUID } from \"node:crypto\";\n\n/** \u5F53\u524D\u5DF2\u8BA2\u9605\u4E8B\u4EF6\u63A8\u9001\u7684 socket \u96C6\u5408 */\nconst subscribers = new Set<net.Socket>();\n\n/** \u662F\u5426\u5DF2\u5F00\u59CB\u4F18\u96C5\u9000\u51FA\uFF08\u907F\u514D\u91CD\u590D shutdown\uFF09 */\nlet shuttingDown = false;\n\n/**\n * \u5411\u6240\u6709\u8BA2\u9605\u8005\u5E7F\u64AD\u4E8B\u4EF6\u5E27\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u670D\u52A1\u65E5\u5FD7\u4E0E\u542F\u505C\u72B6\u6001\u9700\u5B9E\u65F6\u51FA\u73B0\u5728\u5DF2\u8FDE\u63A5\u7684 REPL\u3002\n */\nfunction broadcast(event: DaemonEvent): void {\n const line = JSON.stringify(event) + \"\\n\";\n for (const sock of subscribers) {\n if (sock.destroyed) {\n subscribers.delete(sock);\n continue;\n }\n if (sock.writableLength > 4 * 1024 * 1024) { sock.destroy(); subscribers.delete(sock); continue; }\n try {\n sock.write(line);\n } catch {\n subscribers.delete(sock);\n }\n }\n}\n\nfunction writeRes(sock: net.Socket, res: DaemonResponse): void {\n if (sock.destroyed) return;\n try {\n sock.write(JSON.stringify(res) + \"\\n\");\n } catch {\n /* ignore */\n }\n}\n\n/**\n * \u5206\u53D1\u5355\u6761 RPC \u5230\u73B0\u6709 cmd* / services API\uFF08\u672C\u8FDB\u7A0B\u5DF2\u662F daemon\uFF0Ccmd* \u8D70\u672C\u5730\u5B9E\u73B0\uFF09\u3002\n */\nasync function dispatch(req: DaemonRequest): Promise<DaemonResult> {\n const mutable = [\"start\", \"stop\", \"restart\", \"startAll\", \"stopAll\", \"send\", \"update\", \"shutdown\", \"maintenanceStop\"].includes(req.method);\n if (mutable) {\n const owner = fs.existsSync(path.join(ROOT, \".sfmc\", \"maintenance.lock\")) ? JSON.parse(fs.readFileSync(path.join(ROOT, \".sfmc\", \"maintenance.lock\"), \"utf8\")) as { nonce?: string } : null;\n if (!req.params?.maintenanceToken || req.params.maintenanceToken !== owner?.nonce) {\n return withMaintenanceLock(ROOT, () => dispatchUnlocked(req));\n }\n }\n return dispatchUnlocked(req);\n}\nasync function dispatchUnlocked(req: DaemonRequest): Promise<DaemonResult> {\n switch (req.method) {\n case \"maintenanceStop\": {\n await stopForMaintenance([...START_ORDER], () => {});\n return { kind: \"status\", text: \"\", rows: await queryServicesRuntimeLocal() };\n }\n case \"management\": {\n const request = req.params?.request;\n if (!request || typeof request.id !== \"string\" || typeof request.method !== \"string\") throw new Error(\"invalid management request\");\n try { return { kind: \"management\", response: { type: \"res\", id: request.id, ok: true, result: await dispatchManagement(request) } }; }\n catch (error) { return { kind: \"management\", response: { type: \"res\", id: request.id, ok: false, error: toManagementError(error) } }; }\n }\n case \"ping\":\n return { kind: \"pong\" };\n case \"status\": {\n const text = await cmdStatus();\n const rows = await queryServicesRuntimeLocal();\n return { kind: \"status\", text, rows };\n }\n case \"start\": {\n const name = req.params?.name;\n if (!name) throw new Error(\"missing params.name\");\n if (name === \"all\" || name === \"-all\" || name === \"--all\") {\n return { kind: \"text\", text: await cmdStartAll() };\n }\n return { kind: \"text\", text: await cmdStart(name) };\n }\n case \"stop\": {\n const name = req.params?.name;\n if (!name) throw new Error(\"missing params.name\");\n if (name === \"all\" || name === \"-all\" || name === \"--all\") {\n return { kind: \"text\", text: await cmdStopAll() };\n }\n return { kind: \"text\", text: await cmdStop(name) };\n }\n case \"restart\": {\n const name = req.params?.name;\n if (!name) throw new Error(\"missing params.name\");\n if (name === \"all\" || name === \"-all\" || name === \"--all\") {\n await cmdStopAll();\n return { kind: \"text\", text: await cmdStartAll() };\n }\n return { kind: \"text\", text: await cmdRestart(name) };\n }\n case \"startAll\":\n return { kind: \"text\", text: await cmdStartAll() };\n case \"stopAll\":\n return { kind: \"text\", text: await cmdStopAll() };\n case \"send\": {\n const name = req.params?.name;\n const message = req.params?.message;\n if (!name || message === undefined) throw new Error(\"missing params.name/message\");\n return { kind: \"text\", text: await cmdSend(name, message) };\n }\n case \"update\":\n return { kind: \"text\", text: await cmdUpdate(req.params?.args ?? []) };\n case \"subscribe\":\n return { kind: \"subscribed\" };\n case \"shutdown\": {\n if (!shuttingDown) {\n shuttingDown = true;\n try { await stopForMaintenance([...START_ORDER], () => {}); }\n catch (error) { shuttingDown = false; throw error; }\n setTimeout(() => {\n clearDaemonMeta();\n process.exit(0);\n }, 50).unref();\n }\n return { kind: \"shutdown\" };\n }\n default:\n throw new Error(`unknown method: ${(req as DaemonRequest).method}`);\n }\n}\n\n/**\n * \u5904\u7406\u5355\u6761\u8FDE\u63A5\u4E0A\u7684\u8BF7\u6C42\u884C\uFF1B\u9274\u6743\u5931\u8D25\u5219\u5173\u95ED\u3002\n */\nasync function handleLine(sock: net.Socket, line: string, expectedToken: string): Promise<void> {\n let req: DaemonRequest;\n try {\n req = JSON.parse(line) as DaemonRequest;\n } catch {\n writeRes(sock, { type: \"res\", id: \"?\", ok: false, error: \"invalid json\" });\n return;\n }\n if (!req?.id || !req.method) {\n writeRes(sock, { type: \"res\", id: req?.id ?? \"?\", ok: false, error: \"invalid request\" });\n return;\n }\n if (req.token !== expectedToken) {\n writeRes(sock, { type: \"res\", id: req.id, ok: false, error: \"unauthorized\" });\n sock.end();\n return;\n }\n\n if (req.method === \"subscribe\") {\n subscribers.add(sock);\n sock.once(\"close\", () => subscribers.delete(sock));\n writeRes(sock, { type: \"res\", id: req.id, ok: true, result: { kind: \"subscribed\" } });\n return;\n }\n\n try {\n const result = await dispatch(req);\n writeRes(sock, { type: \"res\", id: req.id, ok: true, result });\n } catch (e) {\n writeRes(sock, {\n type: \"res\",\n id: req.id,\n ok: false,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n}\n\n/**\n * \u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B\uFF1A\u6807\u8BB0\u89D2\u8272\u3001listen \u7BA1\u9053\u3001\u843D\u76D8 daemon.json\uFF0C\u5E76\u8F6C\u53D1\u65E5\u5FD7/\u72B6\u6001\u4E8B\u4EF6\u3002\n * \u672C\u51FD\u6570\u5728\u6210\u529F listen \u540E\u6C38\u4E0D\u8FD4\u56DE\uFF08\u8FDB\u7A0B\u5E38\u9A7B\uFF09\u3002\n */\nexport async function runDaemonServer(): Promise<void> {\n const startLock = path.join(ROOT, \".sfmc\", \"daemon-start.lock\");\n fs.mkdirSync(path.dirname(startLock), { recursive: true });\n const nonce = randomUUID();\n let handle: number;\n try { handle = fs.openSync(startLock, \"wx\", 0o600); }\n catch (error) { if ((error as NodeJS.ErrnoException).code === \"EEXIST\") throw new Error(\"\u5B88\u62A4\u8FDB\u7A0B\u6B63\u5728\u542F\u52A8\u6216\u542F\u52A8\u9501\u9057\u7559\uFF1B\u4E0D\u4F1A\u521B\u5EFA\u7B2C\u4E8C\u5957\u540E\u53F0\uFF0C\u8BF7\u68C0\u67E5 daemon-start.lock\"); throw error; }\n fs.writeFileSync(handle, JSON.stringify({ pid: process.pid, nonce })); fs.closeSync(handle);\n const releaseStartup = () => { try { const owner = JSON.parse(fs.readFileSync(startLock, \"utf8\")) as { nonce: string }; if (owner.nonce === nonce) fs.unlinkSync(startLock); } catch { /* \u5DF2\u91CA\u653E */ } };\n process.once(\"exit\", releaseStartup);\n const previous = readDaemonMeta();\n if (previous && await isProcessAlive(previous.pid)) { releaseStartup(); process.exit(0); }\n if (previous) clearDaemonMeta();\n markDaemonServer();\n const unsubManagement = onManagementEvent(event => broadcast({ type: \"event\", event: \"management\", payload: event }));\n\n const token = createDaemonToken();\n const pipe = daemonPipePath();\n const meta: DaemonMeta = {\n pid: process.pid,\n pipe,\n token,\n startedAt: new Date().toISOString(),\n };\n\n const unsubLog = onLog((log) => {\n broadcast({ type: \"event\", event: \"log\", payload: toLogPayload(log) });\n });\n const unsubState = onServiceStateChange((ev) => {\n broadcast({ type: \"event\", event: \"state\", payload: ev });\n });\n\n const server = net.createServer((sock) => {\n let buf = \"\";\n sock.setEncoding(\"utf8\");\n sock.on(\"data\", (chunk: string) => {\n buf += chunk;\n if (Buffer.byteLength(buf) > 8 * 1024 * 1024) { sock.destroy(); return; }\n let idx: number;\n while ((idx = buf.indexOf(\"\\n\")) >= 0) {\n const line = buf.slice(0, idx).trim();\n buf = buf.slice(idx + 1);\n if (!line) continue;\n void handleLine(sock, line, token);\n }\n });\n sock.on(\"error\", () => {\n subscribers.delete(sock);\n });\n sock.on(\"close\", () => {\n subscribers.delete(sock);\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n const onErr = (err: NodeJS.ErrnoException): void => {\n /* \u53E6\u4E00\u5B9E\u4F8B\u5DF2\u5360\u7528\u7BA1\u9053\uFF1A\u5B89\u9759\u9000\u51FA\uFF0C\u907F\u514D\u53CC\u5B88\u62A4\u8FDB\u7A0B */\n if (err.code === \"EADDRINUSE\") {\n process.exit(0);\n }\n reject(err);\n };\n server.once(\"error\", onErr);\n server.listen(pipe, () => {\n server.off(\"error\", onErr);\n resolve();\n });\n });\n\n writeDaemonMeta(meta);\n releaseStartup();\n // \u542F\u52A8\u65F6\u5C31\u6838\u5BF9\u9057\u7559\u4EFB\u52A1\u3002\u7EF4\u62A4\u8FDB\u7A0B\u88AB\u6740\u6389\u540E\uFF0C\u684C\u9762\u4E0D\u7528\u5148\u53D1\u8BF7\u6C42\u4E5F\u80FD\u770B\u5230\u300C\u5DF2\u4E2D\u65AD\u300D\u3002\n managementTasks();\n if (process.argv.includes(\"--autostart\") && !isMaintenanceLocked(ROOT)) await startAll();\n\n const cleanup = (): void => {\n unsubManagement();\n unsubLog();\n unsubState();\n try {\n server.close();\n } catch {\n /* ignore */\n }\n clearDaemonMeta();\n };\n\n process.on(\"exit\", cleanup);\n process.on(\"SIGTERM\", () => {\n if (shuttingDown) return;\n shuttingDown = true;\n void stopAll().finally(() => {\n cleanup();\n process.exit(0);\n });\n });\n /* \u5B88\u62A4\u8FDB\u7A0B\u5FFD\u7565 SIGINT\uFF1A\u8131\u79BB\u7EC8\u7AEF\u540E\u4E0D\u5E94\u56E0\u4FE1\u53F7\u505C\u670D\uFF1B\u663E\u5F0F shutdown \u9000\u51FA */\n process.on(\"SIGINT\", () => {\n /* no-op */\n });\n\n await new Promise<never>(() => {\n /* park forever */\n });\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * server.ts \u2014 \u5B88\u62A4\u8FDB\u7A0B\u670D\u52A1\u7AEF\uFF1A\u672C\u673A\u7BA1\u9053 listen + \u5C06 RPC \u5206\u53D1\u7ED9\u73B0\u6709\u76D1\u7BA1\u903B\u8F91\n *\n * \u4EC5\u5728 `sfmc --daemon` \u8FDB\u7A0B\u5185\u8FD0\u884C\uFF1B\u6301\u6709 Service \u5B50\u8FDB\u7A0B\u3001\u81EA\u52A8\u91CD\u542F\u4E0E BDS stdin\u3002\n * CLI \u9000\u51FA\u4E0D\u65AD\u5F00\u672C\u8FDB\u7A0B\uFF1B`shutdown` \u65B9\u6CD5\u4F1A\u5148 stopAll \u518D\u9000\u51FA\u3002\n */\n\nimport net from \"node:net\";\nimport process from \"node:process\";\nimport {\n cmdRestart,\n cmdSend,\n cmdStart,\n cmdStartAll,\n cmdStatus,\n cmdStop,\n cmdStopAll,\n cmdUpdate,\n} from \"../commands.js\";\nimport { onLog } from \"../logs.js\";\nimport { onServiceStateChange, queryServicesRuntimeLocal, stopAll } from \"../services.js\";\nimport { startAll } from \"../services.js\";\nimport {\n clearDaemonMeta,\n createDaemonToken,\n daemonPipePath,\n writeDaemonMeta,\n type DaemonMeta,\n} from \"./paths.js\";\nimport type { DaemonEvent, DaemonRequest, DaemonResponse, DaemonResult } from \"./protocol.js\";\nimport { toLogPayload } from \"./protocol.js\";\nimport { markDaemonServer } from \"./role.js\";\nimport { dispatchManagement, managementTasks, onManagementEvent } from \"../management/server.js\";\nimport { toManagementError } from \"@sfmc-bds/management\";\nimport { isMaintenanceLocked, withMaintenanceLock } from \"@sfmc-bds/management/node\";\nimport { ROOT } from \"../runtime.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { stopForMaintenance } from \"../management/maintenance.js\";\nimport { START_ORDER } from \"../services.js\";\nimport { readDaemonMeta } from \"./paths.js\";\nimport { isProcessAlive } from \"@sfmc-bds/bds-tools/process-probe\";\nimport { randomUUID } from \"node:crypto\";\n\n/** \u5F53\u524D\u5DF2\u8BA2\u9605\u4E8B\u4EF6\u63A8\u9001\u7684 socket \u96C6\u5408 */\nconst subscribers = new Set<net.Socket>();\n\n/** \u662F\u5426\u5DF2\u5F00\u59CB\u4F18\u96C5\u9000\u51FA\uFF08\u907F\u514D\u91CD\u590D shutdown\uFF09 */\nlet shuttingDown = false;\n\n/**\n * \u5411\u6240\u6709\u8BA2\u9605\u8005\u5E7F\u64AD\u4E8B\u4EF6\u5E27\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u670D\u52A1\u65E5\u5FD7\u4E0E\u542F\u505C\u72B6\u6001\u9700\u5B9E\u65F6\u51FA\u73B0\u5728\u5DF2\u8FDE\u63A5\u7684 REPL\u3002\n */\nfunction broadcast(event: DaemonEvent): void {\n const line = JSON.stringify(event) + \"\\n\";\n for (const sock of subscribers) {\n if (sock.destroyed) {\n subscribers.delete(sock);\n continue;\n }\n if (sock.writableLength > 4 * 1024 * 1024) { sock.destroy(); subscribers.delete(sock); continue; }\n try {\n sock.write(line);\n } catch {\n subscribers.delete(sock);\n }\n }\n}\n\nfunction writeRes(sock: net.Socket, res: DaemonResponse): void {\n if (sock.destroyed) return;\n try {\n sock.write(JSON.stringify(res) + \"\\n\");\n } catch {\n /* ignore */\n }\n}\n\n/**\n * \u5206\u53D1\u5355\u6761 RPC \u5230\u73B0\u6709 cmd* / services API\uFF08\u672C\u8FDB\u7A0B\u5DF2\u662F daemon\uFF0Ccmd* \u8D70\u672C\u5730\u5B9E\u73B0\uFF09\u3002\n */\nasync function dispatch(req: DaemonRequest): Promise<DaemonResult> {\n const mutable = [\"start\", \"stop\", \"restart\", \"startAll\", \"stopAll\", \"send\", \"update\", \"shutdown\", \"maintenanceStop\"].includes(req.method);\n if (mutable) {\n const owner = fs.existsSync(path.join(ROOT, \".sfmc\", \"maintenance.lock\")) ? JSON.parse(fs.readFileSync(path.join(ROOT, \".sfmc\", \"maintenance.lock\"), \"utf8\")) as { nonce?: string } : null;\n if (!req.params?.maintenanceToken || req.params.maintenanceToken !== owner?.nonce) {\n return withMaintenanceLock(ROOT, () => dispatchUnlocked(req));\n }\n }\n return dispatchUnlocked(req);\n}\nasync function dispatchUnlocked(req: DaemonRequest): Promise<DaemonResult> {\n switch (req.method) {\n case \"maintenanceStop\": {\n await stopForMaintenance([...START_ORDER], () => {});\n return { kind: \"status\", text: \"\", rows: await queryServicesRuntimeLocal() };\n }\n case \"management\": {\n const request = req.params?.request;\n if (!request || typeof request.id !== \"string\" || typeof request.method !== \"string\") throw new Error(\"invalid management request\");\n try { return { kind: \"management\", response: { type: \"res\", id: request.id, ok: true, result: await dispatchManagement(request) } }; }\n catch (error) { return { kind: \"management\", response: { type: \"res\", id: request.id, ok: false, error: toManagementError(error) } }; }\n }\n case \"ping\":\n return { kind: \"pong\" };\n case \"status\": {\n const text = await cmdStatus();\n const rows = await queryServicesRuntimeLocal();\n return { kind: \"status\", text, rows };\n }\n case \"start\": {\n const name = req.params?.name;\n if (!name) throw new Error(\"missing params.name\");\n if (name === \"all\" || name === \"-all\" || name === \"--all\") {\n return { kind: \"text\", text: await cmdStartAll() };\n }\n return { kind: \"text\", text: await cmdStart(name) };\n }\n case \"stop\": {\n const name = req.params?.name;\n if (!name) throw new Error(\"missing params.name\");\n if (name === \"all\" || name === \"-all\" || name === \"--all\") {\n return { kind: \"text\", text: await cmdStopAll() };\n }\n return { kind: \"text\", text: await cmdStop(name) };\n }\n case \"restart\": {\n const name = req.params?.name;\n if (!name) throw new Error(\"missing params.name\");\n if (name === \"all\" || name === \"-all\" || name === \"--all\") {\n await cmdStopAll();\n return { kind: \"text\", text: await cmdStartAll() };\n }\n return { kind: \"text\", text: await cmdRestart(name) };\n }\n case \"startAll\":\n return { kind: \"text\", text: await cmdStartAll() };\n case \"stopAll\":\n return { kind: \"text\", text: await cmdStopAll() };\n case \"send\": {\n const name = req.params?.name;\n const message = req.params?.message;\n if (!name || message === undefined) throw new Error(\"missing params.name/message\");\n return { kind: \"text\", text: await cmdSend(name, message) };\n }\n case \"update\":\n return { kind: \"text\", text: await cmdUpdate(req.params?.args ?? []) };\n case \"subscribe\":\n return { kind: \"subscribed\" };\n case \"shutdown\": {\n if (!shuttingDown) {\n shuttingDown = true;\n try { await stopForMaintenance([...START_ORDER], () => {}); }\n catch (error) { shuttingDown = false; throw error; }\n setTimeout(() => {\n clearDaemonMeta();\n process.exit(0);\n }, 50).unref();\n }\n return { kind: \"shutdown\" };\n }\n default:\n throw new Error(`unknown method: ${(req as DaemonRequest).method}`);\n }\n}\n\n/**\n * \u5904\u7406\u5355\u6761\u8FDE\u63A5\u4E0A\u7684\u8BF7\u6C42\u884C\uFF1B\u9274\u6743\u5931\u8D25\u5219\u5173\u95ED\u3002\n */\nasync function handleLine(sock: net.Socket, line: string, expectedToken: string): Promise<void> {\n let req: DaemonRequest;\n try {\n req = JSON.parse(line) as DaemonRequest;\n } catch {\n writeRes(sock, { type: \"res\", id: \"?\", ok: false, error: \"invalid json\" });\n return;\n }\n if (!req?.id || !req.method) {\n writeRes(sock, { type: \"res\", id: req?.id ?? \"?\", ok: false, error: \"invalid request\" });\n return;\n }\n if (req.token !== expectedToken) {\n writeRes(sock, { type: \"res\", id: req.id, ok: false, error: \"unauthorized\" });\n sock.end();\n return;\n }\n\n if (req.method === \"subscribe\") {\n subscribers.add(sock);\n sock.once(\"close\", () => subscribers.delete(sock));\n writeRes(sock, { type: \"res\", id: req.id, ok: true, result: { kind: \"subscribed\" } });\n return;\n }\n\n try {\n const result = await dispatch(req);\n writeRes(sock, { type: \"res\", id: req.id, ok: true, result });\n } catch (e) {\n writeRes(sock, {\n type: \"res\",\n id: req.id,\n ok: false,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n}\n\n/**\n * \u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B\uFF1A\u6807\u8BB0\u89D2\u8272\u3001listen \u7BA1\u9053\u3001\u843D\u76D8 daemon.json\uFF0C\u5E76\u8F6C\u53D1\u65E5\u5FD7/\u72B6\u6001\u4E8B\u4EF6\u3002\n * \u672C\u51FD\u6570\u5728\u6210\u529F listen \u540E\u6C38\u4E0D\u8FD4\u56DE\uFF08\u8FDB\u7A0B\u5E38\u9A7B\uFF09\u3002\n */\nexport async function runDaemonServer(): Promise<void> {\n const startLock = path.join(ROOT, \".sfmc\", \"daemon-start.lock\");\n fs.mkdirSync(path.dirname(startLock), { recursive: true });\n const nonce = randomUUID();\n let handle: number;\n try { handle = fs.openSync(startLock, \"wx\", 0o600); }\n catch (error) { if ((error as NodeJS.ErrnoException).code === \"EEXIST\") throw new Error(\"\u5B88\u62A4\u8FDB\u7A0B\u6B63\u5728\u542F\u52A8\u6216\u542F\u52A8\u9501\u9057\u7559\uFF1B\u4E0D\u4F1A\u521B\u5EFA\u7B2C\u4E8C\u5957\u540E\u53F0\uFF0C\u8BF7\u68C0\u67E5 daemon-start.lock\"); throw error; }\n fs.writeFileSync(handle, JSON.stringify({ pid: process.pid, nonce })); fs.closeSync(handle);\n const releaseStartup = () => { try { const owner = JSON.parse(fs.readFileSync(startLock, \"utf8\")) as { nonce: string }; if (owner.nonce === nonce) fs.unlinkSync(startLock); } catch { /* \u5DF2\u91CA\u653E */ } };\n process.once(\"exit\", releaseStartup);\n const previous = readDaemonMeta();\n if (previous && await isProcessAlive(previous.pid)) { releaseStartup(); process.exit(0); }\n if (previous) clearDaemonMeta();\n markDaemonServer();\n const unsubManagement = onManagementEvent(event => broadcast({ type: \"event\", event: \"management\", payload: event }));\n\n const token = createDaemonToken();\n const pipe = daemonPipePath();\n const meta: DaemonMeta = {\n pid: process.pid,\n pipe,\n token,\n startedAt: new Date().toISOString(),\n };\n\n const unsubLog = onLog((log) => {\n broadcast({ type: \"event\", event: \"log\", payload: toLogPayload(log) });\n });\n const unsubState = onServiceStateChange((ev) => {\n broadcast({ type: \"event\", event: \"state\", payload: ev });\n });\n\n const server = net.createServer((sock) => {\n let buf = \"\";\n sock.setEncoding(\"utf8\");\n sock.on(\"data\", (chunk: string) => {\n buf += chunk;\n if (Buffer.byteLength(buf) > 8 * 1024 * 1024) { sock.destroy(); return; }\n let idx: number;\n while ((idx = buf.indexOf(\"\\n\")) >= 0) {\n const line = buf.slice(0, idx).trim();\n buf = buf.slice(idx + 1);\n if (!line) continue;\n void handleLine(sock, line, token);\n }\n });\n sock.on(\"error\", () => {\n subscribers.delete(sock);\n });\n sock.on(\"close\", () => {\n subscribers.delete(sock);\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n const onErr = (err: NodeJS.ErrnoException): void => {\n /* \u53E6\u4E00\u5B9E\u4F8B\u5DF2\u5360\u7528\u7BA1\u9053\uFF1A\u5B89\u9759\u9000\u51FA\uFF0C\u907F\u514D\u53CC\u5B88\u62A4\u8FDB\u7A0B */\n if (err.code === \"EADDRINUSE\") {\n process.exit(0);\n }\n reject(err);\n };\n server.once(\"error\", onErr);\n server.listen(pipe, () => {\n server.off(\"error\", onErr);\n resolve();\n });\n });\n\n writeDaemonMeta(meta);\n releaseStartup();\n // \u542F\u52A8\u65F6\u5C31\u6838\u5BF9\u9057\u7559\u4EFB\u52A1\u3002\u7EF4\u62A4\u8FDB\u7A0B\u88AB\u6740\u6389\u540E\uFF0C\u684C\u9762\u4E0D\u7528\u5148\u53D1\u8BF7\u6C42\u4E5F\u80FD\u770B\u5230\u300C\u5DF2\u4E2D\u65AD\u300D\u3002\n managementTasks();\n if (process.argv.includes(\"--autostart\") && !isMaintenanceLocked(ROOT)) await startAll();\n\n const cleanup = (): void => {\n unsubManagement();\n unsubLog();\n unsubState();\n try {\n server.close();\n } catch {\n /* ignore */\n }\n clearDaemonMeta();\n };\n\n process.on(\"exit\", cleanup);\n process.on(\"SIGTERM\", () => {\n if (shuttingDown) return;\n shuttingDown = true;\n void stopAll().finally(() => {\n cleanup();\n process.exit(0);\n });\n });\n /* \u5B88\u62A4\u8FDB\u7A0B\u5FFD\u7565 SIGINT / SIGHUP\uFF1A\u7BA1\u7406\u8FDE\u63A5\u6216\u7EC8\u7AEF\u6302\u8D77\u4E0D\u8868\u793A\u505C\u670D\u3002\u505C\u670D\u53EA\u8D70\u663E\u5F0F shutdown\uFF0C\u6216\u670D\u52A1\u7BA1\u7406\u5668\u53D1\u6765\u7684 SIGTERM\u3002 */\n process.on(\"SIGINT\", () => {\n /* no-op */\n });\n process.on(\"SIGHUP\", () => {\n /* no-op */\n });\n\n await new Promise<never>(() => {\n /* park forever */\n });\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,7 @@
1
+ import type { MetricsResult } from "@sfmc-bds/management";
2
+ /**
3
+ * 管理协议 metrics.read。
4
+ * 落盘读取失败时保留数据服务返回的历史;两边都没有时沿用原来的空结果说明。
5
+ */
6
+ export declare function readRuntimeMetrics(params: unknown): Promise<MetricsResult>;
7
+ //# sourceMappingURL=metrics-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-read.d.ts","sourceRoot":"","sources":["../../src/management/metrics-read.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAiC1D;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CA2ChF"}
@@ -0,0 +1,80 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { clampMetricsSpan, readPersistedMetrics } from "@sfmc-bds/db-server/metrics-store";
4
+ import { getRoot } from "../runtime.js";
5
+ function dbConfig(root) {
6
+ try {
7
+ const parsed = JSON.parse(fs.readFileSync(path.join(root, "configs", "db_config.json"), "utf8"));
8
+ return {
9
+ ...typeof parsed.db_port === "number" ? { db_port: parsed.db_port } : {},
10
+ ...typeof parsed.http_auth === "string" ? { http_auth: parsed.http_auth } : {},
11
+ ...typeof parsed.dbDir === "string" && parsed.dbDir.trim() ? { dbDir: parsed.dbDir } : {}
12
+ };
13
+ } catch {
14
+ return {};
15
+ }
16
+ }
17
+ function metricsDatabasePath(root, dbDir) {
18
+ return path.join(path.dirname(path.resolve(root, dbDir ?? "data/sfmc_data.db")), "runtime-metrics.sqlite");
19
+ }
20
+ function spanOf(params) {
21
+ if (params === void 0) return clampMetricsSpan(void 0);
22
+ if (!params || typeof params !== "object" || Array.isArray(params)) throw new Error("\u53C2\u6570\u5FC5\u987B\u4E3A\u5BF9\u8C61");
23
+ return clampMetricsSpan(params.spanMs);
24
+ }
25
+ function offline(error) {
26
+ const detail = error instanceof Error ? `${error.message} ${String(error.cause ?? "")}` : String(error);
27
+ return /fetch failed|ECONNREFUSED|ENOTFOUND|AbortError|TimeoutError|timed out/i.test(detail);
28
+ }
29
+ async function readRuntimeMetrics(params) {
30
+ const spanMs = spanOf(params);
31
+ const root = getRoot();
32
+ const cfg = dbConfig(root);
33
+ let live;
34
+ try {
35
+ const response = await fetch(`http://127.0.0.1:${cfg.db_port ?? 3001}/api/sfmc/metrics?spanMs=${spanMs}`, {
36
+ headers: cfg.http_auth ? { authorization: `Bearer ${cfg.http_auth}` } : {},
37
+ signal: AbortSignal.timeout(1e4)
38
+ });
39
+ if (!response.ok) throw new Error(`\u8FD0\u884C\u6307\u6807\u8BFB\u53D6\u5931\u8D25 (${response.status})`);
40
+ const body = await response.json();
41
+ if (!body || typeof body !== "object" || !Array.isArray(body.history)) throw new Error("\u8FD0\u884C\u6307\u6807\u8BFB\u53D6\u5931\u8D25");
42
+ live = body;
43
+ } catch (error) {
44
+ if (!offline(error)) throw error;
45
+ }
46
+ let stored = null;
47
+ try {
48
+ stored = readPersistedMetrics(metricsDatabasePath(root, cfg.dbDir), Date.now(), spanMs);
49
+ } catch {
50
+ stored = null;
51
+ }
52
+ if (!live) {
53
+ const history2 = stored?.history ?? [];
54
+ const resourceHistory2 = stored?.resourceHistory ?? [];
55
+ return {
56
+ fresh: false,
57
+ updatedAt: history2.at(-1)?.recordedAt ?? null,
58
+ current: null,
59
+ history: history2,
60
+ host: null,
61
+ processes: null,
62
+ resourcesUpdatedAt: resourceHistory2.at(-1)?.recordedAt ?? null,
63
+ resourceHistory: resourceHistory2,
64
+ note: history2.length || resourceHistory2.length ? "\u6570\u636E\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u5B9E\u65F6\u6570\u503C\u4E0D\u53EF\u7528" : "\u6570\u636E\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u6682\u65F6\u6CA1\u6709\u8FD0\u884C\u6307\u6807"
65
+ };
66
+ }
67
+ const history = stored?.history ?? live.history;
68
+ const resourceHistory = stored?.resourceHistory ?? live.resourceHistory;
69
+ return {
70
+ ...live,
71
+ history,
72
+ ...resourceHistory ? { resourceHistory } : {},
73
+ updatedAt: live.updatedAt ?? history.at(-1)?.recordedAt ?? null,
74
+ resourcesUpdatedAt: live.resourcesUpdatedAt ?? resourceHistory?.at(-1)?.recordedAt ?? null
75
+ };
76
+ }
77
+ export {
78
+ readRuntimeMetrics
79
+ };
80
+ //# sourceMappingURL=metrics-read.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/management/metrics-read.ts"],
4
+ "sourcesContent": ["/**\n * \u8BFB\u53D6\u8FD0\u884C\u6307\u6807\uFF1A\u5B9E\u65F6\u6570\u503C\u8D70\u6570\u636E\u670D\u52A1\uFF0C\u66F2\u7EBF\u8D70\u5DF2\u843D\u76D8\u7684 sqlite\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u684C\u9762\u7AEF\u300C\u8FD0\u884C\u6307\u6807\u300D\u3002\u6570\u636E\u670D\u52A1\u505C\u7740\u65F6\u4ECD\u8FD4\u56DE\u505C\u670D\u524D\u7684\u5386\u53F2\uFF0C\u4E0D\u628A\u6574\u9875\u53D8\u6210\u5931\u8D25\u3002\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { clampMetricsSpan, readPersistedMetrics } from \"@sfmc-bds/db-server/metrics-store\";\nimport type { MetricsResult } from \"@sfmc-bds/management\";\nimport { getRoot } from \"../runtime.js\";\n\n/** \u4E0E\u6570\u636E\u670D\u52A1\u76F8\u540C\u7684\u914D\u7F6E\u8BFB\u53D6\uFF1A\u6587\u4EF6\u7F3A\u5931\u65F6\u7528\u9ED8\u8BA4\u7AEF\u53E3\u548C\u9ED8\u8BA4\u6570\u636E\u5E93\u76F8\u5BF9\u8DEF\u5F84\u3002 */\nfunction dbConfig(root: string): { db_port?: number; http_auth?: string; dbDir?: string } {\n try {\n const parsed = JSON.parse(fs.readFileSync(path.join(root, \"configs\", \"db_config.json\"), \"utf8\")) as { db_port?: unknown; http_auth?: unknown; dbDir?: unknown };\n return {\n ...(typeof parsed.db_port === \"number\" ? { db_port: parsed.db_port } : {}),\n ...(typeof parsed.http_auth === \"string\" ? { http_auth: parsed.http_auth } : {}),\n ...(typeof parsed.dbDir === \"string\" && parsed.dbDir.trim() ? { dbDir: parsed.dbDir } : {}),\n };\n } catch {\n return {};\n }\n}\n\n/** \u6307\u6807\u5E93\u4E0E\u4E1A\u52A1\u5E93\u540C\u76EE\u5F55\uFF0C\u6587\u4EF6\u540D\u4E0E\u6570\u636E\u670D\u52A1\u6253\u5F00\u7684 runtime-metrics.sqlite \u4E00\u81F4\u3002 */\nfunction metricsDatabasePath(root: string, dbDir: string | undefined): string {\n return path.join(path.dirname(path.resolve(root, dbDir ?? \"data/sfmc_data.db\")), \"runtime-metrics.sqlite\");\n}\n\nfunction spanOf(params: unknown): number {\n if (params === undefined) return clampMetricsSpan(undefined);\n if (!params || typeof params !== \"object\" || Array.isArray(params)) throw new Error(\"\u53C2\u6570\u5FC5\u987B\u4E3A\u5BF9\u8C61\");\n return clampMetricsSpan((params as { spanMs?: unknown }).spanMs);\n}\n\nfunction offline(error: unknown): boolean {\n const detail = error instanceof Error ? `${error.message} ${String(error.cause ?? \"\")}` : String(error);\n return /fetch failed|ECONNREFUSED|ENOTFOUND|AbortError|TimeoutError|timed out/i.test(detail);\n}\n\n/**\n * \u7BA1\u7406\u534F\u8BAE metrics.read\u3002\n * \u843D\u76D8\u8BFB\u53D6\u5931\u8D25\u65F6\u4FDD\u7559\u6570\u636E\u670D\u52A1\u8FD4\u56DE\u7684\u5386\u53F2\uFF1B\u4E24\u8FB9\u90FD\u6CA1\u6709\u65F6\u6CBF\u7528\u539F\u6765\u7684\u7A7A\u7ED3\u679C\u8BF4\u660E\u3002\n */\nexport async function readRuntimeMetrics(params: unknown): Promise<MetricsResult> {\n const spanMs = spanOf(params);\n const root = getRoot();\n const cfg = dbConfig(root);\n let live: MetricsResult | undefined;\n try {\n const response = await fetch(`http://127.0.0.1:${cfg.db_port ?? 3001}/api/sfmc/metrics?spanMs=${spanMs}`, {\n headers: cfg.http_auth ? { authorization: `Bearer ${cfg.http_auth}` } : {},\n signal: AbortSignal.timeout(10_000),\n });\n if (!response.ok) throw new Error(`\u8FD0\u884C\u6307\u6807\u8BFB\u53D6\u5931\u8D25 (${response.status})`);\n const body = await response.json() as MetricsResult;\n if (!body || typeof body !== \"object\" || !Array.isArray(body.history)) throw new Error(\"\u8FD0\u884C\u6307\u6807\u8BFB\u53D6\u5931\u8D25\");\n live = body;\n } catch (error) {\n if (!offline(error)) throw error;\n }\n let stored: ReturnType<typeof readPersistedMetrics> = null;\n try { stored = readPersistedMetrics(metricsDatabasePath(root, cfg.dbDir), Date.now(), spanMs); } catch { stored = null; }\n if (!live) {\n const history = stored?.history ?? [];\n const resourceHistory = stored?.resourceHistory ?? [];\n return {\n fresh: false,\n updatedAt: history.at(-1)?.recordedAt ?? null,\n current: null,\n history,\n host: null,\n processes: null,\n resourcesUpdatedAt: resourceHistory.at(-1)?.recordedAt ?? null,\n resourceHistory,\n note: history.length || resourceHistory.length ? \"\u6570\u636E\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u5B9E\u65F6\u6570\u503C\u4E0D\u53EF\u7528\" : \"\u6570\u636E\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u6682\u65F6\u6CA1\u6709\u8FD0\u884C\u6307\u6807\",\n };\n }\n const history = stored?.history ?? live.history;\n const resourceHistory = stored?.resourceHistory ?? live.resourceHistory;\n return {\n ...live,\n history,\n ...(resourceHistory ? { resourceHistory } : {}),\n updatedAt: live.updatedAt ?? history.at(-1)?.recordedAt ?? null,\n resourcesUpdatedAt: live.resourcesUpdatedAt ?? resourceHistory?.at(-1)?.recordedAt ?? null,\n };\n}\n"],
5
+ "mappings": "AAIA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,kBAAkB,4BAA4B;AAEvD,SAAS,eAAe;AAGxB,SAAS,SAAS,MAAwE;AACxF,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,GAAG,aAAa,KAAK,KAAK,MAAM,WAAW,gBAAgB,GAAG,MAAM,CAAC;AAC/F,WAAO;AAAA,MACL,GAAI,OAAO,OAAO,YAAY,WAAW,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,MACxE,GAAI,OAAO,OAAO,cAAc,WAAW,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;AAAA,MAC9E,GAAI,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,KAAK,IAAI,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,IAC3F;AAAA,EACF,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGA,SAAS,oBAAoB,MAAc,OAAmC;AAC5E,SAAO,KAAK,KAAK,KAAK,QAAQ,KAAK,QAAQ,MAAM,SAAS,mBAAmB,CAAC,GAAG,wBAAwB;AAC3G;AAEA,SAAS,OAAO,QAAyB;AACvC,MAAI,WAAW,OAAW,QAAO,iBAAiB,MAAS;AAC3D,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,OAAM,IAAI,MAAM,4CAAS;AAC7F,SAAO,iBAAkB,OAAgC,MAAM;AACjE;AAEA,SAAS,QAAQ,OAAyB;AACxC,QAAM,SAAS,iBAAiB,QAAQ,GAAG,MAAM,OAAO,IAAI,OAAO,MAAM,SAAS,EAAE,CAAC,KAAK,OAAO,KAAK;AACtG,SAAO,yEAAyE,KAAK,MAAM;AAC7F;AAMA,eAAsB,mBAAmB,QAAyC;AAChF,QAAM,SAAS,OAAO,MAAM;AAC5B,QAAM,OAAO,QAAQ;AACrB,QAAM,MAAM,SAAS,IAAI;AACzB,MAAI;AACJ,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,oBAAoB,IAAI,WAAW,IAAI,4BAA4B,MAAM,IAAI;AAAA,MACxG,SAAS,IAAI,YAAY,EAAE,eAAe,UAAU,IAAI,SAAS,GAAG,IAAI,CAAC;AAAA,MACzE,QAAQ,YAAY,QAAQ,GAAM;AAAA,IACpC,CAAC;AACD,QAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,qDAAa,SAAS,MAAM,GAAG;AACjE,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,KAAK,OAAO,EAAG,OAAM,IAAI,MAAM,kDAAU;AACjG,WAAO;AAAA,EACT,SAAS,OAAO;AACd,QAAI,CAAC,QAAQ,KAAK,EAAG,OAAM;AAAA,EAC7B;AACA,MAAI,SAAkD;AACtD,MAAI;AAAE,aAAS,qBAAqB,oBAAoB,MAAM,IAAI,KAAK,GAAG,KAAK,IAAI,GAAG,MAAM;AAAA,EAAG,QAAQ;AAAE,aAAS;AAAA,EAAM;AACxH,MAAI,CAAC,MAAM;AACT,UAAMA,WAAU,QAAQ,WAAW,CAAC;AACpC,UAAMC,mBAAkB,QAAQ,mBAAmB,CAAC;AACpD,WAAO;AAAA,MACL,OAAO;AAAA,MACP,WAAWD,SAAQ,GAAG,EAAE,GAAG,cAAc;AAAA,MACzC,SAAS;AAAA,MACT,SAAAA;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,oBAAoBC,iBAAgB,GAAG,EAAE,GAAG,cAAc;AAAA,MAC1D,iBAAAA;AAAA,MACA,MAAMD,SAAQ,UAAUC,iBAAgB,SAAS,+FAAoB;AAAA,IACvE;AAAA,EACF;AACA,QAAM,UAAU,QAAQ,WAAW,KAAK;AACxC,QAAM,kBAAkB,QAAQ,mBAAmB,KAAK;AACxD,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,IAC7C,WAAW,KAAK,aAAa,QAAQ,GAAG,EAAE,GAAG,cAAc;AAAA,IAC3D,oBAAoB,KAAK,sBAAsB,iBAAiB,GAAG,EAAE,GAAG,cAAc;AAAA,EACxF;AACF;",
6
+ "names": ["history", "resourceHistory"]
7
+ }
@@ -10,7 +10,7 @@ import { createSnapshot, runPnpm } from "./maintenance.js";
10
10
  import { callDaemon, disconnectDaemonClient } from "../daemon/client.js";
11
11
  import { ROOT } from "../runtime.js";
12
12
  import { START_ORDER } from "../services.js";
13
- import { readDaemonMeta } from "../daemon/paths.js";
13
+ import { daemonLogPath, readDaemonMeta } from "../daemon/paths.js";
14
14
  function maintenanceLog(message) {
15
15
  const file = process.env.SFMC_MAINTENANCE_LOG || path.join(ROOT, ".sfmc", "logs", "maintenance.log");
16
16
  try {
@@ -42,8 +42,9 @@ async function main() {
42
42
  const activeFile = path.join(runtime, "active.json");
43
43
  let switched = false;
44
44
  let preparedEntry = "";
45
+ const daemonTeardownMs = 3e4;
45
46
  const waitExit = async (pid) => {
46
- const deadline = Date.now() + 3e4;
47
+ const deadline = Date.now() + daemonTeardownMs;
47
48
  for (; ; ) {
48
49
  let alive = true;
49
50
  try {
@@ -56,6 +57,22 @@ async function main() {
56
57
  await new Promise((resolve) => setTimeout(resolve, 100));
57
58
  }
58
59
  };
60
+ const waitDaemonLogAppendable = async () => {
61
+ const log = daemonLogPath();
62
+ const deadline = Date.now() + daemonTeardownMs;
63
+ for (; ; ) {
64
+ try {
65
+ const fd = fs.openSync(log, "a");
66
+ fs.closeSync(fd);
67
+ return;
68
+ } catch (error) {
69
+ const code = error.code;
70
+ if (code !== "EBUSY") throw error;
71
+ if (Date.now() > deadline) throw new Error("\u5B88\u62A4\u8FDB\u7A0B\u65E5\u5FD7\u4ECD\u88AB\u5360\u7528\uFF0C\u5DF2\u505C\u6B62\u5207\u6362\u5E73\u53F0");
72
+ await new Promise((resolve) => setTimeout(resolve, 100));
73
+ }
74
+ }
75
+ };
59
76
  const stopServices = async () => {
60
77
  const meta = readDaemonMeta();
61
78
  if (!meta) return meta;
@@ -118,6 +135,7 @@ async function main() {
118
135
  for (const key of Object.keys(process.env)) if (key.startsWith("SFMC_SERVICE_") && key.endsWith("_ENTRY") || ["SFMC_FETCH_MODULE", "SFMC_PLATFORM_VERSION"].includes(key)) delete process.env[key];
119
136
  process.env.SFMC_DAEMON_ENTRY = launcher;
120
137
  phase("verify");
138
+ await waitDaemonLogAppendable();
121
139
  await runProcess(process.execPath, [launcher, "status"], ROOT);
122
140
  const handshake = await callDaemon("management", { request: { id: request.id, method: "handshake" } });
123
141
  if (handshake.kind !== "management" || !handshake.response.ok || handshake.response.result.platformVersion !== request.target) throw new Error("\u76EE\u6807\u5E73\u53F0\u63E1\u624B\u9A8C\u8BC1\u5931\u8D25");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/management/platform-worker.ts"],
4
- "sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { pathToFileURL } from \"node:url\";\nimport { withMaintenanceLock } from \"@sfmc-bds/management/node\";\nimport { toManagementError, type OperationRecord } from \"@sfmc-bds/management\";\nimport { atomicJson } from \"./tasks.js\";\nimport { readJson, runProcess } from \"./domain.js\";\nimport { createSnapshot, runPnpm } from \"./maintenance.js\";\nimport { callDaemon, disconnectDaemonClient } from \"../daemon/client.js\";\nimport { ROOT } from \"../runtime.js\";\nimport { START_ORDER } from \"../services.js\";\nimport { readDaemonMeta } from \"../daemon/paths.js\";\n\n/**\n * \u7EF4\u62A4\u8FDB\u7A0B\u81EA\u5DF1\u5199\u65E5\u5FD7\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u7236\u8FDB\u7A0B\u628A\u6807\u51C6\u8F93\u51FA\u63A5\u5230\u81EA\u5DF1\u7684\u6587\u4EF6\u53E5\u67C4\u65F6\uFF0C\u5B88\u62A4\u8FDB\u7A0B\u9000\u51FA\u4F1A\u5BFC\u81F4\u8FD9\u6BB5\u8F93\u51FA\u4E22\u5931\uFF1B\u8FD9\u91CC\u76F4\u63A5\u8FFD\u52A0\u5230\u65E5\u5FD7\u6587\u4EF6\u3002\n */\nfunction maintenanceLog(message: string) {\n const file = process.env.SFMC_MAINTENANCE_LOG || path.join(ROOT, \".sfmc\", \"logs\", \"maintenance.log\");\n try {\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.appendFileSync(file, `${new Date().toISOString()} ${message}\\n`);\n } catch { /* \u65E5\u5FD7\u5199\u5931\u8D25\u65F6\u4ECD\u4EE5\u4EFB\u52A1\u8BB0\u5F55\u4E3A\u51C6 */ }\n}\n\n/** \u672C\u8FDB\u7A0B\u5728\u72EC\u7ACB Node \u4E2D\u5E38\u9A7B\uFF0C\u5E73\u53F0\u6362\u5305\u4E0D\u4F1A\u5220\u9664\u5176\u5F53\u524D\u7248\u672C\u76EE\u5F55\u3002 */\nasync function main() {\n const requestFile = process.argv[2];\n if (!requestFile) throw new Error(\"\u7F3A\u5C11\u7EF4\u62A4\u4EFB\u52A1\u6587\u4EF6\");\n const request = readJson<{ id: string; target: string; running: string[]; previous: { entry: string } | null }>(requestFile, { id: \"\", target: \"\", running: [], previous: null });\n if (!/^[\\w-]+$/.test(request.id) || !/^\\d+\\.\\d+\\.\\d+$/.test(request.target)) throw new Error(\"\u975E\u6CD5\u7EF4\u62A4\u8BF7\u6C42\");\n const recordFile = path.join(ROOT, \".sfmc\", \"operations\", `${request.id}.json`);\n let record = readJson<OperationRecord>(recordFile, {} as OperationRecord);\n const phase = (name: string, message?: string) => {\n record = readJson<OperationRecord>(recordFile, record);\n const previous = record.phases.at(-1); if (previous?.status === \"running\") previous.status = \"done\";\n record.phases.push({ name, status: \"running\", ...(message ? { message } : {}) }); record.status = \"running\"; record.updatedAt = new Date().toISOString(); atomicJson(recordFile, record);\n maintenanceLog(`phase ${name}${message ? ` ${message}` : \"\"}`);\n };\n const runtime = path.join(ROOT, \".sfmc\", \"runtime\");\n const release = path.join(runtime, \"releases\", `${request.target}-${request.id}`);\n const activeFile = path.join(runtime, \"active.json\");\n let switched = false;\n let preparedEntry = \"\";\n const waitExit = async (pid: number) => {\n const deadline = Date.now() + 30_000;\n for (;;) {\n let alive = true; try { process.kill(pid, 0); } catch (error) { alive = (error as NodeJS.ErrnoException).code !== \"ESRCH\"; }\n if (!alive) return;\n if (Date.now() > deadline) throw new Error(\"\u5B88\u62A4\u8FDB\u7A0B\u5C1A\u672A\u9000\u51FA\uFF0C\u7981\u6B62\u5207\u6362\u5E73\u53F0\");\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n };\n /** \u53EA\u505C\u670D\u52A1\uFF0C\u4E0D\u9000\u51FA\u5B88\u62A4\u8FDB\u7A0B\u3002\u5907\u4EFD\u5FC5\u987B\u53D1\u751F\u5728\u5B88\u62A4\u8FDB\u7A0B\u8FD8\u6D3B\u7740\u7684\u65F6\u5019\u3002 */\n const stopServices = async () => {\n const meta = readDaemonMeta();\n if (!meta) return meta;\n const status = await callDaemon(\"status\");\n if (status.kind !== \"status\") throw new Error(\"\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u670D\u52A1\u72B6\u6001\");\n if (status.rows.some(row => row.running)) {\n const stopped = await callDaemon(\"maintenanceStop\");\n if (stopped.kind !== \"status\" || stopped.rows.some(row => row.running)) throw new Error(\"\u670D\u52A1\u6CA1\u6709\u4F18\u96C5\u9000\u51FA\");\n }\n return meta;\n };\n /** \u6587\u4EF6\u5907\u4EFD\u5B8C\u6210\u540E\u518D\u8BA9\u65E7\u5B88\u62A4\u8FDB\u7A0B\u9000\u51FA\uFF0C\u907F\u514D\u9000\u51FA\u65F6\u628A\u672C\u7EF4\u62A4\u8FDB\u7A0B\u4E00\u8D77\u5E26\u8D70\u3001\u5907\u4EFD\u505C\u5728\u534A\u622A\u3002 */\n const exitDaemon = async (meta: { pid: number } | null) => {\n if (!meta) return;\n await callDaemon(\"shutdown\"); disconnectDaemonClient(); await waitExit(meta.pid);\n };\n const shutdown = async () => { await exitDaemon(await stopServices()); };\n try {\n // \u63D0\u4EA4\u8FDB\u7A0B\u4FDD\u5B58 workerPid \u540E\u624D\u91CA\u653E\u9501\uFF1B\u7B49\u5F85\u63A5\u7BA1\uFF0C\u7981\u6B62\u7ADE\u6001\u8986\u76D6\u8BB0\u5F55\u3002\n await new Promise(resolve => setTimeout(resolve, 500));\n let acquired = false;\n for (let attempt = 0; attempt < 100 && !acquired; attempt++) {\n try {\n await withMaintenanceLock(ROOT, async () => {\n acquired = true;\n try {\n phase(\"prepare\", `\u51C6\u5907\u5E73\u53F0 ${request.target}`);\n fs.mkdirSync(release, { recursive: true });\n atomicJson(path.join(release, \"package.json\"), { private: true, dependencies: {} });\n await runPnpm([\"add\", \"--ignore-workspace\", \"--prod\", \"--ignore-scripts\", \"--save-exact\", `@sfmc-bds/sfmc@${request.target}`], release);\n const linked = path.join(release, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\");\n if (!fs.existsSync(linked)) throw new Error(\"\u5E73\u53F0\u5165\u53E3\u4E0D\u5B58\u5728\");\n // pnpm \u7684\u4F9D\u8D56\u94FE\u63A5\u5728\u771F\u5B9E\u5305\u76EE\u5F55\u65C1\u3002\u4ECE junction \u8DEF\u5F84 createRequire \u4F1A\u627E\u4E0D\u5230 @sfmc-bds/cli\u3002\n const entry = fs.realpathSync(linked);\n // \u53D1\u5E03\u7684\u5E73\u53F0\u5FC5\u987B\u5305\u542B\u672C\u6B21\u684C\u9762\u6240\u9700\u7BA1\u7406\u534F\u8BAE\u3002\n const resolver = createRequire(entry);\n const cli = path.join(path.dirname(resolver.resolve(\"@sfmc-bds/cli/package.json\")), \"dist\", \"management\", \"stdio.js\");\n if (!fs.existsSync(cli)) throw new Error(\"\u6700\u65B0\u5E73\u53F0\u5C1A\u672A\u53D1\u5E03\u7BA1\u7406\u5165\u53E3\uFF0C\u4FDD\u7559\u5F53\u524D\u90E8\u7F72\uFF1B\u8BF7\u5148\u5B8C\u6210\u5E73\u53F0\u53D1\u7248\");\n const targetSdk = readJson<{ version: string }>(resolver.resolve(\"@sfmc-bds/sdk/package.json\"), { version: \"\" }).version;\n const { satisfiesSdk } = await import(pathToFileURL(path.join(path.dirname(cli), \"../..\", \"scripts/module-install/lib/semver.mjs\")).href) as { satisfiesSdk: (version: string, range: string) => boolean };\n const modules = path.join(ROOT, \"modules\", \"packages\");\n if (fs.existsSync(modules)) for (const folder of fs.readdirSync(modules)) {\n const pkg = readJson<{ peerDependencies?: Record<string, string> }>(path.join(modules, folder, \"package.json\"), {});\n const manifest = readJson<{ sdk?: string }>(path.join(modules, folder, \"sapi\", \"manifest.json\"), {});\n const range = pkg.peerDependencies?.[\"@sfmc-bds/sdk\"] ?? manifest.sdk;\n if (range && !satisfiesSdk(targetSdk, range)) throw new Error(`\u6A21\u5757 ${folder} \u4E0E\u76EE\u6807 SDK ${targetSdk} \u4E0D\u517C\u5BB9 (${range})\uFF1B\u4FDD\u7559\u56FA\u5B9A\u7248\u672C\u53CA\u672C\u5730\u94FE\u63A5\uFF0C\u5DF2\u505C\u6B62\u5347\u7EA7`);\n }\n preparedEntry = entry;\n phase(\"stop-services\");\n const lock = readJson<{ nonce: string }>(path.join(ROOT, \".sfmc\", \"maintenance.lock\"), { nonce: \"\" });\n process.env.SFMC_MAINTENANCE_TOKEN = lock.nonce;\n const daemon = await stopServices();\n await createSnapshot(request.id, phase);\n await exitDaemon(daemon);\n phase(\"execute\"); atomicJson(activeFile, { entry, version: request.target, pnpm: process.env.SFMC_PNPM_ENTRY }); switched = true;\n const launcher = path.join(runtime, \"launcher.mjs\");\n fs.writeFileSync(launcher, \"import fs from 'node:fs'; import path from 'node:path'; import {pathToFileURL,fileURLToPath} from 'node:url'; const base=path.dirname(fileURLToPath(import.meta.url)); const active=JSON.parse(fs.readFileSync(path.join(base,'active.json'),'utf8')); process.env.SFMC_DAEMON_ENTRY=fileURLToPath(import.meta.url); process.env.SFMC_NODE_BINARY=process.execPath; if(active.pnpm) process.env.SFMC_PNPM_ENTRY=active.pnpm; await import(pathToFileURL(active.entry).href);\\n\");\n for (const key of Object.keys(process.env)) if (key.startsWith(\"SFMC_SERVICE_\") && key.endsWith(\"_ENTRY\") || [\"SFMC_FETCH_MODULE\", \"SFMC_PLATFORM_VERSION\"].includes(key)) delete process.env[key];\n process.env.SFMC_DAEMON_ENTRY = launcher;\n phase(\"verify\");\n await runProcess(process.execPath, [launcher, \"status\"], ROOT);\n const handshake = await callDaemon(\"management\", { request: { id: request.id, method: \"handshake\" } });\n if (handshake.kind !== \"management\" || !handshake.response.ok || (handshake.response.result as { platformVersion?: string }).platformVersion !== request.target) throw new Error(\"\u76EE\u6807\u5E73\u53F0\u63E1\u624B\u9A8C\u8BC1\u5931\u8D25\");\n phase(\"restore\");\n for (const service of START_ORDER.filter(name => request.running.includes(name))) await callDaemon(\"start\", { name: service });\n await new Promise(resolve => setTimeout(resolve, 3000));\n const status = await callDaemon(\"status\");\n if (status.kind !== \"status\" || request.running.some(name => !status.rows.some(row => row.name === name && row.running))) throw new Error(\"\u6B64\u524D\u8FD0\u884C\u7684\u670D\u52A1\u672A\u5168\u90E8\u6062\u590D\");\n record.result = { version: request.target, backupId: request.id }; record.status = \"succeeded\";\n } catch (error) {\n // \u56DE\u9000\u4E5F\u5FC5\u987B\u5728\u540C\u4E00\u628A\u9501\u5185\u5B8C\u6210\uFF0C\u9632\u6B62\u5176\u4ED6\u5BA2\u6237\u7AEF\u5728\u5165\u53E3\u5207\u6362\u671F\u95F4\u5199\u5165\u3002\n let rolledBack = false;\n if (switched && request.previous) {\n try { await shutdown(); atomicJson(activeFile, request.previous); rolledBack = true; }\n catch (rollbackError) { phase(\"rollback-blocked\", `\u65E0\u6CD5\u5B89\u5168\u505C\u6B62\u76EE\u6807\u7248\u672C\uFF1B\u4FDD\u7559\u5165\u53E3\u548C\u5907\u4EFD\uFF0C\u4E0D\u8986\u76D6\u73A9\u5BB6\u6570\u636E: ${String(rollbackError)}`); }\n }\n record.result = { programRolledBack: rolledBack, backupId: request.id, dataRestoreRequired: switched, preparedEntry };\n throw error;\n }\n });\n } catch (error) {\n if (!acquired && (error as { code?: string }).code === \"locked\") { await new Promise(resolve => setTimeout(resolve, 200)); continue; }\n throw error;\n }\n }\n if (!acquired) throw new Error(\"\u65E0\u6CD5\u63A5\u7BA1\u7EF4\u62A4\u9501\");\n } catch (error) {\n record.status = \"failed\"; record.error = toManagementError(error);\n record.result ??= { programRolledBack: false, backupId: request.id, dataRestoreRequired: switched, preparedEntry };\n maintenanceLog(`failed ${record.error.message}`);\n } finally {\n record.updatedAt = new Date().toISOString(); const last = record.phases.at(-1); if (last) last.status = record.status === \"succeeded\" ? \"done\" : \"failed\";\n atomicJson(recordFile, record);\n fs.rmSync(requestFile, { force: true });\n disconnectDaemonClient();\n }\n}\nvoid main().catch(error => { process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`); process.exitCode = 1; });\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { pathToFileURL } from \"node:url\";\nimport { withMaintenanceLock } from \"@sfmc-bds/management/node\";\nimport { toManagementError, type OperationRecord } from \"@sfmc-bds/management\";\nimport { atomicJson } from \"./tasks.js\";\nimport { readJson, runProcess } from \"./domain.js\";\nimport { createSnapshot, runPnpm } from \"./maintenance.js\";\nimport { callDaemon, disconnectDaemonClient } from \"../daemon/client.js\";\nimport { ROOT } from \"../runtime.js\";\nimport { START_ORDER } from \"../services.js\";\nimport { daemonLogPath, readDaemonMeta } from \"../daemon/paths.js\";\n\n/**\n * \u7EF4\u62A4\u8FDB\u7A0B\u81EA\u5DF1\u5199\u65E5\u5FD7\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u7236\u8FDB\u7A0B\u628A\u6807\u51C6\u8F93\u51FA\u63A5\u5230\u81EA\u5DF1\u7684\u6587\u4EF6\u53E5\u67C4\u65F6\uFF0C\u5B88\u62A4\u8FDB\u7A0B\u9000\u51FA\u4F1A\u5BFC\u81F4\u8FD9\u6BB5\u8F93\u51FA\u4E22\u5931\uFF1B\u8FD9\u91CC\u76F4\u63A5\u8FFD\u52A0\u5230\u65E5\u5FD7\u6587\u4EF6\u3002\n */\nfunction maintenanceLog(message: string) {\n const file = process.env.SFMC_MAINTENANCE_LOG || path.join(ROOT, \".sfmc\", \"logs\", \"maintenance.log\");\n try {\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.appendFileSync(file, `${new Date().toISOString()} ${message}\\n`);\n } catch { /* \u65E5\u5FD7\u5199\u5931\u8D25\u65F6\u4ECD\u4EE5\u4EFB\u52A1\u8BB0\u5F55\u4E3A\u51C6 */ }\n}\n\n/** \u672C\u8FDB\u7A0B\u5728\u72EC\u7ACB Node \u4E2D\u5E38\u9A7B\uFF0C\u5E73\u53F0\u6362\u5305\u4E0D\u4F1A\u5220\u9664\u5176\u5F53\u524D\u7248\u672C\u76EE\u5F55\u3002 */\nasync function main() {\n const requestFile = process.argv[2];\n if (!requestFile) throw new Error(\"\u7F3A\u5C11\u7EF4\u62A4\u4EFB\u52A1\u6587\u4EF6\");\n const request = readJson<{ id: string; target: string; running: string[]; previous: { entry: string } | null }>(requestFile, { id: \"\", target: \"\", running: [], previous: null });\n if (!/^[\\w-]+$/.test(request.id) || !/^\\d+\\.\\d+\\.\\d+$/.test(request.target)) throw new Error(\"\u975E\u6CD5\u7EF4\u62A4\u8BF7\u6C42\");\n const recordFile = path.join(ROOT, \".sfmc\", \"operations\", `${request.id}.json`);\n let record = readJson<OperationRecord>(recordFile, {} as OperationRecord);\n const phase = (name: string, message?: string) => {\n record = readJson<OperationRecord>(recordFile, record);\n const previous = record.phases.at(-1); if (previous?.status === \"running\") previous.status = \"done\";\n record.phases.push({ name, status: \"running\", ...(message ? { message } : {}) }); record.status = \"running\"; record.updatedAt = new Date().toISOString(); atomicJson(recordFile, record);\n maintenanceLog(`phase ${name}${message ? ` ${message}` : \"\"}`);\n };\n const runtime = path.join(ROOT, \".sfmc\", \"runtime\");\n const release = path.join(runtime, \"releases\", `${request.target}-${request.id}`);\n const activeFile = path.join(runtime, \"active.json\");\n let switched = false;\n let preparedEntry = \"\";\n /** \u65E7\u8FDB\u7A0B\u9000\u51FA\uFF0C\u4EE5\u53CA\u5B83\u7684\u65E5\u5FD7\u53E5\u67C4\u677E\u5F00\uFF0C\u5171\u7528\u8FD9\u4E00\u6BB5\u7B49\u5F85\u3002 */\n const daemonTeardownMs = 30_000;\n const waitExit = async (pid: number) => {\n const deadline = Date.now() + daemonTeardownMs;\n for (;;) {\n let alive = true; try { process.kill(pid, 0); } catch (error) { alive = (error as NodeJS.ErrnoException).code !== \"ESRCH\"; }\n if (!alive) return;\n if (Date.now() > deadline) throw new Error(\"\u5B88\u62A4\u8FDB\u7A0B\u5C1A\u672A\u9000\u51FA\uFF0C\u7981\u6B62\u5207\u6362\u5E73\u53F0\");\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n };\n /**\n * \u7B49\u5230 daemon.log \u53EF\u4EE5\u518D\u6B21\u8FFD\u52A0\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u5E73\u53F0\u6821\u9A8C\u4F1A\u62C9\u8D77\u4E0B\u4E00\u7248\u5B88\u62A4\u8FDB\u7A0B\uFF0C\u5B83\u4E00\u542F\u52A8\u5C31\u8FFD\u52A0\u8FD9\u4E2A\u6587\u4EF6\u3002\n * \u65E7\u65E5\u5FD7\u6CF5\u8981\u7B49 Node \u8FDB\u7A0B\u9000\u51FA\u540E\u624D\u5173\u95ED\u53E5\u67C4\uFF0C\u4E2D\u95F4\u4F1A\u8BA9\u6253\u5F00\u5931\u8D25\u3002\n */\n const waitDaemonLogAppendable = async () => {\n const log = daemonLogPath();\n const deadline = Date.now() + daemonTeardownMs;\n for (;;) {\n try {\n const fd = fs.openSync(log, \"a\");\n fs.closeSync(fd);\n return;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"EBUSY\") throw error;\n if (Date.now() > deadline) throw new Error(\"\u5B88\u62A4\u8FDB\u7A0B\u65E5\u5FD7\u4ECD\u88AB\u5360\u7528\uFF0C\u5DF2\u505C\u6B62\u5207\u6362\u5E73\u53F0\");\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n }\n };\n /** \u53EA\u505C\u670D\u52A1\uFF0C\u4E0D\u9000\u51FA\u5B88\u62A4\u8FDB\u7A0B\u3002\u5907\u4EFD\u5FC5\u987B\u53D1\u751F\u5728\u5B88\u62A4\u8FDB\u7A0B\u8FD8\u6D3B\u7740\u7684\u65F6\u5019\u3002 */\n const stopServices = async () => {\n const meta = readDaemonMeta();\n if (!meta) return meta;\n const status = await callDaemon(\"status\");\n if (status.kind !== \"status\") throw new Error(\"\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u670D\u52A1\u72B6\u6001\");\n if (status.rows.some(row => row.running)) {\n const stopped = await callDaemon(\"maintenanceStop\");\n if (stopped.kind !== \"status\" || stopped.rows.some(row => row.running)) throw new Error(\"\u670D\u52A1\u6CA1\u6709\u4F18\u96C5\u9000\u51FA\");\n }\n return meta;\n };\n /** \u6587\u4EF6\u5907\u4EFD\u5B8C\u6210\u540E\u518D\u8BA9\u65E7\u5B88\u62A4\u8FDB\u7A0B\u9000\u51FA\uFF0C\u907F\u514D\u9000\u51FA\u65F6\u628A\u672C\u7EF4\u62A4\u8FDB\u7A0B\u4E00\u8D77\u5E26\u8D70\u3001\u5907\u4EFD\u505C\u5728\u534A\u622A\u3002 */\n const exitDaemon = async (meta: { pid: number } | null) => {\n if (!meta) return;\n await callDaemon(\"shutdown\"); disconnectDaemonClient(); await waitExit(meta.pid);\n };\n const shutdown = async () => { await exitDaemon(await stopServices()); };\n try {\n // \u63D0\u4EA4\u8FDB\u7A0B\u4FDD\u5B58 workerPid \u540E\u624D\u91CA\u653E\u9501\uFF1B\u7B49\u5F85\u63A5\u7BA1\uFF0C\u7981\u6B62\u7ADE\u6001\u8986\u76D6\u8BB0\u5F55\u3002\n await new Promise(resolve => setTimeout(resolve, 500));\n let acquired = false;\n for (let attempt = 0; attempt < 100 && !acquired; attempt++) {\n try {\n await withMaintenanceLock(ROOT, async () => {\n acquired = true;\n try {\n phase(\"prepare\", `\u51C6\u5907\u5E73\u53F0 ${request.target}`);\n fs.mkdirSync(release, { recursive: true });\n atomicJson(path.join(release, \"package.json\"), { private: true, dependencies: {} });\n await runPnpm([\"add\", \"--ignore-workspace\", \"--prod\", \"--ignore-scripts\", \"--save-exact\", `@sfmc-bds/sfmc@${request.target}`], release);\n const linked = path.join(release, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\");\n if (!fs.existsSync(linked)) throw new Error(\"\u5E73\u53F0\u5165\u53E3\u4E0D\u5B58\u5728\");\n // pnpm \u7684\u4F9D\u8D56\u94FE\u63A5\u5728\u771F\u5B9E\u5305\u76EE\u5F55\u65C1\u3002\u4ECE junction \u8DEF\u5F84 createRequire \u4F1A\u627E\u4E0D\u5230 @sfmc-bds/cli\u3002\n const entry = fs.realpathSync(linked);\n // \u53D1\u5E03\u7684\u5E73\u53F0\u5FC5\u987B\u5305\u542B\u672C\u6B21\u684C\u9762\u6240\u9700\u7BA1\u7406\u534F\u8BAE\u3002\n const resolver = createRequire(entry);\n const cli = path.join(path.dirname(resolver.resolve(\"@sfmc-bds/cli/package.json\")), \"dist\", \"management\", \"stdio.js\");\n if (!fs.existsSync(cli)) throw new Error(\"\u6700\u65B0\u5E73\u53F0\u5C1A\u672A\u53D1\u5E03\u7BA1\u7406\u5165\u53E3\uFF0C\u4FDD\u7559\u5F53\u524D\u90E8\u7F72\uFF1B\u8BF7\u5148\u5B8C\u6210\u5E73\u53F0\u53D1\u7248\");\n const targetSdk = readJson<{ version: string }>(resolver.resolve(\"@sfmc-bds/sdk/package.json\"), { version: \"\" }).version;\n const { satisfiesSdk } = await import(pathToFileURL(path.join(path.dirname(cli), \"../..\", \"scripts/module-install/lib/semver.mjs\")).href) as { satisfiesSdk: (version: string, range: string) => boolean };\n const modules = path.join(ROOT, \"modules\", \"packages\");\n if (fs.existsSync(modules)) for (const folder of fs.readdirSync(modules)) {\n const pkg = readJson<{ peerDependencies?: Record<string, string> }>(path.join(modules, folder, \"package.json\"), {});\n const manifest = readJson<{ sdk?: string }>(path.join(modules, folder, \"sapi\", \"manifest.json\"), {});\n const range = pkg.peerDependencies?.[\"@sfmc-bds/sdk\"] ?? manifest.sdk;\n if (range && !satisfiesSdk(targetSdk, range)) throw new Error(`\u6A21\u5757 ${folder} \u4E0E\u76EE\u6807 SDK ${targetSdk} \u4E0D\u517C\u5BB9 (${range})\uFF1B\u4FDD\u7559\u56FA\u5B9A\u7248\u672C\u53CA\u672C\u5730\u94FE\u63A5\uFF0C\u5DF2\u505C\u6B62\u5347\u7EA7`);\n }\n preparedEntry = entry;\n phase(\"stop-services\");\n const lock = readJson<{ nonce: string }>(path.join(ROOT, \".sfmc\", \"maintenance.lock\"), { nonce: \"\" });\n process.env.SFMC_MAINTENANCE_TOKEN = lock.nonce;\n const daemon = await stopServices();\n await createSnapshot(request.id, phase);\n await exitDaemon(daemon);\n phase(\"execute\"); atomicJson(activeFile, { entry, version: request.target, pnpm: process.env.SFMC_PNPM_ENTRY }); switched = true;\n const launcher = path.join(runtime, \"launcher.mjs\");\n fs.writeFileSync(launcher, \"import fs from 'node:fs'; import path from 'node:path'; import {pathToFileURL,fileURLToPath} from 'node:url'; const base=path.dirname(fileURLToPath(import.meta.url)); const active=JSON.parse(fs.readFileSync(path.join(base,'active.json'),'utf8')); process.env.SFMC_DAEMON_ENTRY=fileURLToPath(import.meta.url); process.env.SFMC_NODE_BINARY=process.execPath; if(active.pnpm) process.env.SFMC_PNPM_ENTRY=active.pnpm; await import(pathToFileURL(active.entry).href);\\n\");\n for (const key of Object.keys(process.env)) if (key.startsWith(\"SFMC_SERVICE_\") && key.endsWith(\"_ENTRY\") || [\"SFMC_FETCH_MODULE\", \"SFMC_PLATFORM_VERSION\"].includes(key)) delete process.env[key];\n process.env.SFMC_DAEMON_ENTRY = launcher;\n phase(\"verify\");\n await waitDaemonLogAppendable();\n await runProcess(process.execPath, [launcher, \"status\"], ROOT);\n const handshake = await callDaemon(\"management\", { request: { id: request.id, method: \"handshake\" } });\n if (handshake.kind !== \"management\" || !handshake.response.ok || (handshake.response.result as { platformVersion?: string }).platformVersion !== request.target) throw new Error(\"\u76EE\u6807\u5E73\u53F0\u63E1\u624B\u9A8C\u8BC1\u5931\u8D25\");\n phase(\"restore\");\n for (const service of START_ORDER.filter(name => request.running.includes(name))) await callDaemon(\"start\", { name: service });\n await new Promise(resolve => setTimeout(resolve, 3000));\n const status = await callDaemon(\"status\");\n if (status.kind !== \"status\" || request.running.some(name => !status.rows.some(row => row.name === name && row.running))) throw new Error(\"\u6B64\u524D\u8FD0\u884C\u7684\u670D\u52A1\u672A\u5168\u90E8\u6062\u590D\");\n record.result = { version: request.target, backupId: request.id }; record.status = \"succeeded\";\n } catch (error) {\n // \u56DE\u9000\u4E5F\u5FC5\u987B\u5728\u540C\u4E00\u628A\u9501\u5185\u5B8C\u6210\uFF0C\u9632\u6B62\u5176\u4ED6\u5BA2\u6237\u7AEF\u5728\u5165\u53E3\u5207\u6362\u671F\u95F4\u5199\u5165\u3002\n let rolledBack = false;\n if (switched && request.previous) {\n try { await shutdown(); atomicJson(activeFile, request.previous); rolledBack = true; }\n catch (rollbackError) { phase(\"rollback-blocked\", `\u65E0\u6CD5\u5B89\u5168\u505C\u6B62\u76EE\u6807\u7248\u672C\uFF1B\u4FDD\u7559\u5165\u53E3\u548C\u5907\u4EFD\uFF0C\u4E0D\u8986\u76D6\u73A9\u5BB6\u6570\u636E: ${String(rollbackError)}`); }\n }\n record.result = { programRolledBack: rolledBack, backupId: request.id, dataRestoreRequired: switched, preparedEntry };\n throw error;\n }\n });\n } catch (error) {\n if (!acquired && (error as { code?: string }).code === \"locked\") { await new Promise(resolve => setTimeout(resolve, 200)); continue; }\n throw error;\n }\n }\n if (!acquired) throw new Error(\"\u65E0\u6CD5\u63A5\u7BA1\u7EF4\u62A4\u9501\");\n } catch (error) {\n record.status = \"failed\"; record.error = toManagementError(error);\n record.result ??= { programRolledBack: false, backupId: request.id, dataRestoreRequired: switched, preparedEntry };\n maintenanceLog(`failed ${record.error.message}`);\n } finally {\n record.updatedAt = new Date().toISOString(); const last = record.phases.at(-1); if (last) last.status = record.status === \"succeeded\" ? \"done\" : \"failed\";\n atomicJson(recordFile, record);\n fs.rmSync(requestFile, { force: true });\n disconnectDaemonClient();\n }\n}\nvoid main().catch(error => { process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`); process.exitCode = 1; });\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/management/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAA+B,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAMjH,OAAO,EAAE,SAAS,EAAgC,MAAM,YAAY,CAAC;AAmBrE,wBAAgB,eAAe,cAQ9B;AACD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,2BAA+E;AAmC3J,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAwIrF"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/management/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAA+B,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAOjH,OAAO,EAAE,SAAS,EAAgC,MAAM,YAAY,CAAC;AAoBrE,wBAAgB,eAAe,cAQ9B;AACD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,2BAA+E;AAoC3J,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CA0HrF"}
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import os from "node:os";
4
4
  import { EventEmitter } from "node:events";
5
5
  import { MANAGEMENT_PROTOCOL_VERSION } from "@sfmc-bds/management";
6
+ import { readQqBindings } from "@sfmc-bds/db-server/qq-bindings";
6
7
  import { ROOT, isRuntimeInitialized, spawnService } from "../runtime.js";
7
8
  import { queryServicesRuntimeLocal, services, START_ORDER, SERVICE_NAMES, refreshServices, onServiceStateChange } from "../services.js";
8
9
  import { readDiskLogs, onLog } from "../logs.js";
@@ -17,6 +18,7 @@ import { cmdPackBuild, cmdPackDeploy } from "../pack-lifecycle.js";
17
18
  import { withMaintenanceLock } from "@sfmc-bds/management/node";
18
19
  import { deploymentPreflight, deploymentPort } from "./deployment.js";
19
20
  import { resolveBdsContext } from "../pack-lifecycle.js";
21
+ import { readRuntimeMetrics } from "./metrics-read.js";
20
22
  const events = new EventEmitter();
21
23
  function deploymentInitialized() {
22
24
  if (isRuntimeInitialized()) return true;
@@ -62,6 +64,7 @@ async function players() {
62
64
  const files = playerFiles();
63
65
  const allowlist = readJson(files.allowlist, []);
64
66
  const cfg = readJson(path.join(ROOT, "configs", "db_config.json"), {});
67
+ const database = path.resolve(ROOT, typeof cfg.dbDir === "string" && cfg.dbDir.trim() ? cfg.dbDir : "data/sfmc_data.db");
65
68
  let data = {};
66
69
  try {
67
70
  const response = await fetch(`http://127.0.0.1:${cfg.db_port ?? 3001}/api/sfmc/status`, { headers: cfg.http_auth ? { authorization: `Bearer ${cfg.http_auth}` } : {}, signal: AbortSignal.timeout(5e3) });
@@ -69,7 +72,7 @@ async function players() {
69
72
  } catch {
70
73
  }
71
74
  const fresh = typeof data.updatedAt === "number" && Date.now() - data.updatedAt < 6e4;
72
- return { players: (data.online ?? []).map((row) => ({ name: row.name, xuid: "", online: fresh ? true : null })), updatedAt: data.updatedAt ? new Date(data.updatedAt).toISOString() : "", fresh, allowlist, permissions: readJson(files.permissions, []), sfmcPermissions: readJson(files.sfmcPermissions, []) };
75
+ return { players: (data.online ?? []).map((row) => ({ name: row.name, xuid: "", online: fresh ? true : null })), updatedAt: data.updatedAt ? new Date(data.updatedAt).toISOString() : "", fresh, allowlist, permissions: readJson(files.permissions, []), sfmcPermissions: readJson(files.sfmcPermissions, []), bindings: readQqBindings(database) };
73
76
  }
74
77
  async function bdsUpdate(context, checkOnly = false) {
75
78
  context.phase("download", checkOnly ? "\u68C0\u67E5 BDS \u66F4\u65B0" : "\u66F4\u65B0 BDS");
@@ -188,20 +191,8 @@ async function dispatchManagement(request) {
188
191
  return store.submit(request.method, (context) => withStoppedServices(context, [...START_ORDER], () => togglePack(identifier(p.id), p.enabled === true)));
189
192
  case "players.list":
190
193
  return players();
191
- case "metrics.read": {
192
- const cfg = readJson(path.join(ROOT, "configs", "db_config.json"), {});
193
- try {
194
- const response = await fetch(`http://127.0.0.1:${cfg.db_port ?? 3001}/api/sfmc/metrics`, { headers: cfg.http_auth ? { authorization: `Bearer ${cfg.http_auth}` } : {}, signal: AbortSignal.timeout(1e4) });
195
- if (!response.ok) throw new Error(`\u8FD0\u884C\u6307\u6807\u8BFB\u53D6\u5931\u8D25 (${response.status})`);
196
- return response.json();
197
- } catch (error) {
198
- const detail = error instanceof Error ? `${error.message} ${String(error.cause ?? "")}` : String(error);
199
- if (/fetch failed|ECONNREFUSED|ENOTFOUND|AbortError|TimeoutError|timed out/i.test(detail)) {
200
- return { fresh: false, updatedAt: null, current: null, history: [], host: null, processes: null, resourcesUpdatedAt: null, note: "\u6570\u636E\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u6682\u65F6\u6CA1\u6709\u8FD0\u884C\u6307\u6807" };
201
- }
202
- throw error;
203
- }
204
- }
194
+ case "metrics.read":
195
+ return readRuntimeMetrics(request.params);
205
196
  case "players.apply":
206
197
  return store.submit(request.method, (context) => withStoppedServices(context, [...START_ORDER], async () => savePlayerPermissions(string(p.kind, "\u6743\u9650\u7C7B\u578B"), p.entries)));
207
198
  case "attachment.plan":
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/management/server.ts"],
4
- "sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { EventEmitter } from \"node:events\";\nimport { MANAGEMENT_PROTOCOL_VERSION, type ManagementRequest, type ManagementEvent } from \"@sfmc-bds/management\";\nimport { ROOT, isRuntimeInitialized, spawnService } from \"../runtime.js\";\nimport { queryServicesRuntimeLocal, services, START_ORDER, SERVICE_NAMES, refreshServices, onServiceStateChange, type ServiceName } from \"../services.js\";\nimport { readDiskLogs, onLog } from \"../logs.js\";\nimport { cmdModuleEnable, cmdModuleDisable } from \"../module-commands.js\";\nimport { ensureCoreConfigs } from \"@sfmc-bds/sdk/node/config\";\nimport { TaskStore, atomicJson, type TaskContext } from \"./tasks.js\";\nimport { configFiles, readDocument, saveDocument, validateDocument } from \"./config.js\";\nimport { listModules, searchModules, identifier, runFetch, readJson, listPacks, togglePack, importPack, playerFiles, savePlayerPermissions, modulePlan, applyModulePlan } from \"./domain.js\";\nimport { attachmentPlan, platformVersion, withStoppedServices, launchPlatformUpdate, restoreSnapshot, verifyRunning } from \"./maintenance.js\";\nimport { startupPlan } from \"./startup.js\";\nimport { cmdPackBuild, cmdPackDeploy } from \"../pack-lifecycle.js\";\nimport { withMaintenanceLock } from \"@sfmc-bds/management/node\";\nimport { deploymentPreflight, deploymentPort } from \"./deployment.js\";\nimport { resolveBdsContext } from \"../pack-lifecycle.js\";\n\nconst events = new EventEmitter();\n/** \u7A7A\u76EE\u5F55\u4E5F\u8981\u80FD\u5B8C\u6210\u63E1\u624B\uFF0C\u4F9B\u684C\u9762\u521D\u59CB\u5316\u5411\u5BFC\u7EE7\u7EED\uFF1B\u65E7\u90E8\u7F72\u4ECD\u8BC6\u522B\u5DF2\u6709 BDS\u3002 */\nfunction deploymentInitialized(): boolean {\n if (isRuntimeInitialized()) return true;\n const config = readJson<{ bds_path?: string }>(path.join(ROOT, \"configs\", \"bds_updater.json\"), {});\n if (!config.bds_path) return false;\n return fs.existsSync(path.join(resolveBdsContext().bdsRoot, process.platform === \"win32\" ? \"bedrock_server.exe\" : \"bedrock_server\"));\n}\nlet tasks: TaskStore | undefined;\nexport function managementTasks() {\n if (!tasks) {\n tasks = new TaskStore(ROOT);\n tasks.on(\"operation\", payload => events.emit(\"event\", { type: \"event\", event: \"operation\", instanceId: ROOT, payload }));\n onLog(log => events.emit(\"event\", { type: \"event\", event: \"log\", instanceId: ROOT, payload: { ...log, time: log.time.toISOString() } }));\n onServiceStateChange(payload => events.emit(\"event\", { type: \"event\", event: \"serviceState\", instanceId: ROOT, payload }));\n }\n return tasks;\n}\nexport function onManagementEvent(callback: (event: ManagementEvent) => void) { events.on(\"event\", callback); return () => events.off(\"event\", callback); }\nfunction params(request: ManagementRequest): Record<string, unknown> {\n if (request.params === undefined) return {};\n if (!request.params || typeof request.params !== \"object\" || Array.isArray(request.params)) throw new Error(\"\u53C2\u6570\u5FC5\u987B\u4E3A\u5BF9\u8C61\");\n return request.params as Record<string, unknown>;\n}\nfunction string(value: unknown, label: string) { if (typeof value !== \"string\" || value.length > 2 * 1024 * 1024) throw new Error(`\u975E\u6CD5 ${label}`); return value; }\nfunction service(value: unknown): ServiceName { if (!SERVICE_NAMES.includes(value as ServiceName)) throw new Error(\"\u672A\u77E5\u670D\u52A1\"); return value as ServiceName; }\nasync function rebuildModules() {\n const build = await cmdPackBuild([]); if (!build.ok) throw new Error(build.message);\n const deploy = await cmdPackDeploy([]); if (!deploy.ok) throw new Error(deploy.message);\n return { changed: true };\n}\nasync function players() {\n const files = playerFiles(); const allowlist = readJson<unknown[]>(files.allowlist, []);\n const cfg = readJson<{ db_port?: number; http_auth?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\n let data: { online?: { name: string }[]; updatedAt?: number } = {};\n try {\n const response = await fetch(`http://127.0.0.1:${cfg.db_port ?? 3001}/api/sfmc/status`, { headers: cfg.http_auth ? { authorization: `Bearer ${cfg.http_auth}` } : {}, signal: AbortSignal.timeout(5000) });\n if (response.ok) data = await response.json() as typeof data;\n } catch { /* \u672A\u8FDE\u63A5\u65F6\u4F7F\u7528\u672A\u77E5\u72B6\u6001 */ }\n const fresh = typeof data.updatedAt === \"number\" && Date.now() - data.updatedAt < 60_000;\n return { players: (data.online ?? []).map(row => ({ name: row.name, xuid: \"\", online: fresh ? true : null })), updatedAt: data.updatedAt ? new Date(data.updatedAt).toISOString() : \"\", fresh, allowlist, permissions: readJson<unknown[]>(files.permissions, []), sfmcPermissions: readJson<unknown[]>(files.sfmcPermissions, []) };\n}\nasync function bdsUpdate(context: TaskContext, checkOnly = false) {\n context.phase(\"download\", checkOnly ? \"\u68C0\u67E5 BDS \u66F4\u65B0\" : \"\u66F4\u65B0 BDS\");\n const args = checkOnly ? [\"--check-only\", \"--no-notify\"] : [\"--no-start\", \"--no-notify\"];\n let output = \"\";\n await new Promise<void>((resolve, reject) => {\n const child = spawnService(\"update\", args, { stdio: \"pipe\", cwd: ROOT });\n for (const stream of [child.stdout, child.stderr]) stream?.on(\"data\", chunk => { output = (output + String(chunk)).slice(-64_000); });\n child.on(\"error\", reject); child.on(\"close\", code => code === 0 ? resolve() : reject(new Error(`BDS \u66F4\u65B0\u5931\u8D25 (${code})`)));\n });\n return { checked: checkOnly, updated: /SFMC_UPDATE_RESULT=deployed/.test(output), currentVersion: /CURRENT=([^\\r\\n]+)/.exec(output)?.[1] ?? \"unknown\", latestVersion: /LATEST=([^\\r\\n]+)/.exec(output)?.[1] ?? \"unknown\", result: /SFMC_UPDATE_RESULT=([^\\r\\n]+)/.exec(output)?.[1] ?? \"unknown\" };\n}\nexport async function dispatchManagement(request: ManagementRequest): Promise<unknown> {\n const p = params(request); const store = managementTasks();\n switch (request.method) {\n case \"handshake\": return { protocolVersion: MANAGEMENT_PROTOCOL_VERSION, platformVersion: platformVersion(), host: { os: process.platform === \"win32\" ? \"windows\" : process.platform, arch: process.arch, release: os.release() }, root: ROOT, capabilities: [\"services\", \"logs\", \"modules\", \"config\", \"packs\", \"players\", \"updates\", \"operations\", \"metrics\"], daemonPid: process.pid, daemonStartedAt: new Date(Date.now() - process.uptime() * 1000).toISOString(), initialized: deploymentInitialized() };\n case \"events.subscribe\": return { subscribed: true };\n case \"services.list\": return { rows: await queryServicesRuntimeLocal() };\n case \"services.start\": case \"services.stop\": case \"services.restart\": {\n const names = p.name === \"all\" ? [...START_ORDER] : [service(p.name)];\n return store.submit(request.method, async context => {\n context.phase(\"execute\");\n const rows = await queryServicesRuntimeLocal();\n if (rows.some(row => names.includes(row.name) && row.running && row.ownership === \"external\") && request.method !== \"services.start\") throw new Error(\"\u5916\u90E8\u8FDB\u7A0B\u65E0\u6CD5\u5B89\u5168\u505C\u6B62\uFF0C\u8BF7\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u64CD\u4F5C\");\n if (request.method !== \"services.start\") for (const name of [...names].reverse()) await services[name].stop(false, false);\n if (request.method !== \"services.stop\") {\n const outcomes = [];\n for (const name of names) outcomes.push({ name, ...(await services[name].start()) });\n await verifyRunning(outcomes.filter(row => row.status !== \"skipped\").map(row => row.name));\n return { outcomes };\n }\n return { stopped: names };\n });\n }\n case \"services.send\": {\n const name = service(p.name); const message = string(p.message, \"\u547D\u4EE4\");\n if (/[\\r\\n]/.test(message) || !message.trim()) throw new Error(\"\u4E00\u6B21\u53EA\u80FD\u53D1\u9001\u4E00\u884C\u547D\u4EE4\");\n const target = services[name]; if (!target.proc?.stdin || !target.running) throw new Error(\"\u670D\u52A1\u672A\u6258\u7BA1\u6216\u6CA1\u6709\u547D\u4EE4\u8F93\u5165\u901A\u9053\");\n return withMaintenanceLock(ROOT, async () => { target.proc!.stdin!.write(message + \"\\n\"); return { delivered: true }; });\n }\n case \"logs.tail\": return { entries: readDiskLogs({ limit: Math.min(5000, Math.max(1, Number(p.limit) || 1000)), ...(Array.isArray(p.sources) ? { sources: p.sources.map(value => string(value, \"\u65E5\u5FD7\u6765\u6E90\")) } : {}), ...(Array.isArray(p.levels) ? { levels: p.levels as (\"info\" | \"warn\" | \"error\")[] } : {}) }).map(log => ({ ...log, time: log.time.toISOString() })) };\n case \"operations.list\": return { operations: store.list().filter(row => !Array.isArray(p.statuses) || p.statuses.includes(row.status)).slice(0, Math.min(Number(p.limit) || 100, 200)) };\n case \"operations.get\": return { operation: store.get(string(p.operationId, \"\u4EFB\u52A1\u7F16\u53F7\")) };\n case \"modules.list\": return listModules();\n case \"modules.search\": return searchModules(typeof p.query === \"string\" ? p.query : \"\");\n case \"modules.install\": case \"modules.uninstall\": case \"modules.toggle\": {\n const id = identifier(p.id);\n if (request.method !== \"modules.toggle\") {\n const linked = (await listModules()).modules.find(row => row.id === id || row.folder === id)?.linked;\n if (linked) throw new Error(\"\u4FDD\u7559\u672C\u5730\u94FE\u63A5\u6A21\u5757\uFF0C\u4E0D\u901A\u8FC7\u5305\u5B89\u88C5\u6216\u5378\u8F7D\u8986\u76D6\u5F00\u53D1\u76EE\u5F55\");\n }\n return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], async () => {\n if (request.method === \"modules.toggle\") {\n const result = await (p.enabled === true ? cmdModuleEnable([id]) : cmdModuleDisable([id])); if (!result.ok) throw new Error(result.message);\n } else {\n const args = [request.method === \"modules.install\" ? \"install\" : \"uninstall\", id];\n if (request.method === \"modules.install\" && typeof p.source === \"string\" && p.source) args.push(\"--from\", p.source);\n await runFetch(args);\n }\n return rebuildModules();\n }, true, \"modules\"));\n }\n case \"config.list\": return { keys: [...configFiles().keys()] };\n case \"config.read\": return readDocument(string(p.key, \"\u914D\u7F6E\u540D\u79F0\"));\n case \"config.apply\": {\n const key = string(p.key, \"\u914D\u7F6E\u540D\u79F0\"); const text = string(p.text, \"\u914D\u7F6E\u5185\u5BB9\"); const expected = string(p.revision, \"\u914D\u7F6E\u7248\u672C\");\n const document = readDocument(key); validateDocument(document, text);\n if (document.revision !== expected) throw Object.assign(new Error(\"\u914D\u7F6E\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\"), { code: \"conflict\" });\n return store.submit(request.method, async context => {\n let saved = false;\n try { return await withStoppedServices(context, [...START_ORDER], async () => {\n saveDocument(key, expected, text); context.phase(\"apply\", \"\u6587\u4EF6\u5DF2\u4FDD\u5B58\uFF0C\u6B63\u5728\u5E94\u7528\u8FD0\u884C\u914D\u7F6E\");\n saved = true;\n refreshServices(); return { saved: true, revision: readDocument(key).revision, applied: true };\n }); } catch (error) { throw Object.assign(new Error(`${saved ? \"\u6587\u4EF6\u5DF2\u4FDD\u5B58\uFF0C\u8FD0\u884C\u65F6\u5E94\u7528\u5931\u8D25\" : \"\u914D\u7F6E\u672A\u4FDD\u5B58\"}: ${error instanceof Error ? error.message : String(error)}`), { code: \"io\", details: { saved, applied: false, backupId: context.id } }); }\n });\n }\n case \"packs.list\": return listPacks();\n case \"packs.import\": return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], () => importPack(identifier(p.filename))));\n case \"packs.toggle\": return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], () => togglePack(identifier(p.id), p.enabled === true)));\n case \"players.list\": return players();\n case \"metrics.read\": {\n const cfg = readJson<{ db_port?: number; http_auth?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\n try {\n const response = await fetch(`http://127.0.0.1:${cfg.db_port ?? 3001}/api/sfmc/metrics`, { headers: cfg.http_auth ? { authorization: `Bearer ${cfg.http_auth}` } : {}, signal: AbortSignal.timeout(10_000) });\n if (!response.ok) throw new Error(`\u8FD0\u884C\u6307\u6807\u8BFB\u53D6\u5931\u8D25 (${response.status})`);\n return response.json();\n } catch (error) {\n const detail = error instanceof Error ? `${error.message} ${String(error.cause ?? \"\")}` : String(error);\n // \u6570\u636E\u670D\u52A1\u6CA1\u5F00\u65F6 fetch \u4F1A\u629B\u7F51\u7EDC\u9519\u8BEF\uFF1B\u754C\u9762\u7528 note \u5C55\u793A\uFF0C\u800C\u4E0D\u662F\u6574\u9875\u5931\u8D25\u3002\n if (/fetch failed|ECONNREFUSED|ENOTFOUND|AbortError|TimeoutError|timed out/i.test(detail)) {\n return { fresh: false, updatedAt: null, current: null, history: [], host: null, processes: null, resourcesUpdatedAt: null, note: \"\u6570\u636E\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u6682\u65F6\u6CA1\u6709\u8FD0\u884C\u6307\u6807\" };\n }\n throw error;\n }\n }\n case \"players.apply\": return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], async () => savePlayerPermissions(string(p.kind, \"\u6743\u9650\u7C7B\u578B\"), p.entries)));\n case \"attachment.plan\": return attachmentPlan();\n case \"attachment.apply\": return store.submit(request.method, async context => {\n const plan = await attachmentPlan(false);\n if (p.targetVersion !== undefined && p.targetVersion !== plan.targetVersion) throw Object.assign(new Error(\"\u76EE\u6807\u7248\u672C\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0\u65E5\u5FD7\u540E\u786E\u8BA4\"), { code: \"conflict\" });\n if (plan.externalServices.length) throw new Error(\"\u65E0\u6CD5\u53EF\u9760\u8FC1\u79FB\u5916\u90E8\u8FDB\u7A0B\uFF1B\u8BF7\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u4F18\u96C5\u505C\u670D\");\n if (plan.upgradeRequired) return launchPlatformUpdate(store, context, plan.targetVersion);\n return { attached: true, version: plan.currentVersion, development: plan.development };\n });\n case \"updates.check\": {\n const results = await Promise.allSettled([attachmentPlan(), modulePlan(), bdsUpdate({ id: \"check\", phase: () => {} }, true)]);\n return Object.fromEntries(results.map((result, index) => [[\"platform\", \"modules\", \"bds\"][index], result.status === \"fulfilled\" ? result.value : { error: String(result.reason) }]));\n }\n case \"updates.run\": {\n if (p.kind === \"platform\") return store.submit(request.method, async context => { const plan = await attachmentPlan(false); if (p.targetVersion !== undefined && p.targetVersion !== plan.targetVersion) throw Object.assign(new Error(\"\u76EE\u6807\u7248\u672C\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0\u65E5\u5FD7\u540E\u786E\u8BA4\"), { code: \"conflict\" }); return plan.upgradeRequired ? launchPlatformUpdate(store, context, plan.targetVersion) : { upToDate: true, version: plan.currentVersion }; });\n if (p.kind === \"modules\") return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], async () => { const result = await applyModulePlan(Array.isArray(p.ids) ? p.ids.map(identifier) : []); await rebuildModules(); return result; }, true, \"modules\"));\n if (p.kind === \"bds\") return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], () => bdsUpdate(context), true, \"bds\"));\n throw new Error(\"\u672A\u77E5\u66F4\u65B0\u7C7B\u578B\");\n }\n case \"deployment.create\": {\n if (p.acceptEula !== true) throw new Error(\"\u521B\u5EFA\u90E8\u7F72\u524D\u5FC5\u987B\u786E\u8BA4 BDS \u4F7F\u7528\u6761\u6B3E\");\n return store.submit(request.method, async context => {\n if (isRuntimeInitialized()) throw new Error(\"\u76EE\u5F55\u5DF2\u7ECF\u521D\u59CB\u5316\uFF0C\u4E0D\u8986\u76D6\u5DF2\u6709\u90E8\u7F72\");\n const ports = { db: deploymentPort(p.dbPort, 3001), bds: deploymentPort(p.bdsPort, 19132), bds6: deploymentPort(p.bdsPort6, 19133) };\n context.phase(\"preflight\", \"\u68C0\u67E5\u76EE\u5F55\u3001\u78C1\u76D8\u7A7A\u95F4\u548C TCP\uFF0FUDP \u7AEF\u53E3\"); await deploymentPreflight(ports);\n context.phase(\"prepare\"); ensureCoreConfigs(ROOT, [\"db_config\", \"qq_config\", \"bds_updater\", \"permissions\", \"qq_link\"]);\n const updater = path.join(ROOT, \"configs\", \"bds_updater.json\");\n atomicJson(updater, { ...readJson(updater, {}), bds_path: \"BDS\", backup_dir: \"backups\" });\n const dbFile = path.join(ROOT, \"configs\", \"db_config.json\"); atomicJson(dbFile, { ...readJson(dbFile, {}), db_port: ports.db });\n fs.mkdirSync(path.join(ROOT, \"modules\", \"packages\"), { recursive: true });\n await bdsUpdate(context);\n const properties = path.join(ROOT, \"BDS\", \"server.properties\");\n let text = fs.readFileSync(properties, \"utf8\");\n for (const [key, port] of [[\"server-port\", ports.bds], [\"server-portv6\", ports.bds6]] as const) text = text.replace(new RegExp(`^${key}=.*$`, \"m\"), `${key}=${port}`);\n fs.writeFileSync(properties, text);\n await rebuildModules();\n refreshServices(); context.phase(\"start\");\n const started: ServiceName[] = [];\n try { for (const name of START_ORDER) { const result = await services[name].start(); if (result.status !== \"skipped\") started.push(name); } await verifyRunning(started); }\n catch (error) { for (const name of [...START_ORDER].reverse()) await services[name].stop(false, false).catch(() => {}); throw error; }\n atomicJson(path.join(ROOT, \"configs\", \"runtime.json\"), { ...readJson(path.join(ROOT, \"configs\", \"runtime.json\"), {}), initialized_at: new Date().toISOString() });\n return { created: true, rows: await queryServicesRuntimeLocal() };\n });\n }\n case \"backups.list\": { const directory = path.join(ROOT, \".sfmc\", \"backups\"); return { backups: fs.existsSync(directory) ? fs.readdirSync(directory).filter(id => fs.existsSync(path.join(directory, id, \"manifest.json\"))) : [] }; }\n case \"backups.restore\": {\n if (p.confirmDataLoss !== true) throw new Error(\"\u6062\u590D\u6570\u636E\u9700\u8981\u660E\u786E\u786E\u8BA4\u4E22\u5F03\u5907\u4EFD\u4E4B\u540E\u7684\u53D8\u66F4\");\n return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], () => restoreSnapshot(identifier(p.id), context.phase)));\n }\n case \"startup.plan\": return startupPlan();\n default: throw Object.assign(new Error(`\u4E0D\u652F\u6301\u7684\u7BA1\u7406\u65B9\u6CD5: ${request.method}`), { code: \"unsupported\" });\n }\n}\n"],
5
- "mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,SAAS,oBAAoB;AAC7B,SAAS,mCAAiF;AAC1F,SAAS,MAAM,sBAAsB,oBAAoB;AACzD,SAAS,2BAA2B,UAAU,aAAa,eAAe,iBAAiB,4BAA8C;AACzI,SAAS,cAAc,aAAa;AACpC,SAAS,iBAAiB,wBAAwB;AAClD,SAAS,yBAAyB;AAClC,SAAS,WAAW,kBAAoC;AACxD,SAAS,aAAa,cAAc,cAAc,wBAAwB;AAC1E,SAAS,aAAa,eAAe,YAAY,UAAU,UAAU,WAAW,YAAY,YAAY,aAAa,uBAAuB,YAAY,uBAAuB;AAC/K,SAAS,gBAAgB,iBAAiB,qBAAqB,sBAAsB,iBAAiB,qBAAqB;AAC3H,SAAS,mBAAmB;AAC5B,SAAS,cAAc,qBAAqB;AAC5C,SAAS,2BAA2B;AACpC,SAAS,qBAAqB,sBAAsB;AACpD,SAAS,yBAAyB;AAElC,MAAM,SAAS,IAAI,aAAa;AAEhC,SAAS,wBAAiC;AACxC,MAAI,qBAAqB,EAAG,QAAO;AACnC,QAAM,SAAS,SAAgC,KAAK,KAAK,MAAM,WAAW,kBAAkB,GAAG,CAAC,CAAC;AACjG,MAAI,CAAC,OAAO,SAAU,QAAO;AAC7B,SAAO,GAAG,WAAW,KAAK,KAAK,kBAAkB,EAAE,SAAS,QAAQ,aAAa,UAAU,uBAAuB,gBAAgB,CAAC;AACrI;AACA,IAAI;AACG,SAAS,kBAAkB;AAChC,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,UAAU,IAAI;AAC1B,UAAM,GAAG,aAAa,aAAW,OAAO,KAAK,SAAS,EAAE,MAAM,SAAS,OAAO,aAAa,YAAY,MAAM,QAAQ,CAAC,CAAC;AACvH,UAAM,SAAO,OAAO,KAAK,SAAS,EAAE,MAAM,SAAS,OAAO,OAAO,YAAY,MAAM,SAAS,EAAE,GAAG,KAAK,MAAM,IAAI,KAAK,YAAY,EAAE,EAAE,CAAC,CAAC;AACvI,yBAAqB,aAAW,OAAO,KAAK,SAAS,EAAE,MAAM,SAAS,OAAO,gBAAgB,YAAY,MAAM,QAAQ,CAAC,CAAC;AAAA,EAC3H;AACA,SAAO;AACT;AACO,SAAS,kBAAkB,UAA4C;AAAE,SAAO,GAAG,SAAS,QAAQ;AAAG,SAAO,MAAM,OAAO,IAAI,SAAS,QAAQ;AAAG;AAC1J,SAAS,OAAO,SAAqD;AACnE,MAAI,QAAQ,WAAW,OAAW,QAAO,CAAC;AAC1C,MAAI,CAAC,QAAQ,UAAU,OAAO,QAAQ,WAAW,YAAY,MAAM,QAAQ,QAAQ,MAAM,EAAG,OAAM,IAAI,MAAM,4CAAS;AACrH,SAAO,QAAQ;AACjB;AACA,SAAS,OAAO,OAAgB,OAAe;AAAE,MAAI,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,OAAO,KAAM,OAAM,IAAI,MAAM,gBAAM,KAAK,EAAE;AAAG,SAAO;AAAO;AAChK,SAAS,QAAQ,OAA6B;AAAE,MAAI,CAAC,cAAc,SAAS,KAAoB,EAAG,OAAM,IAAI,MAAM,0BAAM;AAAG,SAAO;AAAsB;AACzJ,eAAe,iBAAiB;AAC9B,QAAM,QAAQ,MAAM,aAAa,CAAC,CAAC;AAAG,MAAI,CAAC,MAAM,GAAI,OAAM,IAAI,MAAM,MAAM,OAAO;AAClF,QAAM,SAAS,MAAM,cAAc,CAAC,CAAC;AAAG,MAAI,CAAC,OAAO,GAAI,OAAM,IAAI,MAAM,OAAO,OAAO;AACtF,SAAO,EAAE,SAAS,KAAK;AACzB;AACA,eAAe,UAAU;AACvB,QAAM,QAAQ,YAAY;AAAG,QAAM,YAAY,SAAoB,MAAM,WAAW,CAAC,CAAC;AACtF,QAAM,MAAM,SAAmD,KAAK,KAAK,MAAM,WAAW,gBAAgB,GAAG,CAAC,CAAC;AAC/G,MAAI,OAA4D,CAAC;AACjE,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,oBAAoB,IAAI,WAAW,IAAI,oBAAoB,EAAE,SAAS,IAAI,YAAY,EAAE,eAAe,UAAU,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,QAAQ,YAAY,QAAQ,GAAI,EAAE,CAAC;AACzM,QAAI,SAAS,GAAI,QAAO,MAAM,SAAS,KAAK;AAAA,EAC9C,QAAQ;AAAA,EAAmB;AAC3B,QAAM,QAAQ,OAAO,KAAK,cAAc,YAAY,KAAK,IAAI,IAAI,KAAK,YAAY;AAClF,SAAO,EAAE,UAAU,KAAK,UAAU,CAAC,GAAG,IAAI,UAAQ,EAAE,MAAM,IAAI,MAAM,MAAM,IAAI,QAAQ,QAAQ,OAAO,KAAK,EAAE,GAAG,WAAW,KAAK,YAAY,IAAI,KAAK,KAAK,SAAS,EAAE,YAAY,IAAI,IAAI,OAAO,WAAW,aAAa,SAAoB,MAAM,aAAa,CAAC,CAAC,GAAG,iBAAiB,SAAoB,MAAM,iBAAiB,CAAC,CAAC,EAAE;AACrU;AACA,eAAe,UAAU,SAAsB,YAAY,OAAO;AAChE,UAAQ,MAAM,YAAY,YAAY,kCAAc,kBAAQ;AAC5D,QAAM,OAAO,YAAY,CAAC,gBAAgB,aAAa,IAAI,CAAC,cAAc,aAAa;AACvF,MAAI,SAAS;AACb,QAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAM,QAAQ,aAAa,UAAU,MAAM,EAAE,OAAO,QAAQ,KAAK,KAAK,CAAC;AACvE,eAAW,UAAU,CAAC,MAAM,QAAQ,MAAM,MAAM,EAAG,SAAQ,GAAG,QAAQ,WAAS;AAAE,gBAAU,SAAS,OAAO,KAAK,GAAG,MAAM,KAAO;AAAA,IAAG,CAAC;AACpI,UAAM,GAAG,SAAS,MAAM;AAAG,UAAM,GAAG,SAAS,UAAQ,SAAS,IAAI,QAAQ,IAAI,OAAO,IAAI,MAAM,iCAAa,IAAI,GAAG,CAAC,CAAC;AAAA,EACvH,CAAC;AACD,SAAO,EAAE,SAAS,WAAW,SAAS,8BAA8B,KAAK,MAAM,GAAG,gBAAgB,qBAAqB,KAAK,MAAM,IAAI,CAAC,KAAK,WAAW,eAAe,oBAAoB,KAAK,MAAM,IAAI,CAAC,KAAK,WAAW,QAAQ,gCAAgC,KAAK,MAAM,IAAI,CAAC,KAAK,UAAU;AACnS;AACA,eAAsB,mBAAmB,SAA8C;AACrF,QAAM,IAAI,OAAO,OAAO;AAAG,QAAM,QAAQ,gBAAgB;AACzD,UAAQ,QAAQ,QAAQ;AAAA,IACtB,KAAK;AAAa,aAAO,EAAE,iBAAiB,6BAA6B,iBAAiB,gBAAgB,GAAG,MAAM,EAAE,IAAI,QAAQ,aAAa,UAAU,YAAY,QAAQ,UAAU,MAAM,QAAQ,MAAM,SAAS,GAAG,QAAQ,EAAE,GAAG,MAAM,MAAM,cAAc,CAAC,YAAY,QAAQ,WAAW,UAAU,SAAS,WAAW,WAAW,cAAc,SAAS,GAAG,WAAW,QAAQ,KAAK,iBAAiB,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ,OAAO,IAAI,GAAI,EAAE,YAAY,GAAG,aAAa,sBAAsB,EAAE;AAAA,IAC5e,KAAK;AAAoB,aAAO,EAAE,YAAY,KAAK;AAAA,IACnD,KAAK;AAAiB,aAAO,EAAE,MAAM,MAAM,0BAA0B,EAAE;AAAA,IACvE,KAAK;AAAA,IAAkB,KAAK;AAAA,IAAiB,KAAK,oBAAoB;AACpE,YAAM,QAAQ,EAAE,SAAS,QAAQ,CAAC,GAAG,WAAW,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;AACpE,aAAO,MAAM,OAAO,QAAQ,QAAQ,OAAM,YAAW;AACnD,gBAAQ,MAAM,SAAS;AACvB,cAAM,OAAO,MAAM,0BAA0B;AAC7C,YAAI,KAAK,KAAK,SAAO,MAAM,SAAS,IAAI,IAAI,KAAK,IAAI,WAAW,IAAI,cAAc,UAAU,KAAK,QAAQ,WAAW,iBAAkB,OAAM,IAAI,MAAM,0HAAsB;AAC5K,YAAI,QAAQ,WAAW,iBAAkB,YAAW,QAAQ,CAAC,GAAG,KAAK,EAAE,QAAQ,EAAG,OAAM,SAAS,IAAI,EAAE,KAAK,OAAO,KAAK;AACxH,YAAI,QAAQ,WAAW,iBAAiB;AACtC,gBAAM,WAAW,CAAC;AAClB,qBAAW,QAAQ,MAAO,UAAS,KAAK,EAAE,MAAM,GAAI,MAAM,SAAS,IAAI,EAAE,MAAM,EAAG,CAAC;AACnF,gBAAM,cAAc,SAAS,OAAO,SAAO,IAAI,WAAW,SAAS,EAAE,IAAI,SAAO,IAAI,IAAI,CAAC;AACzF,iBAAO,EAAE,SAAS;AAAA,QACpB;AACA,eAAO,EAAE,SAAS,MAAM;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,IACA,KAAK,iBAAiB;AACpB,YAAM,OAAO,QAAQ,EAAE,IAAI;AAAG,YAAM,UAAU,OAAO,EAAE,SAAS,cAAI;AACpE,UAAI,SAAS,KAAK,OAAO,KAAK,CAAC,QAAQ,KAAK,EAAG,OAAM,IAAI,MAAM,8DAAY;AAC3E,YAAM,SAAS,SAAS,IAAI;AAAG,UAAI,CAAC,OAAO,MAAM,SAAS,CAAC,OAAO,QAAS,OAAM,IAAI,MAAM,sFAAgB;AAC3G,aAAO,oBAAoB,MAAM,YAAY;AAAE,eAAO,KAAM,MAAO,MAAM,UAAU,IAAI;AAAG,eAAO,EAAE,WAAW,KAAK;AAAA,MAAG,CAAC;AAAA,IACzH;AAAA,IACA,KAAK;AAAa,aAAO,EAAE,SAAS,aAAa,EAAE,OAAO,KAAK,IAAI,KAAM,KAAK,IAAI,GAAG,OAAO,EAAE,KAAK,KAAK,GAAI,CAAC,GAAG,GAAI,MAAM,QAAQ,EAAE,OAAO,IAAI,EAAE,SAAS,EAAE,QAAQ,IAAI,WAAS,OAAO,OAAO,0BAAM,CAAC,EAAE,IAAI,CAAC,GAAI,GAAI,MAAM,QAAQ,EAAE,MAAM,IAAI,EAAE,QAAQ,EAAE,OAAwC,IAAI,CAAC,EAAG,CAAC,EAAE,IAAI,UAAQ,EAAE,GAAG,KAAK,MAAM,IAAI,KAAK,YAAY,EAAE,EAAE,EAAE;AAAA,IACrW,KAAK;AAAmB,aAAO,EAAE,YAAY,MAAM,KAAK,EAAE,OAAO,SAAO,CAAC,MAAM,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,SAAS,IAAI,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,IAAI,OAAO,EAAE,KAAK,KAAK,KAAK,GAAG,CAAC,EAAE;AAAA,IACvL,KAAK;AAAkB,aAAO,EAAE,WAAW,MAAM,IAAI,OAAO,EAAE,aAAa,0BAAM,CAAC,EAAE;AAAA,IACpF,KAAK;AAAgB,aAAO,YAAY;AAAA,IACxC,KAAK;AAAkB,aAAO,cAAc,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ,EAAE;AAAA,IACtF,KAAK;AAAA,IAAmB,KAAK;AAAA,IAAqB,KAAK,kBAAkB;AACvE,YAAM,KAAK,WAAW,EAAE,EAAE;AAC1B,UAAI,QAAQ,WAAW,kBAAkB;AACvC,cAAM,UAAU,MAAM,YAAY,GAAG,QAAQ,KAAK,SAAO,IAAI,OAAO,MAAM,IAAI,WAAW,EAAE,GAAG;AAC9F,YAAI,OAAQ,OAAM,IAAI,MAAM,kJAA0B;AAAA,MACxD;AACA,aAAO,MAAM,OAAO,QAAQ,QAAQ,aAAW,oBAAoB,SAAS,CAAC,GAAG,WAAW,GAAG,YAAY;AACxG,YAAI,QAAQ,WAAW,kBAAkB;AACvC,gBAAM,SAAS,OAAO,EAAE,YAAY,OAAO,gBAAgB,CAAC,EAAE,CAAC,IAAI,iBAAiB,CAAC,EAAE,CAAC;AAAI,cAAI,CAAC,OAAO,GAAI,OAAM,IAAI,MAAM,OAAO,OAAO;AAAA,QAC5I,OAAO;AACL,gBAAM,OAAO,CAAC,QAAQ,WAAW,oBAAoB,YAAY,aAAa,EAAE;AAChF,cAAI,QAAQ,WAAW,qBAAqB,OAAO,EAAE,WAAW,YAAY,EAAE,OAAQ,MAAK,KAAK,UAAU,EAAE,MAAM;AAClH,gBAAM,SAAS,IAAI;AAAA,QACrB;AACA,eAAO,eAAe;AAAA,MACxB,GAAG,MAAM,SAAS,CAAC;AAAA,IACrB;AAAA,IACA,KAAK;AAAe,aAAO,EAAE,MAAM,CAAC,GAAG,YAAY,EAAE,KAAK,CAAC,EAAE;AAAA,IAC7D,KAAK;AAAe,aAAO,aAAa,OAAO,EAAE,KAAK,0BAAM,CAAC;AAAA,IAC7D,KAAK,gBAAgB;AACnB,YAAM,MAAM,OAAO,EAAE,KAAK,0BAAM;AAAG,YAAM,OAAO,OAAO,EAAE,MAAM,0BAAM;AAAG,YAAM,WAAW,OAAO,EAAE,UAAU,0BAAM;AAClH,YAAM,WAAW,aAAa,GAAG;AAAG,uBAAiB,UAAU,IAAI;AACnE,UAAI,SAAS,aAAa,SAAU,OAAM,OAAO,OAAO,IAAI,MAAM,oEAAa,GAAG,EAAE,MAAM,WAAW,CAAC;AACtG,aAAO,MAAM,OAAO,QAAQ,QAAQ,OAAM,YAAW;AACnD,YAAI,QAAQ;AACZ,YAAI;AAAE,iBAAO,MAAM,oBAAoB,SAAS,CAAC,GAAG,WAAW,GAAG,YAAY;AAC9E,yBAAa,KAAK,UAAU,IAAI;AAAG,oBAAQ,MAAM,SAAS,sFAAgB;AAC1E,oBAAQ;AACR,4BAAgB;AAAG,mBAAO,EAAE,OAAO,MAAM,UAAU,aAAa,GAAG,EAAE,UAAU,SAAS,KAAK;AAAA,UAC7F,CAAC;AAAA,QAAG,SAAS,OAAO;AAAE,gBAAM,OAAO,OAAO,IAAI,MAAM,GAAG,QAAQ,mFAAkB,gCAAO,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE,GAAG,EAAE,MAAM,MAAM,SAAS,EAAE,OAAO,SAAS,OAAO,UAAU,QAAQ,GAAG,EAAE,CAAC;AAAA,QAAG;AAAA,MACrO,CAAC;AAAA,IACH;AAAA,IACA,KAAK;AAAc,aAAO,UAAU;AAAA,IACpC,KAAK;AAAgB,aAAO,MAAM,OAAO,QAAQ,QAAQ,aAAW,oBAAoB,SAAS,CAAC,GAAG,WAAW,GAAG,MAAM,WAAW,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;AAAA,IAC5J,KAAK;AAAgB,aAAO,MAAM,OAAO,QAAQ,QAAQ,aAAW,oBAAoB,SAAS,CAAC,GAAG,WAAW,GAAG,MAAM,WAAW,WAAW,EAAE,EAAE,GAAG,EAAE,YAAY,IAAI,CAAC,CAAC;AAAA,IAC1K,KAAK;AAAgB,aAAO,QAAQ;AAAA,IACpC,KAAK,gBAAgB;AACnB,YAAM,MAAM,SAAmD,KAAK,KAAK,MAAM,WAAW,gBAAgB,GAAG,CAAC,CAAC;AAC/G,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,oBAAoB,IAAI,WAAW,IAAI,qBAAqB,EAAE,SAAS,IAAI,YAAY,EAAE,eAAe,UAAU,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,QAAQ,YAAY,QAAQ,GAAM,EAAE,CAAC;AAC5M,YAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,qDAAa,SAAS,MAAM,GAAG;AACjE,eAAO,SAAS,KAAK;AAAA,MACvB,SAAS,OAAO;AACd,cAAM,SAAS,iBAAiB,QAAQ,GAAG,MAAM,OAAO,IAAI,OAAO,MAAM,SAAS,EAAE,CAAC,KAAK,OAAO,KAAK;AAEtG,YAAI,yEAAyE,KAAK,MAAM,GAAG;AACzF,iBAAO,EAAE,OAAO,OAAO,WAAW,MAAM,SAAS,MAAM,SAAS,CAAC,GAAG,MAAM,MAAM,WAAW,MAAM,oBAAoB,MAAM,MAAM,mGAAmB;AAAA,QACtJ;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,KAAK;AAAiB,aAAO,MAAM,OAAO,QAAQ,QAAQ,aAAW,oBAAoB,SAAS,CAAC,GAAG,WAAW,GAAG,YAAY,sBAAsB,OAAO,EAAE,MAAM,0BAAM,GAAG,EAAE,OAAO,CAAC,CAAC;AAAA,IACzL,KAAK;AAAmB,aAAO,eAAe;AAAA,IAC9C,KAAK;AAAoB,aAAO,MAAM,OAAO,QAAQ,QAAQ,OAAM,YAAW;AAC5E,cAAM,OAAO,MAAM,eAAe,KAAK;AACvC,YAAI,EAAE,kBAAkB,UAAa,EAAE,kBAAkB,KAAK,cAAe,OAAM,OAAO,OAAO,IAAI,MAAM,0HAAsB,GAAG,EAAE,MAAM,WAAW,CAAC;AACxJ,YAAI,KAAK,iBAAiB,OAAQ,OAAM,IAAI,MAAM,4IAAyB;AAC3E,YAAI,KAAK,gBAAiB,QAAO,qBAAqB,OAAO,SAAS,KAAK,aAAa;AACxF,eAAO,EAAE,UAAU,MAAM,SAAS,KAAK,gBAAgB,aAAa,KAAK,YAAY;AAAA,MACvF,CAAC;AAAA,IACD,KAAK,iBAAiB;AACpB,YAAM,UAAU,MAAM,QAAQ,WAAW,CAAC,eAAe,GAAG,WAAW,GAAG,UAAU,EAAE,IAAI,SAAS,OAAO,MAAM;AAAA,MAAC,EAAE,GAAG,IAAI,CAAC,CAAC;AAC5H,aAAO,OAAO,YAAY,QAAQ,IAAI,CAAC,QAAQ,UAAU,CAAC,CAAC,YAAY,WAAW,KAAK,EAAE,KAAK,GAAG,OAAO,WAAW,cAAc,OAAO,QAAQ,EAAE,OAAO,OAAO,OAAO,MAAM,EAAE,CAAC,CAAC,CAAC;AAAA,IACpL;AAAA,IACA,KAAK,eAAe;AAClB,UAAI,EAAE,SAAS,WAAY,QAAO,MAAM,OAAO,QAAQ,QAAQ,OAAM,YAAW;AAAE,cAAM,OAAO,MAAM,eAAe,KAAK;AAAG,YAAI,EAAE,kBAAkB,UAAa,EAAE,kBAAkB,KAAK,cAAe,OAAM,OAAO,OAAO,IAAI,MAAM,0HAAsB,GAAG,EAAE,MAAM,WAAW,CAAC;AAAG,eAAO,KAAK,kBAAkB,qBAAqB,OAAO,SAAS,KAAK,aAAa,IAAI,EAAE,UAAU,MAAM,SAAS,KAAK,eAAe;AAAA,MAAG,CAAC;AACna,UAAI,EAAE,SAAS,UAAW,QAAO,MAAM,OAAO,QAAQ,QAAQ,aAAW,oBAAoB,SAAS,CAAC,GAAG,WAAW,GAAG,YAAY;AAAE,cAAM,SAAS,MAAM,gBAAgB,MAAM,QAAQ,EAAE,GAAG,IAAI,EAAE,IAAI,IAAI,UAAU,IAAI,CAAC,CAAC;AAAG,cAAM,eAAe;AAAG,eAAO;AAAA,MAAQ,GAAG,MAAM,SAAS,CAAC;AACzR,UAAI,EAAE,SAAS,MAAO,QAAO,MAAM,OAAO,QAAQ,QAAQ,aAAW,oBAAoB,SAAS,CAAC,GAAG,WAAW,GAAG,MAAM,UAAU,OAAO,GAAG,MAAM,KAAK,CAAC;AAC1J,YAAM,IAAI,MAAM,sCAAQ;AAAA,IAC1B;AAAA,IACA,KAAK,qBAAqB;AACxB,UAAI,EAAE,eAAe,KAAM,OAAM,IAAI,MAAM,qFAAoB;AAC/D,aAAO,MAAM,OAAO,QAAQ,QAAQ,OAAM,YAAW;AACnD,YAAI,qBAAqB,EAAG,OAAM,IAAI,MAAM,4FAAiB;AAC7D,cAAM,QAAQ,EAAE,IAAI,eAAe,EAAE,QAAQ,IAAI,GAAG,KAAK,eAAe,EAAE,SAAS,KAAK,GAAG,MAAM,eAAe,EAAE,UAAU,KAAK,EAAE;AACnI,gBAAQ,MAAM,aAAa,wFAAuB;AAAG,cAAM,oBAAoB,KAAK;AACpF,gBAAQ,MAAM,SAAS;AAAG,0BAAkB,MAAM,CAAC,aAAa,aAAa,eAAe,eAAe,SAAS,CAAC;AACrH,cAAM,UAAU,KAAK,KAAK,MAAM,WAAW,kBAAkB;AAC7D,mBAAW,SAAS,EAAE,GAAG,SAAS,SAAS,CAAC,CAAC,GAAG,UAAU,OAAO,YAAY,UAAU,CAAC;AACxF,cAAM,SAAS,KAAK,KAAK,MAAM,WAAW,gBAAgB;AAAG,mBAAW,QAAQ,EAAE,GAAG,SAAS,QAAQ,CAAC,CAAC,GAAG,SAAS,MAAM,GAAG,CAAC;AAC9H,WAAG,UAAU,KAAK,KAAK,MAAM,WAAW,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AACxE,cAAM,UAAU,OAAO;AACvB,cAAM,aAAa,KAAK,KAAK,MAAM,OAAO,mBAAmB;AAC7D,YAAI,OAAO,GAAG,aAAa,YAAY,MAAM;AAC7C,mBAAW,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,eAAe,MAAM,GAAG,GAAG,CAAC,iBAAiB,MAAM,IAAI,CAAC,EAAY,QAAO,KAAK,QAAQ,IAAI,OAAO,IAAI,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,EAAE;AACpK,WAAG,cAAc,YAAY,IAAI;AACjC,cAAM,eAAe;AACrB,wBAAgB;AAAG,gBAAQ,MAAM,OAAO;AACxC,cAAM,UAAyB,CAAC;AAChC,YAAI;AAAE,qBAAW,QAAQ,aAAa;AAAE,kBAAM,SAAS,MAAM,SAAS,IAAI,EAAE,MAAM;AAAG,gBAAI,OAAO,WAAW,UAAW,SAAQ,KAAK,IAAI;AAAA,UAAG;AAAE,gBAAM,cAAc,OAAO;AAAA,QAAG,SACnK,OAAO;AAAE,qBAAW,QAAQ,CAAC,GAAG,WAAW,EAAE,QAAQ,EAAG,OAAM,SAAS,IAAI,EAAE,KAAK,OAAO,KAAK,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC;AAAG,gBAAM;AAAA,QAAO;AACrI,mBAAW,KAAK,KAAK,MAAM,WAAW,cAAc,GAAG,EAAE,GAAG,SAAS,KAAK,KAAK,MAAM,WAAW,cAAc,GAAG,CAAC,CAAC,GAAG,iBAAgB,oBAAI,KAAK,GAAE,YAAY,EAAE,CAAC;AAChK,eAAO,EAAE,SAAS,MAAM,MAAM,MAAM,0BAA0B,EAAE;AAAA,MAClE,CAAC;AAAA,IACH;AAAA,IACA,KAAK,gBAAgB;AAAE,YAAM,YAAY,KAAK,KAAK,MAAM,SAAS,SAAS;AAAG,aAAO,EAAE,SAAS,GAAG,WAAW,SAAS,IAAI,GAAG,YAAY,SAAS,EAAE,OAAO,QAAM,GAAG,WAAW,KAAK,KAAK,WAAW,IAAI,eAAe,CAAC,CAAC,IAAI,CAAC,EAAE;AAAA,IAAG;AAAA,IACpO,KAAK,mBAAmB;AACtB,UAAI,EAAE,oBAAoB,KAAM,OAAM,IAAI,MAAM,oHAAqB;AACrE,aAAO,MAAM,OAAO,QAAQ,QAAQ,aAAW,oBAAoB,SAAS,CAAC,GAAG,WAAW,GAAG,MAAM,gBAAgB,WAAW,EAAE,EAAE,GAAG,QAAQ,KAAK,CAAC,CAAC;AAAA,IACvJ;AAAA,IACA,KAAK;AAAgB,aAAO,YAAY;AAAA,IACxC;AAAS,YAAM,OAAO,OAAO,IAAI,MAAM,qDAAa,QAAQ,MAAM,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAAA,EAChG;AACF;",
4
+ "sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { EventEmitter } from \"node:events\";\nimport { MANAGEMENT_PROTOCOL_VERSION, type ManagementRequest, type ManagementEvent } from \"@sfmc-bds/management\";\nimport { readQqBindings } from \"@sfmc-bds/db-server/qq-bindings\";\nimport { ROOT, isRuntimeInitialized, spawnService } from \"../runtime.js\";\nimport { queryServicesRuntimeLocal, services, START_ORDER, SERVICE_NAMES, refreshServices, onServiceStateChange, type ServiceName } from \"../services.js\";\nimport { readDiskLogs, onLog } from \"../logs.js\";\nimport { cmdModuleEnable, cmdModuleDisable } from \"../module-commands.js\";\nimport { ensureCoreConfigs } from \"@sfmc-bds/sdk/node/config\";\nimport { TaskStore, atomicJson, type TaskContext } from \"./tasks.js\";\nimport { configFiles, readDocument, saveDocument, validateDocument } from \"./config.js\";\nimport { listModules, searchModules, identifier, runFetch, readJson, listPacks, togglePack, importPack, playerFiles, savePlayerPermissions, modulePlan, applyModulePlan } from \"./domain.js\";\nimport { attachmentPlan, platformVersion, withStoppedServices, launchPlatformUpdate, restoreSnapshot, verifyRunning } from \"./maintenance.js\";\nimport { startupPlan } from \"./startup.js\";\nimport { cmdPackBuild, cmdPackDeploy } from \"../pack-lifecycle.js\";\nimport { withMaintenanceLock } from \"@sfmc-bds/management/node\";\nimport { deploymentPreflight, deploymentPort } from \"./deployment.js\";\nimport { resolveBdsContext } from \"../pack-lifecycle.js\";\nimport { readRuntimeMetrics } from \"./metrics-read.js\";\n\nconst events = new EventEmitter();\n/** \u7A7A\u76EE\u5F55\u4E5F\u8981\u80FD\u5B8C\u6210\u63E1\u624B\uFF0C\u4F9B\u684C\u9762\u521D\u59CB\u5316\u5411\u5BFC\u7EE7\u7EED\uFF1B\u65E7\u90E8\u7F72\u4ECD\u8BC6\u522B\u5DF2\u6709 BDS\u3002 */\nfunction deploymentInitialized(): boolean {\n if (isRuntimeInitialized()) return true;\n const config = readJson<{ bds_path?: string }>(path.join(ROOT, \"configs\", \"bds_updater.json\"), {});\n if (!config.bds_path) return false;\n return fs.existsSync(path.join(resolveBdsContext().bdsRoot, process.platform === \"win32\" ? \"bedrock_server.exe\" : \"bedrock_server\"));\n}\nlet tasks: TaskStore | undefined;\nexport function managementTasks() {\n if (!tasks) {\n tasks = new TaskStore(ROOT);\n tasks.on(\"operation\", payload => events.emit(\"event\", { type: \"event\", event: \"operation\", instanceId: ROOT, payload }));\n onLog(log => events.emit(\"event\", { type: \"event\", event: \"log\", instanceId: ROOT, payload: { ...log, time: log.time.toISOString() } }));\n onServiceStateChange(payload => events.emit(\"event\", { type: \"event\", event: \"serviceState\", instanceId: ROOT, payload }));\n }\n return tasks;\n}\nexport function onManagementEvent(callback: (event: ManagementEvent) => void) { events.on(\"event\", callback); return () => events.off(\"event\", callback); }\nfunction params(request: ManagementRequest): Record<string, unknown> {\n if (request.params === undefined) return {};\n if (!request.params || typeof request.params !== \"object\" || Array.isArray(request.params)) throw new Error(\"\u53C2\u6570\u5FC5\u987B\u4E3A\u5BF9\u8C61\");\n return request.params as Record<string, unknown>;\n}\nfunction string(value: unknown, label: string) { if (typeof value !== \"string\" || value.length > 2 * 1024 * 1024) throw new Error(`\u975E\u6CD5 ${label}`); return value; }\nfunction service(value: unknown): ServiceName { if (!SERVICE_NAMES.includes(value as ServiceName)) throw new Error(\"\u672A\u77E5\u670D\u52A1\"); return value as ServiceName; }\nasync function rebuildModules() {\n const build = await cmdPackBuild([]); if (!build.ok) throw new Error(build.message);\n const deploy = await cmdPackDeploy([]); if (!deploy.ok) throw new Error(deploy.message);\n return { changed: true };\n}\nasync function players() {\n const files = playerFiles(); const allowlist = readJson<unknown[]>(files.allowlist, []);\n const cfg = readJson<{ db_port?: number; http_auth?: string; dbDir?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\n const database = path.resolve(ROOT, typeof cfg.dbDir === \"string\" && cfg.dbDir.trim() ? cfg.dbDir : \"data/sfmc_data.db\");\n let data: { online?: { name: string }[]; updatedAt?: number } = {};\n try {\n const response = await fetch(`http://127.0.0.1:${cfg.db_port ?? 3001}/api/sfmc/status`, { headers: cfg.http_auth ? { authorization: `Bearer ${cfg.http_auth}` } : {}, signal: AbortSignal.timeout(5000) });\n if (response.ok) data = await response.json() as typeof data;\n } catch { /* \u672A\u8FDE\u63A5\u65F6\u4F7F\u7528\u672A\u77E5\u72B6\u6001 */ }\n const fresh = typeof data.updatedAt === \"number\" && Date.now() - data.updatedAt < 60_000;\n return { players: (data.online ?? []).map(row => ({ name: row.name, xuid: \"\", online: fresh ? true : null })), updatedAt: data.updatedAt ? new Date(data.updatedAt).toISOString() : \"\", fresh, allowlist, permissions: readJson<unknown[]>(files.permissions, []), sfmcPermissions: readJson<unknown[]>(files.sfmcPermissions, []), bindings: readQqBindings(database) };\n}\nasync function bdsUpdate(context: TaskContext, checkOnly = false) {\n context.phase(\"download\", checkOnly ? \"\u68C0\u67E5 BDS \u66F4\u65B0\" : \"\u66F4\u65B0 BDS\");\n const args = checkOnly ? [\"--check-only\", \"--no-notify\"] : [\"--no-start\", \"--no-notify\"];\n let output = \"\";\n await new Promise<void>((resolve, reject) => {\n const child = spawnService(\"update\", args, { stdio: \"pipe\", cwd: ROOT });\n for (const stream of [child.stdout, child.stderr]) stream?.on(\"data\", chunk => { output = (output + String(chunk)).slice(-64_000); });\n child.on(\"error\", reject); child.on(\"close\", code => code === 0 ? resolve() : reject(new Error(`BDS \u66F4\u65B0\u5931\u8D25 (${code})`)));\n });\n return { checked: checkOnly, updated: /SFMC_UPDATE_RESULT=deployed/.test(output), currentVersion: /CURRENT=([^\\r\\n]+)/.exec(output)?.[1] ?? \"unknown\", latestVersion: /LATEST=([^\\r\\n]+)/.exec(output)?.[1] ?? \"unknown\", result: /SFMC_UPDATE_RESULT=([^\\r\\n]+)/.exec(output)?.[1] ?? \"unknown\" };\n}\nexport async function dispatchManagement(request: ManagementRequest): Promise<unknown> {\n const p = params(request); const store = managementTasks();\n switch (request.method) {\n case \"handshake\": return { protocolVersion: MANAGEMENT_PROTOCOL_VERSION, platformVersion: platformVersion(), host: { os: process.platform === \"win32\" ? \"windows\" : process.platform, arch: process.arch, release: os.release() }, root: ROOT, capabilities: [\"services\", \"logs\", \"modules\", \"config\", \"packs\", \"players\", \"updates\", \"operations\", \"metrics\"], daemonPid: process.pid, daemonStartedAt: new Date(Date.now() - process.uptime() * 1000).toISOString(), initialized: deploymentInitialized() };\n case \"events.subscribe\": return { subscribed: true };\n case \"services.list\": return { rows: await queryServicesRuntimeLocal() };\n case \"services.start\": case \"services.stop\": case \"services.restart\": {\n const names = p.name === \"all\" ? [...START_ORDER] : [service(p.name)];\n return store.submit(request.method, async context => {\n context.phase(\"execute\");\n const rows = await queryServicesRuntimeLocal();\n if (rows.some(row => names.includes(row.name) && row.running && row.ownership === \"external\") && request.method !== \"services.start\") throw new Error(\"\u5916\u90E8\u8FDB\u7A0B\u65E0\u6CD5\u5B89\u5168\u505C\u6B62\uFF0C\u8BF7\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u64CD\u4F5C\");\n if (request.method !== \"services.start\") for (const name of [...names].reverse()) await services[name].stop(false, false);\n if (request.method !== \"services.stop\") {\n const outcomes = [];\n for (const name of names) outcomes.push({ name, ...(await services[name].start()) });\n await verifyRunning(outcomes.filter(row => row.status !== \"skipped\").map(row => row.name));\n return { outcomes };\n }\n return { stopped: names };\n });\n }\n case \"services.send\": {\n const name = service(p.name); const message = string(p.message, \"\u547D\u4EE4\");\n if (/[\\r\\n]/.test(message) || !message.trim()) throw new Error(\"\u4E00\u6B21\u53EA\u80FD\u53D1\u9001\u4E00\u884C\u547D\u4EE4\");\n const target = services[name]; if (!target.proc?.stdin || !target.running) throw new Error(\"\u670D\u52A1\u672A\u6258\u7BA1\u6216\u6CA1\u6709\u547D\u4EE4\u8F93\u5165\u901A\u9053\");\n return withMaintenanceLock(ROOT, async () => { target.proc!.stdin!.write(message + \"\\n\"); return { delivered: true }; });\n }\n case \"logs.tail\": return { entries: readDiskLogs({ limit: Math.min(5000, Math.max(1, Number(p.limit) || 1000)), ...(Array.isArray(p.sources) ? { sources: p.sources.map(value => string(value, \"\u65E5\u5FD7\u6765\u6E90\")) } : {}), ...(Array.isArray(p.levels) ? { levels: p.levels as (\"info\" | \"warn\" | \"error\")[] } : {}) }).map(log => ({ ...log, time: log.time.toISOString() })) };\n case \"operations.list\": return { operations: store.list().filter(row => !Array.isArray(p.statuses) || p.statuses.includes(row.status)).slice(0, Math.min(Number(p.limit) || 100, 200)) };\n case \"operations.get\": return { operation: store.get(string(p.operationId, \"\u4EFB\u52A1\u7F16\u53F7\")) };\n case \"modules.list\": return listModules();\n case \"modules.search\": return searchModules(typeof p.query === \"string\" ? p.query : \"\");\n case \"modules.install\": case \"modules.uninstall\": case \"modules.toggle\": {\n const id = identifier(p.id);\n if (request.method !== \"modules.toggle\") {\n const linked = (await listModules()).modules.find(row => row.id === id || row.folder === id)?.linked;\n if (linked) throw new Error(\"\u4FDD\u7559\u672C\u5730\u94FE\u63A5\u6A21\u5757\uFF0C\u4E0D\u901A\u8FC7\u5305\u5B89\u88C5\u6216\u5378\u8F7D\u8986\u76D6\u5F00\u53D1\u76EE\u5F55\");\n }\n return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], async () => {\n if (request.method === \"modules.toggle\") {\n const result = await (p.enabled === true ? cmdModuleEnable([id]) : cmdModuleDisable([id])); if (!result.ok) throw new Error(result.message);\n } else {\n const args = [request.method === \"modules.install\" ? \"install\" : \"uninstall\", id];\n if (request.method === \"modules.install\" && typeof p.source === \"string\" && p.source) args.push(\"--from\", p.source);\n await runFetch(args);\n }\n return rebuildModules();\n }, true, \"modules\"));\n }\n case \"config.list\": return { keys: [...configFiles().keys()] };\n case \"config.read\": return readDocument(string(p.key, \"\u914D\u7F6E\u540D\u79F0\"));\n case \"config.apply\": {\n const key = string(p.key, \"\u914D\u7F6E\u540D\u79F0\"); const text = string(p.text, \"\u914D\u7F6E\u5185\u5BB9\"); const expected = string(p.revision, \"\u914D\u7F6E\u7248\u672C\");\n const document = readDocument(key); validateDocument(document, text);\n if (document.revision !== expected) throw Object.assign(new Error(\"\u914D\u7F6E\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\"), { code: \"conflict\" });\n return store.submit(request.method, async context => {\n let saved = false;\n try { return await withStoppedServices(context, [...START_ORDER], async () => {\n saveDocument(key, expected, text); context.phase(\"apply\", \"\u6587\u4EF6\u5DF2\u4FDD\u5B58\uFF0C\u6B63\u5728\u5E94\u7528\u8FD0\u884C\u914D\u7F6E\");\n saved = true;\n refreshServices(); return { saved: true, revision: readDocument(key).revision, applied: true };\n }); } catch (error) { throw Object.assign(new Error(`${saved ? \"\u6587\u4EF6\u5DF2\u4FDD\u5B58\uFF0C\u8FD0\u884C\u65F6\u5E94\u7528\u5931\u8D25\" : \"\u914D\u7F6E\u672A\u4FDD\u5B58\"}: ${error instanceof Error ? error.message : String(error)}`), { code: \"io\", details: { saved, applied: false, backupId: context.id } }); }\n });\n }\n case \"packs.list\": return listPacks();\n case \"packs.import\": return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], () => importPack(identifier(p.filename))));\n case \"packs.toggle\": return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], () => togglePack(identifier(p.id), p.enabled === true)));\n case \"players.list\": return players();\n case \"metrics.read\": return readRuntimeMetrics(request.params);\n case \"players.apply\": return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], async () => savePlayerPermissions(string(p.kind, \"\u6743\u9650\u7C7B\u578B\"), p.entries)));\n case \"attachment.plan\": return attachmentPlan();\n case \"attachment.apply\": return store.submit(request.method, async context => {\n const plan = await attachmentPlan(false);\n if (p.targetVersion !== undefined && p.targetVersion !== plan.targetVersion) throw Object.assign(new Error(\"\u76EE\u6807\u7248\u672C\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0\u65E5\u5FD7\u540E\u786E\u8BA4\"), { code: \"conflict\" });\n if (plan.externalServices.length) throw new Error(\"\u65E0\u6CD5\u53EF\u9760\u8FC1\u79FB\u5916\u90E8\u8FDB\u7A0B\uFF1B\u8BF7\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u4F18\u96C5\u505C\u670D\");\n if (plan.upgradeRequired) return launchPlatformUpdate(store, context, plan.targetVersion);\n return { attached: true, version: plan.currentVersion, development: plan.development };\n });\n case \"updates.check\": {\n const results = await Promise.allSettled([attachmentPlan(), modulePlan(), bdsUpdate({ id: \"check\", phase: () => {} }, true)]);\n return Object.fromEntries(results.map((result, index) => [[\"platform\", \"modules\", \"bds\"][index], result.status === \"fulfilled\" ? result.value : { error: String(result.reason) }]));\n }\n case \"updates.run\": {\n if (p.kind === \"platform\") return store.submit(request.method, async context => { const plan = await attachmentPlan(false); if (p.targetVersion !== undefined && p.targetVersion !== plan.targetVersion) throw Object.assign(new Error(\"\u76EE\u6807\u7248\u672C\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0\u65E5\u5FD7\u540E\u786E\u8BA4\"), { code: \"conflict\" }); return plan.upgradeRequired ? launchPlatformUpdate(store, context, plan.targetVersion) : { upToDate: true, version: plan.currentVersion }; });\n if (p.kind === \"modules\") return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], async () => { const result = await applyModulePlan(Array.isArray(p.ids) ? p.ids.map(identifier) : []); await rebuildModules(); return result; }, true, \"modules\"));\n if (p.kind === \"bds\") return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], () => bdsUpdate(context), true, \"bds\"));\n throw new Error(\"\u672A\u77E5\u66F4\u65B0\u7C7B\u578B\");\n }\n case \"deployment.create\": {\n if (p.acceptEula !== true) throw new Error(\"\u521B\u5EFA\u90E8\u7F72\u524D\u5FC5\u987B\u786E\u8BA4 BDS \u4F7F\u7528\u6761\u6B3E\");\n return store.submit(request.method, async context => {\n if (isRuntimeInitialized()) throw new Error(\"\u76EE\u5F55\u5DF2\u7ECF\u521D\u59CB\u5316\uFF0C\u4E0D\u8986\u76D6\u5DF2\u6709\u90E8\u7F72\");\n const ports = { db: deploymentPort(p.dbPort, 3001), bds: deploymentPort(p.bdsPort, 19132), bds6: deploymentPort(p.bdsPort6, 19133) };\n context.phase(\"preflight\", \"\u68C0\u67E5\u76EE\u5F55\u3001\u78C1\u76D8\u7A7A\u95F4\u548C TCP\uFF0FUDP \u7AEF\u53E3\"); await deploymentPreflight(ports);\n context.phase(\"prepare\"); ensureCoreConfigs(ROOT, [\"db_config\", \"qq_config\", \"bds_updater\", \"permissions\", \"qq_link\"]);\n const updater = path.join(ROOT, \"configs\", \"bds_updater.json\");\n atomicJson(updater, { ...readJson(updater, {}), bds_path: \"BDS\", backup_dir: \"backups\" });\n const dbFile = path.join(ROOT, \"configs\", \"db_config.json\"); atomicJson(dbFile, { ...readJson(dbFile, {}), db_port: ports.db });\n fs.mkdirSync(path.join(ROOT, \"modules\", \"packages\"), { recursive: true });\n await bdsUpdate(context);\n const properties = path.join(ROOT, \"BDS\", \"server.properties\");\n let text = fs.readFileSync(properties, \"utf8\");\n for (const [key, port] of [[\"server-port\", ports.bds], [\"server-portv6\", ports.bds6]] as const) text = text.replace(new RegExp(`^${key}=.*$`, \"m\"), `${key}=${port}`);\n fs.writeFileSync(properties, text);\n await rebuildModules();\n refreshServices(); context.phase(\"start\");\n const started: ServiceName[] = [];\n try { for (const name of START_ORDER) { const result = await services[name].start(); if (result.status !== \"skipped\") started.push(name); } await verifyRunning(started); }\n catch (error) { for (const name of [...START_ORDER].reverse()) await services[name].stop(false, false).catch(() => {}); throw error; }\n atomicJson(path.join(ROOT, \"configs\", \"runtime.json\"), { ...readJson(path.join(ROOT, \"configs\", \"runtime.json\"), {}), initialized_at: new Date().toISOString() });\n return { created: true, rows: await queryServicesRuntimeLocal() };\n });\n }\n case \"backups.list\": { const directory = path.join(ROOT, \".sfmc\", \"backups\"); return { backups: fs.existsSync(directory) ? fs.readdirSync(directory).filter(id => fs.existsSync(path.join(directory, id, \"manifest.json\"))) : [] }; }\n case \"backups.restore\": {\n if (p.confirmDataLoss !== true) throw new Error(\"\u6062\u590D\u6570\u636E\u9700\u8981\u660E\u786E\u786E\u8BA4\u4E22\u5F03\u5907\u4EFD\u4E4B\u540E\u7684\u53D8\u66F4\");\n return store.submit(request.method, context => withStoppedServices(context, [...START_ORDER], () => restoreSnapshot(identifier(p.id), context.phase)));\n }\n case \"startup.plan\": return startupPlan();\n default: throw Object.assign(new Error(`\u4E0D\u652F\u6301\u7684\u7BA1\u7406\u65B9\u6CD5: ${request.method}`), { code: \"unsupported\" });\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/management/stdio.ts"],"names":[],"mappings":"AAKA,uCAAuC;AACvC,wBAAsB,kBAAkB,kBAmEvC"}
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/management/stdio.ts"],"names":[],"mappings":"AAKA,uCAAuC;AACvC,wBAAsB,kBAAkB,kBA+EvC"}
@@ -30,6 +30,16 @@ async function runManagementStdio() {
30
30
  }
31
31
  const client = await import("../daemon/client.js");
32
32
  if (!forwarding) forwarding = client.onDaemonManagementEvent((event) => output(JSON.stringify(event) + "\n"));
33
+ if (ready && request.method === "metrics.read") {
34
+ const metrics = await import("./metrics-read.js");
35
+ output(JSON.stringify({ type: "res", id: request.id, ok: true, result: await metrics.readRuntimeMetrics(request.params) }) + "\n");
36
+ return;
37
+ }
38
+ if (ready && request.method === "players.list") {
39
+ const backend2 = await import("./server.js");
40
+ output(JSON.stringify({ type: "res", id: request.id, ok: true, result: await backend2.dispatchManagement(request) }) + "\n");
41
+ return;
42
+ }
33
43
  if (!legacy) {
34
44
  try {
35
45
  const result = await client.callDaemon("management", { request });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/management/stdio.ts"],
4
- "sourcesContent": ["import readline from \"node:readline\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport { toManagementError, type ManagementRequest } from \"@sfmc-bds/management\";\n\n/** \u9996\u5E27\u786E\u5B9A\u5B9E\u4F8B\u76EE\u5F55\uFF0C\u4E4B\u540E\u624D\u52A0\u8F7D\u542B ROOT \u5355\u4F8B\u7684 CLI \u4EE3\u7801\u3002 */\nexport async function runManagementStdio() {\n const output = process.stdout.write.bind(process.stdout);\n for (const key of [\"log\", \"info\", \"warn\", \"error\", \"debug\"] as const) console[key] = (...args: unknown[]) => { process.stderr.write(args.map(value => typeof value === \"string\" ? value : JSON.stringify(value)).join(\" \") + \"\\n\"); };\n const lines = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });\n let ready = false;\n let dispose: (() => void) | undefined;\n let forwarding: (() => void) | undefined;\n let legacy = false;\n const pending = new Set<Promise<void>>();\n const processLine = async (line: string) => {\n let request: ManagementRequest = { id: \"invalid\", method: \"invalid\" };\n try {\n if (Buffer.byteLength(line) > 4 * 1024 * 1024) throw new Error(\"\u7BA1\u7406\u5E27\u8FC7\u5927\");\n request = JSON.parse(line) as ManagementRequest;\n if (!request || typeof request.id !== \"string\" || request.id.length > 128 || typeof request.method !== \"string\" || request.method.length > 128) throw new Error(\"\u975E\u6CD5\u7BA1\u7406\u5E27\");\n if (!ready) {\n if (request.method !== \"handshake\") throw new Error(\"\u9996\u4E2A\u8BF7\u6C42\u5FC5\u987B\u4E3A\u63E1\u624B\");\n const params = request.params as { root?: unknown } | undefined;\n if (typeof params?.root !== \"string\" || !path.isAbsolute(params.root) || !fs.statSync(params.root).isDirectory()) throw new Error(\"\u9700\u8981\u6709\u6548\u7684\u5B9E\u4F8B\u7EDD\u5BF9\u76EE\u5F55\");\n process.env.SFMC_ROOT = path.resolve(params.root); ready = true;\n } else if (request.method === \"handshake\" && (request.params as { root?: string } | undefined)?.root && path.resolve((request.params as { root: string }).root) !== process.env.SFMC_ROOT) {\n throw new Error(\"\u4E00\u4E2A\u7BA1\u7406\u4F1A\u8BDD\u53EA\u80FD\u8FDE\u63A5\u4E00\u4E2A\u5B9E\u4F8B\");\n }\n const client = await import(\"../daemon/client.js\");\n if (!forwarding) forwarding = client.onDaemonManagementEvent(event => output(JSON.stringify(event) + \"\\n\"));\n if (!legacy) {\n try {\n const result = await client.callDaemon(\"management\", { request });\n if (result.kind !== \"management\") throw new Error(\"\u65E7\u5B88\u62A4\u8FDB\u7A0B\u6CA1\u6709\u7BA1\u7406\u5165\u53E3\");\n if (request.method === \"events.subscribe\" && result.response.ok && !dispose) dispose = await client.ensureDaemonSubscription();\n output(JSON.stringify(result.response) + \"\\n\");\n return;\n } catch (error) {\n if (request.method !== \"handshake\" || !/unknown method|\u7BA1\u7406\u5165\u53E3/.test(error instanceof Error ? error.message : String(error))) throw error;\n legacy = true;\n try { process.env.SFMC_PLATFORM_VERSION = (JSON.parse(fs.readFileSync(path.join(process.env.SFMC_ROOT!, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"package.json\"), \"utf8\")) as { version: string }).version; } catch { process.env.SFMC_PLATFORM_VERSION = \"unknown\"; }\n }\n }\n // \u65E7\u90E8\u7F72\u53EA\u5F00\u653E\u63A5\u5165\u89C4\u5212\u3001\u72B6\u6001\u548C\u6301\u4E45\u5316\u4EFB\u52A1\uFF1B\u5347\u7EA7\u4EA4\u7ED9\u72EC\u7ACB\u7EF4\u62A4\u8FDB\u7A0B\u3002\n const backend = await import(\"./server.js\");\n let value: unknown;\n if (request.method === \"handshake\") {\n value = { ...(await backend.dispatchManagement(request) as object), capabilities: [\"services\", \"logs\", \"operations\", \"updates\"], legacy: true };\n } else if (request.method === \"services.list\") {\n const result = await client.callDaemon(\"status\");\n if (result.kind !== \"status\") throw new Error(\"\u65E7\u90E8\u7F72\u65E0\u6CD5\u63D0\u4F9B\u670D\u52A1\u72B6\u6001\");\n value = { rows: result.rows };\n } else if (request.method === \"attachment.plan\" || request.method === \"attachment.apply\") {\n const status = await client.callDaemon(\"status\");\n if (status.kind !== \"status\") throw new Error(\"\u65E7\u90E8\u7F72\u65E0\u6CD5\u63D0\u4F9B\u670D\u52A1\u72B6\u6001\");\n const running = status.rows.filter(row => row.running).map(row => row.name);\n if (request.method === \"attachment.apply\" && running.length) throw Object.assign(new Error(\"\u65E7\u5B88\u62A4\u8FDB\u7A0B\u7F3A\u5C11\u53EF\u786E\u8BA4\u7684\u4F18\u96C5\u7EF4\u62A4\u63A5\u53E3\uFF1B\u8BF7\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u505C\u6B62\u670D\u52A1\uFF0C\u518D\u6267\u884C\u63A5\u5165\u5347\u7EA7\"), { code: \"conflict\" });\n const plan = await backend.dispatchManagement(request);\n value = request.method === \"attachment.plan\" ? { ...plan as object, externalServices: running } : plan;\n } else if ([\"events.subscribe\", \"logs.tail\", \"operations.list\", \"operations.get\", \"backups.list\"].includes(request.method)) value = await backend.dispatchManagement(request);\n else throw Object.assign(new Error(\"\u65E7\u90E8\u7F72\u9700\u5148\u901A\u8FC7\u63A5\u5165\u6D41\u7A0B\u5347\u7EA7\u5E73\u53F0\uFF0C\u518D\u4F7F\u7528\u5B8C\u6574\u7BA1\u7406\u529F\u80FD\"), { code: \"unsupported\" });\n output(JSON.stringify({ type: \"res\", id: request.id, ok: true, result: value }) + \"\\n\");\n } catch (error) { output(JSON.stringify({ type: \"res\", id: request?.id ?? \"invalid\", ok: false, error: toManagementError(error) }) + \"\\n\"); }\n };\n lines.on(\"line\", line => {\n if (pending.size >= 64) { process.stderr.write(\"\u7BA1\u7406\u8BF7\u6C42\u79EF\u538B\uFF0C\u5173\u95ED\u5F53\u524D\u4F1A\u8BDD\\n\"); lines.close(); return; }\n const action = processLine(line).catch(error => { process.stderr.write(String(error) + \"\\n\"); });\n pending.add(action); void action.finally(() => pending.delete(action));\n });\n await new Promise<void>(resolve => lines.once(\"close\", resolve));\n await Promise.allSettled(pending); dispose?.(); forwarding?.();\n if (ready) (await import(\"../daemon/client.js\")).disconnectDaemonClient();\n}\n"],
5
- "mappings": "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",
6
- "names": []
4
+ "sourcesContent": ["import readline from \"node:readline\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport { toManagementError, type ManagementRequest } from \"@sfmc-bds/management\";\n\n/** \u9996\u5E27\u786E\u5B9A\u5B9E\u4F8B\u76EE\u5F55\uFF0C\u4E4B\u540E\u624D\u52A0\u8F7D\u542B ROOT \u5355\u4F8B\u7684 CLI \u4EE3\u7801\u3002 */\nexport async function runManagementStdio() {\n const output = process.stdout.write.bind(process.stdout);\n for (const key of [\"log\", \"info\", \"warn\", \"error\", \"debug\"] as const) console[key] = (...args: unknown[]) => { process.stderr.write(args.map(value => typeof value === \"string\" ? value : JSON.stringify(value)).join(\" \") + \"\\n\"); };\n const lines = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });\n let ready = false;\n let dispose: (() => void) | undefined;\n let forwarding: (() => void) | undefined;\n let legacy = false;\n const pending = new Set<Promise<void>>();\n const processLine = async (line: string) => {\n let request: ManagementRequest = { id: \"invalid\", method: \"invalid\" };\n try {\n if (Buffer.byteLength(line) > 4 * 1024 * 1024) throw new Error(\"\u7BA1\u7406\u5E27\u8FC7\u5927\");\n request = JSON.parse(line) as ManagementRequest;\n if (!request || typeof request.id !== \"string\" || request.id.length > 128 || typeof request.method !== \"string\" || request.method.length > 128) throw new Error(\"\u975E\u6CD5\u7BA1\u7406\u5E27\");\n if (!ready) {\n if (request.method !== \"handshake\") throw new Error(\"\u9996\u4E2A\u8BF7\u6C42\u5FC5\u987B\u4E3A\u63E1\u624B\");\n const params = request.params as { root?: unknown } | undefined;\n if (typeof params?.root !== \"string\" || !path.isAbsolute(params.root) || !fs.statSync(params.root).isDirectory()) throw new Error(\"\u9700\u8981\u6709\u6548\u7684\u5B9E\u4F8B\u7EDD\u5BF9\u76EE\u5F55\");\n process.env.SFMC_ROOT = path.resolve(params.root); ready = true;\n } else if (request.method === \"handshake\" && (request.params as { root?: string } | undefined)?.root && path.resolve((request.params as { root: string }).root) !== process.env.SFMC_ROOT) {\n throw new Error(\"\u4E00\u4E2A\u7BA1\u7406\u4F1A\u8BDD\u53EA\u80FD\u8FDE\u63A5\u4E00\u4E2A\u5B9E\u4F8B\");\n }\n const client = await import(\"../daemon/client.js\");\n if (!forwarding) forwarding = client.onDaemonManagementEvent(event => output(JSON.stringify(event) + \"\\n\"));\n // \u6307\u6807\u548C\u73A9\u5BB6\u540D\u5355\u8BFB\u5F53\u524D\u78C1\u76D8\u4E0A\u7684\u4EE3\u7801\u4E0E\u6570\u636E\u5E93\u3002\u7BA1\u7406\u901A\u9053\u6BCF\u6B21\u8FDE\u63A5\u90FD\u4F1A\u52A0\u8F7D\u65B0\u6587\u4EF6\uFF0C\u4E0D\u5FC5\u4E3A\u6B64\u91CD\u542F\u4ECD\u5728\u6258\u7BA1\u670D\u52A1\u7684\u5B88\u62A4\u8FDB\u7A0B\u3002\n if (ready && request.method === \"metrics.read\") {\n const metrics = await import(\"./metrics-read.js\");\n output(JSON.stringify({ type: \"res\", id: request.id, ok: true, result: await metrics.readRuntimeMetrics(request.params) }) + \"\\n\");\n return;\n }\n if (ready && request.method === \"players.list\") {\n const backend = await import(\"./server.js\");\n output(JSON.stringify({ type: \"res\", id: request.id, ok: true, result: await backend.dispatchManagement(request) }) + \"\\n\");\n return;\n }\n if (!legacy) {\n try {\n const result = await client.callDaemon(\"management\", { request });\n if (result.kind !== \"management\") throw new Error(\"\u65E7\u5B88\u62A4\u8FDB\u7A0B\u6CA1\u6709\u7BA1\u7406\u5165\u53E3\");\n if (request.method === \"events.subscribe\" && result.response.ok && !dispose) dispose = await client.ensureDaemonSubscription();\n output(JSON.stringify(result.response) + \"\\n\");\n return;\n } catch (error) {\n if (request.method !== \"handshake\" || !/unknown method|\u7BA1\u7406\u5165\u53E3/.test(error instanceof Error ? error.message : String(error))) throw error;\n legacy = true;\n try { process.env.SFMC_PLATFORM_VERSION = (JSON.parse(fs.readFileSync(path.join(process.env.SFMC_ROOT!, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"package.json\"), \"utf8\")) as { version: string }).version; } catch { process.env.SFMC_PLATFORM_VERSION = \"unknown\"; }\n }\n }\n // \u65E7\u90E8\u7F72\u53EA\u5F00\u653E\u63A5\u5165\u89C4\u5212\u3001\u72B6\u6001\u548C\u6301\u4E45\u5316\u4EFB\u52A1\uFF1B\u5347\u7EA7\u4EA4\u7ED9\u72EC\u7ACB\u7EF4\u62A4\u8FDB\u7A0B\u3002\n const backend = await import(\"./server.js\");\n let value: unknown;\n if (request.method === \"handshake\") {\n value = { ...(await backend.dispatchManagement(request) as object), capabilities: [\"services\", \"logs\", \"operations\", \"updates\"], legacy: true };\n } else if (request.method === \"services.list\") {\n const result = await client.callDaemon(\"status\");\n if (result.kind !== \"status\") throw new Error(\"\u65E7\u90E8\u7F72\u65E0\u6CD5\u63D0\u4F9B\u670D\u52A1\u72B6\u6001\");\n value = { rows: result.rows };\n } else if (request.method === \"attachment.plan\" || request.method === \"attachment.apply\") {\n const status = await client.callDaemon(\"status\");\n if (status.kind !== \"status\") throw new Error(\"\u65E7\u90E8\u7F72\u65E0\u6CD5\u63D0\u4F9B\u670D\u52A1\u72B6\u6001\");\n const running = status.rows.filter(row => row.running).map(row => row.name);\n if (request.method === \"attachment.apply\" && running.length) throw Object.assign(new Error(\"\u65E7\u5B88\u62A4\u8FDB\u7A0B\u7F3A\u5C11\u53EF\u786E\u8BA4\u7684\u4F18\u96C5\u7EF4\u62A4\u63A5\u53E3\uFF1B\u8BF7\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u505C\u6B62\u670D\u52A1\uFF0C\u518D\u6267\u884C\u63A5\u5165\u5347\u7EA7\"), { code: \"conflict\" });\n const plan = await backend.dispatchManagement(request);\n value = request.method === \"attachment.plan\" ? { ...plan as object, externalServices: running } : plan;\n } else if ([\"events.subscribe\", \"logs.tail\", \"operations.list\", \"operations.get\", \"backups.list\"].includes(request.method)) value = await backend.dispatchManagement(request);\n else throw Object.assign(new Error(\"\u65E7\u90E8\u7F72\u9700\u5148\u901A\u8FC7\u63A5\u5165\u6D41\u7A0B\u5347\u7EA7\u5E73\u53F0\uFF0C\u518D\u4F7F\u7528\u5B8C\u6574\u7BA1\u7406\u529F\u80FD\"), { code: \"unsupported\" });\n output(JSON.stringify({ type: \"res\", id: request.id, ok: true, result: value }) + \"\\n\");\n } catch (error) { output(JSON.stringify({ type: \"res\", id: request?.id ?? \"invalid\", ok: false, error: toManagementError(error) }) + \"\\n\"); }\n };\n lines.on(\"line\", line => {\n if (pending.size >= 64) { process.stderr.write(\"\u7BA1\u7406\u8BF7\u6C42\u79EF\u538B\uFF0C\u5173\u95ED\u5F53\u524D\u4F1A\u8BDD\\n\"); lines.close(); return; }\n const action = processLine(line).catch(error => { process.stderr.write(String(error) + \"\\n\"); });\n pending.add(action); void action.finally(() => pending.delete(action));\n });\n // \u6807\u51C6\u8F93\u5165\u5173\u95ED\u8868\u793A\u7BA1\u7406\u7AEF\u79BB\u5F00\u3002\u53EA\u65AD\u5F00\u4E0E\u5B88\u62A4\u8FDB\u7A0B\u7684\u7BA1\u9053\uFF0C\u4E0D\u505C\u6B62\u670D\u52A1\u3002\n await new Promise<void>(resolve => lines.once(\"close\", resolve));\n await Promise.allSettled(pending); dispose?.(); forwarding?.();\n if (ready) (await import(\"../daemon/client.js\")).disconnectDaemonClient();\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["backend"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sfmc-bds/cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "SFMC management CLI — REPL, service supervisor, module install, behavior-pack build/deploy",
5
5
  "author": "Shiroha7z",
6
6
  "license": "AGPL-3.0-only",
@@ -58,7 +58,8 @@
58
58
  "@sfmc-bds/bds-tools": "0.2.8",
59
59
  "@sfmc-bds/devkit": "2.0.4",
60
60
  "@sfmc-bds/sdk": "0.4.0",
61
- "@sfmc-bds/management": "0.3.2"
61
+ "@sfmc-bds/management": "0.3.3",
62
+ "@sfmc-bds/db-server": "0.5.1"
62
63
  },
63
64
  "devDependencies": {
64
65
  "@sfmc-bds/tools": "0.2.8"