@sfmc-bds/bds-tools 0.2.0-beta.10 → 0.2.0-beta.11

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.
@@ -8,7 +8,7 @@ import os from "node:os";
8
8
  import path from "node:path";
9
9
  import { createBdsManager } from "./bds-manager.js";
10
10
  import { CHANGELOG_BASE, fetchChangelog } from "./changelog.js";
11
- import { copyDirSync, emptyDirSync, hashFileAsync, rmSafe } from "./fsx.js";
11
+ import { copyDirSync, copyFileSyncSafe, emptyDirSync, hashFileAsync, rmSafe } from "./fsx.js";
12
12
  import { bdsExePath, bdsInstallRequiredFiles, ensureBdsExecutable } from "./host-platform.js";
13
13
  import { httpDownload } from "./http.js";
14
14
  import { isMainModule } from "./is-main.js";
@@ -71,7 +71,7 @@ async function doBackup(bdsPath, backupDir, preserve) {
71
71
  if (!fs.existsSync(src)) continue;
72
72
  fs.mkdirSync(path.dirname(target), { recursive: true });
73
73
  if (fs.statSync(src).isDirectory()) copyDirSync(src, target);
74
- else fs.copyFileSync(src, target);
74
+ else copyFileSyncSafe(src, target);
75
75
  anyCopied = true;
76
76
  log.info(`\u5DF2\u5907\u4EFD: ${item}`);
77
77
  }
@@ -91,7 +91,7 @@ async function restorePreserves(bdsPath, backupDir, preserve) {
91
91
  copyDirSync(src, dest);
92
92
  } else {
93
93
  fs.mkdirSync(path.dirname(dest), { recursive: true });
94
- fs.copyFileSync(src, dest);
94
+ copyFileSyncSafe(src, dest);
95
95
  }
96
96
  log.info(`\u5DF2\u6062\u590D: ${item}`);
97
97
  } catch (e) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/check-update.ts"],
