@sfmc-bds/bds-tools 0.2.0-beta.0 → 0.2.0-beta.10
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/LICENSE +663 -0
- package/dist/bds-manager.d.ts +16 -6
- package/dist/bds-manager.d.ts.map +1 -1
- package/dist/bds-manager.js +40 -65
- package/dist/bds-manager.js.map +2 -2
- package/dist/check-update.d.ts.map +1 -1
- package/dist/check-update.js +15 -17
- package/dist/check-update.js.map +2 -2
- package/dist/cli-pack-manager.js +7 -3
- package/dist/cli-pack-manager.js.map +2 -2
- package/dist/fsx.d.ts +6 -1
- package/dist/fsx.d.ts.map +1 -1
- package/dist/fsx.js +9 -1
- package/dist/fsx.js.map +2 -2
- package/dist/host-platform.d.ts +25 -0
- package/dist/host-platform.d.ts.map +1 -0
- package/dist/host-platform.js +50 -0
- package/dist/host-platform.js.map +7 -0
- package/dist/http.d.ts +49 -11
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js.map +2 -2
- package/dist/log.d.ts +2 -3
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +0 -1
- package/dist/log.js.map +2 -2
- package/dist/pack-manager-lifecycle.test.js +252 -0
- package/dist/pack-manager-lifecycle.test.js.map +7 -0
- package/dist/pack-manager.d.ts +24 -29
- package/dist/pack-manager.d.ts.map +1 -1
- package/dist/pack-manager.js +11 -4
- package/dist/pack-manager.js.map +2 -2
- package/dist/pack-update/bindings.d.ts +16 -0
- package/dist/pack-update/bindings.d.ts.map +1 -0
- package/dist/pack-update/bindings.js +69 -0
- package/dist/pack-update/bindings.js.map +7 -0
- package/dist/pack-update/config.d.ts +16 -0
- package/dist/pack-update/config.d.ts.map +1 -0
- package/dist/pack-update/config.js +146 -0
- package/dist/pack-update/config.js.map +7 -0
- package/dist/pack-update/config.test.js +75 -0
- package/dist/pack-update/config.test.js.map +7 -0
- package/dist/pack-update/deps.d.ts +28 -0
- package/dist/pack-update/deps.d.ts.map +1 -0
- package/dist/pack-update/deps.js +20 -0
- package/dist/pack-update/deps.js.map +7 -0
- package/dist/pack-update/index.d.ts +55 -0
- package/dist/pack-update/index.d.ts.map +1 -0
- package/dist/pack-update/index.js +72 -0
- package/dist/pack-update/index.js.map +7 -0
- package/dist/pack-update/providers/curseforge.d.ts +23 -0
- package/dist/pack-update/providers/curseforge.d.ts.map +1 -0
- package/dist/pack-update/providers/curseforge.js +229 -0
- package/dist/pack-update/providers/curseforge.js.map +7 -0
- package/dist/pack-update/providers/index.d.ts +16 -0
- package/dist/pack-update/providers/index.d.ts.map +1 -0
- package/dist/pack-update/providers/index.js +37 -0
- package/dist/pack-update/providers/index.js.map +7 -0
- package/dist/pack-update/service.d.ts +28 -0
- package/dist/pack-update/service.d.ts.map +1 -0
- package/dist/pack-update/service.js +570 -0
- package/dist/pack-update/service.js.map +7 -0
- package/dist/pack-update/types.d.ts +126 -0
- package/dist/pack-update/types.d.ts.map +1 -0
- package/dist/pack-update/types.js +8 -0
- package/dist/pack-update/types.js.map +7 -0
- package/dist/pack-update/version-policy.d.ts +81 -0
- package/dist/pack-update/version-policy.d.ts.map +1 -0
- package/dist/pack-update/version-policy.js +210 -0
- package/dist/pack-update/version-policy.js.map +7 -0
- package/dist/pack-update/version-policy.test.js +137 -0
- package/dist/pack-update/version-policy.test.js.map +7 -0
- package/dist/paths.d.ts +1 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +3 -5
- package/dist/paths.js.map +2 -2
- package/dist/process-probe.d.ts +34 -0
- package/dist/process-probe.d.ts.map +1 -0
- package/dist/process-probe.js +152 -0
- package/dist/process-probe.js.map +7 -0
- package/dist/process-probe.test.js +76 -0
- package/dist/process-probe.test.js.map +7 -0
- package/dist/qq-events-notify.d.ts +16 -0
- package/dist/qq-events-notify.d.ts.map +1 -0
- package/dist/qq-events-notify.js +70 -0
- package/dist/qq-events-notify.js.map +7 -0
- package/dist/qqutil.d.ts +10 -5
- package/dist/qqutil.d.ts.map +1 -1
- package/dist/qqutil.js +49 -8
- package/dist/qqutil.js.map +2 -2
- package/dist/update-result.d.ts +8 -2
- package/dist/update-result.d.ts.map +1 -1
- package/dist/update-result.js +7 -5
- package/dist/update-result.js.map +2 -2
- package/dist/upstream.d.ts +18 -9
- package/dist/upstream.d.ts.map +1 -1
- package/dist/upstream.js +8 -7
- package/dist/upstream.js.map +2 -2
- package/dist/version.js +2 -2
- package/dist/version.js.map +2 -2
- package/dist/world-packs.d.ts +158 -5
- package/dist/world-packs.d.ts.map +1 -1
- package/dist/world-packs.js +294 -48
- package/dist/world-packs.js.map +2 -2
- package/dist/world-packs.test.js +676 -0
- package/dist/world-packs.test.js.map +7 -0
- package/dist/zipx.test.js +36 -0
- package/dist/zipx.test.js.map +7 -0
- package/package.json +43 -39
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/pack-update/version-policy.test.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * version-policy / slug \u5339\u914D\u6D4B\u8BD5\uFF08\u6D4B\u751F\u4EA7\u5951\u7EA6\uFF0C\u7981\u6B62\u5185\u8054\u590D\u5236\uFF09\n */\nimport assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport {\n buildSearchQueries,\n buildSearchQueriesFromSources,\n collectQuerySeeds,\n decideVersionPolicy,\n extractLatinPhrase,\n insertCjkLatinBoundaries,\n nextEnabledVersion,\n normalizePackSearchName,\n packSourceScore,\n toCfSlugCandidate,\n} from \"./index.js\";\n\ndescribe(\"version-policy\", () => {\n it(\"\u540C major \u66F4\u65B0\u5E94 bump RP\", () => {\n const d = decideVersionPolicy([1, 21, 100], [1, 21, 110], {\n authority: \"behavior_pack\",\n onUpdateOverwriteBoth: true,\n rpBumpWhenSameMajor: true,\n rpBumpComponent: \"patch\",\n majorHigherSkipRpBump: true,\n });\n assert.equal(d.remoteNewer, true);\n assert.equal(d.shouldBumpRp, true);\n });\n\n it(\"major \u66F4\u9AD8\u5219\u4E0D\u989D\u5916 bump RP\", () => {\n const d = decideVersionPolicy([1, 21, 100], [2, 0, 0], {\n authority: \"behavior_pack\",\n onUpdateOverwriteBoth: true,\n rpBumpWhenSameMajor: true,\n rpBumpComponent: \"patch\",\n majorHigherSkipRpBump: true,\n });\n assert.equal(d.majorHigher, true);\n assert.equal(d.shouldBumpRp, false);\n });\n\n it(\"\u540C\u7248\u672C\u672A\u66F4\u9AD8\u65F6\u9ED8\u8BA4\u4E0D bump\uFF1BtreatAsUpdate \u5F3A\u5236\u540C\u6B65\u4ECD\u53EF bump RP\", () => {\n const policy = {\n authority: \"behavior_pack\" as const,\n onUpdateOverwriteBoth: true,\n rpBumpWhenSameMajor: true,\n rpBumpComponent: \"patch\" as const,\n majorHigherSkipRpBump: true,\n };\n const plain = decideVersionPolicy([1, 0, 0], [1, 0, 0], policy);\n assert.equal(plain.remoteNewer, false);\n assert.equal(plain.shouldBumpRp, false);\n\n const forced = decideVersionPolicy([1, 0, 0], [1, 0, 0], policy, { treatAsUpdate: true });\n assert.equal(forced.remoteNewer, false);\n assert.equal(forced.shouldBumpRp, true);\n });\n\n it(\"\u8FDC\u7A0B\u66F4\u65E7\u4F46 treatAsUpdate \u65F6\u4ECD\u6309\u540C major \u89C4\u5219 bump RP\", () => {\n const d = decideVersionPolicy(\n [1, 2, 0],\n [1, 1, 0],\n {\n authority: \"behavior_pack\",\n onUpdateOverwriteBoth: true,\n rpBumpWhenSameMajor: true,\n rpBumpComponent: \"patch\",\n majorHigherSkipRpBump: true,\n },\n { treatAsUpdate: true }\n );\n assert.equal(d.remoteNewer, false);\n assert.equal(d.majorHigher, false);\n assert.equal(d.shouldBumpRp, true);\n });\n\n it(\"nextEnabledVersion = bump(max(remote, previous))\", () => {\n assert.deepEqual(nextEnabledVersion([1, 0, 5], [1, 0, 8], \"patch\"), [1, 0, 9]);\n assert.deepEqual(nextEnabledVersion([1, 0, 0], [1, 21, 100], \"patch\"), [1, 21, 101]);\n assert.deepEqual(nextEnabledVersion([2, 0, 0], [1, 99, 99], \"patch\"), [2, 0, 1]);\n assert.deepEqual(nextEnabledVersion([1, 2, 0], [1, 1, 9], \"minor\"), [1, 3, 0]);\n });\n\n it(\"normalize \u53BB\u6389\u65B9\u62EC\u53F7\u3001\u7248\u672C\u4E0E BP\", () => {\n const n = normalizePackSearchName(\"[BA] [\u73A9\u6CD5] Slash Blade v4 BP\");\n assert.equal(n, \"Slash Blade\");\n });\n\n it(\"CJK \u7C98\u8FDE\u5206\u754C\u5E76\u63D0\u53D6\u62C9\u4E01\u6838\u5FC3\", () => {\n const folder = \"[BP] [BA] [\u73A9\u6CD5] \u62D4\u5200\u5251Slash Blade v4 BP\";\n assert.equal(normalizePackSearchName(folder), \"\u62D4\u5200\u5251 Slash Blade\");\n assert.equal(\n extractLatinPhrase(insertCjkLatinBoundaries(folder.replace(/\\[[^\\]]*\\]/g, \" \"))),\n \"Slash Blade v4 BP\"\n );\n const seeds = collectQuerySeeds(folder);\n assert.ok(seeds.includes(\"Slash Blade v4 BP\"));\n assert.ok(seeds.includes(\"Slash Blade v4\"));\n assert.ok(seeds.includes(\"Slash Blade\"));\n assert.ok(seeds.some((s) => s.includes(\"\u62D4\u5200\u5251\")));\n });\n\n it(\"\u810F\u6587\u4EF6\u5939\u540D\u6D3E\u751F\u542B slug / Title-Slug / addon\", () => {\n const qs = buildSearchQueries(\"[BP] [BA] [\u73A9\u6CD5] \u62D4\u5200\u5251Slash Blade v4 BP\");\n assert.ok(qs.includes(\"slash-blade\"), `queries=${JSON.stringify(qs)}`);\n assert.ok(qs.includes(\"slash-blade-addon\"), `queries=${JSON.stringify(qs)}`);\n assert.ok(qs.includes(\"Slash Blade\"), `queries=${JSON.stringify(qs)}`);\n assert.ok(\n qs.some((q) => q.toLowerCase() === \"slash-blade\"),\n `queries=${JSON.stringify(qs)}`\n );\n const iSlug = qs.findIndex((q) => q === \"slash-blade-addon\");\n const iCjk = qs.findIndex((q) => q.includes(\"\u62D4\u5200\u5251\"));\n assert.ok(iSlug >= 0 && (iCjk < 0 || iSlug < iCjk));\n });\n\n it(\"header+\u6587\u4EF6\u5939\u53CC\u6E90\uFF1A\u6709\u62C9\u4E01\u65F6\u4E0D\u641C\u7EAF\u4E2D\u6587\uFF0C\u4E14\u6587\u4EF6\u5939\u8D21\u732E slug\", () => {\n const qs = buildSearchQueries([\"\u62D4\u5200\u5251\", \"[BP] [BA] [\u73A9\u6CD5] \u62D4\u5200\u5251Slash Blade v4 BP\"]);\n assert.ok(qs.includes(\"slash-blade-addon\"));\n assert.ok(qs.includes(\"Slash Blade\"));\n assert.ok(qs.every((q) => /[A-Za-z]/.test(q)), `\u4E0D\u5E94\u518D\u641C\u7EAF\u4E2D\u6587: ${JSON.stringify(qs)}`);\n });\n\n it(\"\u53CC\u6E90\u8F6E\u8BE2\uFF1Aheader \u4E0E folder \u90FD\u4F1A\u8D21\u732E\", () => {\n const plan = buildSearchQueriesFromSources([\n { id: \"header\", raw: \"Cool Swords Pack\" },\n { id: \"folder\", raw: \"[BP] [BA] [\u73A9\u6CD5] \u62D4\u5200\u5251Slash Blade v4 BP\" },\n ]);\n assert.ok(plan.perSource.header?.some((q) => /cool|swords/i.test(q)));\n assert.ok(plan.perSource.folder?.some((q) => /slash-blade/i.test(q)));\n assert.ok(plan.queries.some((q) => /slash-blade/i.test(q)));\n assert.ok(plan.queries.some((q) => /cool|swords/i.test(q)));\n });\n\n it(\"slug \u5019\u9009\u65E0\u7A7A\u683C\", () => {\n assert.equal(toCfSlugCandidate(\"Slash Blade v4\"), \"slash-blade\");\n const qs = buildSearchQueries(\"Slash Blade v4\");\n assert.ok(qs.includes(\"Slash Blade\"));\n assert.ok(qs.includes(\"slash-blade\"));\n assert.ok(qs.includes(\"slash-blade-addon\"));\n });\n\n it(\"slug \u547D\u4E2D slash-blade-addon \u9AD8\u5206\", () => {\n const score = packSourceScore(\"Slash Blade v4\", {\n name: \"Slash Blade Addon\",\n slug: \"slash-blade-addon\",\n });\n assert.ok(score >= 0.95, `score=${score}`);\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/paths.d.ts
CHANGED
|
@@ -28,6 +28,6 @@ export interface BdsPaths {
|
|
|
28
28
|
cfg: BdsUpdaterConfig;
|
|
29
29
|
}
|
|
30
30
|
export declare function resolvePaths(cfg: BdsUpdaterConfig): BdsPaths;
|
|
31
|
-
/** 删除 PID
|
|
31
|
+
/** 删除 PID 文件(委托 process-probe,与 bds-manager / sfmc 共用) */
|
|
32
32
|
export declare function clearPid(): void;
|
|
33
33
|
//# sourceMappingURL=paths.d.ts.map
|
package/dist/paths.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAOL,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAOL,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAQnC,wCAAwC;AACxC,eAAO,MAAM,QAAQ,EAAE,MAAuC,CAAC;AAC/D,eAAO,MAAM,QAAQ,EAAE,MAAiD,CAAC;AAEzE,sCAAsC;AACtC,eAAO,MAAM,SAAS,EAAE,MAA2B,CAAC;AACpD,eAAO,MAAM,QAAQ,EAAE,MAAwC,CAAC;AAChE,eAAO,MAAM,aAAa,EAAE,MAAuD,CAAC;AACpF,eAAO,MAAM,QAAQ,EAAE,MAAwC,CAAC;AAChE,qBAAqB;AACrB,eAAO,MAAM,eAAe,EAAE,MAA0D,CAAC;AAEzF,kDAAkD;AAClD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;yEACyE;AACzE,wBAAgB,UAAU,IAAI,gBAAgB,CAO7C;AAED,yBAAyB;AACzB,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,gBAAgB,CAAC;CACvB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,GAAG,QAAQ,CAS5D;AAED,0DAA0D;AAC1D,wBAAgB,QAAQ,IAAI,IAAI,CAE/B"}
|
package/dist/paths.js
CHANGED
|
@@ -9,9 +9,10 @@ import {
|
|
|
9
9
|
import fs from "node:fs";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { clearBdsPidFile } from "./process-probe.js";
|
|
12
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
14
|
const SCRIPT_DIR = path.dirname(__filename);
|
|
14
|
-
const ROOT_DIR = resolveRuntimeRoot(
|
|
15
|
+
const ROOT_DIR = resolveRuntimeRoot(SCRIPT_DIR);
|
|
15
16
|
const CFG_PATH = configPath(ROOT_DIR, "bds_updater.json");
|
|
16
17
|
const STATE_DIR = stateDir(ROOT_DIR);
|
|
17
18
|
const LOG_PATH = logFile(ROOT_DIR, "bds-update");
|
|
@@ -40,10 +41,7 @@ function resolvePaths(cfg) {
|
|
|
40
41
|
return { bds_path, backup_dir, preserve, cfg };
|
|
41
42
|
}
|
|
42
43
|
function clearPid() {
|
|
43
|
-
|
|
44
|
-
if (fs.existsSync(PID_FILE)) fs.unlinkSync(PID_FILE);
|
|
45
|
-
} catch {
|
|
46
|
-
}
|
|
44
|
+
clearBdsPidFile(ROOT_DIR);
|
|
47
45
|
}
|
|
48
46
|
export {
|
|
49
47
|
CFG_PATH,
|
package/dist/paths.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/paths.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * paths.ts \u2014 \u8DEF\u5F84\u5E38\u91CF & \u52A0\u8F7D bds_updater.json\n *\n * ROOT_DIR = \u9879\u76EE/\u6570\u636E\u6839,\u901A\u8FC7 SDK \u7EDF\u4E00\u89E3\u6790(env SFMC_ROOT > __dirname \u4E0A\u6EAF)\u3002\n * STATE_DIR / LOG_PATH \u7B49\u8FD0\u884C\u6001\u8DEF\u5F84\u4E00\u5F8B\u8D70 SDK stateDir / logFile,\u52FF\u518D\u624B\u5199 \".sfmc\"\u3002\n */\n\nimport {\n configPath,\n DEFAULT_BDS_UPDATER_CONFIG,\n loadEnsuredConfig,\n logFile,\n resolveRuntimeRoot,\n stateDir,\n type BdsUpdaterConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst SCRIPT_DIR: string = path.dirname(__filename);\n/** \u9879\u76EE\u6839\u76EE\u5F55:bds-tools \u7684\u4E0A\u4E00\u7EA7\u3002\u7EDF\u4E00\u901A\u8FC7 SDK \u89E3\u6790\u3002 */\nexport const ROOT_DIR: string = resolveRuntimeRoot(
|
|
5
|
-
"mappings": "AAOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;
|
|
4
|
+
"sourcesContent": ["/**\n * paths.ts \u2014 \u8DEF\u5F84\u5E38\u91CF & \u52A0\u8F7D bds_updater.json\n *\n * ROOT_DIR = \u9879\u76EE/\u6570\u636E\u6839,\u901A\u8FC7 SDK \u7EDF\u4E00\u89E3\u6790(env SFMC_ROOT > __dirname \u4E0A\u6EAF)\u3002\n * STATE_DIR / LOG_PATH \u7B49\u8FD0\u884C\u6001\u8DEF\u5F84\u4E00\u5F8B\u8D70 SDK stateDir / logFile,\u52FF\u518D\u624B\u5199 \".sfmc\"\u3002\n */\n\nimport {\n configPath,\n DEFAULT_BDS_UPDATER_CONFIG,\n loadEnsuredConfig,\n logFile,\n resolveRuntimeRoot,\n stateDir,\n type BdsUpdaterConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { clearBdsPidFile } from \"./process-probe.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst SCRIPT_DIR: string = path.dirname(__filename);\n/** \u9879\u76EE\u6839\u76EE\u5F55:bds-tools \u7684\u4E0A\u4E00\u7EA7\u3002\u7EDF\u4E00\u901A\u8FC7 SDK \u89E3\u6790\u3002 */\nexport const ROOT_DIR: string = resolveRuntimeRoot(SCRIPT_DIR);\nexport const CFG_PATH: string = configPath(ROOT_DIR, \"bds_updater.json\");\n\n/** \u8FD0\u884C\u6001\u76EE\u5F55(\u76F8\u5BF9\u6570\u636E\u6839\uFF0C\u52FF\u843D\u5728 bds-tools/dist) */\nexport const STATE_DIR: string = stateDir(ROOT_DIR);\nexport const LOG_PATH: string = logFile(ROOT_DIR, \"bds-update\");\nexport const VERSION_CACHE: string = path.join(STATE_DIR, \"bds-version-cache.json\");\nexport const PID_FILE: string = path.join(STATE_DIR, \"bds.pid\");\n/** \u66F4\u65B0\u4E2D\u9014\u5931\u8D25\u53EF\u6062\u590D\u7684\u56DE\u6EDA\u6807\u8BB0 */\nexport const ROLLBACK_MARKER: string = path.join(STATE_DIR, \"last_update_rollback.json\");\n\n/** \u786E\u4FDD .sfmc \u8FD0\u884C\u6001\u76EE\u5F55\u5B58\u5728(PID \u5199\u5165\u7B49\u4E0D\u7ECF writeJson \u7684\u8DEF\u5F84\u9700\u8981) */\nexport function ensureStateDir(): void {\n fs.mkdirSync(STATE_DIR, { recursive: true });\n}\n\n/** \u52A0\u8F7D\u5E76\u89E3\u6790 bds_updater.json\u3002\n * \u542F\u52A8\u65F6 ensure \u6587\u4EF6\u5B58\u5728,\u907F\u514D wizard \u6CA1\u8DD1\u65F6 bds_updater.json \u7F3A\u5931\u5BFC\u81F4 loadConfig \u629B\u9519\u3002 */\nexport function loadConfig(): BdsUpdaterConfig {\n return loadEnsuredConfig(\n ROOT_DIR,\n \"bds_updater.json\",\n \"bds_updater\",\n { ...DEFAULT_BDS_UPDATER_CONFIG } as Record<string, unknown>\n ) as BdsUpdaterConfig;\n}\n\n/** \u89E3\u6790\u540E\u7684 BDS \u8DEF\u5F84 / \u5907\u4EFD\u76EE\u5F55 */\nexport interface BdsPaths {\n bds_path: string;\n backup_dir: string;\n preserve: string[];\n cfg: BdsUpdaterConfig;\n}\n\nexport function resolvePaths(cfg: BdsUpdaterConfig): BdsPaths {\n const bds_path = path.resolve(cfg.bds_path || process.cwd());\n const backup_dir = path.resolve(cfg.backup_dir || path.join(bds_path, \"..\", \"backups\"));\n const relativeBackup = path.relative(bds_path, backup_dir);\n if (relativeBackup === \"\" || (!relativeBackup.startsWith(\"..\") && !path.isAbsolute(relativeBackup))) {\n throw new Error(\"backup_dir must be outside bds_path so deployment cannot delete the backup\");\n }\n const preserve = Array.isArray(cfg.preserve) ? cfg.preserve : [];\n return { bds_path, backup_dir, preserve, cfg };\n}\n\n/** \u5220\u9664 PID \u6587\u4EF6\uFF08\u59D4\u6258 process-probe\uFF0C\u4E0E bds-manager / sfmc \u5171\u7528\uFF09 */\nexport function clearPid(): void {\n clearBdsPidFile(ROOT_DIR);\n}\n"],
|
|
5
|
+
"mappings": "AAOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAEhC,MAAM,aAAa,cAAc,YAAY,GAAG;AAChD,MAAM,aAAqB,KAAK,QAAQ,UAAU;AAE3C,MAAM,WAAmB,mBAAmB,UAAU;AACtD,MAAM,WAAmB,WAAW,UAAU,kBAAkB;AAGhE,MAAM,YAAoB,SAAS,QAAQ;AAC3C,MAAM,WAAmB,QAAQ,UAAU,YAAY;AACvD,MAAM,gBAAwB,KAAK,KAAK,WAAW,wBAAwB;AAC3E,MAAM,WAAmB,KAAK,KAAK,WAAW,SAAS;AAEvD,MAAM,kBAA0B,KAAK,KAAK,WAAW,2BAA2B;AAGhF,SAAS,iBAAuB;AACrC,KAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C;AAIO,SAAS,aAA+B;AAC7C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,GAAG,2BAA2B;AAAA,EAClC;AACF;AAUO,SAAS,aAAa,KAAiC;AAC5D,QAAM,WAAW,KAAK,QAAQ,IAAI,YAAY,QAAQ,IAAI,CAAC;AAC3D,QAAM,aAAa,KAAK,QAAQ,IAAI,cAAc,KAAK,KAAK,UAAU,MAAM,SAAS,CAAC;AACtF,QAAM,iBAAiB,KAAK,SAAS,UAAU,UAAU;AACzD,MAAI,mBAAmB,MAAO,CAAC,eAAe,WAAW,IAAI,KAAK,CAAC,KAAK,WAAW,cAAc,GAAI;AACnG,UAAM,IAAI,MAAM,4EAA4E;AAAA,EAC9F;AACA,QAAM,WAAW,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,WAAW,CAAC;AAC/D,SAAO,EAAE,UAAU,YAAY,UAAU,IAAI;AAC/C;AAGO,SAAS,WAAiB;AAC/B,kBAAgB,QAAQ;AAC1B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* process-probe.ts — OS 级 BDS 进程探测与 PID 文件管理
|
|
3
|
+
*
|
|
4
|
+
* 供 bds-manager / sfmc 共用,避免重复 tasklist / taskkill 逻辑。
|
|
5
|
+
*/
|
|
6
|
+
export type ExecFn = (cmd: string, opts?: {
|
|
7
|
+
windowsHide?: boolean;
|
|
8
|
+
}) => Promise<{
|
|
9
|
+
stdout: string;
|
|
10
|
+
stderr: string;
|
|
11
|
+
}>;
|
|
12
|
+
/** 测试注入 exec,传 null 恢复默认 */
|
|
13
|
+
export declare function setExecForTesting(fn: ExecFn | null): void;
|
|
14
|
+
export declare function readBdsPidFile(rootDir?: string): number;
|
|
15
|
+
export declare function writeBdsPidFile(pid: number, rootDir?: string): void;
|
|
16
|
+
export declare function clearBdsPidFile(rootDir?: string): void;
|
|
17
|
+
/** 测试注入探活,传 null 恢复默认(避免 Linux 上 process.kill 碰到真实 PID) */
|
|
18
|
+
export declare function setIsAliveForTesting(fn: ((pid: number) => boolean) | null): void;
|
|
19
|
+
export declare function isProcessAlive(pid: number): Promise<boolean>;
|
|
20
|
+
/** 同步探活(供 sync 的 sendCommand 等路径;避免 Promise 被当 truthy) */
|
|
21
|
+
export declare function isProcessAliveSync(pid: number): boolean;
|
|
22
|
+
export declare function findBedrockServerPids(): Promise<number[]>;
|
|
23
|
+
export declare function killBedrockServerByImage(): Promise<void>;
|
|
24
|
+
export type BdsProbeState = "stopped" | "managed" | "external";
|
|
25
|
+
export interface BdsProbeResult {
|
|
26
|
+
state: BdsProbeState;
|
|
27
|
+
pid: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function probeBdsStatus(opts: {
|
|
30
|
+
managedPid?: number;
|
|
31
|
+
hasStdin?: boolean;
|
|
32
|
+
rootDir?: string;
|
|
33
|
+
}): Promise<BdsProbeResult>;
|
|
34
|
+
//# sourceMappingURL=process-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-probe.d.ts","sourceRoot":"","sources":["../src/process-probe.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH,MAAM,MAAM,MAAM,GAAG,CACnB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,KAC7B,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAOjD,4BAA4B;AAC5B,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAOzD;AAcD,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAOnE;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAOtD;AAID,2DAA2D;AAC3D,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI,CAEhF;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAalE;AAED,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAgBvD;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CA0B/D;AAED,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAU9D;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,cAAc,CAAC,CAuB1B"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { exec, execSync } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { resolveRuntimeRoot, stateDir } from "@sfmc-bds/sdk/node/config";
|
|
7
|
+
import { bdsExeName } from "./host-platform.js";
|
|
8
|
+
const execAsync = promisify(exec);
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
const DEFAULT_ROOT_DIR = resolveRuntimeRoot(__dirname);
|
|
12
|
+
let execImpl = async (cmd, opts) => {
|
|
13
|
+
const result = await execAsync(cmd, opts);
|
|
14
|
+
return { stdout: String(result.stdout), stderr: String(result.stderr) };
|
|
15
|
+
};
|
|
16
|
+
function setExecForTesting(fn) {
|
|
17
|
+
execImpl = fn ?? (async (cmd, opts) => {
|
|
18
|
+
const result = await execAsync(cmd, opts);
|
|
19
|
+
return { stdout: String(result.stdout), stderr: String(result.stderr) };
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function resolveRoot(rootDir) {
|
|
23
|
+
return rootDir ?? DEFAULT_ROOT_DIR;
|
|
24
|
+
}
|
|
25
|
+
function pidFilePath(rootDir) {
|
|
26
|
+
return path.join(stateDir(resolveRoot(rootDir)), "bds.pid");
|
|
27
|
+
}
|
|
28
|
+
function ensureStateDirForRoot(rootDir) {
|
|
29
|
+
fs.mkdirSync(stateDir(resolveRoot(rootDir)), { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
function readBdsPidFile(rootDir) {
|
|
32
|
+
try {
|
|
33
|
+
return parseInt(fs.readFileSync(pidFilePath(rootDir), "utf-8").trim(), 10) || 0;
|
|
34
|
+
} catch {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function writeBdsPidFile(pid, rootDir) {
|
|
39
|
+
try {
|
|
40
|
+
ensureStateDirForRoot(rootDir);
|
|
41
|
+
fs.writeFileSync(pidFilePath(rootDir), String(pid));
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function clearBdsPidFile(rootDir) {
|
|
46
|
+
try {
|
|
47
|
+
const file = pidFilePath(rootDir);
|
|
48
|
+
if (fs.existsSync(file)) fs.unlinkSync(file);
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let aliveOverride = null;
|
|
53
|
+
function setIsAliveForTesting(fn) {
|
|
54
|
+
aliveOverride = fn;
|
|
55
|
+
}
|
|
56
|
+
async function isProcessAlive(pid) {
|
|
57
|
+
if (!pid) return false;
|
|
58
|
+
if (aliveOverride) return aliveOverride(pid);
|
|
59
|
+
try {
|
|
60
|
+
if (process.platform === "win32") {
|
|
61
|
+
const { stdout } = await execImpl(`tasklist /fi "PID eq ${pid}" /nh`, { windowsHide: true });
|
|
62
|
+
return stdout.includes(String(pid));
|
|
63
|
+
}
|
|
64
|
+
process.kill(pid, 0);
|
|
65
|
+
return true;
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function isProcessAliveSync(pid) {
|
|
71
|
+
if (!pid) return false;
|
|
72
|
+
if (aliveOverride) return aliveOverride(pid);
|
|
73
|
+
try {
|
|
74
|
+
if (process.platform === "win32") {
|
|
75
|
+
const stdout = execSync(`tasklist /fi "PID eq ${pid}" /nh`, {
|
|
76
|
+
windowsHide: true,
|
|
77
|
+
encoding: "utf8"
|
|
78
|
+
});
|
|
79
|
+
return String(stdout).includes(String(pid));
|
|
80
|
+
}
|
|
81
|
+
process.kill(pid, 0);
|
|
82
|
+
return true;
|
|
83
|
+
} catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function findBedrockServerPids() {
|
|
88
|
+
try {
|
|
89
|
+
if (process.platform === "win32") {
|
|
90
|
+
const image = bdsExeName("windows");
|
|
91
|
+
const { stdout: stdout2 } = await execImpl(`tasklist /fi "IMAGENAME eq ${image}" /fo csv /nh`, {
|
|
92
|
+
windowsHide: true
|
|
93
|
+
});
|
|
94
|
+
const pids = [];
|
|
95
|
+
const re = new RegExp(`"${image.replace(".", "\\.")}","(\\d+)"`, "i");
|
|
96
|
+
for (const line of stdout2.split(/\r?\n/)) {
|
|
97
|
+
const m = line.match(re);
|
|
98
|
+
if (m) {
|
|
99
|
+
const pid = parseInt(m[1] ?? "0", 10);
|
|
100
|
+
if (pid > 0) pids.push(pid);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return pids;
|
|
104
|
+
}
|
|
105
|
+
const { stdout } = await execImpl("pgrep -x bedrock_server", { windowsHide: true });
|
|
106
|
+
return stdout.split(/\r?\n/).map((s) => parseInt(s.trim(), 10)).filter((n) => n > 0);
|
|
107
|
+
} catch {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function killBedrockServerByImage() {
|
|
112
|
+
try {
|
|
113
|
+
if (process.platform === "win32") {
|
|
114
|
+
await execImpl(`taskkill /f /im ${bdsExeName("windows")}`, { windowsHide: true });
|
|
115
|
+
} else {
|
|
116
|
+
await execImpl("pkill -x bedrock_server", { windowsHide: true });
|
|
117
|
+
}
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async function probeBdsStatus(opts) {
|
|
122
|
+
const managedPid = opts.managedPid ?? 0;
|
|
123
|
+
const hasStdin = opts.hasStdin ?? false;
|
|
124
|
+
if (managedPid > 0 && hasStdin && await isProcessAlive(managedPid)) {
|
|
125
|
+
return { state: "managed", pid: managedPid };
|
|
126
|
+
}
|
|
127
|
+
const filePid = readBdsPidFile(opts.rootDir);
|
|
128
|
+
if (filePid > 0 && await isProcessAlive(filePid)) {
|
|
129
|
+
return { state: "external", pid: filePid };
|
|
130
|
+
}
|
|
131
|
+
const imagePids = await findBedrockServerPids();
|
|
132
|
+
if (imagePids.length > 0) {
|
|
133
|
+
return { state: "external", pid: imagePids[0] ?? 0 };
|
|
134
|
+
}
|
|
135
|
+
if (filePid > 0) {
|
|
136
|
+
clearBdsPidFile(opts.rootDir);
|
|
137
|
+
}
|
|
138
|
+
return { state: "stopped", pid: 0 };
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
clearBdsPidFile,
|
|
142
|
+
findBedrockServerPids,
|
|
143
|
+
isProcessAlive,
|
|
144
|
+
isProcessAliveSync,
|
|
145
|
+
killBedrockServerByImage,
|
|
146
|
+
probeBdsStatus,
|
|
147
|
+
readBdsPidFile,
|
|
148
|
+
setExecForTesting,
|
|
149
|
+
setIsAliveForTesting,
|
|
150
|
+
writeBdsPidFile
|
|
151
|
+
};
|
|
152
|
+
//# sourceMappingURL=process-probe.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/process-probe.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * process-probe.ts \u2014 OS \u7EA7 BDS \u8FDB\u7A0B\u63A2\u6D4B\u4E0E PID \u6587\u4EF6\u7BA1\u7406\n *\n * \u4F9B bds-manager / sfmc \u5171\u7528\uFF0C\u907F\u514D\u91CD\u590D tasklist / taskkill \u903B\u8F91\u3002\n */\n\nimport { exec, execSync } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { resolveRuntimeRoot, stateDir } from \"@sfmc-bds/sdk/node/config\";\nimport { bdsExeName } from \"./host-platform.js\";\n\nconst execAsync = promisify(exec);\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/** \u4E0E paths.ROOT_DIR \u4E00\u81F4\uFF1ASFMC_ROOT > walk-up monorepo */\nconst DEFAULT_ROOT_DIR = resolveRuntimeRoot(__dirname);\n\nexport type ExecFn = (\n cmd: string,\n opts?: { windowsHide?: boolean }\n) => Promise<{ stdout: string; stderr: string }>;\n\nlet execImpl: ExecFn = async (cmd, opts) => {\n const result = await execAsync(cmd, opts);\n return { stdout: String(result.stdout), stderr: String(result.stderr) };\n};\n\n/** \u6D4B\u8BD5\u6CE8\u5165 exec\uFF0C\u4F20 null \u6062\u590D\u9ED8\u8BA4 */\nexport function setExecForTesting(fn: ExecFn | null): void {\n execImpl =\n fn ??\n (async (cmd, opts) => {\n const result = await execAsync(cmd, opts);\n return { stdout: String(result.stdout), stderr: String(result.stderr) };\n });\n}\n\nfunction resolveRoot(rootDir?: string): string {\n return rootDir ?? DEFAULT_ROOT_DIR;\n}\n\nfunction pidFilePath(rootDir?: string): string {\n return path.join(stateDir(resolveRoot(rootDir)), \"bds.pid\");\n}\n\nfunction ensureStateDirForRoot(rootDir?: string): void {\n fs.mkdirSync(stateDir(resolveRoot(rootDir)), { recursive: true });\n}\n\nexport function readBdsPidFile(rootDir?: string): number {\n try {\n return parseInt(fs.readFileSync(pidFilePath(rootDir), \"utf-8\").trim(), 10) || 0;\n } catch {\n return 0;\n }\n}\n\nexport function writeBdsPidFile(pid: number, rootDir?: string): void {\n try {\n ensureStateDirForRoot(rootDir);\n fs.writeFileSync(pidFilePath(rootDir), String(pid));\n } catch {\n /* ignore */\n }\n}\n\nexport function clearBdsPidFile(rootDir?: string): void {\n try {\n const file = pidFilePath(rootDir);\n if (fs.existsSync(file)) fs.unlinkSync(file);\n } catch {\n /* ignore */\n }\n}\n\nlet aliveOverride: ((pid: number) => boolean) | null = null;\n\n/** \u6D4B\u8BD5\u6CE8\u5165\u63A2\u6D3B\uFF0C\u4F20 null \u6062\u590D\u9ED8\u8BA4\uFF08\u907F\u514D Linux \u4E0A process.kill \u78B0\u5230\u771F\u5B9E PID\uFF09 */\nexport function setIsAliveForTesting(fn: ((pid: number) => boolean) | null): void {\n aliveOverride = fn;\n}\n\nexport async function isProcessAlive(pid: number): Promise<boolean> {\n if (!pid) return false;\n if (aliveOverride) return aliveOverride(pid);\n try {\n if (process.platform === \"win32\") {\n const { stdout } = await execImpl(`tasklist /fi \"PID eq ${pid}\" /nh`, { windowsHide: true });\n return stdout.includes(String(pid));\n }\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/** \u540C\u6B65\u63A2\u6D3B\uFF08\u4F9B sync \u7684 sendCommand \u7B49\u8DEF\u5F84\uFF1B\u907F\u514D Promise \u88AB\u5F53 truthy\uFF09 */\nexport function isProcessAliveSync(pid: number): boolean {\n if (!pid) return false;\n if (aliveOverride) return aliveOverride(pid);\n try {\n if (process.platform === \"win32\") {\n const stdout = execSync(`tasklist /fi \"PID eq ${pid}\" /nh`, {\n windowsHide: true,\n encoding: \"utf8\",\n });\n return String(stdout).includes(String(pid));\n }\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function findBedrockServerPids(): Promise<number[]> {\n try {\n if (process.platform === \"win32\") {\n const image = bdsExeName(\"windows\");\n const { stdout } = await execImpl(`tasklist /fi \"IMAGENAME eq ${image}\" /fo csv /nh`, {\n windowsHide: true,\n });\n const pids: number[] = [];\n const re = new RegExp(`\"${image.replace(\".\", \"\\\\.\")}\",\"(\\\\d+)\"`, \"i\");\n for (const line of stdout.split(/\\r?\\n/)) {\n const m = line.match(re);\n if (m) {\n const pid = parseInt(m[1] ?? \"0\", 10);\n if (pid > 0) pids.push(pid);\n }\n }\n return pids;\n }\n const { stdout } = await execImpl(\"pgrep -x bedrock_server\", { windowsHide: true });\n return stdout\n .split(/\\r?\\n/)\n .map((s) => parseInt(s.trim(), 10))\n .filter((n) => n > 0);\n } catch {\n return [];\n }\n}\n\nexport async function killBedrockServerByImage(): Promise<void> {\n try {\n if (process.platform === \"win32\") {\n await execImpl(`taskkill /f /im ${bdsExeName(\"windows\")}`, { windowsHide: true });\n } else {\n await execImpl(\"pkill -x bedrock_server\", { windowsHide: true });\n }\n } catch {\n /* ignore \u2014 \u65E0\u8FDB\u7A0B\u65F6 taskkill/pkill \u4F1A\u975E\u96F6\u9000\u51FA */\n }\n}\n\nexport type BdsProbeState = \"stopped\" | \"managed\" | \"external\";\n\nexport interface BdsProbeResult {\n state: BdsProbeState;\n pid: number;\n}\n\nexport async function probeBdsStatus(opts: {\n managedPid?: number;\n hasStdin?: boolean;\n rootDir?: string;\n}): Promise<BdsProbeResult> {\n const managedPid = opts.managedPid ?? 0;\n const hasStdin = opts.hasStdin ?? false;\n\n if (managedPid > 0 && hasStdin && (await isProcessAlive(managedPid))) {\n return { state: \"managed\", pid: managedPid };\n }\n\n const filePid = readBdsPidFile(opts.rootDir);\n if (filePid > 0 && (await isProcessAlive(filePid))) {\n return { state: \"external\", pid: filePid };\n }\n\n const imagePids = await findBedrockServerPids();\n if (imagePids.length > 0) {\n return { state: \"external\", pid: imagePids[0] ?? 0 };\n }\n\n if (filePid > 0) {\n clearBdsPidFile(opts.rootDir);\n }\n\n return { state: \"stopped\", pid: 0 };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["stdout"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { after, describe, it } from "node:test";
|
|
6
|
+
import * as probe from "./process-probe.js";
|
|
7
|
+
describe("process-probe pid file", () => {
|
|
8
|
+
let tempRoot = "";
|
|
9
|
+
after(() => {
|
|
10
|
+
if (tempRoot) {
|
|
11
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
it("read/write/clear bds.pid \u5728\u72EC\u7ACB temp \u6839\u76EE\u5F55", () => {
|
|
15
|
+
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "sfmc-probe-"));
|
|
16
|
+
assert.equal(probe.readBdsPidFile(tempRoot), 0);
|
|
17
|
+
probe.writeBdsPidFile(4242, tempRoot);
|
|
18
|
+
assert.equal(probe.readBdsPidFile(tempRoot), 4242);
|
|
19
|
+
probe.clearBdsPidFile(tempRoot);
|
|
20
|
+
assert.equal(probe.readBdsPidFile(tempRoot), 0);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe("process-probe probeBdsStatus", () => {
|
|
24
|
+
let tempRoot = "";
|
|
25
|
+
const calls = [];
|
|
26
|
+
after(() => {
|
|
27
|
+
probe.setExecForTesting(null);
|
|
28
|
+
probe.setIsAliveForTesting(null);
|
|
29
|
+
if (tempRoot) {
|
|
30
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
it("managedPid + hasStdin \u4E14\u8FDB\u7A0B\u5B58\u6D3B \u2192 managed", async () => {
|
|
34
|
+
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "sfmc-probe-"));
|
|
35
|
+
calls.length = 0;
|
|
36
|
+
probe.setIsAliveForTesting((pid) => pid === 100);
|
|
37
|
+
probe.setExecForTesting(async (cmd) => {
|
|
38
|
+
calls.push(cmd);
|
|
39
|
+
if (cmd.includes("PID eq 100")) {
|
|
40
|
+
return { stdout: "bedrock_server.exe 100 Console", stderr: "" };
|
|
41
|
+
}
|
|
42
|
+
return { stdout: "", stderr: "" };
|
|
43
|
+
});
|
|
44
|
+
const result = await probe.probeBdsStatus({ managedPid: 100, hasStdin: true, rootDir: tempRoot });
|
|
45
|
+
assert.deepEqual(result, { state: "managed", pid: 100 });
|
|
46
|
+
});
|
|
47
|
+
it("PID \u6587\u4EF6\u5B58\u6D3B\u4F46\u65E0 stdin \u2192 external", async () => {
|
|
48
|
+
probe.writeBdsPidFile(200, tempRoot);
|
|
49
|
+
probe.setIsAliveForTesting((pid) => pid === 200);
|
|
50
|
+
probe.setExecForTesting(async (cmd) => {
|
|
51
|
+
if (cmd.includes("PID eq 200")) {
|
|
52
|
+
return { stdout: "bedrock_server.exe 200 Console", stderr: "" };
|
|
53
|
+
}
|
|
54
|
+
return { stdout: "", stderr: "" };
|
|
55
|
+
});
|
|
56
|
+
const result = await probe.probeBdsStatus({ managedPid: 200, hasStdin: false, rootDir: tempRoot });
|
|
57
|
+
assert.equal(result.state, "external");
|
|
58
|
+
assert.equal(result.pid, 200);
|
|
59
|
+
});
|
|
60
|
+
it("\u65E0 PID \u6587\u4EF6\u4F46\u6709 bedrock_server \u955C\u50CF \u2192 external", async () => {
|
|
61
|
+
probe.clearBdsPidFile(tempRoot);
|
|
62
|
+
probe.setIsAliveForTesting(() => false);
|
|
63
|
+
probe.setExecForTesting(async (cmd) => {
|
|
64
|
+
if (cmd.includes("IMAGENAME eq bedrock_server.exe")) {
|
|
65
|
+
return { stdout: '"bedrock_server.exe","555","Console","1","999 K"\n', stderr: "" };
|
|
66
|
+
}
|
|
67
|
+
if (cmd.includes("pgrep")) {
|
|
68
|
+
return { stdout: "555\n", stderr: "" };
|
|
69
|
+
}
|
|
70
|
+
return { stdout: "", stderr: "" };
|
|
71
|
+
});
|
|
72
|
+
const result = await probe.probeBdsStatus({ rootDir: tempRoot });
|
|
73
|
+
assert.deepEqual(result, { state: "external", pid: 555 });
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=process-probe.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/process-probe.test.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * process-probe \u5355\u5143\u6D4B\u8BD5\uFF1APID \u6587\u4EF6\u7EAF\u51FD\u6570 + \u53EF\u6CE8\u5165 exec \u7684\u63A2\u6D4B\u903B\u8F91\n */\nimport assert from \"node:assert/strict\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { after, describe, it } from \"node:test\";\nimport * as probe from \"./process-probe.js\";\n\ndescribe(\"process-probe pid file\", () => {\n let tempRoot = \"\";\n\n after(() => {\n if (tempRoot) {\n fs.rmSync(tempRoot, { recursive: true, force: true });\n }\n });\n\n it(\"read/write/clear bds.pid \u5728\u72EC\u7ACB temp \u6839\u76EE\u5F55\", () => {\n tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), \"sfmc-probe-\"));\n\n assert.equal(probe.readBdsPidFile(tempRoot), 0);\n\n probe.writeBdsPidFile(4242, tempRoot);\n assert.equal(probe.readBdsPidFile(tempRoot), 4242);\n\n probe.clearBdsPidFile(tempRoot);\n assert.equal(probe.readBdsPidFile(tempRoot), 0);\n });\n});\n\ndescribe(\"process-probe probeBdsStatus\", () => {\n let tempRoot = \"\";\n const calls: string[] = [];\n\n after(() => {\n probe.setExecForTesting(null);\n probe.setIsAliveForTesting(null);\n if (tempRoot) {\n fs.rmSync(tempRoot, { recursive: true, force: true });\n }\n });\n\n it(\"managedPid + hasStdin \u4E14\u8FDB\u7A0B\u5B58\u6D3B \u2192 managed\", async () => {\n tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), \"sfmc-probe-\"));\n calls.length = 0;\n probe.setIsAliveForTesting((pid) => pid === 100);\n\n probe.setExecForTesting(async (cmd) => {\n calls.push(cmd);\n if (cmd.includes(\"PID eq 100\")) {\n return { stdout: \"bedrock_server.exe 100 Console\", stderr: \"\" };\n }\n return { stdout: \"\", stderr: \"\" };\n });\n\n const result = await probe.probeBdsStatus({ managedPid: 100, hasStdin: true, rootDir: tempRoot });\n assert.deepEqual(result, { state: \"managed\", pid: 100 });\n });\n\n it(\"PID \u6587\u4EF6\u5B58\u6D3B\u4F46\u65E0 stdin \u2192 external\", async () => {\n probe.writeBdsPidFile(200, tempRoot);\n probe.setIsAliveForTesting((pid) => pid === 200);\n\n probe.setExecForTesting(async (cmd) => {\n if (cmd.includes(\"PID eq 200\")) {\n return { stdout: \"bedrock_server.exe 200 Console\", stderr: \"\" };\n }\n return { stdout: \"\", stderr: \"\" };\n });\n\n const result = await probe.probeBdsStatus({ managedPid: 200, hasStdin: false, rootDir: tempRoot });\n assert.equal(result.state, \"external\");\n assert.equal(result.pid, 200);\n });\n\n it(\"\u65E0 PID \u6587\u4EF6\u4F46\u6709 bedrock_server \u955C\u50CF \u2192 external\", async () => {\n probe.clearBdsPidFile(tempRoot);\n probe.setIsAliveForTesting(() => false);\n\n probe.setExecForTesting(async (cmd) => {\n if (cmd.includes(\"IMAGENAME eq bedrock_server.exe\")) {\n return { stdout: '\"bedrock_server.exe\",\"555\",\"Console\",\"1\",\"999 K\"\\n', stderr: \"\" };\n }\n if (cmd.includes(\"pgrep\")) {\n return { stdout: \"555\\n\", stderr: \"\" };\n }\n return { stdout: \"\", stderr: \"\" };\n });\n\n const result = await probe.probeBdsStatus({ rootDir: tempRoot });\n assert.deepEqual(result, { state: \"external\", pid: 555 });\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* qq-events-notify.ts — 向 db-server 上报 BDS 启停事件
|
|
3
|
+
*
|
|
4
|
+
* 只 POST 结构化事件;群 openid / 频控由 db-server 处理(DIP)。
|
|
5
|
+
* 失败仅 warn,不抛错。
|
|
6
|
+
*/
|
|
7
|
+
export type BdsLifecycleEventType = "crash" | "start";
|
|
8
|
+
/**
|
|
9
|
+
* POST /api/sfmc/qq/events;超时/非 2xx 不抛。
|
|
10
|
+
*/
|
|
11
|
+
export declare function postBdsLifecycleEvent(type: BdsLifecycleEventType, detail?: string, opts?: {
|
|
12
|
+
host?: string;
|
|
13
|
+
port?: number;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=qq-events-notify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qq-events-notify.d.ts","sourceRoot":"","sources":["../src/qq-events-notify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,OAAO,CAAC;AAiBtD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,qBAAqB,EAC3B,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAAC,IAAI,CAAC,CA6Cf"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_DB_CONFIG,
|
|
3
|
+
loadEnsuredConfig
|
|
4
|
+
} from "@sfmc-bds/sdk/node/config";
|
|
5
|
+
import http from "node:http";
|
|
6
|
+
import { log } from "./log.js";
|
|
7
|
+
import { ROOT_DIR } from "./paths.js";
|
|
8
|
+
function resolveDbPort() {
|
|
9
|
+
try {
|
|
10
|
+
const cfg = loadEnsuredConfig(
|
|
11
|
+
ROOT_DIR,
|
|
12
|
+
"db_config.json",
|
|
13
|
+
"db_config",
|
|
14
|
+
{ ...DEFAULT_DB_CONFIG }
|
|
15
|
+
);
|
|
16
|
+
const n = Number(cfg.db_port ?? 3001);
|
|
17
|
+
return Number.isFinite(n) && n > 0 ? n : 3001;
|
|
18
|
+
} catch {
|
|
19
|
+
return 3001;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function postBdsLifecycleEvent(type, detail, opts) {
|
|
23
|
+
const host = opts?.host ?? "127.0.0.1";
|
|
24
|
+
const port = opts?.port ?? resolveDbPort();
|
|
25
|
+
const timeoutMs = opts?.timeoutMs ?? 3e3;
|
|
26
|
+
const payload = JSON.stringify({
|
|
27
|
+
type,
|
|
28
|
+
detail: detail ?? void 0
|
|
29
|
+
});
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
const req = http.request(
|
|
32
|
+
{
|
|
33
|
+
hostname: host,
|
|
34
|
+
port,
|
|
35
|
+
path: "/api/sfmc/qq/events",
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: {
|
|
38
|
+
"Content-Type": "application/json",
|
|
39
|
+
"Content-Length": Buffer.byteLength(payload)
|
|
40
|
+
},
|
|
41
|
+
timeout: timeoutMs
|
|
42
|
+
},
|
|
43
|
+
(res) => {
|
|
44
|
+
res.resume();
|
|
45
|
+
res.on("end", () => {
|
|
46
|
+
const code = res.statusCode ?? 0;
|
|
47
|
+
if (code < 200 || code >= 300) {
|
|
48
|
+
log.warn(`[QQ\u4E8B\u4EF6] db-server \u8FD4\u56DE HTTP ${code} (type=${type})`);
|
|
49
|
+
}
|
|
50
|
+
resolve();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
req.on("timeout", () => {
|
|
55
|
+
req.destroy();
|
|
56
|
+
log.warn(`[QQ\u4E8B\u4EF6] \u4E0A\u62A5\u8D85\u65F6 ${timeoutMs}ms (type=${type})`);
|
|
57
|
+
resolve();
|
|
58
|
+
});
|
|
59
|
+
req.on("error", (err) => {
|
|
60
|
+
log.warn(`[QQ\u4E8B\u4EF6] \u4E0A\u62A5\u5931\u8D25: ${err.message} (type=${type})`);
|
|
61
|
+
resolve();
|
|
62
|
+
});
|
|
63
|
+
req.write(payload);
|
|
64
|
+
req.end();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
postBdsLifecycleEvent
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=qq-events-notify.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/qq-events-notify.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * qq-events-notify.ts \u2014 \u5411 db-server \u4E0A\u62A5 BDS \u542F\u505C\u4E8B\u4EF6\n *\n * \u53EA POST \u7ED3\u6784\u5316\u4E8B\u4EF6\uFF1B\u7FA4 openid / \u9891\u63A7\u7531 db-server \u5904\u7406\uFF08DIP\uFF09\u3002\n * \u5931\u8D25\u4EC5 warn\uFF0C\u4E0D\u629B\u9519\u3002\n */\n\nimport {\n DEFAULT_DB_CONFIG,\n loadEnsuredConfig,\n type DBConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport http from \"node:http\";\nimport { log } from \"./log.js\";\nimport { ROOT_DIR } from \"./paths.js\";\n\nexport type BdsLifecycleEventType = \"crash\" | \"start\";\n\nfunction resolveDbPort(): number {\n try {\n const cfg = loadEnsuredConfig(\n ROOT_DIR,\n \"db_config.json\",\n \"db_config\",\n { ...DEFAULT_DB_CONFIG } as Record<string, unknown>\n ) as DBConfig;\n const n = Number(cfg.db_port ?? 3001);\n return Number.isFinite(n) && n > 0 ? n : 3001;\n } catch {\n return 3001;\n }\n}\n\n/**\n * POST /api/sfmc/qq/events\uFF1B\u8D85\u65F6/\u975E 2xx \u4E0D\u629B\u3002\n */\nexport function postBdsLifecycleEvent(\n type: BdsLifecycleEventType,\n detail?: string,\n opts?: { host?: string; port?: number; timeoutMs?: number }\n): Promise<void> {\n const host = opts?.host ?? \"127.0.0.1\";\n const port = opts?.port ?? resolveDbPort();\n const timeoutMs = opts?.timeoutMs ?? 3_000;\n const payload = JSON.stringify({\n type,\n detail: detail ?? undefined,\n });\n\n return new Promise((resolve) => {\n const req = http.request(\n {\n hostname: host,\n port,\n path: \"/api/sfmc/qq/events\",\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(payload),\n },\n timeout: timeoutMs,\n },\n (res) => {\n res.resume();\n res.on(\"end\", () => {\n const code = res.statusCode ?? 0;\n if (code < 200 || code >= 300) {\n log.warn(`[QQ\u4E8B\u4EF6] db-server \u8FD4\u56DE HTTP ${code} (type=${type})`);\n }\n resolve();\n });\n }\n );\n req.on(\"timeout\", () => {\n req.destroy();\n log.warn(`[QQ\u4E8B\u4EF6] \u4E0A\u62A5\u8D85\u65F6 ${timeoutMs}ms (type=${type})`);\n resolve();\n });\n req.on(\"error\", (err) => {\n log.warn(`[QQ\u4E8B\u4EF6] \u4E0A\u62A5\u5931\u8D25: ${err.message} (type=${type})`);\n resolve();\n });\n req.write(payload);\n req.end();\n });\n}\n"],
|
|
5
|
+
"mappings": "AAOA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,OAAO,UAAU;AACjB,SAAS,WAAW;AACpB,SAAS,gBAAgB;AAIzB,SAAS,gBAAwB;AAC/B,MAAI;AACF,UAAM,MAAM;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,GAAG,kBAAkB;AAAA,IACzB;AACA,UAAM,IAAI,OAAO,IAAI,WAAW,IAAI;AACpC,WAAO,OAAO,SAAS,CAAC,KAAK,IAAI,IAAI,IAAI;AAAA,EAC3C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,sBACd,MACA,QACA,MACe;AACf,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,OAAO,MAAM,QAAQ,cAAc;AACzC,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,UAAU,KAAK,UAAU;AAAA,IAC7B;AAAA,IACA,QAAQ,UAAU;AAAA,EACpB,CAAC;AAED,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,MAAM,KAAK;AAAA,MACf;AAAA,QACE,UAAU;AAAA,QACV;AAAA,QACA,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,kBAAkB,OAAO,WAAW,OAAO;AAAA,QAC7C;AAAA,QACA,SAAS;AAAA,MACX;AAAA,MACA,CAAC,QAAQ;AACP,YAAI,OAAO;AACX,YAAI,GAAG,OAAO,MAAM;AAClB,gBAAM,OAAO,IAAI,cAAc;AAC/B,cAAI,OAAO,OAAO,QAAQ,KAAK;AAC7B,gBAAI,KAAK,gDAA4B,IAAI,UAAU,IAAI,GAAG;AAAA,UAC5D;AACA,kBAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF;AACA,QAAI,GAAG,WAAW,MAAM;AACtB,UAAI,QAAQ;AACZ,UAAI,KAAK,6CAAe,SAAS,YAAY,IAAI,GAAG;AACpD,cAAQ;AAAA,IACV,CAAC;AACD,QAAI,GAAG,SAAS,CAAC,QAAQ;AACvB,UAAI,KAAK,8CAAgB,IAAI,OAAO,UAAU,IAAI,GAAG;AACrD,cAAQ;AAAA,IACV,CAAC;AACD,QAAI,MAAM,OAAO;AACjB,QAAI,IAAI;AAAA,EACV,CAAC;AACH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/qqutil.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* qqutil.ts —
|
|
2
|
+
* qqutil.ts — BDS 运维与更新通知推送工具(支持官方 Bot 与 LLBot 双后端)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* 核心机制:
|
|
5
|
+
* - 双后端适配:根据 `qq_backend` 配置自动分发至官方开放平台发群接口或 LLBot OneBot HTTP 接口
|
|
6
|
+
* - 故障隔离:通知发送失败仅记录告警日志并不中断主流程,确保主服务运维正常执行
|
|
7
|
+
* - 发送超时熔断:设置请求超时时间,防止外部网络响应延迟堵塞 BDS 启动与更新
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* 检查平台中 `qq-bridge` 模块是否处于启用状态。
|
|
11
|
+
*
|
|
12
|
+
* @returns 若启用返回 `true`,否则返回 `false`。
|
|
7
13
|
*/
|
|
8
|
-
/** 检查 qq-bridge 模块是否启用 */
|
|
9
14
|
export declare function isQqBridgeEnabled(): boolean;
|
|
10
15
|
export declare function sendText(text: string): Promise<void>;
|
|
11
16
|
export declare function sendMixed(segments: unknown[]): Promise<void>;
|
package/dist/qqutil.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qqutil.d.ts","sourceRoot":"","sources":["../src/qqutil.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"qqutil.d.ts","sourceRoot":"","sources":["../src/qqutil.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiCH;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C;AAgED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB1D;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BlE;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlF"}
|