@sfmc-bds/bds-tools 0.1.0 → 0.2.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bds-manager.d.ts.map +1 -1
- package/dist/bds-manager.js +236 -263
- package/dist/bds-manager.js.map +7 -1
- package/dist/changelog.js +39 -50
- package/dist/changelog.js.map +7 -1
- package/dist/check-update.d.ts +2 -2
- package/dist/check-update.d.ts.map +1 -1
- package/dist/check-update.js +361 -401
- package/dist/check-update.js.map +7 -1
- package/dist/cli-pack-manager.d.ts +10 -6
- package/dist/cli-pack-manager.d.ts.map +1 -1
- package/dist/cli-pack-manager.js +229 -134
- package/dist/cli-pack-manager.js.map +7 -1
- package/dist/fsx.d.ts +9 -0
- package/dist/fsx.d.ts.map +1 -1
- package/dist/fsx.js +105 -100
- package/dist/fsx.js.map +7 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +166 -185
- package/dist/http.js.map +7 -1
- package/dist/is-main.d.ts +17 -0
- package/dist/is-main.d.ts.map +1 -0
- package/dist/is-main.js +32 -0
- package/dist/is-main.js.map +7 -0
- package/dist/log.d.ts +2 -4
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +12 -19
- package/dist/log.js.map +7 -1
- package/dist/logger.js +6 -10
- package/dist/logger.js.map +7 -1
- package/dist/pack-manager.d.ts +88 -24
- package/dist/pack-manager.d.ts.map +1 -1
- package/dist/pack-manager.js +282 -246
- package/dist/pack-manager.js.map +7 -1
- package/dist/paths.d.ts +8 -3
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +53 -39
- package/dist/paths.js.map +7 -1
- package/dist/qqutil.d.ts.map +1 -1
- package/dist/qqutil.js +90 -87
- package/dist/qqutil.js.map +7 -1
- package/dist/recovery.js +26 -37
- package/dist/recovery.js.map +7 -1
- package/dist/rollback.d.ts +1 -1
- package/dist/rollback.js +55 -74
- package/dist/rollback.js.map +7 -1
- package/dist/server-properties.d.ts +12 -0
- package/dist/server-properties.d.ts.map +1 -0
- package/dist/server-properties.js +28 -0
- package/dist/server-properties.js.map +7 -0
- package/dist/taskbar.d.ts +2 -0
- package/dist/taskbar.d.ts.map +1 -1
- package/dist/taskbar.js +51 -82
- package/dist/taskbar.js.map +7 -1
- package/dist/types.js +1 -5
- package/dist/types.js.map +7 -1
- package/dist/update-result.d.ts +18 -0
- package/dist/update-result.d.ts.map +1 -0
- package/dist/update-result.js +17 -0
- package/dist/update-result.js.map +7 -0
- package/dist/upstream.js +94 -108
- package/dist/upstream.js.map +7 -1
- package/dist/version.js +63 -81
- package/dist/version.js.map +7 -1
- package/dist/world-packs.d.ts +174 -0
- package/dist/world-packs.d.ts.map +1 -0
- package/dist/world-packs.js +509 -0
- package/dist/world-packs.js.map +7 -0
- package/dist/zipx.d.ts +10 -0
- package/dist/zipx.d.ts.map +1 -0
- package/dist/zipx.js +48 -0
- package/dist/zipx.js.map +7 -0
- package/package.json +17 -6
package/dist/rollback.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/rollback.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * rollback.ts \u2014 \u56DE\u6EDA\u652F\u6301\n *\n * \u5728\u66F4\u65B0\u5F00\u59CB\u524D\u8BB0\u5F55: \u5F53\u524D BDS \u76EE\u5F55 + \u5907\u4EFD\u76EE\u5F55\u3002\n * \u4E3B\u6D41\u7A0B\u4EFB\u610F\u9636\u6BB5\u5931\u8D25\u65F6\uFF0C\u5C1D\u8BD5\u53CD\u5411\u6062\u590D preserves \u5230 BDS_PATH\uFF0C\n * \u7136\u540E\u4ECE\u5907\u4EFD\u91CD\u65B0\u653E\u56DE preserve \u5185\u5BB9\uFF0C\u6062\u590D\u65E7\u914D\u7F6E\u3002\n *\n * \u6301\u4E45\u5316: <SFMC_ROOT>/.sfmc/last_update_rollback.json \u7528\u4E8E\u8DE8\u8FDB\u7A0B\u8BB0\u5F55\u3002\n */\n\nimport { readJson, writeJson } from \"@sfmc-bds/sdk/node/config\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { ROLLBACK_MARKER } from \"./paths.js\";\nimport { copyDirSync, getDirSize, emptyDirSync } from \"./fsx.js\";\nimport { log } from \"./log.js\";\n\nexport interface RollbackMarker {\n timestamp: number;\n bds_path: string;\n backup_dir: string;\n preserve: string[];\n previous_version: string;\n}\n\n/** \u5728\u5907\u4EFD\u5B8C\u6210\u540E\u8C03\u7528: \u8BB0\u5F55\u5FEB\u7167\u6307\u793A\u7B26\u3002 */\nexport function writeRollbackMarker(marker: RollbackMarker): void {\n try {\n writeJson(ROLLBACK_MARKER, marker);\n log.info(`[\u56DE\u6EDA] \u5DF2\u8BB0\u5F55\u56DE\u6EDA\u6807\u8BB0 -> ${ROLLBACK_MARKER}`);\n } catch (e) {\n log.warn(`[\u56DE\u6EDA] \u65E0\u6CD5\u5199\u5165\u6807\u8BB0: ${(e as Error).message}`);\n }\n}\n\nexport function clearRollbackMarker(): void {\n try {\n if (fs.existsSync(ROLLBACK_MARKER)) fs.unlinkSync(ROLLBACK_MARKER);\n } catch {\n /* ignore */\n }\n}\n\nexport function readRollbackMarker(): RollbackMarker | null {\n return readJson<RollbackMarker>(ROLLBACK_MARKER) ?? null;\n}\n\n/**\n * \u7D27\u6025\u56DE\u6EDA: \u628A preserve \u9879\u4ECE backup_dir \u62F7\u56DE bds_path\u3002\n * \u7528\u6CD5: \u5728 catch \u5206\u652F\u8C03\u7528\uFF0C\u5982\u679C\u4E3B\u6D41\u7A0B\u5931\u8D25\u5BFC\u81F4 BDS \u76EE\u5F55\u7834\u574F\u3002\n */\nexport function rollbackFromBackup(marker: RollbackMarker): { ok: boolean; reason?: string } {\n const { bds_path, backup_dir, preserve } = marker;\n if (!fs.existsSync(backup_dir)) {\n return { ok: false, reason: `\u5907\u4EFD\u76EE\u5F55\u4E0D\u5B58\u5728: ${backup_dir}` };\n }\n log.warn(`[\u56DE\u6EDA] \u5F00\u59CB\u6062\u590D ${preserve.length} \u9879\u5230 ${bds_path}`);\n for (const item of preserve) {\n const src = path.join(backup_dir, item);\n const dest = path.join(bds_path, item);\n if (!fs.existsSync(src)) {\n log.warn(`[\u56DE\u6EDA] \u8DF3\u8FC7 (\u5907\u4EFD\u4E2D\u4E0D\u5B58\u5728): ${item}`);\n continue;\n }\n try {\n // \u5148\u786E\u4FDD\u76EE\u6807\u76EE\u5F55\u5B58\u5728 (BDS \u76EE\u5F55\u53EF\u80FD\u5DF2\u88AB\u89E3\u538B\u8986\u76D6\u4E3A\u7A7A)\n const destDir = path.dirname(dest);\n if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });\n if (fs.statSync(src).isDirectory()) {\n // \u5148\u5220\u9664\u76EE\u6807\uFF0C\u518D\u590D\u5236\u76EE\u5F55\n if (fs.existsSync(dest)) emptyDirSync(dest);\n copyDirSync(src, dest);\n } else {\n fs.copyFileSync(src, dest);\n }\n log.info(`[\u56DE\u6EDA] \u5DF2\u6062\u590D: ${item}`);\n } catch (e) {\n log.warn(`[\u56DE\u6EDA] \u6062\u590D\u5931\u8D25 ${item}: ${(e as Error).message}`);\n }\n }\n return { ok: true };\n}\n\n/** \u68C0\u67E5 BDS_PATH \u4E2D\u5173\u952E\u6587\u4EF6\u662F\u5426\u90FD\u8FD8\u5728 (\u66F4\u65B0\u540E\u5B8C\u6574\u6027 sanity check) */\nexport function verifyBdsInstall(bds_path: string, expected: string[]): { ok: boolean; missing: string[] } {\n const missing: string[] = [];\n for (const f of expected) {\n if (!fs.existsSync(path.join(bds_path, f))) missing.push(f);\n }\n return { ok: missing.length === 0, missing };\n}\n\nexport { getDirSize };\n"],
|
|
5
|
+
"mappings": "AAUA,SAAS,UAAU,iBAAiB;AACpC,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,uBAAuB;AAChC,SAAS,aAAa,YAAY,oBAAoB;AACtD,SAAS,WAAW;AAWb,SAAS,oBAAoB,QAA8B;AAChE,MAAI;AACF,cAAU,iBAAiB,MAAM;AACjC,QAAI,KAAK,gEAAmB,eAAe,EAAE;AAAA,EAC/C,SAAS,GAAG;AACV,QAAI,KAAK,wDAAiB,EAAY,OAAO,EAAE;AAAA,EACjD;AACF;AAEO,SAAS,sBAA4B;AAC1C,MAAI;AACF,QAAI,GAAG,WAAW,eAAe,EAAG,IAAG,WAAW,eAAe;AAAA,EACnE,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,qBAA4C;AAC1D,SAAO,SAAyB,eAAe,KAAK;AACtD;AAMO,SAAS,mBAAmB,QAA0D;AAC3F,QAAM,EAAE,UAAU,YAAY,SAAS,IAAI;AAC3C,MAAI,CAAC,GAAG,WAAW,UAAU,GAAG;AAC9B,WAAO,EAAE,IAAI,OAAO,QAAQ,+CAAY,UAAU,GAAG;AAAA,EACvD;AACA,MAAI,KAAK,2CAAa,SAAS,MAAM,iBAAO,QAAQ,EAAE;AACtD,aAAW,QAAQ,UAAU;AAC3B,UAAM,MAAM,KAAK,KAAK,YAAY,IAAI;AACtC,UAAM,OAAO,KAAK,KAAK,UAAU,IAAI;AACrC,QAAI,CAAC,GAAG,WAAW,GAAG,GAAG;AACvB,UAAI,KAAK,uEAAqB,IAAI,EAAE;AACpC;AAAA,IACF;AACA,QAAI;AAEF,YAAM,UAAU,KAAK,QAAQ,IAAI;AACjC,UAAI,CAAC,GAAG,WAAW,OAAO,EAAG,IAAG,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACtE,UAAI,GAAG,SAAS,GAAG,EAAE,YAAY,GAAG;AAElC,YAAI,GAAG,WAAW,IAAI,EAAG,cAAa,IAAI;AAC1C,oBAAY,KAAK,IAAI;AAAA,MACvB,OAAO;AACL,WAAG,aAAa,KAAK,IAAI;AAAA,MAC3B;AACA,UAAI,KAAK,sCAAa,IAAI,EAAE;AAAA,IAC9B,SAAS,GAAG;AACV,UAAI,KAAK,2CAAa,IAAI,KAAM,EAAY,OAAO,EAAE;AAAA,IACvD;AAAA,EACF;AACA,SAAO,EAAE,IAAI,KAAK;AACpB;AAGO,SAAS,iBAAiB,UAAkB,UAAwD;AACzG,QAAM,UAAoB,CAAC;AAC3B,aAAW,KAAK,UAAU;AACxB,QAAI,CAAC,GAAG,WAAW,KAAK,KAAK,UAAU,CAAC,CAAC,EAAG,SAAQ,KAAK,CAAC;AAAA,EAC5D;AACA,SAAO,EAAE,IAAI,QAAQ,WAAW,GAAG,QAAQ;AAC7C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const EMIT_SERVER_TELEMETRY_KEY = "emit-server-telemetry";
|
|
2
|
+
export declare const EMIT_SERVER_TELEMETRY_LINE = "emit-server-telemetry=true";
|
|
3
|
+
export type ServerPropertiesLogger = {
|
|
4
|
+
info: (msg: string) => void;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* 若 `<bdsRoot>/server.properties` 中尚无 emit-server-telemetry,则追加 `=true`。
|
|
8
|
+
* 已有该键(任意值)则跳过。文件不存在时跳过(BDS 尚未解压)。
|
|
9
|
+
* @returns true = 本次新追加;false = 跳过
|
|
10
|
+
*/
|
|
11
|
+
export declare function ensureEmitServerTelemetry(bdsRoot: string, logger?: ServerPropertiesLogger): boolean;
|
|
12
|
+
//# sourceMappingURL=server-properties.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-properties.d.ts","sourceRoot":"","sources":["../src/server-properties.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,yBAAyB,0BAA0B,CAAC;AACjE,eAAO,MAAM,0BAA0B,+BAA+B,CAAC;AAEvE,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,sBAAsB,GAC9B,OAAO,CAmBT"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { serverPropertiesPath } from "./pack-manager.js";
|
|
3
|
+
const EMIT_SERVER_TELEMETRY_KEY = "emit-server-telemetry";
|
|
4
|
+
const EMIT_SERVER_TELEMETRY_LINE = "emit-server-telemetry=true";
|
|
5
|
+
function ensureEmitServerTelemetry(bdsRoot, logger) {
|
|
6
|
+
const file = serverPropertiesPath(bdsRoot);
|
|
7
|
+
if (!fs.existsSync(file)) return false;
|
|
8
|
+
let text = fs.readFileSync(file, "utf8");
|
|
9
|
+
if (/^\s*emit-server-telemetry\s*=/im.test(text)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (text.length > 0 && !text.endsWith("\n")) {
|
|
13
|
+
text += "\n";
|
|
14
|
+
}
|
|
15
|
+
text += `${EMIT_SERVER_TELEMETRY_LINE}
|
|
16
|
+
`;
|
|
17
|
+
fs.writeFileSync(file, text, "utf8");
|
|
18
|
+
logger?.info(
|
|
19
|
+
"\u5DF2\u5411 server.properties \u8FFD\u52A0 emit-server-telemetry=true\uFF08\u56E0\u60A8\u5DF2\u540C\u610F Mojang EULA\uFF0C\u6309\u534F\u8BAE\u542F\u7528\u670D\u52A1\u5668\u9065\u6D4B\uFF09"
|
|
20
|
+
);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
EMIT_SERVER_TELEMETRY_KEY,
|
|
25
|
+
EMIT_SERVER_TELEMETRY_LINE,
|
|
26
|
+
ensureEmitServerTelemetry
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=server-properties.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/server-properties.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * server.properties \u8F85\u52A9\uFF1A\u5B89\u88C5/\u542F\u52A8\u65F6\u786E\u4FDD emit-server-telemetry=true\n */\nimport fs from \"node:fs\";\nimport { serverPropertiesPath } from \"./pack-manager.js\";\n\nexport const EMIT_SERVER_TELEMETRY_KEY = \"emit-server-telemetry\";\nexport const EMIT_SERVER_TELEMETRY_LINE = \"emit-server-telemetry=true\";\n\nexport type ServerPropertiesLogger = {\n info: (msg: string) => void;\n};\n\n/**\n * \u82E5 `<bdsRoot>/server.properties` \u4E2D\u5C1A\u65E0 emit-server-telemetry\uFF0C\u5219\u8FFD\u52A0 `=true`\u3002\n * \u5DF2\u6709\u8BE5\u952E\uFF08\u4EFB\u610F\u503C\uFF09\u5219\u8DF3\u8FC7\u3002\u6587\u4EF6\u4E0D\u5B58\u5728\u65F6\u8DF3\u8FC7\uFF08BDS \u5C1A\u672A\u89E3\u538B\uFF09\u3002\n * @returns true = \u672C\u6B21\u65B0\u8FFD\u52A0\uFF1Bfalse = \u8DF3\u8FC7\n */\nexport function ensureEmitServerTelemetry(\n bdsRoot: string,\n logger?: ServerPropertiesLogger\n): boolean {\n const file = serverPropertiesPath(bdsRoot);\n if (!fs.existsSync(file)) return false;\n\n let text = fs.readFileSync(file, \"utf8\");\n if (/^\\s*emit-server-telemetry\\s*=/im.test(text)) {\n return false;\n }\n\n if (text.length > 0 && !text.endsWith(\"\\n\")) {\n text += \"\\n\";\n }\n text += `${EMIT_SERVER_TELEMETRY_LINE}\\n`;\n fs.writeFileSync(file, text, \"utf8\");\n\n logger?.info(\n \"\u5DF2\u5411 server.properties \u8FFD\u52A0 emit-server-telemetry=true\uFF08\u56E0\u60A8\u5DF2\u540C\u610F Mojang EULA\uFF0C\u6309\u534F\u8BAE\u542F\u7528\u670D\u52A1\u5668\u9065\u6D4B\uFF09\"\n );\n return true;\n}\n"],
|
|
5
|
+
"mappings": "AAGA,OAAO,QAAQ;AACf,SAAS,4BAA4B;AAE9B,MAAM,4BAA4B;AAClC,MAAM,6BAA6B;AAWnC,SAAS,0BACd,SACA,QACS;AACT,QAAM,OAAO,qBAAqB,OAAO;AACzC,MAAI,CAAC,GAAG,WAAW,IAAI,EAAG,QAAO;AAEjC,MAAI,OAAO,GAAG,aAAa,MAAM,MAAM;AACvC,MAAI,kCAAkC,KAAK,IAAI,GAAG;AAChD,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,SAAS,KAAK,CAAC,KAAK,SAAS,IAAI,GAAG;AAC3C,YAAQ;AAAA,EACV;AACA,UAAQ,GAAG,0BAA0B;AAAA;AACrC,KAAG,cAAc,MAAM,MAAM,MAAM;AAEnC,UAAQ;AAAA,IACN;AAAA,EACF;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/taskbar.d.ts
CHANGED
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
* clearTaskbarProgress(); // 隐藏
|
|
28
28
|
*/
|
|
29
29
|
type ProgressState = "normal" | "error" | "indeterminate";
|
|
30
|
+
/** 从日志文本剥离 WT 任务栏 OSC 9;4(与写入侧同一权威,供父进程 DRY)。 */
|
|
31
|
+
export declare function stripTaskbarOsc(s: string): string;
|
|
30
32
|
/**
|
|
31
33
|
* 设置任务栏进度。
|
|
32
34
|
* - normal: 绿色 (pct 0-100)
|
package/dist/taskbar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taskbar.d.ts","sourceRoot":"","sources":["../src/taskbar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,KAAK,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"taskbar.d.ts","sourceRoot":"","sources":["../src/taskbar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,KAAK,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,eAAe,CAAC;AAmC1D,iDAAiD;AACjD,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,GAAE,aAAwB,GAAG,IAAI,CAmBrF;AAED,yBAAyB;AACzB,wBAAgB,oBAAoB,IAAI,IAAI,CAM3C;AAED,8CAA8C;AAC9C,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C"}
|
package/dist/taskbar.js
CHANGED
|
@@ -1,94 +1,63 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* taskbar.ts — Windows Terminal 任务栏进度 (OSC 9;4)
|
|
3
|
-
*
|
|
4
|
-
* 通过 OSC 9;4 转义序列直接驱动 Windows Terminal 任务栏图标上的进度条。
|
|
5
|
-
* 不需要 native 绑定(ffi / ITaskbarList3),但**仅 Windows Terminal 支持**。
|
|
6
|
-
* cmd.exe / PowerShell ISE 等老终端会忽略该序列,本模块在不支持的终端
|
|
7
|
-
* 上静默 no-op。
|
|
8
|
-
*
|
|
9
|
-
* 兼容性:
|
|
10
|
-
* - Windows Terminal ✅
|
|
11
|
-
* - ConEmu / Cmder ⚠️ 部分
|
|
12
|
-
* - cmd.exe / ISE ❌(不解析 OSC)
|
|
13
|
-
*
|
|
14
|
-
* 检测方式:WT_SESSION 或 TERM_PROGRAM === "Windows Terminal"。
|
|
15
|
-
*
|
|
16
|
-
* 序列格式(Windows Terminal 私有):
|
|
17
|
-
* \x1b]9;4;0;\x07 清除(隐藏)
|
|
18
|
-
* \x1b]9;4;1;<pct>\x07 正常(绿,pct 0-100)
|
|
19
|
-
* \x1b]9;4;2;<pct>\x07 错误(红,pct 0-100)
|
|
20
|
-
* \x1b]9;4;3;\x07 不确定(动画条纹)
|
|
21
|
-
*
|
|
22
|
-
* 幂等:相同 state+pct 不重复输出,避免刷屏。
|
|
23
|
-
*
|
|
24
|
-
* 用法:
|
|
25
|
-
* setTaskbarProgress(50); // 50% 绿
|
|
26
|
-
* setTaskbarProgress(100, "error"); // 100% 红
|
|
27
|
-
* clearTaskbarProgress(); // 隐藏
|
|
28
|
-
*/
|
|
29
1
|
function detect() {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (process.env["TERM_PROGRAM"] === "Windows Terminal")
|
|
35
|
-
return true;
|
|
36
|
-
return false;
|
|
2
|
+
if (process.platform !== "win32") return false;
|
|
3
|
+
if (process.env["WT_SESSION"]) return true;
|
|
4
|
+
if (process.env["TERM_PROGRAM"] === "Windows Terminal") return true;
|
|
5
|
+
return false;
|
|
37
6
|
}
|
|
38
7
|
let supported = detect();
|
|
39
8
|
let active = false;
|
|
40
9
|
let lastPct = -1;
|
|
41
10
|
let lastState = 0;
|
|
42
11
|
function stateCode(s) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
12
|
+
switch (s) {
|
|
13
|
+
case "clear":
|
|
14
|
+
return 0;
|
|
15
|
+
case "normal":
|
|
16
|
+
return 1;
|
|
17
|
+
case "error":
|
|
18
|
+
return 2;
|
|
19
|
+
case "indeterminate":
|
|
20
|
+
return 3;
|
|
21
|
+
}
|
|
53
22
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*
|
|
59
|
-
*/
|
|
60
|
-
export function setTaskbarProgress(pct, state = "normal") {
|
|
61
|
-
if (!supported)
|
|
62
|
-
return;
|
|
63
|
-
if (state === "indeterminate") {
|
|
64
|
-
if (lastState === 3)
|
|
65
|
-
return; // 已在 indeterminate,不再重发
|
|
66
|
-
process.stdout.write("\x1b]9;4;3\x07");
|
|
67
|
-
lastState = 3;
|
|
68
|
-
lastPct = -1;
|
|
69
|
-
active = true;
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const p = Math.max(0, Math.min(100, Math.round(pct)));
|
|
73
|
-
const sc = stateCode(state);
|
|
74
|
-
if (lastState === sc && lastPct === p)
|
|
75
|
-
return; // 无变化,跳过
|
|
76
|
-
process.stdout.write(`\x1b]9;4;${sc};${p}\x07`);
|
|
77
|
-
lastPct = p;
|
|
78
|
-
lastState = sc;
|
|
79
|
-
active = true;
|
|
23
|
+
function canWriteOsc() {
|
|
24
|
+
return supported && !!process.stdout.isTTY;
|
|
25
|
+
}
|
|
26
|
+
function stripTaskbarOsc(s) {
|
|
27
|
+
return s.replace(/\x1b\]9;4[^\x07\x1b]*(?:\x07|\x1b\\)/g, "");
|
|
80
28
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
process.stdout.write("\
|
|
29
|
+
function setTaskbarProgress(pct, state = "normal") {
|
|
30
|
+
if (!canWriteOsc()) return;
|
|
31
|
+
if (state === "indeterminate") {
|
|
32
|
+
if (lastState === 3) return;
|
|
33
|
+
process.stdout.write("\x1B]9;4;3\x07");
|
|
34
|
+
lastState = 3;
|
|
86
35
|
lastPct = -1;
|
|
87
|
-
|
|
88
|
-
|
|
36
|
+
active = true;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const p = Math.max(0, Math.min(100, Math.round(pct)));
|
|
40
|
+
const sc = stateCode(state);
|
|
41
|
+
if (lastState === sc && lastPct === p) return;
|
|
42
|
+
process.stdout.write(`\x1B]9;4;${sc};${p}\x07`);
|
|
43
|
+
lastPct = p;
|
|
44
|
+
lastState = sc;
|
|
45
|
+
active = true;
|
|
46
|
+
}
|
|
47
|
+
function clearTaskbarProgress() {
|
|
48
|
+
if (!canWriteOsc() || !active) return;
|
|
49
|
+
process.stdout.write("\x1B]9;4;0\x07");
|
|
50
|
+
lastPct = -1;
|
|
51
|
+
lastState = 0;
|
|
52
|
+
active = false;
|
|
89
53
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return supported;
|
|
54
|
+
function isTaskbarSupported() {
|
|
55
|
+
return supported;
|
|
93
56
|
}
|
|
94
|
-
|
|
57
|
+
export {
|
|
58
|
+
clearTaskbarProgress,
|
|
59
|
+
isTaskbarSupported,
|
|
60
|
+
setTaskbarProgress,
|
|
61
|
+
stripTaskbarOsc
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=taskbar.js.map
|
package/dist/taskbar.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/taskbar.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * taskbar.ts \u2014 Windows Terminal \u4EFB\u52A1\u680F\u8FDB\u5EA6 (OSC 9;4)\n *\n * \u901A\u8FC7 OSC 9;4 \u8F6C\u4E49\u5E8F\u5217\u76F4\u63A5\u9A71\u52A8 Windows Terminal \u4EFB\u52A1\u680F\u56FE\u6807\u4E0A\u7684\u8FDB\u5EA6\u6761\u3002\n * \u4E0D\u9700\u8981 native \u7ED1\u5B9A(ffi / ITaskbarList3),\u4F46**\u4EC5 Windows Terminal \u652F\u6301**\u3002\n * cmd.exe / PowerShell ISE \u7B49\u8001\u7EC8\u7AEF\u4F1A\u5FFD\u7565\u8BE5\u5E8F\u5217,\u672C\u6A21\u5757\u5728\u4E0D\u652F\u6301\u7684\u7EC8\u7AEF\n * \u4E0A\u9759\u9ED8 no-op\u3002\n *\n * \u517C\u5BB9\u6027:\n * - Windows Terminal \u2705\n * - ConEmu / Cmder \u26A0\uFE0F \u90E8\u5206\n * - cmd.exe / ISE \u274C(\u4E0D\u89E3\u6790 OSC)\n *\n * \u68C0\u6D4B\u65B9\u5F0F:WT_SESSION \u6216 TERM_PROGRAM === \"Windows Terminal\"\u3002\n *\n * \u5E8F\u5217\u683C\u5F0F(Windows Terminal \u79C1\u6709):\n * \\x1b]9;4;0;\\x07 \u6E05\u9664(\u9690\u85CF)\n * \\x1b]9;4;1;<pct>\\x07 \u6B63\u5E38(\u7EFF,pct 0-100)\n * \\x1b]9;4;2;<pct>\\x07 \u9519\u8BEF(\u7EA2,pct 0-100)\n * \\x1b]9;4;3;\\x07 \u4E0D\u786E\u5B9A(\u52A8\u753B\u6761\u7EB9)\n *\n * \u5E42\u7B49:\u76F8\u540C state+pct \u4E0D\u91CD\u590D\u8F93\u51FA,\u907F\u514D\u5237\u5C4F\u3002\n *\n * \u7528\u6CD5:\n * setTaskbarProgress(50); // 50% \u7EFF\n * setTaskbarProgress(100, \"error\"); // 100% \u7EA2\n * clearTaskbarProgress(); // \u9690\u85CF\n */\n\ntype ProgressState = \"normal\" | \"error\" | \"indeterminate\";\n\nfunction detect(): boolean {\n if (process.platform !== \"win32\") return false;\n if (process.env[\"WT_SESSION\"]) return true;\n if (process.env[\"TERM_PROGRAM\"] === \"Windows Terminal\") return true;\n return false;\n}\n\nlet supported = detect();\nlet active = false;\nlet lastPct = -1;\nlet lastState: 0 | 1 | 2 | 3 = 0;\n\nfunction stateCode(s: ProgressState | \"clear\"): 0 | 1 | 2 | 3 {\n switch (s) {\n case \"clear\":\n return 0;\n case \"normal\":\n return 1;\n case \"error\":\n return 2;\n case \"indeterminate\":\n return 3;\n }\n}\n\n/**\n * stdout \u88AB pipe\uFF08\u5982 sfmc REPL \u6355\u83B7\u5B50\u8FDB\u7A0B\u8F93\u51FA\uFF09\u65F6\u4E0D\u5E94\u5199 OSC\uFF1A\n * \u7EC8\u7AEF\u4E0D\u4F1A\u89E3\u6790\uFF0C\u7236\u8FDB\u7A0B\u5374\u4F1A\u628A\u5E8F\u5217\u5F53\u6210\u300C\u7A7A\u767D\u65E5\u5FD7\u884C\u300D\u5237\u5C4F\u3002\n */\nfunction canWriteOsc(): boolean {\n return supported && !!process.stdout.isTTY;\n}\n\n/** \u4ECE\u65E5\u5FD7\u6587\u672C\u5265\u79BB WT \u4EFB\u52A1\u680F OSC 9;4\uFF08\u4E0E\u5199\u5165\u4FA7\u540C\u4E00\u6743\u5A01\uFF0C\u4F9B\u7236\u8FDB\u7A0B DRY\uFF09\u3002 */\nexport function stripTaskbarOsc(s: string): string {\n return s.replace(/\\x1b\\]9;4[^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)/g, \"\");\n}\n\n/**\n * \u8BBE\u7F6E\u4EFB\u52A1\u680F\u8FDB\u5EA6\u3002\n * - normal: \u7EFF\u8272 (pct 0-100)\n * - error: \u7EA2\u8272 (pct 0-100)\n * - indeterminate: \u52A8\u753B\u6761\u7EB9(pct \u5FFD\u7565)\n */\nexport function setTaskbarProgress(pct: number, state: ProgressState = \"normal\"): void {\n if (!canWriteOsc()) return;\n\n if (state === \"indeterminate\") {\n if (lastState === 3) return; // \u5DF2\u5728 indeterminate,\u4E0D\u518D\u91CD\u53D1\n process.stdout.write(\"\\x1b]9;4;3\\x07\");\n lastState = 3;\n lastPct = -1;\n active = true;\n return;\n }\n\n const p = Math.max(0, Math.min(100, Math.round(pct)));\n const sc = stateCode(state);\n if (lastState === sc && lastPct === p) return; // \u65E0\u53D8\u5316,\u8DF3\u8FC7\n process.stdout.write(`\\x1b]9;4;${sc};${p}\\x07`);\n lastPct = p;\n lastState = sc;\n active = true;\n}\n\n/** \u6E05\u9664\u4EFB\u52A1\u680F\u8FDB\u5EA6(\u9690\u85CF\u8FDB\u5EA6\u6761)\u3002\u5E42\u7B49\u3002 */\nexport function clearTaskbarProgress(): void {\n if (!canWriteOsc() || !active) return;\n process.stdout.write(\"\\x1b]9;4;0\\x07\");\n lastPct = -1;\n lastState = 0;\n active = false;\n}\n\n/** \u6A21\u5757\u662F\u5426\u542F\u7528(Windows Terminal \u63A2\u6D4B\u7ED3\u679C)\u3002\u4F9B\u65E5\u5FD7 / \u8C03\u8BD5\u3002 */\nexport function isTaskbarSupported(): boolean {\n return supported;\n}\n"],
|
|
5
|
+
"mappings": "AA+BA,SAAS,SAAkB;AACzB,MAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,MAAI,QAAQ,IAAI,YAAY,EAAG,QAAO;AACtC,MAAI,QAAQ,IAAI,cAAc,MAAM,mBAAoB,QAAO;AAC/D,SAAO;AACT;AAEA,IAAI,YAAY,OAAO;AACvB,IAAI,SAAS;AACb,IAAI,UAAU;AACd,IAAI,YAA2B;AAE/B,SAAS,UAAU,GAA2C;AAC5D,UAAQ,GAAG;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAMA,SAAS,cAAuB;AAC9B,SAAO,aAAa,CAAC,CAAC,QAAQ,OAAO;AACvC;AAGO,SAAS,gBAAgB,GAAmB;AACjD,SAAO,EAAE,QAAQ,yCAAyC,EAAE;AAC9D;AAQO,SAAS,mBAAmB,KAAa,QAAuB,UAAgB;AACrF,MAAI,CAAC,YAAY,EAAG;AAEpB,MAAI,UAAU,iBAAiB;AAC7B,QAAI,cAAc,EAAG;AACrB,YAAQ,OAAO,MAAM,gBAAgB;AACrC,gBAAY;AACZ,cAAU;AACV,aAAS;AACT;AAAA,EACF;AAEA,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG,CAAC,CAAC;AACpD,QAAM,KAAK,UAAU,KAAK;AAC1B,MAAI,cAAc,MAAM,YAAY,EAAG;AACvC,UAAQ,OAAO,MAAM,YAAY,EAAE,IAAI,CAAC,MAAM;AAC9C,YAAU;AACV,cAAY;AACZ,WAAS;AACX;AAGO,SAAS,uBAA6B;AAC3C,MAAI,CAAC,YAAY,KAAK,CAAC,OAAQ;AAC/B,UAAQ,OAAO,MAAM,gBAAgB;AACrC,YAAU;AACV,cAAY;AACZ,WAAS;AACX;AAGO,SAAS,qBAA8B;AAC5C,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/types.js
CHANGED
package/dist/types.js.map
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update-result.ts — BDS updater ↔ sfmc 监督器机器可读结果契约(DRY / DIP)
|
|
3
|
+
*
|
|
4
|
+
* 勿依赖本地化日志文案判断「是否真正部署」;一律解析本标记。
|
|
5
|
+
* 写出走统一 Logger(bare stdout),避免 console.log 旁路。
|
|
6
|
+
*/
|
|
7
|
+
import type { Logger } from "@sfmc-bds/sdk/logs";
|
|
8
|
+
export declare const UPDATE_RESULT_PREFIX = "SFMC_UPDATE_RESULT=";
|
|
9
|
+
export type UpdateResultKind = "uptodate" | "skipped" | "check-only" | "deployed";
|
|
10
|
+
type InfoLogger = Pick<Logger, "info">;
|
|
11
|
+
/** 向 logger 打印机器标记(bare stdout 下仍为可解析纯文本)。 */
|
|
12
|
+
export declare function emitUpdateResult(kind: UpdateResultKind, log: InfoLogger): void;
|
|
13
|
+
/** KEY=value 机器行(CURRENT/LATEST/CHANNEL/URLS 等) */
|
|
14
|
+
export declare function emitUpdateKv(key: string, value: string, log: InfoLogger): void;
|
|
15
|
+
/** 从 updater 合并输出中解析是否完成部署。 */
|
|
16
|
+
export declare function didUpdateDeploy(out: string): boolean;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=update-result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-result.d.ts","sourceRoot":"","sources":["../src/update-result.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,CAAC;AAElF,KAAK,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvC,8CAA8C;AAC9C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAE9E;AAED,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAE9E;AAED,+BAA+B;AAC/B,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const UPDATE_RESULT_PREFIX = "SFMC_UPDATE_RESULT=";
|
|
2
|
+
function emitUpdateResult(kind, log) {
|
|
3
|
+
log.info(`${UPDATE_RESULT_PREFIX}${kind}`);
|
|
4
|
+
}
|
|
5
|
+
function emitUpdateKv(key, value, log) {
|
|
6
|
+
log.info(`${key}=${value}`);
|
|
7
|
+
}
|
|
8
|
+
function didUpdateDeploy(out) {
|
|
9
|
+
return new RegExp(`(?:^|\\n)${UPDATE_RESULT_PREFIX}deployed(?:\\r?\\n|$)`).test(out);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
UPDATE_RESULT_PREFIX,
|
|
13
|
+
didUpdateDeploy,
|
|
14
|
+
emitUpdateKv,
|
|
15
|
+
emitUpdateResult
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=update-result.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/update-result.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * update-result.ts \u2014 BDS updater \u2194 sfmc \u76D1\u7763\u5668\u673A\u5668\u53EF\u8BFB\u7ED3\u679C\u5951\u7EA6\uFF08DRY / DIP\uFF09\n *\n * \u52FF\u4F9D\u8D56\u672C\u5730\u5316\u65E5\u5FD7\u6587\u6848\u5224\u65AD\u300C\u662F\u5426\u771F\u6B63\u90E8\u7F72\u300D\uFF1B\u4E00\u5F8B\u89E3\u6790\u672C\u6807\u8BB0\u3002\n * \u5199\u51FA\u8D70\u7EDF\u4E00 Logger\uFF08bare stdout\uFF09\uFF0C\u907F\u514D console.log \u65C1\u8DEF\u3002\n */\nimport type { Logger } from \"@sfmc-bds/sdk/logs\";\n\nexport const UPDATE_RESULT_PREFIX = \"SFMC_UPDATE_RESULT=\";\n\nexport type UpdateResultKind = \"uptodate\" | \"skipped\" | \"check-only\" | \"deployed\";\n\ntype InfoLogger = Pick<Logger, \"info\">;\n\n/** \u5411 logger \u6253\u5370\u673A\u5668\u6807\u8BB0\uFF08bare stdout \u4E0B\u4ECD\u4E3A\u53EF\u89E3\u6790\u7EAF\u6587\u672C\uFF09\u3002 */\nexport function emitUpdateResult(kind: UpdateResultKind, log: InfoLogger): void {\n log.info(`${UPDATE_RESULT_PREFIX}${kind}`);\n}\n\n/** KEY=value \u673A\u5668\u884C\uFF08CURRENT/LATEST/CHANNEL/URLS \u7B49\uFF09 */\nexport function emitUpdateKv(key: string, value: string, log: InfoLogger): void {\n log.info(`${key}=${value}`);\n}\n\n/** \u4ECE updater \u5408\u5E76\u8F93\u51FA\u4E2D\u89E3\u6790\u662F\u5426\u5B8C\u6210\u90E8\u7F72\u3002 */\nexport function didUpdateDeploy(out: string): boolean {\n return new RegExp(`(?:^|\\\\n)${UPDATE_RESULT_PREFIX}deployed(?:\\\\r?\\\\n|$)`).test(out);\n}\n"],
|
|
5
|
+
"mappings": "AAQO,MAAM,uBAAuB;AAO7B,SAAS,iBAAiB,MAAwB,KAAuB;AAC9E,MAAI,KAAK,GAAG,oBAAoB,GAAG,IAAI,EAAE;AAC3C;AAGO,SAAS,aAAa,KAAa,OAAe,KAAuB;AAC9E,MAAI,KAAK,GAAG,GAAG,IAAI,KAAK,EAAE;AAC5B;AAGO,SAAS,gBAAgB,KAAsB;AACpD,SAAO,IAAI,OAAO,YAAY,oBAAoB,uBAAuB,EAAE,KAAK,GAAG;AACrF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/upstream.js
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* upstream.ts — 版本源 / 下载源 / 哈希校验
|
|
3
|
-
*
|
|
4
|
-
* 改进:
|
|
5
|
-
* - 3 次重试 + 指数退避
|
|
6
|
-
* - sha1 / sha256 同时校验
|
|
7
|
-
* - 流式校验 + 边下边校验
|
|
8
|
-
*/
|
|
9
1
|
import crypto from "node:crypto";
|
|
10
2
|
import fs from "node:fs";
|
|
11
3
|
import { fetchJsonWithFallback } from "./http.js";
|
|
@@ -14,113 +6,107 @@ import { toVer3 } from "./version.js";
|
|
|
14
6
|
const DEFAULT_VERSIONS_API = "https://raw.githubusercontent.com/Bedrock-OSS/BDS-Versions/main/versions.json";
|
|
15
7
|
const DEFAULT_VERSIONS_MIRROR = "https://cdn.jsdelivr.net/gh/Bedrock-OSS/BDS-Versions@main/versions.json";
|
|
16
8
|
function resolveTemplate(tpl, vars) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
let s = tpl;
|
|
10
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
11
|
+
s = s.replace(new RegExp(`\\{${k}\\}`, "g"), v);
|
|
12
|
+
}
|
|
13
|
+
return s;
|
|
22
14
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const wait = attempt * 3000;
|
|
50
|
-
log.warn(`版本号获取失败 (${attempt}/3): ${e.message},${wait / 1000}s 后重试...`);
|
|
51
|
-
await new Promise((r) => setTimeout(r, wait));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
15
|
+
async function getVersionInfo(cfg, channel) {
|
|
16
|
+
const api = cfg.version_versions || process.env["BDS_VERSIONS_API"] || DEFAULT_VERSIONS_API;
|
|
17
|
+
const mirror = cfg.version_versions_mirror || process.env["BDS_VERSIONS_MIRROR"] || DEFAULT_VERSIONS_MIRROR;
|
|
18
|
+
const sources = [api, mirror].filter(Boolean);
|
|
19
|
+
const versionMode = cfg.version_mode || "bedrock-oss";
|
|
20
|
+
let lastErr;
|
|
21
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
22
|
+
try {
|
|
23
|
+
const json = await fetchJsonWithFallback(sources);
|
|
24
|
+
let ver;
|
|
25
|
+
if (versionMode === "endstone") {
|
|
26
|
+
const entry = channel === "preview" ? json.preview : json.release;
|
|
27
|
+
ver = entry?.latest;
|
|
28
|
+
} else {
|
|
29
|
+
const platform = json.windows || json.linux;
|
|
30
|
+
ver = channel === "preview" ? platform?.preview : platform?.stable;
|
|
31
|
+
}
|
|
32
|
+
if (!ver) throw new Error("\u672A\u627E\u5230\u6700\u65B0\u7248\u672C\u53F7");
|
|
33
|
+
return { version: ver, cdnRoot: json.cdn_root ?? "" };
|
|
34
|
+
} catch (e) {
|
|
35
|
+
lastErr = e;
|
|
36
|
+
if (attempt < 3) {
|
|
37
|
+
const wait = attempt * 3e3;
|
|
38
|
+
log.warn(`\u7248\u672C\u53F7\u83B7\u53D6\u5931\u8D25 (${attempt}/3): ${e.message}\uFF0C${wait / 1e3}s \u540E\u91CD\u8BD5...`);
|
|
39
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
40
|
+
}
|
|
54
41
|
}
|
|
55
|
-
|
|
42
|
+
}
|
|
43
|
+
throw lastErr instanceof Error ? lastErr : new Error("\u7248\u672C\u53F7\u83B7\u53D6\u5931\u8D25");
|
|
56
44
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const bw = json.binary?.windows;
|
|
69
|
-
return {
|
|
70
|
-
downloadUrl: bw?.url ?? "",
|
|
71
|
-
sha1: "",
|
|
72
|
-
sha256: bw?.sha256 ?? "",
|
|
73
|
-
size: bw?.size_in_bytes ?? 0,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
45
|
+
async function fetchVersionDetails(cfg, channel, version) {
|
|
46
|
+
const platform = channel === "preview" ? "windows_preview" : "windows";
|
|
47
|
+
const ch = channel === "preview" ? "preview" : "release";
|
|
48
|
+
const vars = { version, ver3: toVer3(version), platform, channel: ch };
|
|
49
|
+
const detailsTpl = cfg.version_details || "https://raw.githubusercontent.com/Bedrock-OSS/BDS-Versions/main/{platform}/{version}.json";
|
|
50
|
+
const mirrorTpl = cfg.version_details_mirror || "https://cdn.jsdelivr.net/gh/Bedrock-OSS/BDS-Versions@main/{platform}/{version}.json";
|
|
51
|
+
const sources = [detailsTpl, mirrorTpl].filter(Boolean).map((t) => resolveTemplate(t, vars));
|
|
52
|
+
const json = await fetchJsonWithFallback(sources);
|
|
53
|
+
const mode = cfg.version_mode || "bedrock-oss";
|
|
54
|
+
if (mode === "endstone") {
|
|
55
|
+
const bw = json.binary?.windows;
|
|
76
56
|
return {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
57
|
+
downloadUrl: bw?.url ?? "",
|
|
58
|
+
sha1: "",
|
|
59
|
+
sha256: bw?.sha256 ?? "",
|
|
60
|
+
size: bw?.size_in_bytes ?? 0
|
|
81
61
|
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
downloadUrl: json.download_url ?? "",
|
|
65
|
+
sha1: json.sha1 ?? "",
|
|
66
|
+
sha256: "",
|
|
67
|
+
size: json.size_in_bytes ?? 0
|
|
68
|
+
};
|
|
82
69
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
: `/bin-win/bedrock-server-${version}.zip`;
|
|
96
|
-
urls.push(cdnRoot + suffix);
|
|
97
|
-
urls.push(`https://minecraft.azureedge.net${suffix}`);
|
|
98
|
-
return [...new Set(urls)];
|
|
70
|
+
function buildDownloadUrls(cfg, channel, version, details) {
|
|
71
|
+
const urls = [];
|
|
72
|
+
if (cfg.download_mirror) {
|
|
73
|
+
const mirrorVer = channel === "preview" ? `${version}-preview` : version;
|
|
74
|
+
urls.push(resolveTemplate(cfg.download_mirror, { version: mirrorVer }));
|
|
75
|
+
}
|
|
76
|
+
if (details.downloadUrl) urls.push(details.downloadUrl);
|
|
77
|
+
const cdnRoot = cfg.cdn_root || "https://www.minecraft.net/bedrockdedicatedserver";
|
|
78
|
+
const suffix = channel === "preview" ? `/bin-win-preview/bedrock-server-${version}-preview.zip` : `/bin-win/bedrock-server-${version}.zip`;
|
|
79
|
+
urls.push(cdnRoot + suffix);
|
|
80
|
+
urls.push(`https://minecraft.azureedge.net${suffix}`);
|
|
81
|
+
return [...new Set(urls)];
|
|
99
82
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const actual = h.digest("hex").toLowerCase();
|
|
114
|
-
resolve(actual === expected.toLowerCase());
|
|
115
|
-
});
|
|
116
|
-
stream.on("error", reject);
|
|
83
|
+
async function verifyFileHash(filePath, expectedSha1, expectedSha256) {
|
|
84
|
+
const expected = expectedSha256 || expectedSha1;
|
|
85
|
+
if (!expected) return true;
|
|
86
|
+
const algo = expectedSha256 ? "sha256" : "sha1";
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
const h = crypto.createHash(algo);
|
|
89
|
+
const stream = fs.createReadStream(filePath);
|
|
90
|
+
stream.on("data", (chunk) => {
|
|
91
|
+
h.update(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
92
|
+
});
|
|
93
|
+
stream.on("end", () => {
|
|
94
|
+
const actual = h.digest("hex").toLowerCase();
|
|
95
|
+
resolve(actual === expected.toLowerCase());
|
|
117
96
|
});
|
|
97
|
+
stream.on("error", reject);
|
|
98
|
+
});
|
|
118
99
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return true;
|
|
124
|
-
return allow.includes(version) || allow.includes(toVer3(version));
|
|
100
|
+
function isVersionCompatible(cfg, version) {
|
|
101
|
+
const allow = cfg.compatible_versions;
|
|
102
|
+
if (!allow || allow.length === 0) return true;
|
|
103
|
+
return allow.includes(version) || allow.includes(toVer3(version));
|
|
125
104
|
}
|
|
126
|
-
|
|
105
|
+
export {
|
|
106
|
+
buildDownloadUrls,
|
|
107
|
+
fetchVersionDetails,
|
|
108
|
+
getVersionInfo,
|
|
109
|
+
isVersionCompatible,
|
|
110
|
+
verifyFileHash
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=upstream.js.map
|
package/dist/upstream.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/upstream.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * upstream.ts \u2014 \u7248\u672C\u6E90 / \u4E0B\u8F7D\u6E90 / \u54C8\u5E0C\u6821\u9A8C\n *\n * \u6539\u8FDB:\n * - 3 \u6B21\u91CD\u8BD5 + \u6307\u6570\u9000\u907F\n * - sha1 / sha256 \u540C\u65F6\u6821\u9A8C\n * - \u6D41\u5F0F\u6821\u9A8C + \u8FB9\u4E0B\u8FB9\u6821\u9A8C\n */\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport { fetchJsonWithFallback } from \"./http.js\";\nimport { log } from \"./log.js\";\nimport type { BdsUpdaterConfig, VersionDetails, VersionInfo } from \"./types.js\";\nimport { toVer3 } from \"./version.js\";\n\nconst DEFAULT_VERSIONS_API = \"https://raw.githubusercontent.com/Bedrock-OSS/BDS-Versions/main/versions.json\";\nconst DEFAULT_VERSIONS_MIRROR = \"https://cdn.jsdelivr.net/gh/Bedrock-OSS/BDS-Versions@main/versions.json\";\n\nfunction resolveTemplate(tpl: string, vars: Record<string, string>): string {\n let s = tpl;\n for (const [k, v] of Object.entries(vars)) {\n s = s.replace(new RegExp(`\\\\{${k}\\\\}`, \"g\"), v);\n }\n return s;\n}\n\n/** \u83B7\u53D6\u6700\u65B0\u7248\u672C\u53F7 (\u542B cdn_root)\uFF0C3 \u6B21\u91CD\u8BD5 */\nexport async function getVersionInfo(cfg: BdsUpdaterConfig, channel: string): Promise<VersionInfo> {\n const api = cfg.version_versions || process.env[\"BDS_VERSIONS_API\"] || DEFAULT_VERSIONS_API;\n const mirror = cfg.version_versions_mirror || process.env[\"BDS_VERSIONS_MIRROR\"] || DEFAULT_VERSIONS_MIRROR;\n const sources = [api, mirror].filter(Boolean);\n const versionMode = cfg.version_mode || \"bedrock-oss\";\n\n let lastErr: unknown;\n for (let attempt = 1; attempt <= 3; attempt++) {\n try {\n const json = await fetchJsonWithFallback<any>(sources);\n let ver: string | undefined;\n if (versionMode === \"endstone\") {\n const entry = channel === \"preview\" ? json.preview : json.release;\n ver = entry?.latest;\n } else {\n const platform = json.windows || json.linux;\n ver = channel === \"preview\" ? platform?.preview : platform?.stable;\n }\n if (!ver) throw new Error(\"\u672A\u627E\u5230\u6700\u65B0\u7248\u672C\u53F7\");\n return { version: ver, cdnRoot: json.cdn_root ?? \"\" };\n } catch (e) {\n lastErr = e;\n if (attempt < 3) {\n const wait = attempt * 3000;\n log.warn(`\u7248\u672C\u53F7\u83B7\u53D6\u5931\u8D25 (${attempt}/3): ${(e as Error).message}\uFF0C${wait / 1000}s \u540E\u91CD\u8BD5...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n }\n }\n throw lastErr instanceof Error ? lastErr : new Error(\"\u7248\u672C\u53F7\u83B7\u53D6\u5931\u8D25\");\n}\n\n/** \u83B7\u53D6 per-version \u7684\u4E0B\u8F7D\u94FE\u63A5 + \u54C8\u5E0C (fallback GitHub \u2192 jsdelivr) */\nexport async function fetchVersionDetails(\n cfg: BdsUpdaterConfig,\n channel: string,\n version: string\n): Promise<VersionDetails> {\n const platform = channel === \"preview\" ? \"windows_preview\" : \"windows\";\n const ch = channel === \"preview\" ? \"preview\" : \"release\";\n const vars = { version, ver3: toVer3(version), platform, channel: ch };\n const detailsTpl =\n cfg.version_details || \"https://raw.githubusercontent.com/Bedrock-OSS/BDS-Versions/main/{platform}/{version}.json\";\n const mirrorTpl =\n cfg.version_details_mirror || \"https://cdn.jsdelivr.net/gh/Bedrock-OSS/BDS-Versions@main/{platform}/{version}.json\";\n const sources = [detailsTpl, mirrorTpl].filter(Boolean).map((t) => resolveTemplate(t, vars));\n\n const json = await fetchJsonWithFallback<any>(sources);\n const mode = cfg.version_mode || \"bedrock-oss\";\n if (mode === \"endstone\") {\n const bw = json.binary?.windows;\n return {\n downloadUrl: bw?.url ?? \"\",\n sha1: \"\",\n sha256: bw?.sha256 ?? \"\",\n size: bw?.size_in_bytes ?? 0,\n };\n }\n return {\n downloadUrl: json.download_url ?? \"\",\n sha1: json.sha1 ?? \"\",\n sha256: \"\",\n size: json.size_in_bytes ?? 0,\n };\n}\n\n/** \u5019\u9009\u4E0B\u8F7D URL (\u6309\u4F18\u5148\u7EA7) */\nexport function buildDownloadUrls(\n cfg: BdsUpdaterConfig,\n channel: string,\n version: string,\n details: VersionDetails\n): string[] {\n const urls: string[] = [];\n if (cfg.download_mirror) {\n const mirrorVer = channel === \"preview\" ? `${version}-preview` : version;\n urls.push(resolveTemplate(cfg.download_mirror, { version: mirrorVer }));\n }\n if (details.downloadUrl) urls.push(details.downloadUrl);\n const cdnRoot = cfg.cdn_root || \"https://www.minecraft.net/bedrockdedicatedserver\";\n const suffix =\n channel === \"preview\"\n ? `/bin-win-preview/bedrock-server-${version}-preview.zip`\n : `/bin-win/bedrock-server-${version}.zip`;\n urls.push(cdnRoot + suffix);\n urls.push(`https://minecraft.azureedge.net${suffix}`);\n return [...new Set(urls)];\n}\n\n/** \u540C\u6B65 / \u5F02\u6B65\u6821\u9A8C\u6587\u4EF6\u54C8\u5E0C */\nexport async function verifyFileHash(filePath: string, expectedSha1: string, expectedSha256: string): Promise<boolean> {\n const expected = expectedSha256 || expectedSha1;\n if (!expected) return true;\n const algo: \"sha1\" | \"sha256\" = expectedSha256 ? \"sha256\" : \"sha1\";\n\n return new Promise((resolve, reject) => {\n const h = crypto.createHash(algo);\n const stream = fs.createReadStream(filePath);\n stream.on(\"data\", (chunk: Buffer | string) => {\n h.update(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n stream.on(\"end\", () => {\n const actual = h.digest(\"hex\").toLowerCase();\n resolve(actual === expected.toLowerCase());\n });\n stream.on(\"error\", reject);\n });\n}\n\n/** \u68C0\u67E5\u7248\u672C\u517C\u5BB9\u6027 (\u767D\u540D\u5355) */\nexport function isVersionCompatible(cfg: BdsUpdaterConfig, version: string): boolean {\n const allow = cfg.compatible_versions;\n if (!allow || allow.length === 0) return true;\n return allow.includes(version) || allow.includes(toVer3(version));\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|