4
- "sourcesContent": ["/**\n * check-update.ts \u2014 BDS \u81EA\u52A8\u66F4\u65B0\u5668 (\u4E3B\u6D41\u7A0B)\n *\n * 1. \u4E34\u65F6 staging \u76EE\u5F55 (mkdtempSync) - \u907F\u514D\u6C61\u67D3\u6570\u636E\u6839\n * 2. \u4E0B\u8F7D/\u89E3\u538B\u5931\u8D25 \u2192 \u81EA\u52A8\u4ECE\u5907\u4EFD\u56DE\u6EDA preserves\n * 3. \u6D41\u5F0F SHA256 \u6821\u9A8C - \u4E0D\u628A 250MB \u6587\u4EF6\u8BFB\u5165\u5185\u5B58\n * 4. \u517C\u5BB9\u7248\u672C\u767D\u540D\u5355 - \u4E0D\u5339\u914D\u5219\u8DF3\u8FC7\u5347\u7EA7\n * 5. QQ \u901A\u77E5\u7EDF\u4E00\u52A0 5s \u8D85\u65F6 - \u6C38\u8FDC\u4E0D\u963B\u585E\u4E3B\u6D41\u7A0B\n * 6. Rollback marker \u843D\u76D8\u5230 <ROOT>/.sfmc/ - \u8DE8\u8FDB\u7A0B / \u8DE8\u91CD\u542F\u53EF\u6062\u590D\n */\n\nimport {\n bindByteProgressToBar,\n createNodeServiceLogger,\n createTerminalProgress,\n} from \"@sfmc-bds/sdk/logs\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { createBdsManager } from \"./bds-manager.js\";\nimport { CHANGELOG_BASE, fetchChangelog } from \"./changelog.js\";\nimport { copyDirSync, emptyDirSync, hashFileAsync, rmSafe } from \"./fsx.js\";\nimport { bdsExePath, bdsInstallRequiredFiles, ensureBdsExecutable } from \"./host-platform.js\";\nimport { httpDownload } from \"./http.js\";\nimport { isMainModule } from \"./is-main.js\";\nimport { loadConfig, LOG_PATH, resolvePaths } from \"./paths.js\";\nimport { sendText, sendWithImage } from \"./qqutil.js\";\nimport {\n clearRollbackMarker,\n getDirSize,\n rollbackFromBackup,\n verifyBdsInstall,\n writeRollbackMarker,\n} from \"./rollback.js\";\nimport { ensureEmitServerTelemetry } from \"./server-properties.js\";\nimport { clearTaskbarProgress, isTaskbarSupported, setTaskbarProgress } from \"./taskbar.js\";\nimport { emitUpdateKv, emitUpdateResult } from \"./update-result.js\";\nimport {\n buildDownloadUrls,\n fetchVersionDetails,\n getVersionInfo,\n isVersionCompatible,\n verifyFileHash,\n} from \"./upstream.js\";\nimport { compareVersions, getCurrentVersionAsync, getCurrentVersionSync, saveVersionCache } from \"./version.js\";\nimport { extractZipFileToDir } from \"./zipx.js\";\n\n// \u72EC\u7ACB\u5165\u53E3:source = \"updater\",\u4E0E bds-manager \u7684 \"bds-tools\" \u533A\u5206;\u540C\u843D\u76D8 bds-update.log\nconst log = createNodeServiceLogger({ source: \"updater\", logPath: LOG_PATH });\nconst closeLog = (): void => log.close();\n\nfunction parseArgs(argv: string[]): Record<string, string | boolean> {\n const out: Record<string, string | boolean> = {};\n for (const a of argv) {\n const m = a.match(/^--([\\w-]+)(?:=(.+))?$/);\n if (m) out[m[1]!] = m[2] || true;\n }\n return out;\n}\n\ninterface UpdateContext {\n cfg: ReturnType<typeof loadConfig>;\n channel: \"release\" | \"preview\" | string;\n checkOnly: boolean;\n force: boolean;\n bdsPath: string;\n backupDir: string;\n preserve: string[];\n autoRestart: boolean;\n qqNotify: boolean;\n}\n\nfunction buildContext(): UpdateContext {\n const cfg = loadConfig();\n const args = parseArgs(process.argv.slice(2));\n const { bds_path, backup_dir, preserve } = resolvePaths(cfg);\n const channel = String(args[\"channel\"] || cfg.channel || \"release\");\n return {\n cfg,\n channel,\n checkOnly: !!args[\"check-only\"],\n force: !!args[\"force\"],\n bdsPath: bds_path,\n backupDir: backup_dir,\n preserve,\n autoRestart: !args[\"no-start\"] && cfg.auto_restart !== false,\n qqNotify: !!cfg.qq_notify,\n };\n}\n\nasync function doBackup(\n bdsPath: string,\n backupDir: string,\n preserve: string[]\n): Promise<{ path: string; size: number }> {\n const dateStr = new Date().toISOString().slice(0, 10);\n const dest = path.join(backupDir, dateStr);\n fs.mkdirSync(dest, { recursive: true });\n\n let anyCopied = false;\n for (const item of preserve) {\n const src = path.join(bdsPath, item);\n const target = path.join(dest, item);\n if (!fs.existsSync(src)) continue;\n fs.mkdirSync(path.dirname(target), { recursive: true });\n if (fs.statSync(src).isDirectory()) copyDirSync(src, target);\n else fs.copyFileSync(src, target);\n anyCopied = true;\n log.info(`\u5DF2\u5907\u4EFD: ${item}`);\n }\n\n // \u5373\u4F7F\u5168\u90E8 preserve \u90FD\u8DF3\u8FC7\uFF0C\u4E5F\u8BA9\u76EE\u5F55\u5B58\u5728\u4EE5\u4FBF\u8BB0\u5F55\u65F6\u95F4\u6233\n if (!anyCopied) {\n log.info(`\u6CA1\u6709\u9700\u8981\u5907\u4EFD\u7684\u6587\u4EF6 (preserve \u5217\u8868\u4E3A\u7A7A\u6216\u5168\u90E8\u7F3A\u5931)`);\n }\n return { path: dest, size: getDirSize(dest) };\n}\n\n/** \u5F02\u6B65\u6062\u590D preserves \u4ECE\u5907\u4EFD\u5230 BDS \u8DEF\u5F84 */\nasync function restorePreserves(bdsPath: string, backupDir: string, preserve: string[]): Promise<void> {\n for (const item of preserve) {\n const src = path.join(backupDir, item);\n const dest = path.join(bdsPath, item);\n if (!fs.existsSync(src)) continue;\n try {\n if (fs.statSync(src).isDirectory()) {\n if (fs.existsSync(dest)) emptyDirSync(dest);\n copyDirSync(src, dest);\n } else {\n fs.mkdirSync(path.dirname(dest), { recursive: true });\n fs.copyFileSync(src, dest);\n }\n log.info(`\u5DF2\u6062\u590D: ${item}`);\n } catch (e) {\n log.warn(`\u6062\u590D\u5931\u8D25 ${item}: ${(e as Error).message}`);\n }\n }\n}\n\n/** \u628A zip \u89E3\u538B\u5230 destDir (\u8986\u76D6) \u2014 \u7ECF zipx \u5B89\u5168\u89E3\u538B */\nasync function extractZipToBds(zipPath: string, destDir: string): Promise<void> {\n // \u62BD\u51FA\u5230\u4E34\u65F6\u76EE\u5F55\uFF0C\u907F\u514D\u65E7\u5185\u5BB9\u5E72\u6270\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"bds-extract-\"));\n try {\n await extractZipFileToDir(zipPath, tmpDir);\n // \u628A\u4E34\u65F6\u76EE\u5F55\u91CC\u7684\u5185\u5BB9\u590D\u5236\u5230 BDS \u8DEF\u5F84\n for (const entry of fs.readdirSync(tmpDir)) {\n const srcPath = path.join(tmpDir, entry);\n const destPath = path.join(destDir, entry);\n if (fs.statSync(srcPath).isDirectory()) {\n if (fs.existsSync(destPath)) emptyDirSync(destPath);\n copyDirSync(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n } finally {\n rmSafe(tmpDir);\n }\n}\n\nexport async function runUpdate(): Promise<number> {\n const startTime = Date.now();\n const ctx = buildContext();\n const { cfg, channel, checkOnly, force, bdsPath, backupDir, preserve, autoRestart, qqNotify } = ctx;\n\n log.info(`===== \u5F00\u59CB\u68C0\u67E5\u66F4\u65B0 (${channel}) =====`);\n fs.mkdirSync(bdsPath, { recursive: true });\n fs.mkdirSync(backupDir, { recursive: true });\n\n // 1. \u5F53\u524D\u7248\u672C\n const exePath = bdsExePath(bdsPath);\n const currentVer = await getCurrentVersionAsync(exePath).catch(() => getCurrentVersionSync(exePath));\n log.info(`\u5F53\u524D\u7248\u672C: ${currentVer}`);\n\n // 2. \u83B7\u53D6\u6700\u65B0\u7248\u672C\n let latestVer: string;\n try {\n const info = await getVersionInfo(cfg, channel);\n latestVer = info.version;\n log.info(`\u6700\u65B0\u7248\u672C: ${latestVer}`);\n const cmp = compareVersions(latestVer, currentVer);\n if (cmp <= 0 && !force) {\n log.info(\"\u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0\");\n if (qqNotify) {\n await sendText(`\u2705 BDS \u5DF2\u662F\u6700\u65B0\u7248\u672C\\n\\n\u5F53\u524D: ${currentVer}\\n\u6700\u65B0: ${latestVer}`);\n }\n emitUpdateKv(\"CURRENT\", currentVer, log);\n emitUpdateKv(\"LATEST\", latestVer, log);\n emitUpdateResult(\"uptodate\", log);\n return 0;\n }\n } catch (e) {\n log.error(`\u83B7\u53D6\u7248\u672C\u4FE1\u606F\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u65E0\u6CD5\u83B7\u53D6\u7248\u672C\u4FE1\u606F: ${(e as Error).message}`);\n return 1;\n }\n\n // \u517C\u5BB9\u6027\u68C0\u67E5\n if (!force && !isVersionCompatible(cfg, latestVer)) {\n log.warn(`${latestVer} \u4E0D\u5728\u517C\u5BB9\u7248\u672C\u767D\u540D\u5355\u4E2D\uFF0C\u8DF3\u8FC7\u5347\u7EA7`);\n if (qqNotify) {\n await sendText(`\u26A0\uFE0F BDS ${latestVer} \u4E0D\u5728\u517C\u5BB9\u6027\u767D\u540D\u5355\uFF0C\u5DF2\u8DF3\u8FC7\u5347\u7EA7\u3002\u8BF7\u4EBA\u5DE5\u786E\u8BA4\u3002`);\n }\n emitUpdateResult(\"skipped\", log);\n return 2;\n }\n\n // 3. \u53D6\u4E0B\u8F7D\u94FE\u63A5\n let downloadUrls: string[];\n let hash: { sha1: string; sha256: string };\n try {\n const details = await fetchVersionDetails(cfg, channel, latestVer);\n downloadUrls = buildDownloadUrls(cfg, channel, latestVer, details);\n hash = { sha1: details.sha1, sha256: details.sha256 };\n } catch (e) {\n log.error(`\u83B7\u53D6\u4E0B\u8F7D\u8BE6\u60C5\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u4E0B\u8F7D\u8BE6\u60C5\u83B7\u53D6\u5931\u8D25: ${(e as Error).message}`);\n return 1;\n }\n\n if (checkOnly) {\n emitUpdateKv(\"CURRENT\", currentVer, log);\n emitUpdateKv(\"LATEST\", latestVer, log);\n emitUpdateKv(\"CHANNEL\", channel, log);\n emitUpdateKv(\"URLS\", String(downloadUrls.length), log);\n emitUpdateResult(\"check-only\", log);\n return 0;\n }\n\n log.info(`\u53D1\u73B0\u65B0\u7248\u672C: ${currentVer} \u2192 ${latestVer}`);\n\n // 4. QQ \u9884\u544A\n if (qqNotify) {\n await sendText(\n `\uD835\uDC0C\uD835\uDC22\uD835\uDC27\uD835\uDC1E\uD835\uDC1C\uD835\uDC2B\uD835\uDC1A\uD835\uDC1F\uD835\uDC2D \uD835\uDC01\uD835\uDC03\uD835\uDC12 \u66F4\u65B0\u901A\u77E5\\n\\n` +\n `\u68C0\u6D4B\u5230\u65B0\u7248\u672C\uFF01\\n\\n` +\n `\u5F53\u524D: ${currentVer}\\n` +\n `\u6700\u65B0: ${latestVer}\\n` +\n `\u9891\u9053: ${channel === \"preview\" ? \"\u9884\u89C8\u7248\" : \"\u6B63\u5F0F\u7248\"}\\n\\n` +\n `\u670D\u52A1\u5668\u5373\u5C06\u5F00\u59CB\u66F4\u65B0~ \u8BF7\u8010\u5FC3\u7B49\u5F85^(*\uFFE3(oo)\uFFE3)^`\n );\n const cl = await fetchChangelog(channel);\n if (cl) {\n const text = `\uD83D\uDCCB \u66F4\u65B0\u5185\u5BB9\u6982\u8981\\n\\n${cl.text.slice(0, 1500)}\\n\\n\u5B8C\u6574\u65E5\u5FD7: ${CHANGELOG_BASE}`;\n if (cl.imageBase64) await sendWithImage(text, cl.imageBase64);\n else await sendText(text);\n } else {\n await sendText(`\uD83D\uDCCB \u66F4\u65B0\u65E5\u5FD7: ${CHANGELOG_BASE}`);\n }\n }\n\n // 5. \u5907\u4EFD\n let backupInfo: { path: string; size: number };\n try {\n backupInfo = await doBackup(bdsPath, backupDir, preserve);\n log.info(`\u5907\u4EFD\u5B8C\u6210: ${backupInfo.path} (${(backupInfo.size / 1024 / 1024).toFixed(1)} MB)`);\n if (qqNotify) {\n await sendText(`\u2705 \u5907\u4EFD\u5B8C\u6210\\n\\n\u5927\u5C0F: ${(backupInfo.size / 1024 / 1024).toFixed(1)} MB\\n\u4F4D\u7F6E: ${backupInfo.path}`);\n }\n } catch (e) {\n log.error(`\u5907\u4EFD\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u5907\u4EFD\u5931\u8D25: ${(e as Error).message}\\n\u64CD\u4F5C\u5DF2\u4E2D\u6B62`);\n return 1;\n }\n\n // 6. \u5199\u56DE\u6EDA\u6807\u8BB0 (\u8DE8\u8FDB\u7A0B\u53EF\u6062\u590D)\n writeRollbackMarker({\n timestamp: Date.now(),\n bds_path: bdsPath,\n backup_dir: backupInfo.path,\n preserve,\n previous_version: currentVer,\n });\n\n // 7. \u505C\u670D\n const bds = createBdsManager({ detached: true });\n try {\n log.info(\"\u505C\u6B62 BDS \u670D\u52A1...\");\n await bds.stop();\n log.info(\"BDS \u5DF2\u505C\u6B62\");\n } catch (e) {\n log.warn(`BDS \u505C\u6B62\u5F02\u5E38: ${(e as Error).message}`);\n }\n\n // 8. \u4E0B\u8F7D (\u5168\u90E8\u5931\u8D25\u5219\u56DE\u6EDA)\n // \u7528 mkdtempSync \u521B\u5EFA\u4E34\u65F6 staging \u76EE\u5F55 - \u907F\u514D\u6C61\u67D3 SCRIPT_DIR\n const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), \"bds-update-\"));\n const zipPath = path.join(stagingDir, `bedrock-server-${latestVer}.zip`);\n let downloaded = false;\n try {\n log.info(`\u5F00\u59CB\u4E0B\u8F7D ${latestVer}...`);\n if (qqNotify) await sendText(`\uD83D\uDCE5 \u6B63\u5728\u4E0B\u8F7D BDS ${latestVer}...`);\n\n let lastErr: Error | null = null;\n const downloadTimeoutMs = (cfg.download_timeout ?? 120) * 1000;\n /* stderr \u88AB pipe \u65F6\u4E0D\u753B bar\uFF1B\u7528\u6587\u672C\u8FDB\u5EA6\u7ED9 sfmc REPL \u7B49\u7236\u8FDB\u7A0B */\n if (isTaskbarSupported() && process.stdout.isTTY) {\n log.info(\"\u68C0\u6D4B\u5230 Windows Terminal,\u4EFB\u52A1\u680F\u8FDB\u5EA6\u5DF2\u542F\u7528 (OSC 9;4)\");\n }\n for (const url of downloadUrls) {\n /* \u6BCF\u6B21\u5C1D\u8BD5\u65B0\u5EFA bar + binder\uFF0C\u907F\u514D\u5931\u8D25\u91CD\u8BD5\u65F6 started \u72B6\u6001\u6B8B\u7559\uFF08LSP\uFF09 */\n const progressBar = createTerminalProgress({\n stream: process.stderr,\n logger: (msg) => log.info(msg.startsWith(\"\u8FDB\u5EA6\") ? `\u4E0B\u8F7D${msg.slice(2)}` : msg),\n format: \"\u4E0B\u8F7D\u8FDB\u5EA6 | {bar} | {percentage}% | {value}/{total} MB | \u901F\u5EA6: {speed}\",\n });\n const onByteProgress = bindByteProgressToBar(progressBar, {\n speedSampleMs: 0,\n onProgress: (dl, total) => {\n const pct = total > 0 ? (dl / total) * 100 : 0;\n setTaskbarProgress(pct);\n },\n });\n try {\n setTaskbarProgress(0);\n await httpDownload(url, zipPath, {\n totalTimeoutMs: Math.max(downloadTimeoutMs, 600_000), // \u4E0D\u5C11\u4E8E 10 \u5206\u949F\n onProgress: onByteProgress,\n });\n if (progressBar.active) progressBar.stop();\n // \u4E0B\u8F7D\u5B8C\u6210,\u4EFB\u52A1\u680F\u6536\u5230 100% \u7EFF\u6761\u540E\u6E05\u6389\n setTaskbarProgress(100);\n clearTaskbarProgress();\n downloaded = true;\n lastErr = null;\n break;\n } catch (e) {\n if (progressBar.active) progressBar.stop();\n // \u4E0B\u8F7D\u5931\u8D25,\u4EFB\u52A1\u680F\u4EAE\u7EA2\n setTaskbarProgress(100, \"error\");\n clearTaskbarProgress();\n lastErr = e as Error;\n log.warn(`${url} \u4E0D\u53EF\u7528: ${lastErr.message}\uFF0C\u5C1D\u8BD5\u5907\u7528\u5730\u5740...`);\n }\n }\n if (!downloaded && lastErr) throw lastErr;\n\n const zipSizeMB = (fs.statSync(zipPath).size / 1024 / 1024).toFixed(1);\n log.info(`\u4E0B\u8F7D\u5B8C\u6210 (${zipSizeMB} MB)`);\n\n // \u6D41\u5F0F\u54C8\u5E0C\u6821\u9A8C\n if (hash.sha1 || hash.sha256) {\n const algo = hash.sha256 ? \"SHA256\" : \"SHA1\";\n log.info(`\u6821\u9A8C\u6587\u4EF6\u5B8C\u6574\u6027 (${algo})...`);\n const ok = await verifyFileHash(zipPath, hash.sha1, hash.sha256);\n if (!ok) throw new Error(`${algo} \u6821\u9A8C\u4E0D\u901A\u8FC7\uFF0C\u6587\u4EF6\u53EF\u80FD\u635F\u574F`);\n log.info(`${algo} \u6821\u9A8C\u901A\u8FC7`);\n }\n } catch (e) {\n log.error(`\u4E0B\u8F7D\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u4E0B\u8F7D\u5931\u8D25: ${(e as Error).message}\\nBDS \u5DF2\u505C\u6B62\uFF0C\u8BF7\u624B\u52A8\u6062\u590D`);\n // \u81EA\u52A8\u56DE\u6EDA\n rollbackFromBackup({\n timestamp: Date.now(),\n bds_path: bdsPath,\n backup_dir: backupInfo.path,\n preserve,\n previous_version: currentVer,\n });\n rmSafe(stagingDir);\n return 1;\n }\n\n // 9. \u89E3\u538B + \u90E8\u7F72\n try {\n log.info(\"\u89E3\u538B\u4E2D...\");\n // \u5148\u6E05\u7A7A BDS \u76EE\u5F55\n emptyDirSync(bdsPath);\n await extractZipToBds(zipPath, bdsPath);\n ensureBdsExecutable(exePath);\n log.info(\"\u89E3\u538B\u5B8C\u6210\");\n } catch (e) {\n log.error(`\u89E3\u538B\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u89E3\u538B\u5931\u8D25: ${(e as Error).message}\\nBDS \u5DF2\u505C\u6B62\uFF0C\u8BF7\u624B\u52A8\u6062\u590D`);\n // \u56DE\u6EDA: \u6E05\u7A7A + \u4ECE\u5907\u4EFD\u6062\u590D preserves\n emptyDirSync(bdsPath);\n await restorePreserves(bdsPath, backupInfo.path, preserve);\n rmSafe(stagingDir);\n return 1;\n } finally {\n rmSafe(zipPath); // \u6E05\u6389 staging zip\n }\n\n // 10. \u5B8C\u6574\u6027\u68C0\u67E5 (\u907F\u514D\u89E3\u538B\u51FA\u7A7A/\u7F3A\u6587\u4EF6\u7684\u75C5\u6001\u5305)\n const verify = verifyBdsInstall(bdsPath, bdsInstallRequiredFiles());\n if (!verify.ok) {\n log.error(`\u89E3\u538B\u540E\u7684 BDS \u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5931\u6587\u4EF6: ${verify.missing.join(\", \")}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u90E8\u7F72\u540E\u7F3A\u5931\u5173\u952E\u6587\u4EF6: ${verify.missing.join(\", \")}`);\n emptyDirSync(bdsPath);\n await restorePreserves(bdsPath, backupInfo.path, preserve);\n rmSafe(stagingDir);\n return 1;\n }\n\n // 11. \u6062\u590D preserves (zip \u89E3\u538B\u65F6\u8FD9\u4E9B\u76EE\u5F55\u53EF\u80FD\u88AB\u8986\u76D6)\n await restorePreserves(bdsPath, backupInfo.path, preserve);\n\n // 11b. \u5B89\u88C5\u6536\u5C3E\uFF1A\u56E0 EULA \u5DF2\u540C\u610F\uFF0C\u786E\u4FDD\u9065\u6D4B\u5F00\u5173\uFF08\u5DF2\u6709\u5219\u8DF3\u8FC7\uFF09\n ensureEmitServerTelemetry(bdsPath, log);\n\n // 12. \u5199\u5165\u7248\u672C\u7F13\u5B58\n const newExeHash = await hashFileAsync(exePath, \"sha256\").catch(() => \"\");\n if (newExeHash) {\n saveVersionCache(latestVer, newExeHash);\n log.info(`\u5DF2\u8BB0\u5F55\u7248\u672C ${latestVer} \u7684 SHA256`);\n }\n\n // 13. \u542F\u52A8 BDS\n if (autoRestart) {\n try {\n log.info(\"\u542F\u52A8 BDS...\");\n await bds.start();\n } catch (e) {\n log.error(`\u542F\u52A8\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u542F\u52A8\u5931\u8D25: ${(e as Error).message}\\n\u8BF7\u624B\u52A8\u542F\u52A8 BDS`);\n // \u6CE8\u610F: \u6B64\u65F6 BDS \u5DF2\u7ECF\u90E8\u7F72\u5B8C\u6210\uFF0C\u542F\u52A8\u5931\u8D25 \u2192 \u542F\u52A8\u95EE\u9898\uFF0C\u4E0D\u505A\u6587\u4EF6\u7EA7\u56DE\u6EDA\n rmSafe(stagingDir);\n clearRollbackMarker();\n return 1;\n }\n }\n\n rmSafe(stagingDir);\n clearRollbackMarker();\n\n // 14. QQ \u901A\u77E5\u7ED3\u679C\n const durationMs = Date.now() - startTime;\n if (qqNotify) {\n await sendText(\n `\u2705 BDS \u66F4\u65B0\u5B8C\u6210\\n\\n` +\n `${currentVer} \u2192 ${latestVer}\\n` +\n `\u8017\u65F6: ${(durationMs / 1000).toFixed(1)}s\\n` +\n `${autoRestart ? \"\u670D\u52A1\u5668\u5DF2\u91CD\u65B0\u542F\u52A8\" : \"\u8BF7\u624B\u52A8\u91CD\u542F\u670D\u52A1\u5668\"}`\n );\n }\n log.info(`===== \u66F4\u65B0\u5B8C\u6210 (${(durationMs / 1000).toFixed(1)}s) =====`);\n /* \u673A\u5668\u53EF\u8BFB\u7ED3\u679C\u6807\u8BB0\uFF1A\u4F9B sfmc \u7B49\u76D1\u7763\u5668\u5224\u65AD\u300C\u771F\u6B63\u5B8C\u6210\u90E8\u7F72\u300D\uFF0C\u52FF\u4F9D\u8D56\u672C\u5730\u5316\u65E5\u5FD7\u6587\u6848\u3002 */\n emitUpdateResult(\"deployed\", log);\n return 0;\n}\n\nfunction isMain(): boolean {\n // sfmc supervisor \u901A\u8FC7 SFMC_SERVICE \u62C9\u8D77\u5B50\u8FDB\u7A0B\u65F6\u4F18\u5148\u5224\u5B9A\n if (process.env.SFMC_SERVICE === \"update\") return true;\n return isMainModule(import.meta.url);\n}\n\nif (isMain()) {\n runUpdate()\n .then((code) => {\n closeLog();\n process.exit(code);\n })\n .catch((e) => {\n log.error(`\u672A\u6355\u83B7\u9519\u8BEF: ${(e as Error).message}`);\n closeLog();\n process.exit(1);\n });\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * check-update.ts \u2014 BDS \u81EA\u52A8\u66F4\u65B0\u5668 (\u4E3B\u6D41\u7A0B)\n *\n * 1. \u4E34\u65F6 staging \u76EE\u5F55 (mkdtempSync) - \u907F\u514D\u6C61\u67D3\u6570\u636E\u6839\n * 2. \u4E0B\u8F7D/\u89E3\u538B\u5931\u8D25 \u2192 \u81EA\u52A8\u4ECE\u5907\u4EFD\u56DE\u6EDA preserves\n * 3. \u6D41\u5F0F SHA256 \u6821\u9A8C - \u4E0D\u628A 250MB \u6587\u4EF6\u8BFB\u5165\u5185\u5B58\n * 4. \u517C\u5BB9\u7248\u672C\u767D\u540D\u5355 - \u4E0D\u5339\u914D\u5219\u8DF3\u8FC7\u5347\u7EA7\n * 5. QQ \u901A\u77E5\u7EDF\u4E00\u52A0 5s \u8D85\u65F6 - \u6C38\u8FDC\u4E0D\u963B\u585E\u4E3B\u6D41\u7A0B\n * 6. Rollback marker \u843D\u76D8\u5230 <ROOT>/.sfmc/ - \u8DE8\u8FDB\u7A0B / \u8DE8\u91CD\u542F\u53EF\u6062\u590D\n */\n\nimport {\n bindByteProgressToBar,\n createNodeServiceLogger,\n createTerminalProgress,\n} from \"@sfmc-bds/sdk/logs\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { createBdsManager } from \"./bds-manager.js\";\nimport { CHANGELOG_BASE, fetchChangelog } from \"./changelog.js\";\nimport { copyDirSync, copyFileSyncSafe, emptyDirSync, hashFileAsync, rmSafe } from \"./fsx.js\";\nimport { bdsExePath, bdsInstallRequiredFiles, ensureBdsExecutable } from \"./host-platform.js\";\nimport { httpDownload } from \"./http.js\";\nimport { isMainModule } from \"./is-main.js\";\nimport { loadConfig, LOG_PATH, resolvePaths } from \"./paths.js\";\nimport { sendText, sendWithImage } from \"./qqutil.js\";\nimport {\n clearRollbackMarker,\n getDirSize,\n rollbackFromBackup,\n verifyBdsInstall,\n writeRollbackMarker,\n} from \"./rollback.js\";\nimport { ensureEmitServerTelemetry } from \"./server-properties.js\";\nimport { clearTaskbarProgress, isTaskbarSupported, setTaskbarProgress } from \"./taskbar.js\";\nimport { emitUpdateKv, emitUpdateResult } from \"./update-result.js\";\nimport {\n buildDownloadUrls,\n fetchVersionDetails,\n getVersionInfo,\n isVersionCompatible,\n verifyFileHash,\n} from \"./upstream.js\";\nimport { compareVersions, getCurrentVersionAsync, getCurrentVersionSync, saveVersionCache } from \"./version.js\";\nimport { extractZipFileToDir } from \"./zipx.js\";\n\n// \u72EC\u7ACB\u5165\u53E3:source = \"updater\",\u4E0E bds-manager \u7684 \"bds-tools\" \u533A\u5206;\u540C\u843D\u76D8 bds-update.log\nconst log = createNodeServiceLogger({ source: \"updater\", logPath: LOG_PATH });\nconst closeLog = (): void => log.close();\n\nfunction parseArgs(argv: string[]): Record<string, string | boolean> {\n const out: Record<string, string | boolean> = {};\n for (const a of argv) {\n const m = a.match(/^--([\\w-]+)(?:=(.+))?$/);\n if (m) out[m[1]!] = m[2] || true;\n }\n return out;\n}\n\ninterface UpdateContext {\n cfg: ReturnType<typeof loadConfig>;\n channel: \"release\" | \"preview\" | string;\n checkOnly: boolean;\n force: boolean;\n bdsPath: string;\n backupDir: string;\n preserve: string[];\n autoRestart: boolean;\n qqNotify: boolean;\n}\n\nfunction buildContext(): UpdateContext {\n const cfg = loadConfig();\n const args = parseArgs(process.argv.slice(2));\n const { bds_path, backup_dir, preserve } = resolvePaths(cfg);\n const channel = String(args[\"channel\"] || cfg.channel || \"release\");\n return {\n cfg,\n channel,\n checkOnly: !!args[\"check-only\"],\n force: !!args[\"force\"],\n bdsPath: bds_path,\n backupDir: backup_dir,\n preserve,\n autoRestart: !args[\"no-start\"] && cfg.auto_restart !== false,\n qqNotify: !!cfg.qq_notify,\n };\n}\n\nasync function doBackup(\n bdsPath: string,\n backupDir: string,\n preserve: string[]\n): Promise<{ path: string; size: number }> {\n const dateStr = new Date().toISOString().slice(0, 10);\n const dest = path.join(backupDir, dateStr);\n fs.mkdirSync(dest, { recursive: true });\n\n let anyCopied = false;\n for (const item of preserve) {\n const src = path.join(bdsPath, item);\n const target = path.join(dest, item);\n if (!fs.existsSync(src)) continue;\n fs.mkdirSync(path.dirname(target), { recursive: true });\n if (fs.statSync(src).isDirectory()) copyDirSync(src, target);\n else copyFileSyncSafe(src, target);\n anyCopied = true;\n log.info(`\u5DF2\u5907\u4EFD: ${item}`);\n }\n\n // \u5373\u4F7F\u5168\u90E8 preserve \u90FD\u8DF3\u8FC7\uFF0C\u4E5F\u8BA9\u76EE\u5F55\u5B58\u5728\u4EE5\u4FBF\u8BB0\u5F55\u65F6\u95F4\u6233\n if (!anyCopied) {\n log.info(`\u6CA1\u6709\u9700\u8981\u5907\u4EFD\u7684\u6587\u4EF6 (preserve \u5217\u8868\u4E3A\u7A7A\u6216\u5168\u90E8\u7F3A\u5931)`);\n }\n return { path: dest, size: getDirSize(dest) };\n}\n\n/** \u5F02\u6B65\u6062\u590D preserves \u4ECE\u5907\u4EFD\u5230 BDS \u8DEF\u5F84 */\nasync function restorePreserves(bdsPath: string, backupDir: string, preserve: string[]): Promise<void> {\n for (const item of preserve) {\n const src = path.join(backupDir, item);\n const dest = path.join(bdsPath, item);\n if (!fs.existsSync(src)) continue;\n try {\n if (fs.statSync(src).isDirectory()) {\n if (fs.existsSync(dest)) emptyDirSync(dest);\n copyDirSync(src, dest);\n } else {\n fs.mkdirSync(path.dirname(dest), { recursive: true });\n copyFileSyncSafe(src, dest);\n }\n log.info(`\u5DF2\u6062\u590D: ${item}`);\n } catch (e) {\n log.warn(`\u6062\u590D\u5931\u8D25 ${item}: ${(e as Error).message}`);\n }\n }\n}\n\n/** \u628A zip \u89E3\u538B\u5230 destDir (\u8986\u76D6) \u2014 \u7ECF zipx \u5B89\u5168\u89E3\u538B */\nasync function extractZipToBds(zipPath: string, destDir: string): Promise<void> {\n // \u62BD\u51FA\u5230\u4E34\u65F6\u76EE\u5F55\uFF0C\u907F\u514D\u65E7\u5185\u5BB9\u5E72\u6270\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"bds-extract-\"));\n try {\n await extractZipFileToDir(zipPath, tmpDir);\n // \u628A\u4E34\u65F6\u76EE\u5F55\u91CC\u7684\u5185\u5BB9\u590D\u5236\u5230 BDS \u8DEF\u5F84\n for (const entry of fs.readdirSync(tmpDir)) {\n const srcPath = path.join(tmpDir, entry);\n const destPath = path.join(destDir, entry);\n if (fs.statSync(srcPath).isDirectory()) {\n if (fs.existsSync(destPath)) emptyDirSync(destPath);\n copyDirSync(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n } finally {\n rmSafe(tmpDir);\n }\n}\n\nexport async function runUpdate(): Promise<number> {\n const startTime = Date.now();\n const ctx = buildContext();\n const { cfg, channel, checkOnly, force, bdsPath, backupDir, preserve, autoRestart, qqNotify } = ctx;\n\n log.info(`===== \u5F00\u59CB\u68C0\u67E5\u66F4\u65B0 (${channel}) =====`);\n fs.mkdirSync(bdsPath, { recursive: true });\n fs.mkdirSync(backupDir, { recursive: true });\n\n // 1. \u5F53\u524D\u7248\u672C\n const exePath = bdsExePath(bdsPath);\n const currentVer = await getCurrentVersionAsync(exePath).catch(() => getCurrentVersionSync(exePath));\n log.info(`\u5F53\u524D\u7248\u672C: ${currentVer}`);\n\n // 2. \u83B7\u53D6\u6700\u65B0\u7248\u672C\n let latestVer: string;\n try {\n const info = await getVersionInfo(cfg, channel);\n latestVer = info.version;\n log.info(`\u6700\u65B0\u7248\u672C: ${latestVer}`);\n const cmp = compareVersions(latestVer, currentVer);\n if (cmp <= 0 && !force) {\n log.info(\"\u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0\");\n if (qqNotify) {\n await sendText(`\u2705 BDS \u5DF2\u662F\u6700\u65B0\u7248\u672C\\n\\n\u5F53\u524D: ${currentVer}\\n\u6700\u65B0: ${latestVer}`);\n }\n emitUpdateKv(\"CURRENT\", currentVer, log);\n emitUpdateKv(\"LATEST\", latestVer, log);\n emitUpdateResult(\"uptodate\", log);\n return 0;\n }\n } catch (e) {\n log.error(`\u83B7\u53D6\u7248\u672C\u4FE1\u606F\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u65E0\u6CD5\u83B7\u53D6\u7248\u672C\u4FE1\u606F: ${(e as Error).message}`);\n return 1;\n }\n\n // \u517C\u5BB9\u6027\u68C0\u67E5\n if (!force && !isVersionCompatible(cfg, latestVer)) {\n log.warn(`${latestVer} \u4E0D\u5728\u517C\u5BB9\u7248\u672C\u767D\u540D\u5355\u4E2D\uFF0C\u8DF3\u8FC7\u5347\u7EA7`);\n if (qqNotify) {\n await sendText(`\u26A0\uFE0F BDS ${latestVer} \u4E0D\u5728\u517C\u5BB9\u6027\u767D\u540D\u5355\uFF0C\u5DF2\u8DF3\u8FC7\u5347\u7EA7\u3002\u8BF7\u4EBA\u5DE5\u786E\u8BA4\u3002`);\n }\n emitUpdateResult(\"skipped\", log);\n return 2;\n }\n\n // 3. \u53D6\u4E0B\u8F7D\u94FE\u63A5\n let downloadUrls: string[];\n let hash: { sha1: string; sha256: string };\n try {\n const details = await fetchVersionDetails(cfg, channel, latestVer);\n downloadUrls = buildDownloadUrls(cfg, channel, latestVer, details);\n hash = { sha1: details.sha1, sha256: details.sha256 };\n } catch (e) {\n log.error(`\u83B7\u53D6\u4E0B\u8F7D\u8BE6\u60C5\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u4E0B\u8F7D\u8BE6\u60C5\u83B7\u53D6\u5931\u8D25: ${(e as Error).message}`);\n return 1;\n }\n\n if (checkOnly) {\n emitUpdateKv(\"CURRENT\", currentVer, log);\n emitUpdateKv(\"LATEST\", latestVer, log);\n emitUpdateKv(\"CHANNEL\", channel, log);\n emitUpdateKv(\"URLS\", String(downloadUrls.length), log);\n emitUpdateResult(\"check-only\", log);\n return 0;\n }\n\n log.info(`\u53D1\u73B0\u65B0\u7248\u672C: ${currentVer} \u2192 ${latestVer}`);\n\n // 4. QQ \u9884\u544A\n if (qqNotify) {\n await sendText(\n `\uD835\uDC0C\uD835\uDC22\uD835\uDC27\uD835\uDC1E\uD835\uDC1C\uD835\uDC2B\uD835\uDC1A\uD835\uDC1F\uD835\uDC2D \uD835\uDC01\uD835\uDC03\uD835\uDC12 \u66F4\u65B0\u901A\u77E5\\n\\n` +\n `\u68C0\u6D4B\u5230\u65B0\u7248\u672C\uFF01\\n\\n` +\n `\u5F53\u524D: ${currentVer}\\n` +\n `\u6700\u65B0: ${latestVer}\\n` +\n `\u9891\u9053: ${channel === \"preview\" ? \"\u9884\u89C8\u7248\" : \"\u6B63\u5F0F\u7248\"}\\n\\n` +\n `\u670D\u52A1\u5668\u5373\u5C06\u5F00\u59CB\u66F4\u65B0~ \u8BF7\u8010\u5FC3\u7B49\u5F85^(*\uFFE3(oo)\uFFE3)^`\n );\n const cl = await fetchChangelog(channel);\n if (cl) {\n const text = `\uD83D\uDCCB \u66F4\u65B0\u5185\u5BB9\u6982\u8981\\n\\n${cl.text.slice(0, 1500)}\\n\\n\u5B8C\u6574\u65E5\u5FD7: ${CHANGELOG_BASE}`;\n if (cl.imageBase64) await sendWithImage(text, cl.imageBase64);\n else await sendText(text);\n } else {\n await sendText(`\uD83D\uDCCB \u66F4\u65B0\u65E5\u5FD7: ${CHANGELOG_BASE}`);\n }\n }\n\n // 5. \u5907\u4EFD\n let backupInfo: { path: string; size: number };\n try {\n backupInfo = await doBackup(bdsPath, backupDir, preserve);\n log.info(`\u5907\u4EFD\u5B8C\u6210: ${backupInfo.path} (${(backupInfo.size / 1024 / 1024).toFixed(1)} MB)`);\n if (qqNotify) {\n await sendText(`\u2705 \u5907\u4EFD\u5B8C\u6210\\n\\n\u5927\u5C0F: ${(backupInfo.size / 1024 / 1024).toFixed(1)} MB\\n\u4F4D\u7F6E: ${backupInfo.path}`);\n }\n } catch (e) {\n log.error(`\u5907\u4EFD\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u5907\u4EFD\u5931\u8D25: ${(e as Error).message}\\n\u64CD\u4F5C\u5DF2\u4E2D\u6B62`);\n return 1;\n }\n\n // 6. \u5199\u56DE\u6EDA\u6807\u8BB0 (\u8DE8\u8FDB\u7A0B\u53EF\u6062\u590D)\n writeRollbackMarker({\n timestamp: Date.now(),\n bds_path: bdsPath,\n backup_dir: backupInfo.path,\n preserve,\n previous_version: currentVer,\n });\n\n // 7. \u505C\u670D\n const bds = createBdsManager({ detached: true });\n try {\n log.info(\"\u505C\u6B62 BDS \u670D\u52A1...\");\n await bds.stop();\n log.info(\"BDS \u5DF2\u505C\u6B62\");\n } catch (e) {\n log.warn(`BDS \u505C\u6B62\u5F02\u5E38: ${(e as Error).message}`);\n }\n\n // 8. \u4E0B\u8F7D (\u5168\u90E8\u5931\u8D25\u5219\u56DE\u6EDA)\n // \u7528 mkdtempSync \u521B\u5EFA\u4E34\u65F6 staging \u76EE\u5F55 - \u907F\u514D\u6C61\u67D3 SCRIPT_DIR\n const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), \"bds-update-\"));\n const zipPath = path.join(stagingDir, `bedrock-server-${latestVer}.zip`);\n let downloaded = false;\n try {\n log.info(`\u5F00\u59CB\u4E0B\u8F7D ${latestVer}...`);\n if (qqNotify) await sendText(`\uD83D\uDCE5 \u6B63\u5728\u4E0B\u8F7D BDS ${latestVer}...`);\n\n let lastErr: Error | null = null;\n const downloadTimeoutMs = (cfg.download_timeout ?? 120) * 1000;\n /* stderr \u88AB pipe \u65F6\u4E0D\u753B bar\uFF1B\u7528\u6587\u672C\u8FDB\u5EA6\u7ED9 sfmc REPL \u7B49\u7236\u8FDB\u7A0B */\n if (isTaskbarSupported() && process.stdout.isTTY) {\n log.info(\"\u68C0\u6D4B\u5230 Windows Terminal,\u4EFB\u52A1\u680F\u8FDB\u5EA6\u5DF2\u542F\u7528 (OSC 9;4)\");\n }\n for (const url of downloadUrls) {\n /* \u6BCF\u6B21\u5C1D\u8BD5\u65B0\u5EFA bar + binder\uFF0C\u907F\u514D\u5931\u8D25\u91CD\u8BD5\u65F6 started \u72B6\u6001\u6B8B\u7559\uFF08LSP\uFF09 */\n const progressBar = createTerminalProgress({\n stream: process.stderr,\n logger: (msg) => log.info(msg.startsWith(\"\u8FDB\u5EA6\") ? `\u4E0B\u8F7D${msg.slice(2)}` : msg),\n format: \"\u4E0B\u8F7D\u8FDB\u5EA6 | {bar} | {percentage}% | {value}/{total} MB | \u901F\u5EA6: {speed}\",\n });\n const onByteProgress = bindByteProgressToBar(progressBar, {\n speedSampleMs: 0,\n onProgress: (dl, total) => {\n const pct = total > 0 ? (dl / total) * 100 : 0;\n setTaskbarProgress(pct);\n },\n });\n try {\n setTaskbarProgress(0);\n await httpDownload(url, zipPath, {\n totalTimeoutMs: Math.max(downloadTimeoutMs, 600_000), // \u4E0D\u5C11\u4E8E 10 \u5206\u949F\n onProgress: onByteProgress,\n });\n if (progressBar.active) progressBar.stop();\n // \u4E0B\u8F7D\u5B8C\u6210,\u4EFB\u52A1\u680F\u6536\u5230 100% \u7EFF\u6761\u540E\u6E05\u6389\n setTaskbarProgress(100);\n clearTaskbarProgress();\n downloaded = true;\n lastErr = null;\n break;\n } catch (e) {\n if (progressBar.active) progressBar.stop();\n // \u4E0B\u8F7D\u5931\u8D25,\u4EFB\u52A1\u680F\u4EAE\u7EA2\n setTaskbarProgress(100, \"error\");\n clearTaskbarProgress();\n lastErr = e as Error;\n log.warn(`${url} \u4E0D\u53EF\u7528: ${lastErr.message}\uFF0C\u5C1D\u8BD5\u5907\u7528\u5730\u5740...`);\n }\n }\n if (!downloaded && lastErr) throw lastErr;\n\n const zipSizeMB = (fs.statSync(zipPath).size / 1024 / 1024).toFixed(1);\n log.info(`\u4E0B\u8F7D\u5B8C\u6210 (${zipSizeMB} MB)`);\n\n // \u6D41\u5F0F\u54C8\u5E0C\u6821\u9A8C\n if (hash.sha1 || hash.sha256) {\n const algo = hash.sha256 ? \"SHA256\" : \"SHA1\";\n log.info(`\u6821\u9A8C\u6587\u4EF6\u5B8C\u6574\u6027 (${algo})...`);\n const ok = await verifyFileHash(zipPath, hash.sha1, hash.sha256);\n if (!ok) throw new Error(`${algo} \u6821\u9A8C\u4E0D\u901A\u8FC7\uFF0C\u6587\u4EF6\u53EF\u80FD\u635F\u574F`);\n log.info(`${algo} \u6821\u9A8C\u901A\u8FC7`);\n }\n } catch (e) {\n log.error(`\u4E0B\u8F7D\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u4E0B\u8F7D\u5931\u8D25: ${(e as Error).message}\\nBDS \u5DF2\u505C\u6B62\uFF0C\u8BF7\u624B\u52A8\u6062\u590D`);\n // \u81EA\u52A8\u56DE\u6EDA\n rollbackFromBackup({\n timestamp: Date.now(),\n bds_path: bdsPath,\n backup_dir: backupInfo.path,\n preserve,\n previous_version: currentVer,\n });\n rmSafe(stagingDir);\n return 1;\n }\n\n // 9. \u89E3\u538B + \u90E8\u7F72\n try {\n log.info(\"\u89E3\u538B\u4E2D...\");\n // \u5148\u6E05\u7A7A BDS \u76EE\u5F55\n emptyDirSync(bdsPath);\n await extractZipToBds(zipPath, bdsPath);\n ensureBdsExecutable(exePath);\n log.info(\"\u89E3\u538B\u5B8C\u6210\");\n } catch (e) {\n log.error(`\u89E3\u538B\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u89E3\u538B\u5931\u8D25: ${(e as Error).message}\\nBDS \u5DF2\u505C\u6B62\uFF0C\u8BF7\u624B\u52A8\u6062\u590D`);\n // \u56DE\u6EDA: \u6E05\u7A7A + \u4ECE\u5907\u4EFD\u6062\u590D preserves\n emptyDirSync(bdsPath);\n await restorePreserves(bdsPath, backupInfo.path, preserve);\n rmSafe(stagingDir);\n return 1;\n } finally {\n rmSafe(zipPath); // \u6E05\u6389 staging zip\n }\n\n // 10. \u5B8C\u6574\u6027\u68C0\u67E5 (\u907F\u514D\u89E3\u538B\u51FA\u7A7A/\u7F3A\u6587\u4EF6\u7684\u75C5\u6001\u5305)\n const verify = verifyBdsInstall(bdsPath, bdsInstallRequiredFiles());\n if (!verify.ok) {\n log.error(`\u89E3\u538B\u540E\u7684 BDS \u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5931\u6587\u4EF6: ${verify.missing.join(\", \")}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u90E8\u7F72\u540E\u7F3A\u5931\u5173\u952E\u6587\u4EF6: ${verify.missing.join(\", \")}`);\n emptyDirSync(bdsPath);\n await restorePreserves(bdsPath, backupInfo.path, preserve);\n rmSafe(stagingDir);\n return 1;\n }\n\n // 11. \u6062\u590D preserves (zip \u89E3\u538B\u65F6\u8FD9\u4E9B\u76EE\u5F55\u53EF\u80FD\u88AB\u8986\u76D6)\n await restorePreserves(bdsPath, backupInfo.path, preserve);\n\n // 11b. \u5B89\u88C5\u6536\u5C3E\uFF1A\u56E0 EULA \u5DF2\u540C\u610F\uFF0C\u786E\u4FDD\u9065\u6D4B\u5F00\u5173\uFF08\u5DF2\u6709\u5219\u8DF3\u8FC7\uFF09\n ensureEmitServerTelemetry(bdsPath, log);\n\n // 12. \u5199\u5165\u7248\u672C\u7F13\u5B58\n const newExeHash = await hashFileAsync(exePath, \"sha256\").catch(() => \"\");\n if (newExeHash) {\n saveVersionCache(latestVer, newExeHash);\n log.info(`\u5DF2\u8BB0\u5F55\u7248\u672C ${latestVer} \u7684 SHA256`);\n }\n\n // 13. \u542F\u52A8 BDS\n if (autoRestart) {\n try {\n log.info(\"\u542F\u52A8 BDS...\");\n await bds.start();\n } catch (e) {\n log.error(`\u542F\u52A8\u5931\u8D25: ${(e as Error).message}`);\n await sendText(`\u274C BDS \u66F4\u65B0\u5931\u8D25\\n\\n\u542F\u52A8\u5931\u8D25: ${(e as Error).message}\\n\u8BF7\u624B\u52A8\u542F\u52A8 BDS`);\n // \u6CE8\u610F: \u6B64\u65F6 BDS \u5DF2\u7ECF\u90E8\u7F72\u5B8C\u6210\uFF0C\u542F\u52A8\u5931\u8D25 \u2192 \u542F\u52A8\u95EE\u9898\uFF0C\u4E0D\u505A\u6587\u4EF6\u7EA7\u56DE\u6EDA\n rmSafe(stagingDir);\n clearRollbackMarker();\n return 1;\n }\n }\n\n rmSafe(stagingDir);\n clearRollbackMarker();\n\n // 14. QQ \u901A\u77E5\u7ED3\u679C\n const durationMs = Date.now() - startTime;\n if (qqNotify) {\n await sendText(\n `\u2705 BDS \u66F4\u65B0\u5B8C\u6210\\n\\n` +\n `${currentVer} \u2192 ${latestVer}\\n` +\n `\u8017\u65F6: ${(durationMs / 1000).toFixed(1)}s\\n` +\n `${autoRestart ? \"\u670D\u52A1\u5668\u5DF2\u91CD\u65B0\u542F\u52A8\" : \"\u8BF7\u624B\u52A8\u91CD\u542F\u670D\u52A1\u5668\"}`\n );\n }\n log.info(`===== \u66F4\u65B0\u5B8C\u6210 (${(durationMs / 1000).toFixed(1)}s) =====`);\n /* \u673A\u5668\u53EF\u8BFB\u7ED3\u679C\u6807\u8BB0\uFF1A\u4F9B sfmc \u7B49\u76D1\u7763\u5668\u5224\u65AD\u300C\u771F\u6B63\u5B8C\u6210\u90E8\u7F72\u300D\uFF0C\u52FF\u4F9D\u8D56\u672C\u5730\u5316\u65E5\u5FD7\u6587\u6848\u3002 */\n emitUpdateResult(\"deployed\", log);\n return 0;\n}\n\nfunction isMain(): boolean {\n // sfmc supervisor \u901A\u8FC7 SFMC_SERVICE \u62C9\u8D77\u5B50\u8FDB\u7A0B\u65F6\u4F18\u5148\u5224\u5B9A\n if (process.env.SFMC_SERVICE === \"update\") return true;\n return isMainModule(import.meta.url);\n}\n\nif (isMain()) {\n runUpdate()\n .then((code) => {\n closeLog();\n process.exit(code);\n })\n .catch((e) => {\n log.error(`\u672A\u6355\u83B7\u9519\u8BEF: ${(e as Error).message}`);\n closeLog();\n process.exit(1);\n });\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/fsx.d.ts CHANGED
@@ -8,14 +8,22 @@
8
8
  export declare function hashFileAsync(filePath: string, algo?: "sha1" | "sha256"): Promise<string>;
9
9
  /** 同步版本(用于小文件) */
10
10
  export declare function hashFileSync(filePath: string, algo?: "sha1" | "sha256"): string;
11
- /** 同步流式拷贝单文件 (复制中) */
11
+ /** 排除无需备份/复制的仓库与系统垃圾元数据 */
12
+ export declare const DEFAULT_COPY_IGNORE: Set<string>;
13
+ /**
14
+ * Windows 兼容的安全单文件拷贝。
15
+ * 若目标文件已存在且处于只读状态(例如 git objects 属性为只读),先赋写权限并覆写,
16
+ * 并确保拷贝后的目标文件具有可写权限,避免后续重复备份报错。
17
+ */
18
+ export declare function copyFileSyncSafe(src: string, dest: string): void;
19
+ /** 同步流式拷贝单文件,目标只读时自动解除并覆写 */
12
20
  export declare function copyFileAsync(src: string, dest: string): Promise<void>;
13
- /** 同步目录复制 (递归) */
14
- export declare function copyDirSync(src: string, dest: string): void;
15
- /** 异步目录复制 (基于流) */
16
- export declare function copyDirAsync(src: string, dest: string): Promise<void>;
17
- /** 计算目录大小 (字节) */
18
- export declare function getDirSize(dir: string): number;
21
+ /** 同步目录复制 (递归),默认排除 .git / node_modules 等元数据 */
22
+ export declare function copyDirSync(src: string, dest: string, ignore?: Set<string>): void;
23
+ /** 异步目录复制 (基于流),默认排除 .git / node_modules 等元数据 */
24
+ export declare function copyDirAsync(src: string, dest: string, ignore?: Set<string>): Promise<void>;
25
+ /** 计算目录大小 (字节),默认排除 .git / node_modules 等元数据 */
26
+ export declare function getDirSize(dir: string, ignore?: Set<string>): number;
19
27
  /** 强制清空目录内容 (但保留目录本身) */
20
28
  export declare function emptyDirSync(dir: string): void;
21
29
  /** 安全删除整个目录 */
package/dist/fsx.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fsx.d.ts","sourceRoot":"","sources":["../src/fsx.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,QAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAUzG;AAED,kBAAkB;AAClB,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,QAAmB,GAAG,MAAM,CAQzF;AAED,sBAAsB;AACtB,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;AAED,kBAAkB;AAClB,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAW3D;AAED,mBAAmB;AACnB,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc3E;AAED,kBAAkB;AAClB,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAU9C;AAED,yBAAyB;AACzB,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAY9C;AAED,eAAe;AACf,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzC;AAED,iCAAiC;AACjC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,CAM7D"}
1
+ {"version":3,"file":"fsx.d.ts","sourceRoot":"","sources":["../src/fsx.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,QAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAUzG;AAED,kBAAkB;AAClB,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,QAAmB,GAAG,MAAM,CAQzF;AAED,2BAA2B;AAC3B,eAAO,MAAM,mBAAmB,aAQ9B,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAwBhE;AAED,6BAA6B;AAC7B,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB5E;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,GAAG,CAAC,MAAM,CAAuB,GACxC,IAAI,CAYN;AAED,iDAAiD;AACjD,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,GAAG,CAAC,MAAM,CAAuB,GACxC,OAAO,CAAC,IAAI,CAAC,CAef;AAED,gDAAgD;AAChD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,GAAG,CAAC,MAAM,CAAuB,GAAG,MAAM,CAWzF;AAED,yBAAyB;AACzB,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAY9C;AAED,eAAe;AACf,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzC;AAED,iCAAiC;AACjC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,CAM7D"}
package/dist/fsx.js CHANGED
@@ -22,42 +22,99 @@ function hashFileSync(filePath, algo = "sha256") {
22
22
  return "";
23
23
  }
24
24
  }
25
+ const DEFAULT_COPY_IGNORE = /* @__PURE__ */ new Set([
26
+ ".git",
27
+ ".svn",
28
+ ".hg",
29
+ "node_modules",
30
+ ".DS_Store",
31
+ "Thumbs.db",
32
+ "desktop.ini"
33
+ ]);
34
+ function copyFileSyncSafe(src, dest) {
35
+ try {
36
+ fs.copyFileSync(src, dest);
37
+ } catch (err) {
38
+ const code = err?.code;
39
+ if (code === "EPERM" || code === "EACCES") {
40
+ try {
41
+ if (fs.existsSync(dest)) {
42
+ fs.chmodSync(dest, 438);
43
+ fs.unlinkSync(dest);
44
+ }
45
+ fs.copyFileSync(src, dest);
46
+ } catch {
47
+ throw err;
48
+ }
49
+ } else {
50
+ throw err;
51
+ }
52
+ }
53
+ try {
54
+ fs.chmodSync(dest, 438);
55
+ } catch {
56
+ }
57
+ }
25
58
  async function copyFileAsync(src, dest) {
26
- await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));
59
+ try {
60
+ await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));
61
+ } catch (err) {
62
+ const code = err?.code;
63
+ if (code === "EPERM" || code === "EACCES") {
64
+ try {
65
+ if (fs.existsSync(dest)) {
66
+ fs.chmodSync(dest, 438);
67
+ fs.unlinkSync(dest);
68
+ }
69
+ await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));
70
+ } catch {
71
+ throw err;
72
+ }
73
+ } else {
74
+ throw err;
75
+ }
76
+ }
77
+ try {
78
+ fs.chmodSync(dest, 438);
79
+ } catch {
80
+ }
27
81
  }
