@sfmc-bds/cli 0.4.4 → 0.5.0
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.
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +5 -2
- package/dist/daemon/client.js.map +2 -2
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +4 -3
- package/dist/daemon/server.js.map +2 -2
- package/dist/management/maintenance.js +3 -4
- package/dist/management/maintenance.js.map +2 -2
- package/dist/management/platform-worker.js +22 -3
- package/dist/management/platform-worker.js.map +2 -2
- package/dist/management/server.js +1 -1
- package/dist/management/server.js.map +2 -2
- package/dist/management/tasks.js +2 -9
- package/dist/management/tasks.js.map +2 -2
- package/dist/module-commands.d.ts.map +1 -1
- package/dist/module-commands.js +9 -3
- package/dist/module-commands.js.map +2 -2
- package/dist/services.js +1 -1
- package/dist/services.js.map +2 -2
- package/dist/wizard.js +1 -1
- package/dist/wizard.js.map +2 -2
- package/package.json +6 -6
- package/scripts/module-install/fetch-module.mjs +6 -2
|
@@ -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;
|
|
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"}
|
package/dist/daemon/client.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import { isLogPayload } from "./protocol.js";
|
|
19
19
|
import { isDaemonServer } from "./role.js";
|
|
20
20
|
import { fileURLToPath } from "node:url";
|
|
21
|
-
import { maintenanceToken } from "@sfmc-bds/management/node";
|
|
21
|
+
import { lockOwnerAlive, maintenanceToken } from "@sfmc-bds/management/node";
|
|
22
22
|
function onDaemonManagementEvent(callback) {
|
|
23
23
|
remoteStateBus.on("management", callback);
|
|
24
24
|
return () => {
|
|
@@ -189,7 +189,10 @@ function spawnDaemonProcess() {
|
|
|
189
189
|
const lockFile = path.join(ROOT, ".sfmc", "maintenance.lock");
|
|
190
190
|
if (fs.existsSync(lockFile)) {
|
|
191
191
|
const owner = JSON.parse(fs.readFileSync(lockFile, "utf8"));
|
|
192
|
-
|
|
192
|
+
const token = maintenanceToken(ROOT) ?? process.env.SFMC_MAINTENANCE_TOKEN;
|
|
193
|
+
const holder = token === owner.nonce;
|
|
194
|
+
const pidKnown = Number.isSafeInteger(owner.pid) && (owner.pid ?? 0) > 0;
|
|
195
|
+
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");
|
|
193
196
|
}
|
|
194
197
|
const entry = process.env.SFMC_DAEMON_ENTRY ?? fileURLToPath(new URL("../main.js", import.meta.url));
|
|
195
198
|
if (!entry) throw new Error("cannot resolve sfmc entry for daemon spawn");
|
|
@@ -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 { 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 { nonce: string };\n if ((maintenanceToken(ROOT) ?? process.env.SFMC_MAINTENANCE_TOKEN) !== owner.nonce) 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": "AAOA,SAAS,sBAAsB;AAC/B,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,mBAAmB;AAC5B,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,SAAS;AAChB,OAAO,aAAa;AACpB,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,YAAY;AAErB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AASP,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAE9B,SAAS,wBAAwB;
|
|
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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",
|
|
6
6
|
"names": ["deadline"]
|
|
7
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,
|
|
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"}
|
package/dist/daemon/server.js
CHANGED
|
@@ -21,9 +21,9 @@ import {
|
|
|
21
21
|
} from "./paths.js";
|
|
22
22
|
import { toLogPayload } from "./protocol.js";
|
|
23
23
|
import { markDaemonServer } from "./role.js";
|
|
24
|
-
import { dispatchManagement, onManagementEvent } from "../management/server.js";
|
|
24
|
+
import { dispatchManagement, managementTasks, onManagementEvent } from "../management/server.js";
|
|
25
25
|
import { toManagementError } from "@sfmc-bds/management";
|
|
26
|
-
import { withMaintenanceLock } from "@sfmc-bds/management/node";
|
|
26
|
+
import { isMaintenanceLocked, withMaintenanceLock } from "@sfmc-bds/management/node";
|
|
27
27
|
import { ROOT } from "../runtime.js";
|
|
28
28
|
import fs from "node:fs";
|
|
29
29
|
import path from "node:path";
|
|
@@ -270,7 +270,8 @@ async function runDaemonServer() {
|
|
|
270
270
|
});
|
|
271
271
|
writeDaemonMeta(meta);
|
|
272
272
|
releaseStartup();
|
|
273
|
-
|
|
273
|
+
managementTasks();
|
|
274
|
+
if (process.argv.includes("--autostart") && !isMaintenanceLocked(ROOT)) await startAll();
|
|
274
275
|
const cleanup = () => {
|
|
275
276
|
unsubManagement();
|
|
276
277
|
unsubLog();
|
|
@@ -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, onManagementEvent } from \"../management/server.js\";\nimport { toManagementError } from \"@sfmc-bds/management\";\nimport { 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 if (process.argv.includes(\"--autostart\") && !fs.existsSync(path.join(ROOT, \".sfmc\", \"maintenance.lock\"))) 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": "AAOA,OAAO,SAAS;AAChB,OAAO,aAAa;AACpB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,sBAAsB,2BAA2B,eAAe;AACzE,SAAS,gBAAgB;AACzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,SAAS,oBAAoB,yBAAyB;
|
|
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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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -170,10 +170,9 @@ async function launchPlatformUpdate(store, context, target) {
|
|
|
170
170
|
const previous = readJson(path.join(ROOT, ".sfmc", "runtime", "active.json"), { entry: fs.existsSync(path.join(ROOT, "node_modules", "@sfmc-bds", "sfmc", "bin", "sfmc.mjs")) ? path.join(ROOT, "node_modules", "@sfmc-bds", "sfmc", "bin", "sfmc.mjs") : process.env.SFMC_DAEMON_ENTRY, version: platformVersion() });
|
|
171
171
|
atomicJson(request, { root: ROOT, id: context.id, target, running: rows.filter((row) => row.running).map((row) => row.name), previous });
|
|
172
172
|
const entry = fileURLToPath(new URL("./platform-worker.js", import.meta.url));
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const child = spawn(process.execPath, [entry, request], { cwd: ROOT, env: { ...process.env, SFMC_ROOT: ROOT }, detached: true, windowsHide: true, stdio:
|
|
176
|
-
fs.closeSync(fd);
|
|
173
|
+
const log = path.join(ROOT, ".sfmc", "logs", "maintenance.log");
|
|
174
|
+
fs.mkdirSync(path.dirname(log), { recursive: true });
|
|
175
|
+
const child = spawn(process.execPath, [entry, request], { cwd: ROOT, env: { ...process.env, SFMC_ROOT: ROOT, SFMC_MAINTENANCE_LOG: log }, detached: true, windowsHide: true, stdio: "ignore" });
|
|
177
176
|
await new Promise((resolve, reject) => {
|
|
178
177
|
child.once("spawn", resolve);
|
|
179
178
|
child.once("error", reject);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/management/maintenance.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { spawn } from \"node:child_process\";\nimport { fileURLToPath } from \"node:url\";\nimport { ROOT, isMonorepoLayout, isSourceCheckout } from \"../runtime.js\";\nimport { queryServicesRuntimeLocal, services, START_ORDER, type ServiceName } from \"../services.js\";\nimport { resolveBdsContext } from \"../pack-lifecycle.js\";\nimport { atomicJson, type TaskContext, type TaskStore } from \"./tasks.js\";\nimport { readJson, runProcess } from \"./domain.js\";\nimport type { AttachmentPlan } from \"@sfmc-bds/management\";\nimport { isDaemonServer } from \"../daemon/role.js\";\nimport { callDaemon } from \"../daemon/client.js\";\nimport { platformReleaseNotes } from \"@sfmc-bds/management/node\";\n\nasync function runtimeRows() {\n if (isDaemonServer()) return queryServicesRuntimeLocal();\n const result = await callDaemon(\"status\");\n if (result.kind !== \"status\") throw new Error(\"\u65E0\u6CD5\u8BFB\u53D6\u5B88\u62A4\u8FDB\u7A0B\u670D\u52A1\u72B6\u6001\");\n return result.rows;\n}\n\nconst require = createRequire(import.meta.url);\nexport function platformVersion(): string {\n if (isMonorepoLayout(ROOT)) return readJson<{ version: string }>(path.join(ROOT, \"packages\", \"meta\", \"package.json\"), { version: \"unknown\" }).version;\n if (process.env.SFMC_PLATFORM_VERSION) return process.env.SFMC_PLATFORM_VERSION;\n const active = readJson<{ version?: string }>(path.join(ROOT, \".sfmc\", \"runtime\", \"active.json\"), {});\n if (active.version) return active.version;\n const deployed = readJson<{ version?: string }>(path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"package.json\"), {});\n if (deployed.version) return deployed.version;\n try { return (require(\"@sfmc-bds/sfmc/package.json\") as { version: string }).version; }\n catch { return (readJson<{ version: string }>(path.join(fileURLToPath(new URL(\"../../..\", import.meta.url)), \"package.json\"), { version: \"unknown\" })).version; }\n}\nexport async function attachmentPlan(includeReleaseNotes = true): Promise<AttachmentPlan> {\n const development = isMonorepoLayout(ROOT) || isSourceCheckout();\n const currentVersion = platformVersion();\n let targetVersion = currentVersion;\n if (!development) {\n const response = await fetch(\"https://registry.npmjs.org/@sfmc-bds%2fsfmc/latest\", { signal: AbortSignal.timeout(15_000) });\n if (!response.ok) throw new Error(`\u5E73\u53F0\u7248\u672C\u68C0\u67E5\u5931\u8D25 (${response.status})`);\n const metadata = await response.json() as { version?: string };\n if (!metadata.version || !/^\\d+\\.\\d+\\.\\d+$/.test(metadata.version)) throw new Error(\"latest \u6CA1\u6709\u6307\u5411\u6709\u6548\u7684\u7A33\u5B9A\u5E73\u53F0\u7248\u672C\");\n targetVersion = metadata.version;\n }\n const [rows, releaseNotes] = await Promise.all([runtimeRows(), includeReleaseNotes && !development ? platformReleaseNotes(targetVersion) : undefined]);\n return { currentVersion, targetVersion, development, upgradeRequired: !development && targetVersion !== currentVersion, externalServices: rows.filter(row => row.running && row.ownership === \"external\").map(row => row.name), steps: development ? [\"\u4FDD\u7559\u6E90\u7801\u5DE5\u4F5C\u533A\uFF0C\u8FDE\u63A5\u5F53\u524D\u5F00\u53D1\u90E8\u7F72\"] : [\"\u4E0B\u8F7D\u56FA\u5B9A\u7248\u672C\u7684\u5E73\u53F0\u4F9D\u8D56\u7EC4\u5408\", \"\u505C\u6B62\u53D7\u5F71\u54CD\u670D\u52A1\u5E76\u786E\u8BA4\u8FDB\u7A0B\u9000\u51FA\", \"\u5907\u4EFD\u914D\u7F6E\u3001\u6A21\u5757\u3001\u6570\u636E\u5E93\u4E0E\u4E16\u754C\", \"\u5207\u6362\u5E73\u53F0\u5E76\u9A8C\u8BC1\", \"\u6062\u590D\u6B64\u524D\u8FD0\u884C\u7684\u670D\u52A1\"], ...(releaseNotes ? { releaseNotes } : {}) };\n}\nexport async function stopForMaintenance(names: ServiceName[], phase: TaskContext[\"phase\"]): Promise<ServiceName[]> {\n const before = await queryServicesRuntimeLocal();\n const affected = before.filter(row => names.includes(row.name) && row.running);\n if (affected.some(row => row.ownership === \"external\")) throw Object.assign(new Error(\"\u5B58\u5728\u65E0\u6CD5\u901A\u8FC7\u5F53\u524D\u5B88\u62A4\u8FDB\u7A0B\u4F18\u96C5\u505C\u6B62\u7684\u5916\u90E8\u670D\u52A1\uFF1B\u8BF7\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u505C\u6B62\u540E\u91CD\u65B0\u63A5\u5165\"), { code: \"conflict\" });\n phase(\"stop-services\", \"\u4F18\u96C5\u505C\u6B62\u5E76\u786E\u8BA4\u8FDB\u7A0B\u9000\u51FA\");\n const running = affected.map(row => row.name);\n for (const name of [...START_ORDER].reverse().filter(name => names.includes(name))) await services[name].stop(false, false);\n const after = await queryServicesRuntimeLocal();\n if (after.some(row => names.includes(row.name) && row.running)) throw new Error(\"\u670D\u52A1\u672A\u5B8C\u5168\u9000\u51FA\uFF0C\u5DF2\u4E2D\u6B62\u6587\u4EF6\u64CD\u4F5C\");\n return running;\n}\nexport async function restoreRunning(names: ServiceName[], phase: TaskContext[\"phase\"]) {\n phase(\"restore\", \"\u6062\u590D\u7EF4\u62A4\u524D\u8FD0\u884C\u7684\u670D\u52A1\");\n for (const name of START_ORDER.filter(name => names.includes(name))) {\n const result = await services[name].start();\n if (result.status === \"skipped\") throw new Error(`\u6062\u590D ${name} \u5931\u8D25: ${result.reason}`);\n }\n await verifyRunning(names);\n}\nexport async function verifyRunning(names: ServiceName[]) {\n if (!names.length) return;\n await new Promise(resolve => setTimeout(resolve, 2000));\n for (const name of names) {\n if (!services[name].running || !services[name].pid) throw new Error(`${name} \u542F\u52A8\u540E\u5DF2\u9000\u51FA`);\n }\n if (names.includes(\"db\")) {\n const cfg = readJson<{ db_port?: number; http_auth?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\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) throw new Error(`DB \u5065\u5EB7\u68C0\u67E5\u5931\u8D25 (${response.status})`);\n }\n}\nfunction snapshotTargets() {\n const db = readJson<{ dbDir?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\n const bds = resolveBdsContext().bdsRoot;\n return { configs: path.join(ROOT, \"configs\"), modules: path.join(ROOT, \"modules\"), data: path.dirname(path.resolve(ROOT, db.dbDir ?? \"data/sfmc_data.db\")), bds };\n}\nexport async function createSnapshot(id: string, phase: TaskContext[\"phase\"]) {\n phase(\"backup\", \"\u521B\u5EFA\u5DF2\u505C\u670D\u7684\u4E00\u81F4\u5907\u4EFD\");\n const destination = path.join(ROOT, \".sfmc\", \"backups\", id);\n fs.mkdirSync(destination, { recursive: true });\n const targets = snapshotTargets();\n for (const target of Object.values(targets)) {\n const absolute = path.resolve(target);\n if (absolute === path.parse(absolute).root || absolute === path.resolve(ROOT) || destination.startsWith(absolute + path.sep)) throw new Error(\"\u5907\u4EFD\u76EE\u6807\u5305\u542B\u5B9E\u4F8B\u6839\u76EE\u5F55\u6216\u5907\u4EFD\u76EE\u5F55\uFF0C\u5DF2\u4E2D\u6B62\");\n }\n for (const [key, target] of Object.entries(targets)) {\n if (fs.existsSync(target)) await fs.promises.cp(target, path.join(destination, key), { recursive: true, dereference: false });\n }\n atomicJson(path.join(destination, \"manifest.json\"), { createdAt: new Date().toISOString(), targets, complete: true });\n return destination;\n}\nexport async function restoreSnapshot(id: string, phase: TaskContext[\"phase\"]) {\n if (!/^[a-zA-Z0-9-]{1,80}$/.test(id)) throw new Error(\"\u975E\u6CD5\u5907\u4EFD\u7F16\u53F7\");\n const source = path.join(ROOT, \".sfmc\", \"backups\", id);\n const manifest = readJson<{ complete: boolean; targets: Record<string, string> }>(path.join(source, \"manifest.json\"), { complete: false, targets: {} });\n if (!manifest.complete) throw new Error(\"\u5907\u4EFD\u4E0D\u5B8C\u6574\uFF0C\u7981\u6B62\u6062\u590D\");\n const targets = snapshotTargets();\n phase(\"restore-data\", \"\u6309\u7528\u6237\u660E\u786E\u9009\u62E9\u6062\u590D\u914D\u7F6E\u3001\u6A21\u5757\u3001\u6570\u636E\u5E93\u548C\u4E16\u754C\");\n for (const [key, target] of Object.entries(targets)) {\n if (path.resolve(manifest.targets[key] ?? \"\") !== path.resolve(target)) throw new Error(\"\u5907\u4EFD\u76EE\u6807\u4E0E\u5F53\u524D\u90E8\u7F72\u4E0D\u4E00\u81F4\");\n const saved = path.join(source, key);\n if (!fs.existsSync(saved)) continue;\n const absolute = path.resolve(target);\n if (absolute === path.parse(absolute).root || absolute === path.resolve(ROOT) || fs.lstatSync(saved).isSymbolicLink()) throw new Error(\"\u4E0D\u5B89\u5168\u7684\u6062\u590D\u76EE\u6807\");\n await fs.promises.rm(absolute, { recursive: true, force: true });\n await fs.promises.cp(saved, absolute, { recursive: true, dereference: false });\n }\n return { restored: id };\n}\n/** \u53EA\u56DE\u9000\u7A0B\u5E8F\u5185\u5BB9\uFF0C\u4E16\u754C\u3001\u73A9\u5BB6\u6743\u9650\u548C\u6570\u636E\u5E93\u59CB\u7EC8\u4FDD\u7559\u5728\u5F53\u524D\u72B6\u6001\u3002 */\nasync function restoreProgramSnapshot(id: string, kind: \"modules\" | \"bds\") {\n const source = path.join(ROOT, \".sfmc\", \"backups\", id);\n const manifest = readJson<{ complete: boolean; targets: Record<string, string> }>(path.join(source, \"manifest.json\"), { complete: false, targets: {} });\n const targets = snapshotTargets();\n if (!manifest.complete || path.resolve(manifest.targets[kind] ?? \"\") !== path.resolve(targets[kind])) throw new Error(\"\u7A0B\u5E8F\u5907\u4EFD\u4E0D\u5B8C\u6574\u6216\u76EE\u6807\u4E0D\u5339\u914D\");\n const saved = path.join(source, kind);\n if (kind === \"modules\") {\n if (!fs.existsSync(saved)) return;\n await fs.promises.rm(targets.modules, { recursive: true, force: true });\n await fs.promises.cp(saved, targets.modules, { recursive: true, dereference: false });\n return;\n }\n const cfg = readJson<{ preserve?: string[] }>(path.join(ROOT, \"configs\", \"bds_updater.json\"), {});\n const preserved = new Set([\"worlds\", \"config\", \"server.properties\", \"allowlist.json\", \"whitelist.json\", \"permissions.json\", ...(cfg.preserve ?? []).map(name => name.split(/[\\\\/]/)[0]!)]);\n if (!fs.existsSync(saved)) throw new Error(\"\u7F3A\u5C11\u539F BDS \u7A0B\u5E8F\u5907\u4EFD\");\n const target = path.resolve(targets.bds);\n if (target === path.parse(target).root || target === path.resolve(ROOT)) throw new Error(\"\u4E0D\u5B89\u5168\u7684\u7A0B\u5E8F\u56DE\u9000\u76EE\u6807\");\n fs.mkdirSync(target, { recursive: true });\n for (const entry of fs.readdirSync(target)) if (!preserved.has(entry)) await fs.promises.rm(path.join(target, entry), { recursive: true, force: true });\n for (const entry of fs.readdirSync(saved)) if (!preserved.has(entry)) await fs.promises.cp(path.join(saved, entry), path.join(target, entry), { recursive: true, dereference: false });\n}\nexport async function withStoppedServices<T>(context: TaskContext, names: ServiceName[], action: () => Promise<T>, backup = true, rollbackPrograms?: \"modules\" | \"bds\"): Promise<T> {\n const running = await stopForMaintenance(names, context.phase);\n try {\n if (backup) await createSnapshot(context.id, context.phase);\n context.phase(\"execute\");\n const result = await action();\n context.phase(\"verify\");\n await restoreRunning(running, context.phase);\n return result;\n } catch (error) {\n // \u5931\u8D25\u540E\u4FDD\u6301\u505C\u670D\uFF0C\u4E0D\u731C\u6D4B\u672A\u77E5\u6570\u636E\u8FC1\u79FB\u662F\u5426\u53EF\u4EE5\u5B89\u5168\u6062\u590D\u8FD0\u884C\u3002\n for (const name of [...START_ORDER].reverse().filter(name => running.includes(name))) await services[name].stop(false, false).catch(() => {});\n let programRolledBack = false;\n let rollbackError: string | undefined;\n if (rollbackPrograms) {\n context.phase(\"rollback-program\", \"\u56DE\u9000\u7A0B\u5E8F\u7248\u672C\uFF0C\u4FDD\u7559\u5F53\u524D\u73A9\u5BB6\u6570\u636E\");\n try { await restoreProgramSnapshot(context.id, rollbackPrograms); programRolledBack = true; }\n catch (failure) { rollbackError = String(failure); }\n }\n throw Object.assign(new Error(`\u7EF4\u62A4\u5931\u8D25\uFF0C\u670D\u52A1\u4FDD\u6301\u505C\u6B62\uFF1B\u5907\u4EFD\u7F16\u53F7 ${context.id}: ${error instanceof Error ? error.message : String(error)}`), { code: \"io\", details: { backupId: context.id, programRolledBack, dataRestoreRequired: Boolean(rollbackPrograms), ...(rollbackError ? { rollbackError } : {}), ...((error as { details?: object }).details ?? {}) } });\n }\n}\nexport async function launchPlatformUpdate(store: TaskStore, context: TaskContext, target: string) {\n if (isMonorepoLayout(ROOT)) throw new Error(\"\u6E90\u7801\u90E8\u7F72\u4E0D\u8986\u76D6\u5DE5\u4F5C\u533A\uFF1B\u8BF7\u4F7F\u7528\u6B63\u5E38\u5F00\u53D1\u53D1\u5E03\u6D41\u7A0B\");\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(target)) throw new Error(\"\u9700\u8981\u56FA\u5B9A\u7A33\u5B9A\u7248\u672C\");\n const rows = await runtimeRows();\n if (rows.some(row => row.running && row.ownership === \"external\")) throw new Error(\"\u5916\u90E8\u670D\u52A1\u5FC5\u987B\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u4F18\u96C5\u505C\u6B62\");\n const request = path.join(ROOT, \".sfmc\", \"operations\", `${context.id}.request.json`);\n const previous = readJson(path.join(ROOT, \".sfmc\", \"runtime\", \"active.json\"), { entry: fs.existsSync(path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\")) ? path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\") : process.env.SFMC_DAEMON_ENTRY, version: platformVersion() });\n atomicJson(request, { root: ROOT, id: context.id, target, running: rows.filter(row => row.running).map(row => row.name), previous });\n const entry = fileURLToPath(new URL(\"./platform-worker.js\", import.meta.url));\n fs.mkdirSync(path.join(ROOT, \".sfmc\", \"logs\"), { recursive: true });\n const fd = fs.openSync(path.join(ROOT, \".sfmc\", \"logs\", \"maintenance.log\"), \"a\");\n const child = spawn(process.execPath, [entry, request], { cwd: ROOT, env: { ...process.env, SFMC_ROOT: ROOT }, detached: true, windowsHide: true, stdio: [\"ignore\", fd, fd] });\n fs.closeSync(fd);\n await new Promise<void>((resolve, reject) => { child.once(\"spawn\", resolve); child.once(\"error\", reject); });\n child.unref();\n const record = store.get(context.id) as ReturnType<TaskStore[\"get\"]> & { workerPid?: number };\n record.status = \"running\"; if (child.pid) record.workerPid = child.pid;\n store.save(record);\n return { detached: true };\n}\nexport async function runPnpm(args: string[], cwd: string) {\n const script = process.env.SFMC_PNPM_ENTRY;\n if (script) return runProcess(process.execPath, [script, ...args], cwd);\n const command = process.platform === \"win32\" ? \"pnpm.cmd\" : \"pnpm\";\n const crossSpawn = require(\"cross-spawn\") as typeof spawn;\n await new Promise<void>((resolve, reject) => {\n const child = crossSpawn(command, args, { cwd, env: process.env, windowsHide: true, stdio: \"ignore\" });\n child.on(\"error\", reject); child.on(\"close\", code => code === 0 ? resolve() : reject(new Error(`pnpm \u6267\u884C\u5931\u8D25 (${code})`)));\n });\n}\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 { spawn } from \"node:child_process\";\nimport { fileURLToPath } from \"node:url\";\nimport { ROOT, isMonorepoLayout, isSourceCheckout } from \"../runtime.js\";\nimport { queryServicesRuntimeLocal, services, START_ORDER, type ServiceName } from \"../services.js\";\nimport { resolveBdsContext } from \"../pack-lifecycle.js\";\nimport { atomicJson, type TaskContext, type TaskStore } from \"./tasks.js\";\nimport { readJson, runProcess } from \"./domain.js\";\nimport type { AttachmentPlan } from \"@sfmc-bds/management\";\nimport { isDaemonServer } from \"../daemon/role.js\";\nimport { callDaemon } from \"../daemon/client.js\";\nimport { platformReleaseNotes } from \"@sfmc-bds/management/node\";\n\nasync function runtimeRows() {\n if (isDaemonServer()) return queryServicesRuntimeLocal();\n const result = await callDaemon(\"status\");\n if (result.kind !== \"status\") throw new Error(\"\u65E0\u6CD5\u8BFB\u53D6\u5B88\u62A4\u8FDB\u7A0B\u670D\u52A1\u72B6\u6001\");\n return result.rows;\n}\n\nconst require = createRequire(import.meta.url);\nexport function platformVersion(): string {\n if (isMonorepoLayout(ROOT)) return readJson<{ version: string }>(path.join(ROOT, \"packages\", \"meta\", \"package.json\"), { version: \"unknown\" }).version;\n if (process.env.SFMC_PLATFORM_VERSION) return process.env.SFMC_PLATFORM_VERSION;\n const active = readJson<{ version?: string }>(path.join(ROOT, \".sfmc\", \"runtime\", \"active.json\"), {});\n if (active.version) return active.version;\n const deployed = readJson<{ version?: string }>(path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"package.json\"), {});\n if (deployed.version) return deployed.version;\n try { return (require(\"@sfmc-bds/sfmc/package.json\") as { version: string }).version; }\n catch { return (readJson<{ version: string }>(path.join(fileURLToPath(new URL(\"../../..\", import.meta.url)), \"package.json\"), { version: \"unknown\" })).version; }\n}\nexport async function attachmentPlan(includeReleaseNotes = true): Promise<AttachmentPlan> {\n const development = isMonorepoLayout(ROOT) || isSourceCheckout();\n const currentVersion = platformVersion();\n let targetVersion = currentVersion;\n if (!development) {\n const response = await fetch(\"https://registry.npmjs.org/@sfmc-bds%2fsfmc/latest\", { signal: AbortSignal.timeout(15_000) });\n if (!response.ok) throw new Error(`\u5E73\u53F0\u7248\u672C\u68C0\u67E5\u5931\u8D25 (${response.status})`);\n const metadata = await response.json() as { version?: string };\n if (!metadata.version || !/^\\d+\\.\\d+\\.\\d+$/.test(metadata.version)) throw new Error(\"latest \u6CA1\u6709\u6307\u5411\u6709\u6548\u7684\u7A33\u5B9A\u5E73\u53F0\u7248\u672C\");\n targetVersion = metadata.version;\n }\n const [rows, releaseNotes] = await Promise.all([runtimeRows(), includeReleaseNotes && !development ? platformReleaseNotes(targetVersion) : undefined]);\n return { currentVersion, targetVersion, development, upgradeRequired: !development && targetVersion !== currentVersion, externalServices: rows.filter(row => row.running && row.ownership === \"external\").map(row => row.name), steps: development ? [\"\u4FDD\u7559\u6E90\u7801\u5DE5\u4F5C\u533A\uFF0C\u8FDE\u63A5\u5F53\u524D\u5F00\u53D1\u90E8\u7F72\"] : [\"\u4E0B\u8F7D\u56FA\u5B9A\u7248\u672C\u7684\u5E73\u53F0\u4F9D\u8D56\u7EC4\u5408\", \"\u505C\u6B62\u53D7\u5F71\u54CD\u670D\u52A1\u5E76\u786E\u8BA4\u8FDB\u7A0B\u9000\u51FA\", \"\u5907\u4EFD\u914D\u7F6E\u3001\u6A21\u5757\u3001\u6570\u636E\u5E93\u4E0E\u4E16\u754C\", \"\u5207\u6362\u5E73\u53F0\u5E76\u9A8C\u8BC1\", \"\u6062\u590D\u6B64\u524D\u8FD0\u884C\u7684\u670D\u52A1\"], ...(releaseNotes ? { releaseNotes } : {}) };\n}\nexport async function stopForMaintenance(names: ServiceName[], phase: TaskContext[\"phase\"]): Promise<ServiceName[]> {\n const before = await queryServicesRuntimeLocal();\n const affected = before.filter(row => names.includes(row.name) && row.running);\n if (affected.some(row => row.ownership === \"external\")) throw Object.assign(new Error(\"\u5B58\u5728\u65E0\u6CD5\u901A\u8FC7\u5F53\u524D\u5B88\u62A4\u8FDB\u7A0B\u4F18\u96C5\u505C\u6B62\u7684\u5916\u90E8\u670D\u52A1\uFF1B\u8BF7\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u505C\u6B62\u540E\u91CD\u65B0\u63A5\u5165\"), { code: \"conflict\" });\n phase(\"stop-services\", \"\u4F18\u96C5\u505C\u6B62\u5E76\u786E\u8BA4\u8FDB\u7A0B\u9000\u51FA\");\n const running = affected.map(row => row.name);\n for (const name of [...START_ORDER].reverse().filter(name => names.includes(name))) await services[name].stop(false, false);\n const after = await queryServicesRuntimeLocal();\n if (after.some(row => names.includes(row.name) && row.running)) throw new Error(\"\u670D\u52A1\u672A\u5B8C\u5168\u9000\u51FA\uFF0C\u5DF2\u4E2D\u6B62\u6587\u4EF6\u64CD\u4F5C\");\n return running;\n}\nexport async function restoreRunning(names: ServiceName[], phase: TaskContext[\"phase\"]) {\n phase(\"restore\", \"\u6062\u590D\u7EF4\u62A4\u524D\u8FD0\u884C\u7684\u670D\u52A1\");\n for (const name of START_ORDER.filter(name => names.includes(name))) {\n const result = await services[name].start();\n if (result.status === \"skipped\") throw new Error(`\u6062\u590D ${name} \u5931\u8D25: ${result.reason}`);\n }\n await verifyRunning(names);\n}\nexport async function verifyRunning(names: ServiceName[]) {\n if (!names.length) return;\n await new Promise(resolve => setTimeout(resolve, 2000));\n for (const name of names) {\n if (!services[name].running || !services[name].pid) throw new Error(`${name} \u542F\u52A8\u540E\u5DF2\u9000\u51FA`);\n }\n if (names.includes(\"db\")) {\n const cfg = readJson<{ db_port?: number; http_auth?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\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) throw new Error(`DB \u5065\u5EB7\u68C0\u67E5\u5931\u8D25 (${response.status})`);\n }\n}\nfunction snapshotTargets() {\n const db = readJson<{ dbDir?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\n const bds = resolveBdsContext().bdsRoot;\n return { configs: path.join(ROOT, \"configs\"), modules: path.join(ROOT, \"modules\"), data: path.dirname(path.resolve(ROOT, db.dbDir ?? \"data/sfmc_data.db\")), bds };\n}\nexport async function createSnapshot(id: string, phase: TaskContext[\"phase\"]) {\n phase(\"backup\", \"\u521B\u5EFA\u5DF2\u505C\u670D\u7684\u4E00\u81F4\u5907\u4EFD\");\n const destination = path.join(ROOT, \".sfmc\", \"backups\", id);\n fs.mkdirSync(destination, { recursive: true });\n const targets = snapshotTargets();\n for (const target of Object.values(targets)) {\n const absolute = path.resolve(target);\n if (absolute === path.parse(absolute).root || absolute === path.resolve(ROOT) || destination.startsWith(absolute + path.sep)) throw new Error(\"\u5907\u4EFD\u76EE\u6807\u5305\u542B\u5B9E\u4F8B\u6839\u76EE\u5F55\u6216\u5907\u4EFD\u76EE\u5F55\uFF0C\u5DF2\u4E2D\u6B62\");\n }\n for (const [key, target] of Object.entries(targets)) {\n if (fs.existsSync(target)) await fs.promises.cp(target, path.join(destination, key), { recursive: true, dereference: false });\n }\n atomicJson(path.join(destination, \"manifest.json\"), { createdAt: new Date().toISOString(), targets, complete: true });\n return destination;\n}\nexport async function restoreSnapshot(id: string, phase: TaskContext[\"phase\"]) {\n if (!/^[a-zA-Z0-9-]{1,80}$/.test(id)) throw new Error(\"\u975E\u6CD5\u5907\u4EFD\u7F16\u53F7\");\n const source = path.join(ROOT, \".sfmc\", \"backups\", id);\n const manifest = readJson<{ complete: boolean; targets: Record<string, string> }>(path.join(source, \"manifest.json\"), { complete: false, targets: {} });\n if (!manifest.complete) throw new Error(\"\u5907\u4EFD\u4E0D\u5B8C\u6574\uFF0C\u7981\u6B62\u6062\u590D\");\n const targets = snapshotTargets();\n phase(\"restore-data\", \"\u6309\u7528\u6237\u660E\u786E\u9009\u62E9\u6062\u590D\u914D\u7F6E\u3001\u6A21\u5757\u3001\u6570\u636E\u5E93\u548C\u4E16\u754C\");\n for (const [key, target] of Object.entries(targets)) {\n if (path.resolve(manifest.targets[key] ?? \"\") !== path.resolve(target)) throw new Error(\"\u5907\u4EFD\u76EE\u6807\u4E0E\u5F53\u524D\u90E8\u7F72\u4E0D\u4E00\u81F4\");\n const saved = path.join(source, key);\n if (!fs.existsSync(saved)) continue;\n const absolute = path.resolve(target);\n if (absolute === path.parse(absolute).root || absolute === path.resolve(ROOT) || fs.lstatSync(saved).isSymbolicLink()) throw new Error(\"\u4E0D\u5B89\u5168\u7684\u6062\u590D\u76EE\u6807\");\n await fs.promises.rm(absolute, { recursive: true, force: true });\n await fs.promises.cp(saved, absolute, { recursive: true, dereference: false });\n }\n return { restored: id };\n}\n/** \u53EA\u56DE\u9000\u7A0B\u5E8F\u5185\u5BB9\uFF0C\u4E16\u754C\u3001\u73A9\u5BB6\u6743\u9650\u548C\u6570\u636E\u5E93\u59CB\u7EC8\u4FDD\u7559\u5728\u5F53\u524D\u72B6\u6001\u3002 */\nasync function restoreProgramSnapshot(id: string, kind: \"modules\" | \"bds\") {\n const source = path.join(ROOT, \".sfmc\", \"backups\", id);\n const manifest = readJson<{ complete: boolean; targets: Record<string, string> }>(path.join(source, \"manifest.json\"), { complete: false, targets: {} });\n const targets = snapshotTargets();\n if (!manifest.complete || path.resolve(manifest.targets[kind] ?? \"\") !== path.resolve(targets[kind])) throw new Error(\"\u7A0B\u5E8F\u5907\u4EFD\u4E0D\u5B8C\u6574\u6216\u76EE\u6807\u4E0D\u5339\u914D\");\n const saved = path.join(source, kind);\n if (kind === \"modules\") {\n if (!fs.existsSync(saved)) return;\n await fs.promises.rm(targets.modules, { recursive: true, force: true });\n await fs.promises.cp(saved, targets.modules, { recursive: true, dereference: false });\n return;\n }\n const cfg = readJson<{ preserve?: string[] }>(path.join(ROOT, \"configs\", \"bds_updater.json\"), {});\n const preserved = new Set([\"worlds\", \"config\", \"server.properties\", \"allowlist.json\", \"whitelist.json\", \"permissions.json\", ...(cfg.preserve ?? []).map(name => name.split(/[\\\\/]/)[0]!)]);\n if (!fs.existsSync(saved)) throw new Error(\"\u7F3A\u5C11\u539F BDS \u7A0B\u5E8F\u5907\u4EFD\");\n const target = path.resolve(targets.bds);\n if (target === path.parse(target).root || target === path.resolve(ROOT)) throw new Error(\"\u4E0D\u5B89\u5168\u7684\u7A0B\u5E8F\u56DE\u9000\u76EE\u6807\");\n fs.mkdirSync(target, { recursive: true });\n for (const entry of fs.readdirSync(target)) if (!preserved.has(entry)) await fs.promises.rm(path.join(target, entry), { recursive: true, force: true });\n for (const entry of fs.readdirSync(saved)) if (!preserved.has(entry)) await fs.promises.cp(path.join(saved, entry), path.join(target, entry), { recursive: true, dereference: false });\n}\nexport async function withStoppedServices<T>(context: TaskContext, names: ServiceName[], action: () => Promise<T>, backup = true, rollbackPrograms?: \"modules\" | \"bds\"): Promise<T> {\n const running = await stopForMaintenance(names, context.phase);\n try {\n if (backup) await createSnapshot(context.id, context.phase);\n context.phase(\"execute\");\n const result = await action();\n context.phase(\"verify\");\n await restoreRunning(running, context.phase);\n return result;\n } catch (error) {\n // \u5931\u8D25\u540E\u4FDD\u6301\u505C\u670D\uFF0C\u4E0D\u731C\u6D4B\u672A\u77E5\u6570\u636E\u8FC1\u79FB\u662F\u5426\u53EF\u4EE5\u5B89\u5168\u6062\u590D\u8FD0\u884C\u3002\n for (const name of [...START_ORDER].reverse().filter(name => running.includes(name))) await services[name].stop(false, false).catch(() => {});\n let programRolledBack = false;\n let rollbackError: string | undefined;\n if (rollbackPrograms) {\n context.phase(\"rollback-program\", \"\u56DE\u9000\u7A0B\u5E8F\u7248\u672C\uFF0C\u4FDD\u7559\u5F53\u524D\u73A9\u5BB6\u6570\u636E\");\n try { await restoreProgramSnapshot(context.id, rollbackPrograms); programRolledBack = true; }\n catch (failure) { rollbackError = String(failure); }\n }\n throw Object.assign(new Error(`\u7EF4\u62A4\u5931\u8D25\uFF0C\u670D\u52A1\u4FDD\u6301\u505C\u6B62\uFF1B\u5907\u4EFD\u7F16\u53F7 ${context.id}: ${error instanceof Error ? error.message : String(error)}`), { code: \"io\", details: { backupId: context.id, programRolledBack, dataRestoreRequired: Boolean(rollbackPrograms), ...(rollbackError ? { rollbackError } : {}), ...((error as { details?: object }).details ?? {}) } });\n }\n}\nexport async function launchPlatformUpdate(store: TaskStore, context: TaskContext, target: string) {\n if (isMonorepoLayout(ROOT)) throw new Error(\"\u6E90\u7801\u90E8\u7F72\u4E0D\u8986\u76D6\u5DE5\u4F5C\u533A\uFF1B\u8BF7\u4F7F\u7528\u6B63\u5E38\u5F00\u53D1\u53D1\u5E03\u6D41\u7A0B\");\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(target)) throw new Error(\"\u9700\u8981\u56FA\u5B9A\u7A33\u5B9A\u7248\u672C\");\n const rows = await runtimeRows();\n if (rows.some(row => row.running && row.ownership === \"external\")) throw new Error(\"\u5916\u90E8\u670D\u52A1\u5FC5\u987B\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u4F18\u96C5\u505C\u6B62\");\n const request = path.join(ROOT, \".sfmc\", \"operations\", `${context.id}.request.json`);\n const previous = readJson(path.join(ROOT, \".sfmc\", \"runtime\", \"active.json\"), { entry: fs.existsSync(path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\")) ? path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\") : process.env.SFMC_DAEMON_ENTRY, version: platformVersion() });\n atomicJson(request, { root: ROOT, id: context.id, target, running: rows.filter(row => row.running).map(row => row.name), previous });\n const entry = fileURLToPath(new URL(\"./platform-worker.js\", import.meta.url));\n const log = path.join(ROOT, \".sfmc\", \"logs\", \"maintenance.log\");\n fs.mkdirSync(path.dirname(log), { recursive: true });\n // \u4E0D\u628A\u7236\u8FDB\u7A0B\u7684\u65E5\u5FD7\u53E5\u67C4\u4EA4\u7ED9\u5B50\u8FDB\u7A0B\u3002Windows \u4E0A\u7EE7\u627F\u53E5\u67C4\u65F6\uFF0C\u5B88\u62A4\u8FDB\u7A0B\u9000\u51FA\u4F1A\u7ED3\u675F\u5C1A\u672A\u8131\u79BB\u7684\u7EF4\u62A4\u8FDB\u7A0B\uFF0C\u5907\u4EFD\u4F1A\u505C\u5728\u534A\u622A\u4E14\u9501\u65E0\u4EBA\u91CA\u653E\u3002\n const child = spawn(process.execPath, [entry, request], { cwd: ROOT, env: { ...process.env, SFMC_ROOT: ROOT, SFMC_MAINTENANCE_LOG: log }, detached: true, windowsHide: true, stdio: \"ignore\" });\n await new Promise<void>((resolve, reject) => { child.once(\"spawn\", resolve); child.once(\"error\", reject); });\n child.unref();\n const record = store.get(context.id) as ReturnType<TaskStore[\"get\"]> & { workerPid?: number };\n record.status = \"running\"; if (child.pid) record.workerPid = child.pid;\n store.save(record);\n return { detached: true };\n}\nexport async function runPnpm(args: string[], cwd: string) {\n const script = process.env.SFMC_PNPM_ENTRY;\n if (script) return runProcess(process.execPath, [script, ...args], cwd);\n const command = process.platform === \"win32\" ? \"pnpm.cmd\" : \"pnpm\";\n const crossSpawn = require(\"cross-spawn\") as typeof spawn;\n await new Promise<void>((resolve, reject) => {\n const child = crossSpawn(command, args, { cwd, env: process.env, windowsHide: true, stdio: \"ignore\" });\n child.on(\"error\", reject); child.on(\"close\", code => code === 0 ? resolve() : reject(new Error(`pnpm \u6267\u884C\u5931\u8D25 (${code})`)));\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["require", "name"]
|
|
7
7
|
}
|
|
@@ -11,6 +11,15 @@ import { callDaemon, disconnectDaemonClient } from "../daemon/client.js";
|
|
|
11
11
|
import { ROOT } from "../runtime.js";
|
|
12
12
|
import { START_ORDER } from "../services.js";
|
|
13
13
|
import { readDaemonMeta } from "../daemon/paths.js";
|
|
14
|
+
function maintenanceLog(message) {
|
|
15
|
+
const file = process.env.SFMC_MAINTENANCE_LOG || path.join(ROOT, ".sfmc", "logs", "maintenance.log");
|
|
16
|
+
try {
|
|
17
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
18
|
+
fs.appendFileSync(file, `${(/* @__PURE__ */ new Date()).toISOString()} ${message}
|
|
19
|
+
`);
|
|
20
|
+
} catch {
|
|
21
|
+
}
|
|
22
|
+
}
|
|
14
23
|
async function main() {
|
|
15
24
|
const requestFile = process.argv[2];
|
|
16
25
|
if (!requestFile) throw new Error("\u7F3A\u5C11\u7EF4\u62A4\u4EFB\u52A1\u6587\u4EF6");
|
|
@@ -26,6 +35,7 @@ async function main() {
|
|
|
26
35
|
record.status = "running";
|
|
27
36
|
record.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28
37
|
atomicJson(recordFile, record);
|
|
38
|
+
maintenanceLog(`phase ${name}${message ? ` ${message}` : ""}`);
|
|
29
39
|
};
|
|
30
40
|
const runtime = path.join(ROOT, ".sfmc", "runtime");
|
|
31
41
|
const release = path.join(runtime, "releases", `${request.target}-${request.id}`);
|
|
@@ -46,19 +56,26 @@ async function main() {
|
|
|
46
56
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
47
57
|
}
|
|
48
58
|
};
|
|
49
|
-
const
|
|
59
|
+
const stopServices = async () => {
|
|
50
60
|
const meta = readDaemonMeta();
|
|
51
|
-
if (!meta) return;
|
|
61
|
+
if (!meta) return meta;
|
|
52
62
|
const status = await callDaemon("status");
|
|
53
63
|
if (status.kind !== "status") throw new Error("\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u670D\u52A1\u72B6\u6001");
|
|
54
64
|
if (status.rows.some((row) => row.running)) {
|
|
55
65
|
const stopped = await callDaemon("maintenanceStop");
|
|
56
66
|
if (stopped.kind !== "status" || stopped.rows.some((row) => row.running)) throw new Error("\u670D\u52A1\u6CA1\u6709\u4F18\u96C5\u9000\u51FA");
|
|
57
67
|
}
|
|
68
|
+
return meta;
|
|
69
|
+
};
|
|
70
|
+
const exitDaemon = async (meta) => {
|
|
71
|
+
if (!meta) return;
|
|
58
72
|
await callDaemon("shutdown");
|
|
59
73
|
disconnectDaemonClient();
|
|
60
74
|
await waitExit(meta.pid);
|
|
61
75
|
};
|
|
76
|
+
const shutdown = async () => {
|
|
77
|
+
await exitDaemon(await stopServices());
|
|
78
|
+
};
|
|
62
79
|
try {
|
|
63
80
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
64
81
|
let acquired = false;
|
|
@@ -90,8 +107,9 @@ async function main() {
|
|
|
90
107
|
phase("stop-services");
|
|
91
108
|
const lock = readJson(path.join(ROOT, ".sfmc", "maintenance.lock"), { nonce: "" });
|
|
92
109
|
process.env.SFMC_MAINTENANCE_TOKEN = lock.nonce;
|
|
93
|
-
await
|
|
110
|
+
const daemon = await stopServices();
|
|
94
111
|
await createSnapshot(request.id, phase);
|
|
112
|
+
await exitDaemon(daemon);
|
|
95
113
|
phase("execute");
|
|
96
114
|
atomicJson(activeFile, { entry, version: request.target, pnpm: process.env.SFMC_PNPM_ENTRY });
|
|
97
115
|
switched = true;
|
|
@@ -138,6 +156,7 @@ async function main() {
|
|
|
138
156
|
record.status = "failed";
|
|
139
157
|
record.error = toManagementError(error);
|
|
140
158
|
record.result ??= { programRolledBack: false, backupId: request.id, dataRestoreRequired: switched, preparedEntry };
|
|
159
|
+
maintenanceLog(`failed ${record.error.message}`);
|
|
141
160
|
} finally {
|
|
142
161
|
record.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
143
162
|
const last = record.phases.at(-1);
|
|
@@ -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/** \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 };\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 const shutdown = async () => {\n const meta = readDaemonMeta();\n if (!meta) return;\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 await callDaemon(\"shutdown\"); disconnectDaemonClient(); await waitExit(meta.pid);\n };\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 await shutdown();\n await createSnapshot(request.id, phase);\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 } 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": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,yBAA+C;AACxD,SAAS,kBAAkB;AAC3B,SAAS,UAAU,kBAAkB;AACrC,SAAS,gBAAgB,eAAe;AACxC,SAAS,YAAY,8BAA8B;AACnD,SAAS,YAAY;AACrB,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;
|
|
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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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|