28
- function copyDirSync(src, dest) {
82
+ function copyDirSync(src, dest, ignore = DEFAULT_COPY_IGNORE) {
29
83
  fs.mkdirSync(dest, { recursive: true });
30
84
  for (const entry of fs.readdirSync(src)) {
85
+ if (ignore.has(entry)) continue;
31
86
  const srcPath = path.join(src, entry);
32
87
  const destPath = path.join(dest, entry);
33
88
  if (fs.statSync(srcPath).isDirectory()) {
34
- copyDirSync(srcPath, destPath);
89
+ copyDirSync(srcPath, destPath, ignore);
35
90
  } else {
36
- fs.copyFileSync(srcPath, destPath);
91
+ copyFileSyncSafe(srcPath, destPath);
37
92
  }
38
93
  }
39
94
  }
40
- async function copyDirAsync(src, dest) {
95
+ async function copyDirAsync(src, dest, ignore = DEFAULT_COPY_IGNORE) {
41
96
  fs.mkdirSync(dest, { recursive: true });
42
97
  await Promise.all(
43
98
  fs.readdirSync(src).map(async (entry) => {
99
+ if (ignore.has(entry)) return;
44
100
  const srcPath = path.join(src, entry);
45
101
  const destPath = path.join(dest, entry);
46
102
  const stat = fs.statSync(srcPath);
47
103
  if (stat.isDirectory()) {
48
- await copyDirAsync(srcPath, destPath);
104
+ await copyDirAsync(srcPath, destPath, ignore);
49
105
  } else {
50
106
  await copyFileAsync(srcPath, destPath);
51
107
  }
52
108
  })
53
109
  );
54
110
  }
55
- function getDirSize(dir) {
111
+ function getDirSize(dir, ignore = DEFAULT_COPY_IGNORE) {
56
112
  let total = 0;
57
113
  try {
58
114
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
115
+ if (ignore.has(entry.name)) continue;
59
116
  const full = path.join(dir, entry.name);
60
- if (entry.isDirectory()) total += getDirSize(full);
117
+ if (entry.isDirectory()) total += getDirSize(full, ignore);
61
118
  else if (entry.isFile()) total += fs.statSync(full).size;
62
119
  }
63
120
  } catch {
@@ -97,9 +154,11 @@ function readJsonFile(filePath) {
97
154
  return JSON.parse(text);
98
155
  }
99
156
  export {
157
+ DEFAULT_COPY_IGNORE,
100
158
  copyDirAsync,
101
159
  copyDirSync,
102
160
  copyFileAsync,
161
+ copyFileSyncSafe,
103
162
  emptyDirSync,
104
163
  getDirSize,
105
164
  hashFileAsync,
package/dist/fsx.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/fsx.ts"],
4
- "sourcesContent": ["/**\n * fsx.ts \u2014 \u5F02\u6B65/\u6D41\u5F0F\u6587\u4EF6\u64CD\u4F5C (\u907F\u514D\u5927\u6587\u4EF6\u52A0\u8F7D\u8FDB\u5185\u5B58)\n */\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\n\n/**\n * \u6D41\u5F0F\u8BA1\u7B97\u6587\u4EF6\u54C8\u5E0C (sha1 / sha256)\uFF0C\n * \u7528\u4E8E\u5927\u6587\u4EF6 (\u4F8B\u5982 BDS \u53EF\u6267\u884C\u6587\u4EF6 ~80MB)\uFF0C\u4E0D\u4F1A OOM\u3002\n */\nexport async function hashFileAsync(filePath: string, algo: \"sha1\" | \"sha256\" = \"sha256\"): Promise<string> {\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\", () => resolve(h.digest(\"hex\").toLowerCase()));\n stream.on(\"error\", reject);\n });\n}\n\n/** \u540C\u6B65\u7248\u672C\uFF08\u7528\u4E8E\u5C0F\u6587\u4EF6\uFF09 */\nexport function hashFileSync(filePath: string, algo: \"sha1\" | \"sha256\" = \"sha256\"): string {\n try {\n const h = crypto.createHash(algo);\n h.update(fs.readFileSync(filePath));\n return h.digest(\"hex\").toLowerCase();\n } catch {\n return \"\";\n }\n}\n\n/** \u540C\u6B65\u6D41\u5F0F\u62F7\u8D1D\u5355\u6587\u4EF6 (\u590D\u5236\u4E2D) */\nexport async function copyFileAsync(src: string, dest: string): Promise<void> {\n await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));\n}\n\n/** \u540C\u6B65\u76EE\u5F55\u590D\u5236 (\u9012\u5F52) */\nexport function copyDirSync(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src)) {\n const srcPath = path.join(src, entry);\n const destPath = path.join(dest, entry);\n if (fs.statSync(srcPath).isDirectory()) {\n copyDirSync(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\n/** \u5F02\u6B65\u76EE\u5F55\u590D\u5236 (\u57FA\u4E8E\u6D41) */\nexport async function copyDirAsync(src: string, dest: string): Promise<void> {\n fs.mkdirSync(dest, { recursive: true });\n await Promise.all(\n fs.readdirSync(src).map(async (entry) => {\n const srcPath = path.join(src, entry);\n const destPath = path.join(dest, entry);\n const stat = fs.statSync(srcPath);\n if (stat.isDirectory()) {\n await copyDirAsync(srcPath, destPath);\n } else {\n await copyFileAsync(srcPath, destPath);\n }\n })\n );\n}\n\n/** \u8BA1\u7B97\u76EE\u5F55\u5927\u5C0F (\u5B57\u8282) */\nexport function getDirSize(dir: string): number {\n let total = 0;\n try {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) total += getDirSize(full);\n else if (entry.isFile()) total += fs.statSync(full).size;\n }\n } catch {}\n return total;\n}\n\n/** \u5F3A\u5236\u6E05\u7A7A\u76EE\u5F55\u5185\u5BB9 (\u4F46\u4FDD\u7559\u76EE\u5F55\u672C\u8EAB) */\nexport function emptyDirSync(dir: string): void {\n if (!fs.existsSync(dir)) return;\n for (const entry of fs.readdirSync(dir)) {\n const full = path.join(dir, entry);\n try {\n const stat = fs.statSync(full);\n if (stat.isDirectory()) fs.rmSync(full, { recursive: true, force: true });\n else fs.unlinkSync(full);\n } catch (e) {\n // \u5FFD\u7565: \u9876\u5C42\u4ECD\u4FDD\u7559\u76EE\u5F55\uFF0C\u5373\u4F7F\u90E8\u5206\u5B50\u9879\u65E0\u6CD5\u5220\u9664\n }\n }\n}\n\n/** \u5B89\u5168\u5220\u9664\u6574\u4E2A\u76EE\u5F55 */\nexport function rmSafe(path: string): void {\n try {\n fs.rmSync(path, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n}\n\n/** \u5B89\u5168\u5199\u6587\u4EF6 (\u539F\u5B50: \u5199\u4E34\u65F6\u6587\u4EF6 \u2192 rename) */\nexport function writeFileSafe(filePath: string, data: string | Buffer): void {\n const dir = path.dirname(filePath);\n fs.mkdirSync(dir, { recursive: true });\n const tmp = `${filePath}.${process.pid}.tmp`;\n fs.writeFileSync(tmp, data);\n fs.renameSync(tmp, filePath);\n}\n\n/**\n * \u8BFB JSON \u6587\u4EF6\uFF08utf8\uFF09\u3002\n * \u82E5\u6587\u4EF6\u4EE5 UTF-8 BOM\uFF08U+FEFF\uFF09\u5F00\u5934\u5219\u5265\u79BB\u540E\u518D\u89E3\u6790\uFF08\u8BB0\u4E8B\u672C\u300CUTF-8 with BOM\u300D\uFF09\u3002\n */\nexport function readJsonFile<T = unknown>(filePath: string): T {\n let text = fs.readFileSync(filePath, \"utf8\");\n if (text.length > 0 && text.charCodeAt(0) === 0xfeff) {\n text = text.slice(1);\n }\n return JSON.parse(text) as T;\n}\n"],
5
- "mappings": "AAIA,OAAO,YAAY;AACnB,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,gBAAgB;AAMzB,eAAsB,cAAc,UAAkB,OAA0B,UAA2B;AACzG,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,IAAI,OAAO,WAAW,IAAI;AAChC,UAAM,SAAS,GAAG,iBAAiB,QAAQ;AAC3C,WAAO,GAAG,QAAQ,CAAC,UAA2B;AAC5C,QAAE,OAAO,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,IACjE,CAAC;AACD,WAAO,GAAG,OAAO,MAAM,QAAQ,EAAE,OAAO,KAAK,EAAE,YAAY,CAAC,CAAC;AAC7D,WAAO,GAAG,SAAS,MAAM;AAAA,EAC3B,CAAC;AACH;AAGO,SAAS,aAAa,UAAkB,OAA0B,UAAkB;AACzF,MAAI;AACF,UAAM,IAAI,OAAO,WAAW,IAAI;AAChC,MAAE,OAAO,GAAG,aAAa,QAAQ,CAAC;AAClC,WAAO,EAAE,OAAO,KAAK,EAAE,YAAY;AAAA,EACrC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,eAAsB,cAAc,KAAa,MAA6B;AAC5E,QAAM,SAAS,GAAG,iBAAiB,GAAG,GAAG,GAAG,kBAAkB,IAAI,CAAC;AACrE;AAGO,SAAS,YAAY,KAAa,MAAoB;AAC3D,KAAG,UAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACtC,aAAW,SAAS,GAAG,YAAY,GAAG,GAAG;AACvC,UAAM,UAAU,KAAK,KAAK,KAAK,KAAK;AACpC,UAAM,WAAW,KAAK,KAAK,MAAM,KAAK;AACtC,QAAI,GAAG,SAAS,OAAO,EAAE,YAAY,GAAG;AACtC,kBAAY,SAAS,QAAQ;AAAA,IAC/B,OAAO;AACL,SAAG,aAAa,SAAS,QAAQ;AAAA,IACnC;AAAA,EACF;AACF;AAGA,eAAsB,aAAa,KAAa,MAA6B;AAC3E,KAAG,UAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACtC,QAAM,QAAQ;AAAA,IACZ,GAAG,YAAY,GAAG,EAAE,IAAI,OAAO,UAAU;AACvC,YAAM,UAAU,KAAK,KAAK,KAAK,KAAK;AACpC,YAAM,WAAW,KAAK,KAAK,MAAM,KAAK;AACtC,YAAM,OAAO,GAAG,SAAS,OAAO;AAChC,UAAI,KAAK,YAAY,GAAG;AACtB,cAAM,aAAa,SAAS,QAAQ;AAAA,MACtC,OAAO;AACL,cAAM,cAAc,SAAS,QAAQ;AAAA,MACvC;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAGO,SAAS,WAAW,KAAqB;AAC9C,MAAI,QAAQ;AACZ,MAAI;AACF,eAAW,SAAS,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAChE,YAAM,OAAO,KAAK,KAAK,KAAK,MAAM,IAAI;AACtC,UAAI,MAAM,YAAY,EAAG,UAAS,WAAW,IAAI;AAAA,eACxC,MAAM,OAAO,EAAG,UAAS,GAAG,SAAS,IAAI,EAAE;AAAA,IACtD;AAAA,EACF,QAAQ;AAAA,EAAC;AACT,SAAO;AACT;AAGO,SAAS,aAAa,KAAmB;AAC9C,MAAI,CAAC,GAAG,WAAW,GAAG,EAAG;AACzB,aAAW,SAAS,GAAG,YAAY,GAAG,GAAG;AACvC,UAAM,OAAO,KAAK,KAAK,KAAK,KAAK;AACjC,QAAI;AACF,YAAM,OAAO,GAAG,SAAS,IAAI;AAC7B,UAAI,KAAK,YAAY,EAAG,IAAG,OAAO,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,UACnE,IAAG,WAAW,IAAI;AAAA,IACzB,SAAS,GAAG;AAAA,IAEZ;AAAA,EACF;AACF;AAGO,SAAS,OAAOA,OAAoB;AACzC,MAAI;AACF,OAAG,OAAOA,OAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EAClD,QAAQ;AAAA,EAER;AACF;AAGO,SAAS,cAAc,UAAkB,MAA6B;AAC3E,QAAM,MAAM,KAAK,QAAQ,QAAQ;AACjC,KAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACrC,QAAM,MAAM,GAAG,QAAQ,IAAI,QAAQ,GAAG;AACtC,KAAG,cAAc,KAAK,IAAI;AAC1B,KAAG,WAAW,KAAK,QAAQ;AAC7B;AAMO,SAAS,aAA0B,UAAqB;AAC7D,MAAI,OAAO,GAAG,aAAa,UAAU,MAAM;AAC3C,MAAI,KAAK,SAAS,KAAK,KAAK,WAAW,CAAC,MAAM,OAAQ;AACpD,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB;AACA,SAAO,KAAK,MAAM,IAAI;AACxB;",
4
+ "sourcesContent": ["/**\n * fsx.ts \u2014 \u5F02\u6B65/\u6D41\u5F0F\u6587\u4EF6\u64CD\u4F5C (\u907F\u514D\u5927\u6587\u4EF6\u52A0\u8F7D\u8FDB\u5185\u5B58)\n */\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\n\n/**\n * \u6D41\u5F0F\u8BA1\u7B97\u6587\u4EF6\u54C8\u5E0C (sha1 / sha256)\uFF0C\n * \u7528\u4E8E\u5927\u6587\u4EF6 (\u4F8B\u5982 BDS \u53EF\u6267\u884C\u6587\u4EF6 ~80MB)\uFF0C\u4E0D\u4F1A OOM\u3002\n */\nexport async function hashFileAsync(filePath: string, algo: \"sha1\" | \"sha256\" = \"sha256\"): Promise<string> {\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\", () => resolve(h.digest(\"hex\").toLowerCase()));\n stream.on(\"error\", reject);\n });\n}\n\n/** \u540C\u6B65\u7248\u672C\uFF08\u7528\u4E8E\u5C0F\u6587\u4EF6\uFF09 */\nexport function hashFileSync(filePath: string, algo: \"sha1\" | \"sha256\" = \"sha256\"): string {\n try {\n const h = crypto.createHash(algo);\n h.update(fs.readFileSync(filePath));\n return h.digest(\"hex\").toLowerCase();\n } catch {\n return \"\";\n }\n}\n\n/** \u6392\u9664\u65E0\u9700\u5907\u4EFD/\u590D\u5236\u7684\u4ED3\u5E93\u4E0E\u7CFB\u7EDF\u5783\u573E\u5143\u6570\u636E */\nexport const DEFAULT_COPY_IGNORE = new Set([\n \".git\",\n \".svn\",\n \".hg\",\n \"node_modules\",\n \".DS_Store\",\n \"Thumbs.db\",\n \"desktop.ini\",\n]);\n\n/**\n * Windows \u517C\u5BB9\u7684\u5B89\u5168\u5355\u6587\u4EF6\u62F7\u8D1D\u3002\n * \u82E5\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\u5728\u4E14\u5904\u4E8E\u53EA\u8BFB\u72B6\u6001\uFF08\u4F8B\u5982 git objects \u5C5E\u6027\u4E3A\u53EA\u8BFB\uFF09\uFF0C\u5148\u8D4B\u5199\u6743\u9650\u5E76\u8986\u5199\uFF0C\n * \u5E76\u786E\u4FDD\u62F7\u8D1D\u540E\u7684\u76EE\u6807\u6587\u4EF6\u5177\u6709\u53EF\u5199\u6743\u9650\uFF0C\u907F\u514D\u540E\u7EED\u91CD\u590D\u5907\u4EFD\u62A5\u9519\u3002\n */\nexport function copyFileSyncSafe(src: string, dest: string): void {\n try {\n fs.copyFileSync(src, dest);\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"EPERM\" || code === \"EACCES\") {\n try {\n if (fs.existsSync(dest)) {\n fs.chmodSync(dest, 0o666);\n fs.unlinkSync(dest);\n }\n fs.copyFileSync(src, dest);\n } catch {\n throw err;\n }\n } else {\n throw err;\n }\n }\n try {\n fs.chmodSync(dest, 0o666);\n } catch {\n /* ignore */\n }\n}\n\n/** \u540C\u6B65\u6D41\u5F0F\u62F7\u8D1D\u5355\u6587\u4EF6\uFF0C\u76EE\u6807\u53EA\u8BFB\u65F6\u81EA\u52A8\u89E3\u9664\u5E76\u8986\u5199 */\nexport async function copyFileAsync(src: string, dest: string): Promise<void> {\n try {\n await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"EPERM\" || code === \"EACCES\") {\n try {\n if (fs.existsSync(dest)) {\n fs.chmodSync(dest, 0o666);\n fs.unlinkSync(dest);\n }\n await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));\n } catch {\n throw err;\n }\n } else {\n throw err;\n }\n }\n try {\n fs.chmodSync(dest, 0o666);\n } catch {\n /* ignore */\n }\n}\n\n/** \u540C\u6B65\u76EE\u5F55\u590D\u5236 (\u9012\u5F52)\uFF0C\u9ED8\u8BA4\u6392\u9664 .git / node_modules \u7B49\u5143\u6570\u636E */\nexport function copyDirSync(\n src: string,\n dest: string,\n ignore: Set<string> = DEFAULT_COPY_IGNORE\n): void {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src)) {\n if (ignore.has(entry)) continue;\n const srcPath = path.join(src, entry);\n const destPath = path.join(dest, entry);\n if (fs.statSync(srcPath).isDirectory()) {\n copyDirSync(srcPath, destPath, ignore);\n } else {\n copyFileSyncSafe(srcPath, destPath);\n }\n }\n}\n\n/** \u5F02\u6B65\u76EE\u5F55\u590D\u5236 (\u57FA\u4E8E\u6D41)\uFF0C\u9ED8\u8BA4\u6392\u9664 .git / node_modules \u7B49\u5143\u6570\u636E */\nexport async function copyDirAsync(\n src: string,\n dest: string,\n ignore: Set<string> = DEFAULT_COPY_IGNORE\n): Promise<void> {\n fs.mkdirSync(dest, { recursive: true });\n await Promise.all(\n fs.readdirSync(src).map(async (entry) => {\n if (ignore.has(entry)) return;\n const srcPath = path.join(src, entry);\n const destPath = path.join(dest, entry);\n const stat = fs.statSync(srcPath);\n if (stat.isDirectory()) {\n await copyDirAsync(srcPath, destPath, ignore);\n } else {\n await copyFileAsync(srcPath, destPath);\n }\n })\n );\n}\n\n/** \u8BA1\u7B97\u76EE\u5F55\u5927\u5C0F (\u5B57\u8282)\uFF0C\u9ED8\u8BA4\u6392\u9664 .git / node_modules \u7B49\u5143\u6570\u636E */\nexport function getDirSize(dir: string, ignore: Set<string> = DEFAULT_COPY_IGNORE): number {\n let total = 0;\n try {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (ignore.has(entry.name)) continue;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) total += getDirSize(full, ignore);\n else if (entry.isFile()) total += fs.statSync(full).size;\n }\n } catch {}\n return total;\n}\n\n/** \u5F3A\u5236\u6E05\u7A7A\u76EE\u5F55\u5185\u5BB9 (\u4F46\u4FDD\u7559\u76EE\u5F55\u672C\u8EAB) */\nexport function emptyDirSync(dir: string): void {\n if (!fs.existsSync(dir)) return;\n for (const entry of fs.readdirSync(dir)) {\n const full = path.join(dir, entry);\n try {\n const stat = fs.statSync(full);\n if (stat.isDirectory()) fs.rmSync(full, { recursive: true, force: true });\n else fs.unlinkSync(full);\n } catch (e) {\n // \u5FFD\u7565: \u9876\u5C42\u4ECD\u4FDD\u7559\u76EE\u5F55\uFF0C\u5373\u4F7F\u90E8\u5206\u5B50\u9879\u65E0\u6CD5\u5220\u9664\n }\n }\n}\n\n/** \u5B89\u5168\u5220\u9664\u6574\u4E2A\u76EE\u5F55 */\nexport function rmSafe(path: string): void {\n try {\n fs.rmSync(path, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n}\n\n/** \u5B89\u5168\u5199\u6587\u4EF6 (\u539F\u5B50: \u5199\u4E34\u65F6\u6587\u4EF6 \u2192 rename) */\nexport function writeFileSafe(filePath: string, data: string | Buffer): void {\n const dir = path.dirname(filePath);\n fs.mkdirSync(dir, { recursive: true });\n const tmp = `${filePath}.${process.pid}.tmp`;\n fs.writeFileSync(tmp, data);\n fs.renameSync(tmp, filePath);\n}\n\n/**\n * \u8BFB JSON \u6587\u4EF6\uFF08utf8\uFF09\u3002\n * \u82E5\u6587\u4EF6\u4EE5 UTF-8 BOM\uFF08U+FEFF\uFF09\u5F00\u5934\u5219\u5265\u79BB\u540E\u518D\u89E3\u6790\uFF08\u8BB0\u4E8B\u672C\u300CUTF-8 with BOM\u300D\uFF09\u3002\n */\nexport function readJsonFile<T = unknown>(filePath: string): T {\n let text = fs.readFileSync(filePath, \"utf8\");\n if (text.length > 0 && text.charCodeAt(0) === 0xfeff) {\n text = text.slice(1);\n }\n return JSON.parse(text) as T;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["path"]
7
7
  }
@@ -0,0 +1,60 @@
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 { describe, it } from "node:test";
6
+ import { copyDirSync, copyFileSyncSafe, getDirSize, rmSafe } from "./fsx.js";
7
+ describe("fsx: copyDirSync & copyFileSyncSafe", () => {
8
+ it("copyDirSync \u81EA\u52A8\u5FFD\u7565 .git / node_modules \u7B49\u5143\u6570\u636E", () => {
9
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "sfmc-fsx-test-"));
10
+ try {
11
+ const src = path.join(tmp, "src");
12
+ const dest = path.join(tmp, "dest");
13
+ fs.mkdirSync(path.join(src, ".git", "objects"), { recursive: true });
14
+ fs.mkdirSync(path.join(src, "scripts"), { recursive: true });
15
+ fs.writeFileSync(path.join(src, ".git", "HEAD"), "ref: refs/heads/main\n");
16
+ fs.writeFileSync(path.join(src, "scripts", "main.js"), "console.log('hello');\n");
17
+ fs.writeFileSync(path.join(src, ".DS_Store"), "junk");
18
+ copyDirSync(src, dest);
19
+ assert.ok(fs.existsSync(path.join(dest, "scripts", "main.js")));
20
+ assert.ok(!fs.existsSync(path.join(dest, ".git")));
21
+ assert.ok(!fs.existsSync(path.join(dest, ".DS_Store")));
22
+ } finally {
23
+ rmSafe(tmp);
24
+ }
25
+ });
26
+ it("copyFileSyncSafe \u80FD\u591F\u5B89\u5168\u8986\u5199 Windows \u5E73\u53F0\u4E0B\u7684\u53EA\u8BFB\u53EA\u8BFB\u5C5E\u6027\u6587\u4EF6", () => {
27
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "sfmc-fsx-ro-"));
28
+ try {
29
+ const src = path.join(tmp, "src.txt");
30
+ const dest = path.join(tmp, "dest.txt");
31
+ fs.writeFileSync(src, "version 2");
32
+ fs.writeFileSync(dest, "version 1");
33
+ fs.chmodSync(dest, 292);
34
+ copyFileSyncSafe(src, dest);
35
+ assert.equal(fs.readFileSync(dest, "utf8"), "version 2");
36
+ fs.writeFileSync(src, "version 3");
37
+ copyFileSyncSafe(src, dest);
38
+ assert.equal(fs.readFileSync(dest, "utf8"), "version 3");
39
+ } finally {
40
+ try {
41
+ fs.chmodSync(path.join(tmp, "dest.txt"), 438);
42
+ } catch {
43
+ }
44
+ rmSafe(tmp);
45
+ }
46
+ });
47
+ it("getDirSize \u5FFD\u7565 .git \u76EE\u5F55\u5927\u5C0F", () => {
48
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "sfmc-fsx-size-"));
49
+ try {
50
+ fs.mkdirSync(path.join(tmp, ".git"), { recursive: true });
51
+ fs.writeFileSync(path.join(tmp, ".git", "pack"), "x".repeat(1e4));
52
+ fs.writeFileSync(path.join(tmp, "data.txt"), "hello");
53
+ const size = getDirSize(tmp);
54
+ assert.equal(size, 5);
55
+ } finally {
56
+ rmSafe(tmp);
57
+ }
58
+ });
59
+ });
60
+ //# sourceMappingURL=fsx.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/fsx.test.ts"],
4
+ "sourcesContent": ["import assert from \"node:assert/strict\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { describe, it } from \"node:test\";\nimport { copyDirSync, copyFileSyncSafe, getDirSize, rmSafe } from \"./fsx.js\";\n\ndescribe(\"fsx: copyDirSync & copyFileSyncSafe\", () => {\n it(\"copyDirSync \u81EA\u52A8\u5FFD\u7565 .git / node_modules \u7B49\u5143\u6570\u636E\", () => {\n const tmp = fs.mkdtempSync(path.join(os.tmpdir(), \"sfmc-fsx-test-\"));\n try {\n const src = path.join(tmp, \"src\");\n const dest = path.join(tmp, \"dest\");\n fs.mkdirSync(path.join(src, \".git\", \"objects\"), { recursive: true });\n fs.mkdirSync(path.join(src, \"scripts\"), { recursive: true });\n fs.writeFileSync(path.join(src, \".git\", \"HEAD\"), \"ref: refs/heads/main\\n\");\n fs.writeFileSync(path.join(src, \"scripts\", \"main.js\"), \"console.log('hello');\\n\");\n fs.writeFileSync(path.join(src, \".DS_Store\"), \"junk\");\n\n copyDirSync(src, dest);\n\n assert.ok(fs.existsSync(path.join(dest, \"scripts\", \"main.js\")));\n assert.ok(!fs.existsSync(path.join(dest, \".git\")));\n assert.ok(!fs.existsSync(path.join(dest, \".DS_Store\")));\n } finally {\n rmSafe(tmp);\n }\n });\n\n it(\"copyFileSyncSafe \u80FD\u591F\u5B89\u5168\u8986\u5199 Windows \u5E73\u53F0\u4E0B\u7684\u53EA\u8BFB\u53EA\u8BFB\u5C5E\u6027\u6587\u4EF6\", () => {\n const tmp = fs.mkdtempSync(path.join(os.tmpdir(), \"sfmc-fsx-ro-\"));\n try {\n const src = path.join(tmp, \"src.txt\");\n const dest = path.join(tmp, \"dest.txt\");\n fs.writeFileSync(src, \"version 2\");\n fs.writeFileSync(dest, \"version 1\");\n // \u8BBE\u7F6E\u76EE\u6807\u6587\u4EF6\u53EA\u8BFB (Windows 0444)\n fs.chmodSync(dest, 0o444);\n\n // copyFileSyncSafe \u5E94\u5F53\u6355\u83B7 EPERM \u5E76\u8986\u5199\u6210\u529F\uFF0C\u800C\u4E0D\u662F\u5D29\u6E83\n copyFileSyncSafe(src, dest);\n\n assert.equal(fs.readFileSync(dest, \"utf8\"), \"version 2\");\n\n // \u518D\u6B21\u8986\u5199\uFF0C\u786E\u4FDD\u4E0D\u4F1A\u9057\u7559\u53EA\u8BFB\u963B\u65AD\u4E0B\u4E00\u6B21\u5907\u4EFD\n fs.writeFileSync(src, \"version 3\");\n copyFileSyncSafe(src, dest);\n assert.equal(fs.readFileSync(dest, \"utf8\"), \"version 3\");\n } finally {\n try {\n fs.chmodSync(path.join(tmp, \"dest.txt\"), 0o666);\n } catch {}\n rmSafe(tmp);\n }\n });\n\n it(\"getDirSize \u5FFD\u7565 .git \u76EE\u5F55\u5927\u5C0F\", () => {\n const tmp = fs.mkdtempSync(path.join(os.tmpdir(), \"sfmc-fsx-size-\"));\n try {\n fs.mkdirSync(path.join(tmp, \".git\"), { recursive: true });\n fs.writeFileSync(path.join(tmp, \".git\", \"pack\"), \"x\".repeat(10000));\n fs.writeFileSync(path.join(tmp, \"data.txt\"), \"hello\");\n\n const size = getDirSize(tmp);\n assert.equal(size, 5);\n } finally {\n rmSafe(tmp);\n }\n });\n});\n"],
5
+ "mappings": "AAAA,OAAO,YAAY;AACnB,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,UAAU,UAAU;AAC7B,SAAS,aAAa,kBAAkB,YAAY,cAAc;AAElE,SAAS,uCAAuC,MAAM;AACpD,KAAG,qFAA6C,MAAM;AACpD,UAAM,MAAM,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,gBAAgB,CAAC;AACnE,QAAI;AACF,YAAM,MAAM,KAAK,KAAK,KAAK,KAAK;AAChC,YAAM,OAAO,KAAK,KAAK,KAAK,MAAM;AAClC,SAAG,UAAU,KAAK,KAAK,KAAK,QAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AACnE,SAAG,UAAU,KAAK,KAAK,KAAK,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAC3D,SAAG,cAAc,KAAK,KAAK,KAAK,QAAQ,MAAM,GAAG,wBAAwB;AACzE,SAAG,cAAc,KAAK,KAAK,KAAK,WAAW,SAAS,GAAG,yBAAyB;AAChF,SAAG,cAAc,KAAK,KAAK,KAAK,WAAW,GAAG,MAAM;AAEpD,kBAAY,KAAK,IAAI;AAErB,aAAO,GAAG,GAAG,WAAW,KAAK,KAAK,MAAM,WAAW,SAAS,CAAC,CAAC;AAC9D,aAAO,GAAG,CAAC,GAAG,WAAW,KAAK,KAAK,MAAM,MAAM,CAAC,CAAC;AACjD,aAAO,GAAG,CAAC,GAAG,WAAW,KAAK,KAAK,MAAM,WAAW,CAAC,CAAC;AAAA,IACxD,UAAE;AACA,aAAO,GAAG;AAAA,IACZ;AAAA,EACF,CAAC;AAED,KAAG,0IAAgD,MAAM;AACvD,UAAM,MAAM,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,cAAc,CAAC;AACjE,QAAI;AACF,YAAM,MAAM,KAAK,KAAK,KAAK,SAAS;AACpC,YAAM,OAAO,KAAK,KAAK,KAAK,UAAU;AACtC,SAAG,cAAc,KAAK,WAAW;AACjC,SAAG,cAAc,MAAM,WAAW;AAElC,SAAG,UAAU,MAAM,GAAK;AAGxB,uBAAiB,KAAK,IAAI;AAE1B,aAAO,MAAM,GAAG,aAAa,MAAM,MAAM,GAAG,WAAW;AAGvD,SAAG,cAAc,KAAK,WAAW;AACjC,uBAAiB,KAAK,IAAI;AAC1B,aAAO,MAAM,GAAG,aAAa,MAAM,MAAM,GAAG,WAAW;AAAA,IACzD,UAAE;AACA,UAAI;AACF,WAAG,UAAU,KAAK,KAAK,KAAK,UAAU,GAAG,GAAK;AAAA,MAChD,QAAQ;AAAA,MAAC;AACT,aAAO,GAAG;AAAA,IACZ;AAAA,EACF,CAAC;AAED,KAAG,yDAA2B,MAAM;AAClC,UAAM,MAAM,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,gBAAgB,CAAC;AACnE,QAAI;AACF,SAAG,UAAU,KAAK,KAAK,KAAK,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AACxD,SAAG,cAAc,KAAK,KAAK,KAAK,QAAQ,MAAM,GAAG,IAAI,OAAO,GAAK,CAAC;AAClE,SAAG,cAAc,KAAK,KAAK,KAAK,UAAU,GAAG,OAAO;AAEpD,YAAM,OAAO,WAAW,GAAG;AAC3B,aAAO,MAAM,MAAM,CAAC;AAAA,IACtB,UAAE;AACA,aAAO,GAAG;AAAA,IACZ;AAAA,EACF,CAAC;AACH,CAAC;",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../src/rollback.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAAe,UAAU,EAAgB,MAAM,UAAU,CAAC;AAGjE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,yBAAyB;AACzB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAOhE;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAM1C;AAED,wBAAgB,kBAAkB,IAAI,cAAc,GAAG,IAAI,CAE1D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA8B3F;AAED,mDAAmD;AACnD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAMzG;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../src/rollback.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAAiC,UAAU,EAAgB,MAAM,UAAU,CAAC;AAGnF,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,yBAAyB;AACzB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAOhE;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAM1C;AAED,wBAAgB,kBAAkB,IAAI,cAAc,GAAG,IAAI,CAE1D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA8B3F;AAED,mDAAmD;AACnD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAMzG;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
package/dist/rollback.js CHANGED
@@ -2,7 +2,7 @@ import { readJson, writeJson } from "@sfmc-bds/sdk/node/config";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { ROLLBACK_MARKER } from "./paths.js";
5
- import { copyDirSync, getDirSize, emptyDirSync } from "./fsx.js";
5
+ import { copyDirSync, copyFileSyncSafe, getDirSize, emptyDirSync } from "./fsx.js";
6
6
  import { log } from "./log.js";
7
7
  function writeRollbackMarker(marker) {
8
8
  try {
@@ -41,7 +41,7 @@ function rollbackFromBackup(marker) {
41
41
  if (fs.existsSync(dest)) emptyDirSync(dest);
42
42
  copyDirSync(src, dest);
43
43
  } else {
44
- fs.copyFileSync(src, dest);
44
+ copyFileSyncSafe(src, dest);
45
45
  }
46
46
  log.info(`[\u56DE\u6EDA] \u5DF2\u6062\u590D: ${item}`);
47
47
  } catch (e) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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;",
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, copyFileSyncSafe, 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 copyFileSyncSafe(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,kBAAkB,YAAY,oBAAoB;AACxE,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,yBAAiB,KAAK,IAAI;AAAA,MAC5B;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
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sfmc-bds/bds-tools",
3
- "version": "0.2.0-beta.10",
3
+ "version": "0.2.0-beta.11",
4
4
  "description": "SFMC BDS auto-updater, lifecycle manager, and behavior-pack assembler",
5
5
  "author": "Shiroha7z",
6
6
  "license": "AGPL-3.0-only",
@@ -50,10 +50,10 @@
50
50
  "dependencies": {
51
51
  "jszip": "^3.10.1",
52
52
  "node-html-parser": "^9.0.0",
53
- "@sfmc-bds/sdk": "0.2.0-beta.10"
53
+ "@sfmc-bds/sdk": "0.2.0-beta.11"
54
54
  },
55
55
  "devDependencies": {
56
- "@sfmc-bds/tools": "0.2.0-beta.11"
56
+ "@sfmc-bds/tools": "0.2.0-beta.12"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public",