@sfmc-bds/cli 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/logs.d.ts +21 -0
- package/dist/logs.d.ts.map +1 -1
- package/dist/logs.js +67 -1
- package/dist/logs.js.map +2 -2
- package/dist/management/domain.d.ts +46 -2
- package/dist/management/domain.d.ts.map +1 -1
- package/dist/management/domain.js +112 -26
- package/dist/management/domain.js.map +2 -2
- package/dist/management/maintenance.d.ts +8 -0
- package/dist/management/maintenance.d.ts.map +1 -1
- package/dist/management/maintenance.js +18 -0
- package/dist/management/maintenance.js.map +2 -2
- package/dist/management/pack-import.d.ts +29 -0
- package/dist/management/pack-import.d.ts.map +1 -0
- package/dist/management/pack-import.js +108 -0
- package/dist/management/pack-import.js.map +7 -0
- package/dist/management/server.d.ts.map +1 -1
- package/dist/management/server.js +67 -10
- package/dist/management/server.js.map +2 -2
- package/dist/registry.d.ts +11 -5
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +35 -11
- package/dist/registry.js.map +2 -2
- package/dist/world-packs.d.ts +47 -0
- package/dist/world-packs.d.ts.map +1 -1
- package/dist/world-packs.js +38 -11
- package/dist/world-packs.js.map +2 -2
- package/package.json +6 -6
- package/scripts/module-install/lib/registry-index.mjs +50 -13
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/management/domain.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { spawn } from \"node:child_process\";\nimport { resolveRegistryIndex } from \"../registry.js\";\nimport { ROOT, resolveFetchModule } from \"../runtime.js\";\nimport { resolveBdsContext, scanLocalModules } from \"../pack-lifecycle.js\";\nimport { listInstalledWorldPacks, resolvePackRoots, readPackManifestInfo, installPackDirectory, enableInstalledPack, disableInstalledPack, worldPackParentDir } from \"@sfmc-bds/bds-tools/world-packs\";\nimport { atomicJson } from \"./tasks.js\";\nimport { isRetiredPlatformModule } from \"@sfmc-bds/sdk/contracts\";\n\n/**\n * \u53BB\u6389 UTF-8 BOM\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u7F16\u8F91\u5668\u6216 BDS \u5199\u51FA\u7684 JSON\uFF08\u4F8B\u5982 configs/permissions.json\uFF09\u5E38\u5E26 BOM\uFF0C\u76F4\u63A5 JSON.parse \u4F1A\u5931\u8D25\u3002\n */\nexport function stripBom(text: string): string {\n return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n}\nexport function readJson<T>(file: string, fallback: T): T {\n try { return JSON.parse(stripBom(fs.readFileSync(file, \"utf8\"))) as T; }\n catch (error) { if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return fallback; throw error; }\n}\nexport function identifier(value: unknown): string {\n if (typeof value !== \"string\" || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(value) || value.includes(\"..\")) throw new Error(\"\u975E\u6CD5\u6807\u8BC6\u7B26\");\n return value;\n}\nexport async function listModules() {\n const rows = (await scanLocalModules()).filter(row => !isRetiredPlatformModule(row.logicalId));\n // \u76EE\u5F55\u91CC\u7684\u5C55\u793A\u540D\u6765\u81EA modules/catalog.json\uFF1B\u6CA1\u6709\u4E2D\u6587\u540D\u65F6\u4ECD\u7528\u903B\u8F91 id\uFF0C\u907F\u514D\u754C\u9762\u53EA\u5269\u6587\u4EF6\u5939\u540D\u3002\n const catalog = readJson<{ modules?: { id?: string; name?: string }[] }>(path.join(ROOT, \"modules\", \"catalog.json\"), {});\n const titles = new Map((catalog.modules ?? []).filter(row => row.id && row.name).map(row => [row.id!, row.name!]));\n return { modules: rows.map(row => ({ id: row.logicalId, folder: row.folderId, name: titles.get(row.logicalId) || row.logicalId, version: row.version ?? \"unknown\", enabled: row.enabled, linked: fs.lstatSync(path.join(ROOT, \"modules\", \"packages\", row.folderId)).isSymbolicLink() })) };\n}\nfunction fetchEntry() { const entry = resolveFetchModule(); if (!entry) throw new Error(\"\u627E\u4E0D\u5230\u6A21\u5757\u5B89\u88C5\u5668\"); return entry; }\nexport async function searchModules(query: string) {\n const result = await resolveRegistryIndex();\n return { modules: Object.entries(result.index).filter(([id]) => !isRetiredPlatformModule(id) && id.includes(query)).map(([id, metadata]) => ({ id, ...metadata })), stale: result.stale };\n}\nexport async function runFetch(args: string[]) {\n await runProcess(process.execPath, [fetchEntry(), ...args], ROOT);\n return { changed: true };\n}\nexport function runProcess(command: string, args: string[], cwd: string, onLine?: (text: string) => void): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, { cwd, env: { ...process.env, SFMC_ROOT: ROOT, FORCE_COLOR: \"0\" }, windowsHide: true, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let diagnostic = \"\";\n for (const stream of [child.stdout, child.stderr]) stream.on(\"data\", (chunk: Buffer) => { const text = chunk.toString(); diagnostic = (diagnostic + text).slice(-6000); onLine?.(text); });\n child.on(\"error\", reject); child.on(\"close\", code => code === 0 ? resolve() : reject(new Error(`\u5B50\u8FDB\u7A0B\u5931\u8D25 (${code}): ${diagnostic}`)));\n });\n}\nexport async function modulePlan(ids: string[] = []) {\n const url = pathToFileURL(path.join(path.dirname(fetchEntry()), \"lib\", \"module-update.mjs\")).href;\n const api = await import(url) as { planModuleUpdates: (options: { root: string; ids: string[] }) => Promise<unknown> };\n return api.planModuleUpdates({ root: ROOT, ids });\n}\nexport async function applyModulePlan(ids: string[]) {\n const directory = path.dirname(fetchEntry());\n const api = await import(pathToFileURL(path.join(directory, \"lib\", \"module-update.mjs\")).href) as {\n planModuleUpdates: (options: { root: string; ids: string[] }) => Promise<{ upgrades: { id: string; spec: string }[]; failMode: \"abort\" | \"continue\" }>;\n applyModuleUpgrades: (upgrades: unknown[], deps: object) => Promise<{ failed: { id: string; message: string }[] }>;\n resyncInstalledCatalog: (id: string) => void;\n };\n const fetchApi = await import(pathToFileURL(fetchEntry()).href) as { installPreservingLock: (id: string, spec: string) => Promise<void> };\n const plan = await api.planModuleUpdates({ root: ROOT, ids });\n const result = await api.applyModuleUpgrades(plan.upgrades, { root: ROOT, failMode: plan.failMode, install: fetchApi.installPreservingLock, resync: api.resyncInstalledCatalog });\n if (result.failed.length) throw new Error(JSON.stringify(result.failed));\n return result;\n}\nexport function listPacks() {\n const context = resolveBdsContext();\n return { packs: listInstalledWorldPacks(context.bdsRoot, context.levelName).map(pack => ({ id: pack.uuid, name: pack.name, kind: pack.kind, enabled: pack.enabled, version: pack.version.join(\".\") })) };\n}\nexport async function togglePack(id: string, enabled: boolean) {\n const context = resolveBdsContext();\n const pack = listInstalledWorldPacks(context.bdsRoot, context.levelName).find(row => row.uuid === id);\n if (!pack) throw new Error(\"\u627E\u4E0D\u5230\u4E16\u754C\u5305\");\n if (enabled) await enableInstalledPack({ ...context, info: { uuid: pack.uuid, version: pack.version, kind: pack.kind, name: pack.name } });\n else await disableInstalledPack({ ...context, kind: pack.kind, packUuid: pack.uuid, version: pack.version });\n return { changed: true, restartRequired: true };\n}\nexport async function importPack(filename: string) {\n const inbox = path.resolve(ROOT, \"packs\", \"_desktop-inbox\");\n const file = path.resolve(inbox, identifier(filename));\n if (!file.startsWith(inbox + path.sep) || !fs.existsSync(file)) throw new Error(\"\u4E16\u754C\u5305\u5C1A\u672A\u4E0A\u4F20\u5230\u5B9E\u4F8B\u6536\u4EF6\u7BB1\");\n const context = resolveBdsContext();\n const resolved = await resolvePackRoots(file);\n try {\n if (!resolved.roots.length) throw new Error(\"\u5F52\u6863\u4E0D\u542B\u53EF\u8BC6\u522B\u7684\u4E16\u754C\u5305\");\n for (const root of resolved.roots) {\n const info = readPackManifestInfo(root);\n if (!info) throw new Error(\"\u4E16\u754C\u5305 manifest \u65E0\u6548\");\n const result = await installPackDirectory({ srcDir: root, destParent: worldPackParentDir(context.bdsRoot, context.levelName, info.kind) });\n if (!result.ok) throw new Error(result.reason ?? \"\u5B89\u88C5\u5931\u8D25\uFF1B\u53EF\u80FD\u4E0E\u5DF2\u6709\u5305\u51B2\u7A81\");\n await enableInstalledPack({ ...context, info });\n }\n } finally { resolved.dispose?.(); }\n return { changed: true, restartRequired: true };\n}\nexport function playerFiles() {\n const bds = resolveBdsContext().bdsRoot;\n return { allowlist: path.join(bds, \"allowlist.json\"), permissions: path.join(bds, \"permissions.json\"), sfmcPermissions: path.join(ROOT, \"configs\", \"permissions.json\") };\n}\nexport function savePlayerPermissions(kind: string, entries: unknown) {\n const files = playerFiles();\n if (!(kind in files) || !Array.isArray(entries)) throw new Error(\"\u975E\u6CD5\u73A9\u5BB6\u6743\u9650\u7C7B\u578B\u6216\u5185\u5BB9\");\n for (const entry of entries) {\n if (!entry || typeof entry !== \"object\") throw new Error(\"\u6743\u9650\u6761\u76EE\u5FC5\u987B\u4E3A\u5BF9\u8C61\");\n const row = entry as Record<string, unknown>;\n if (kind === \"allowlist\" && (typeof row.name !== \"string\" || /[\\r\\n]/.test(row.name))) throw new Error(\"\u5141\u8BB8\u540D\u5355\u9700\u63D0\u4F9B\u5408\u6CD5\u73A9\u5BB6\u540D\u79F0\");\n if (kind === \"permissions\" && (typeof row.xuid !== \"string\" || !/^\\d+$/.test(row.xuid) || ![\"visitor\", \"member\", \"operator\"].includes(String(row.permission)))) throw new Error(\"BDS \u6743\u9650\u9700\u6709\u6548 XUID \u548C\u6743\u9650\u7B49\u7EA7\");\n if (kind === \"sfmcPermissions\" && (typeof row.player_name !== \"string\" || !row.player_name.trim() || /[\\r\\n\\0]/.test(row.player_name) || !Number.isInteger(row.level) || Number(row.level) < 0 || Number(row.level) > 3)) throw new Error(\"SFMC \u6743\u9650\u9700\u5408\u6CD5\u73A9\u5BB6\u540D\u53CA 0 \u5230 3 \u7684\u6574\u6570\u7B49\u7EA7\");\n }\n atomicJson(files[kind as keyof typeof files], entries);\n return { saved: true };\n}\n"],
|
|
5
|
-
"mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,aAAa;AACtB,SAAS,4BAA4B;AACrC,SAAS,MAAM,0BAA0B;AACzC,SAAS,mBAAmB,wBAAwB;AACpD,SAAS,yBAAyB,
|
|
4
|
+
"sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { spawn } from \"node:child_process\";\nimport { resolveRegistryIndex } from \"../registry.js\";\nimport { ROOT, resolveFetchModule } from \"../runtime.js\";\nimport { resolveBdsContext, scanLocalModules } from \"../pack-lifecycle.js\";\nimport { listInstalledWorldPacks, enableInstalledPack, disableInstalledPack, writePackHeaderVersion } from \"@sfmc-bds/bds-tools/world-packs\";\nimport { buildPackUninstallQueue, isProtectedSfmcPack, resolveUninstallTargets, runPackUninstallQueue } from \"../world-packs.js\";\nimport { atomicJson } from \"./tasks.js\";\nimport { assessModuleRequires, moduleRequireBlockMessage } from \"@sfmc-bds/management\";\nimport { isRetiredPlatformModule } from \"@sfmc-bds/sdk/contracts\";\n\n/**\n * \u53BB\u6389 UTF-8 BOM\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u7F16\u8F91\u5668\u6216 BDS \u5199\u51FA\u7684 JSON\uFF08\u4F8B\u5982 configs/permissions.json\uFF09\u5E38\u5E26 BOM\uFF0C\u76F4\u63A5 JSON.parse \u4F1A\u5931\u8D25\u3002\n */\nexport function stripBom(text: string): string {\n return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n}\nexport function readJson<T>(file: string, fallback: T): T {\n try { return JSON.parse(stripBom(fs.readFileSync(file, \"utf8\"))) as T; }\n catch (error) { if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return fallback; throw error; }\n}\nexport function identifier(value: unknown): string {\n if (typeof value !== \"string\" || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(value) || value.includes(\"..\")) throw new Error(\"\u975E\u6CD5\u6807\u8BC6\u7B26\");\n return value;\n}\nexport async function listModules() {\n const rows = (await scanLocalModules()).filter(row => !isRetiredPlatformModule(row.logicalId));\n // \u76EE\u5F55\u91CC\u7684\u5C55\u793A\u540D\u6765\u81EA modules/catalog.json\uFF1B\u6CA1\u6709\u4E2D\u6587\u540D\u65F6\u4ECD\u7528\u903B\u8F91 id\uFF0C\u907F\u514D\u754C\u9762\u53EA\u5269\u6587\u4EF6\u5939\u540D\u3002\n const catalog = readJson<{ modules?: { id?: string; name?: string }[] }>(path.join(ROOT, \"modules\", \"catalog.json\"), {});\n const titles = new Map((catalog.modules ?? []).filter(row => row.id && row.name).map(row => [row.id!, row.name!]));\n return { modules: rows.map(row => ({ id: row.logicalId, folder: row.folderId, name: titles.get(row.logicalId) || row.logicalId, version: row.version ?? \"unknown\", enabled: row.enabled, linked: fs.lstatSync(path.join(ROOT, \"modules\", \"packages\", row.folderId)).isSymbolicLink() })) };\n}\nfunction fetchEntry() { const entry = resolveFetchModule(); if (!entry) throw new Error(\"\u627E\u4E0D\u5230\u6A21\u5757\u5B89\u88C5\u5668\"); return entry; }\nexport async function searchModules(query: string) {\n let result = await resolveRegistryIndex();\n // \u65E7\u7F13\u5B58\u662F\u6309\u7CBE\u7B80\u5B57\u6BB5\u5199\u5165\u7684\uFF0C\u6CA1\u6709 requires\u3002\u5F3A\u5236\u5237\u65B0\u4E00\u6B21\uFF0C\u907F\u514D\u628A\u201C\u6CA1\u58F0\u660E\u201D\u548C\u201C\u7F13\u5B58\u592A\u65E7\u201D\u6DF7\u5728\u4E00\u8D77\u3002\n if (Object.values(result.index).some((entry) => !Array.isArray(entry.requires))) {\n result = await resolveRegistryIndex({ force: true });\n }\n const needle = query.trim().toLowerCase();\n return {\n modules: Object.entries(result.index).filter(([id, metadata]) => {\n if (isRetiredPlatformModule(id)) return false;\n if (!needle) return true;\n return [id, metadata.name, metadata.description, metadata.npm].some((value) => value?.toLowerCase().includes(needle));\n }).map(([id, metadata]) => ({ id, ...metadata })),\n stale: result.stale,\n };\n}\n\n/**\n * \u5B89\u88C5\u524D\u6838\u5BF9\u7D22\u5F15\u91CC\u7684 requires\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1Amodules.install \u5728\u521B\u5EFA\u4E0B\u8F7D\u4EFB\u52A1\u4E4B\u524D\u8C03\u7528\u3002\u7D22\u5F15\u6CA1\u6709\u8FD9\u4E2A id \u65F6\u8FD4\u56DE null\uFF0C\u7EE7\u7EED\u539F\u6765\u7684\u5B89\u88C5\u8DEF\u5F84\u3002\n * \u6709\u6761\u76EE\u4F46\u6CA1\u6709\u5408\u6CD5 requires\uFF0C\u6216\u4F9D\u8D56\u672A\u5B89\u88C5\u3001\u672A\u542F\u7528\u65F6\u8FD4\u56DE\u8BF4\u660E\uFF0C\u8C03\u7528\u65B9\u4E0D\u5F97\u5F00\u59CB\u5B89\u88C5\u3002\n */\nexport async function moduleInstallBlock(id: string): Promise<string | null> {\n let result = await resolveRegistryIndex();\n const cached = result.index[id];\n if (cached && !Array.isArray(cached.requires)) result = await resolveRegistryIndex({ force: true });\n const entry = result.index[id];\n if (!entry) return null;\n const installed = (await listModules()).modules;\n return moduleRequireBlockMessage(id, assessModuleRequires(entry.requires, installed));\n}\nexport async function runFetch(args: string[]) {\n await runProcess(process.execPath, [fetchEntry(), ...args], ROOT);\n return { changed: true };\n}\nexport function runProcess(command: string, args: string[], cwd: string, onLine?: (text: string) => void): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, { cwd, env: { ...process.env, SFMC_ROOT: ROOT, FORCE_COLOR: \"0\" }, windowsHide: true, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let diagnostic = \"\";\n for (const stream of [child.stdout, child.stderr]) stream.on(\"data\", (chunk: Buffer) => { const text = chunk.toString(); diagnostic = (diagnostic + text).slice(-6000); onLine?.(text); });\n child.on(\"error\", reject); child.on(\"close\", code => code === 0 ? resolve() : reject(new Error(`\u5B50\u8FDB\u7A0B\u5931\u8D25 (${code}): ${diagnostic}`)));\n });\n}\nexport async function modulePlan(ids: string[] = []) {\n const url = pathToFileURL(path.join(path.dirname(fetchEntry()), \"lib\", \"module-update.mjs\")).href;\n const api = await import(url) as { planModuleUpdates: (options: { root: string; ids: string[] }) => Promise<unknown> };\n return api.planModuleUpdates({ root: ROOT, ids });\n}\nexport async function applyModulePlan(ids: string[]) {\n const directory = path.dirname(fetchEntry());\n const api = await import(pathToFileURL(path.join(directory, \"lib\", \"module-update.mjs\")).href) as {\n planModuleUpdates: (options: { root: string; ids: string[] }) => Promise<{ upgrades: { id: string; spec: string }[]; failMode: \"abort\" | \"continue\" }>;\n applyModuleUpgrades: (upgrades: unknown[], deps: object) => Promise<{ failed: { id: string; message: string }[] }>;\n resyncInstalledCatalog: (id: string) => void;\n };\n const fetchApi = await import(pathToFileURL(fetchEntry()).href) as { installPreservingLock: (id: string, spec: string) => Promise<void> };\n const plan = await api.planModuleUpdates({ root: ROOT, ids });\n const result = await api.applyModuleUpgrades(plan.upgrades, { root: ROOT, failMode: plan.failMode, install: fetchApi.installPreservingLock, resync: api.resyncInstalledCatalog });\n if (result.failed.length) throw new Error(JSON.stringify(result.failed));\n return result;\n}\n/** pack_icon.png \u4E0A\u9650\u3002\u8D85\u8FC7\u5219\u4E0D\u63D0\u4F9B\u56FE\u6807\uFF0C\u907F\u514D\u628A\u8D85\u5927\u6587\u4EF6\u585E\u8FDB\u7BA1\u7406\u5E27\u3002 */\nconst PACK_ICON_MAX_BYTES = 1_572_864;\nconst PNG_MAGIC = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);\n\n/**\n * \u4E16\u754C\u5305\u6839\u76EE\u5F55\u91CC\u7684 pack_icon.png \u4FEE\u8BA2\u6807\u8BB0\uFF08size:mtime\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1Apacks.list \u544A\u8BC9\u684C\u9762\u7AEF\u8981\u4E0D\u8981\u518D\u62C9\u56FE\u6807\uFF0C\u4EE5\u53CA\u7F13\u5B58\u662F\u5426\u5931\u6548\u3002\n * \u7B26\u53F7\u94FE\u63A5\u3001\u7A7A\u6587\u4EF6\u548C\u8D85\u9650\u6587\u4EF6\u4E00\u5F8B\u89C6\u4E3A\u6CA1\u6709\u56FE\u6807\u3002\n */\nfunction packIconStamp(dir: string): string | null {\n const file = path.join(dir, \"pack_icon.png\");\n let stat: fs.Stats;\n try { stat = fs.lstatSync(file); } catch { return null; }\n if (!stat.isFile() || stat.isSymbolicLink() || stat.size <= 0 || stat.size > PACK_ICON_MAX_BYTES) return null;\n return `${stat.size}:${Math.trunc(stat.mtimeMs)}`;\n}\n\nexport function listPacks() {\n const context = resolveBdsContext();\n return { packs: listInstalledWorldPacks(context.bdsRoot, context.levelName).map(pack => {\n const iconStamp = packIconStamp(pack.dir);\n return {\n id: pack.uuid,\n name: pack.name,\n kind: pack.kind,\n enabled: pack.enabled,\n version: pack.version.join(\".\"),\n ...(iconStamp ? { iconStamp } : {}),\n ...(isProtectedSfmcPack(pack) ? { protected: true } : {}),\n };\n }) };\n}\n\n/**\n * \u8BFB\u53D6\u67D0\u4E2A\u5DF2\u5B89\u88C5\u4E16\u754C\u5305\u7684 pack_icon.png\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u684C\u9762\u4E16\u754C\u5305\u5217\u8868\u6309 iconStamp \u6309\u9700\u62C9\u53D6\uFF0C\u4E0D\u653E\u8FDB\u6BCF 5 \u79D2\u7684 packs.list\u3002\n * \u627E\u4E0D\u5230\u5305\u3001\u6587\u4EF6\u7F3A\u5931\u6216\u5185\u5BB9\u4E0D\u662F PNG \u65F6\u8FD4\u56DE\u7A7A\u56FE\u6807\uFF0C\u4E0D\u629B\u9519\u3002\n */\nexport function readPackIcon(id: string): { id: string; mime: \"image/png\" | null; data: string | null } {\n const empty: { id: string; mime: null; data: null } = { id, mime: null, data: null };\n const context = resolveBdsContext();\n const pack = listInstalledWorldPacks(context.bdsRoot, context.levelName).find(row => row.uuid.toLowerCase() === id.toLowerCase());\n if (!pack || !packIconStamp(pack.dir)) return empty;\n const file = path.join(pack.dir, \"pack_icon.png\");\n let data: Buffer;\n try { data = fs.readFileSync(file); } catch { return empty; }\n if (data.length < PNG_MAGIC.length || !data.subarray(0, PNG_MAGIC.length).equals(PNG_MAGIC) || data.length > PACK_ICON_MAX_BYTES) return empty;\n return { id: pack.uuid, mime: \"image/png\", data: data.toString(\"base64\") };\n}\n\n/**\n * \u5378\u8F7D\u4E00\u4E2A\u4E16\u754C\u5305\uFF0C\u5E76\u6CBF\u7528 CLI \u7684\u914D\u5BF9\u8D44\u6E90\u5305\u4E0E\u56DE\u6536\u7AD9\u89C4\u5219\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u684C\u9762 packs.uninstall\u3002\u5E73\u53F0\u805A\u5408\u5305\u76F4\u63A5\u62D2\u7EDD\u3002\n */\nexport async function uninstallPack(id: string) {\n const context = resolveBdsContext();\n const packs = listInstalledWorldPacks(context.bdsRoot, context.levelName);\n const resolved = resolveUninstallTargets(packs, [id]);\n if (resolved.status === \"not_found\") throw new Error(\"\u627E\u4E0D\u5230\u4E16\u754C\u5305\");\n if (resolved.status === \"protected\") throw new Error(\"\u5E73\u53F0\u805A\u5408\u5305\u4E0D\u53EF\u901A\u8FC7\u4E16\u754C\u5305\u5378\u8F7D\uFF0C\u8BF7\u4F7F\u7528\u6A21\u5757\u7BA1\u7406\");\n const queue = buildPackUninstallQueue(resolved.selected, packs, false);\n const removed = await runPackUninstallQueue(queue, { bdsRoot: context.bdsRoot, levelName: context.levelName, purge: false });\n return { changed: true, restartRequired: true, removed };\n}\n/**\n * \u89E3\u6790\u684C\u9762\u4F20\u5165\u7684\u8D44\u6E90\u5305\u7248\u672C\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1Apacks.version\u3002\u53EA\u63A5\u53D7 major.minor.patch\uFF0C\u6BCF\u4E00\u6BB5\u90FD\u662F\u975E\u8D1F\u5B89\u5168\u6574\u6570\u3002\n */\nexport function parsePackVersion(value: unknown): [number, number, number] {\n if (typeof value !== \"string\") throw new Error(\"\u7248\u672C\u53F7\u5FC5\u987B\u4E3A major.minor.patch\");\n const parts = value.split(\".\");\n if (parts.length !== 3) throw new Error(\"\u7248\u672C\u53F7\u5FC5\u987B\u4E3A major.minor.patch\");\n const numbers = parts.map((part) => {\n if (!/^\\d+$/.test(part)) throw new Error(\"\u7248\u672C\u53F7\u5FC5\u987B\u4E3A\u975E\u8D1F\u6574\u6570\");\n const number = Number(part);\n if (!Number.isSafeInteger(number)) throw new Error(\"\u7248\u672C\u53F7\u8D85\u51FA\u53EF\u7CBE\u786E\u8868\u793A\u7684\u6574\u6570\u8303\u56F4\");\n return number;\n });\n const major = numbers[0];\n const minor = numbers[1];\n const patch = numbers[2];\n if (major === undefined || minor === undefined || patch === undefined) throw new Error(\"\u7248\u672C\u53F7\u5FC5\u987B\u4E3A major.minor.patch\");\n return [major, minor, patch];\n}\n\n/**\n * \u4FEE\u6539\u4E00\u4E2A\u5DF2\u5B89\u88C5\u8D44\u6E90\u5305\u7684\u6E05\u5355\u7248\u672C\uFF0C\u5E76\u5728\u5DF2\u542F\u7528\u65F6\u540C\u6B65\u4E16\u754C\u542F\u7528\u5217\u8868\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u684C\u9762 packs.version\u3002\u884C\u4E3A\u5305\u76F4\u63A5\u62D2\u7EDD\u3002\n * \u6A21\u5757\u6761\u76EE\u5199\u6210\u4E0E header \u76F8\u540C\u7684\u5B8C\u6574\u7248\u672C\uFF1B\u547D\u4EE4\u884C packs bump \u4ECD\u53EA\u62AC\u4FEE\u8BA2\u53F7\u3002\n */\nexport async function setPackVersion(id: string, versionText: unknown) {\n const version = parsePackVersion(versionText);\n const context = resolveBdsContext();\n const pack = listInstalledWorldPacks(context.bdsRoot, context.levelName).find(row => row.uuid === id);\n if (!pack) throw new Error(\"\u627E\u4E0D\u5230\u4E16\u754C\u5305\");\n if (pack.kind !== \"resource\") throw new Error(\"\u53EA\u80FD\u4FEE\u6539\u8D44\u6E90\u5305\u7684\u7248\u672C\u53F7\");\n if (pack.version[0] === version[0] && pack.version[1] === version[1] && pack.version[2] === version[2]) {\n return { changed: false, restartRequired: false, version: pack.version.join(\".\") };\n }\n const next = writePackHeaderVersion(pack.dir, version, \"full\");\n if (pack.enabled) {\n await enableInstalledPack({ ...context, info: { uuid: pack.uuid, version: next, kind: \"resource\", name: pack.name } });\n }\n return { changed: true, restartRequired: true, version: next.join(\".\") };\n}\n\nexport async function togglePack(id: string, enabled: boolean) {\n const context = resolveBdsContext();\n const pack = listInstalledWorldPacks(context.bdsRoot, context.levelName).find(row => row.uuid === id);\n if (!pack) throw new Error(\"\u627E\u4E0D\u5230\u4E16\u754C\u5305\");\n if (enabled) await enableInstalledPack({ ...context, info: { uuid: pack.uuid, version: pack.version, kind: pack.kind, name: pack.name } });\n else await disableInstalledPack({ ...context, kind: pack.kind, packUuid: pack.uuid, version: pack.version });\n return { changed: true, restartRequired: true };\n}\nexport function playerFiles() {\n const bds = resolveBdsContext().bdsRoot;\n return { allowlist: path.join(bds, \"allowlist.json\"), permissions: path.join(bds, \"permissions.json\"), sfmcPermissions: path.join(ROOT, \"configs\", \"permissions.json\") };\n}\nexport function savePlayerPermissions(kind: string, entries: unknown) {\n const files = playerFiles();\n if (!(kind in files) || !Array.isArray(entries)) throw new Error(\"\u975E\u6CD5\u73A9\u5BB6\u6743\u9650\u7C7B\u578B\u6216\u5185\u5BB9\");\n for (const entry of entries) {\n if (!entry || typeof entry !== \"object\") throw new Error(\"\u6743\u9650\u6761\u76EE\u5FC5\u987B\u4E3A\u5BF9\u8C61\");\n const row = entry as Record<string, unknown>;\n if (kind === \"allowlist\" && (typeof row.name !== \"string\" || /[\\r\\n]/.test(row.name))) throw new Error(\"\u5141\u8BB8\u540D\u5355\u9700\u63D0\u4F9B\u5408\u6CD5\u73A9\u5BB6\u540D\u79F0\");\n if (kind === \"permissions\" && (typeof row.xuid !== \"string\" || !/^\\d+$/.test(row.xuid) || ![\"visitor\", \"member\", \"operator\"].includes(String(row.permission)))) throw new Error(\"BDS \u6743\u9650\u9700\u6709\u6548 XUID \u548C\u6743\u9650\u7B49\u7EA7\");\n if (kind === \"sfmcPermissions\" && (typeof row.player_name !== \"string\" || !row.player_name.trim() || /[\\r\\n\\0]/.test(row.player_name) || !Number.isInteger(row.level) || Number(row.level) < 0 || Number(row.level) > 3)) throw new Error(\"SFMC \u6743\u9650\u9700\u5408\u6CD5\u73A9\u5BB6\u540D\u53CA 0 \u5230 3 \u7684\u6574\u6570\u7B49\u7EA7\");\n }\n atomicJson(files[kind as keyof typeof files], entries);\n return { saved: true };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,aAAa;AACtB,SAAS,4BAA4B;AACrC,SAAS,MAAM,0BAA0B;AACzC,SAAS,mBAAmB,wBAAwB;AACpD,SAAS,yBAAyB,qBAAqB,sBAAsB,8BAA8B;AAC3G,SAAS,yBAAyB,qBAAqB,yBAAyB,6BAA6B;AAC7G,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB,iCAAiC;AAChE,SAAS,+BAA+B;AAMjC,SAAS,SAAS,MAAsB;AAC7C,SAAO,KAAK,WAAW,CAAC,MAAM,QAAS,KAAK,MAAM,CAAC,IAAI;AACzD;AACO,SAAS,SAAY,MAAc,UAAgB;AACxD,MAAI;AAAE,WAAO,KAAK,MAAM,SAAS,GAAG,aAAa,MAAM,MAAM,CAAC,CAAC;AAAA,EAAQ,SAChE,OAAO;AAAE,QAAK,MAAgC,SAAS,SAAU,QAAO;AAAU,UAAM;AAAA,EAAO;AACxG;AACO,SAAS,WAAW,OAAwB;AACjD,MAAI,OAAO,UAAU,YAAY,CAAC,qCAAqC,KAAK,KAAK,KAAK,MAAM,SAAS,IAAI,EAAG,OAAM,IAAI,MAAM,gCAAO;AACnI,SAAO;AACT;AACA,eAAsB,cAAc;AAClC,QAAM,QAAQ,MAAM,iBAAiB,GAAG,OAAO,SAAO,CAAC,wBAAwB,IAAI,SAAS,CAAC;AAE7F,QAAM,UAAU,SAAyD,KAAK,KAAK,MAAM,WAAW,cAAc,GAAG,CAAC,CAAC;AACvH,QAAM,SAAS,IAAI,KAAK,QAAQ,WAAW,CAAC,GAAG,OAAO,SAAO,IAAI,MAAM,IAAI,IAAI,EAAE,IAAI,SAAO,CAAC,IAAI,IAAK,IAAI,IAAK,CAAC,CAAC;AACjH,SAAO,EAAE,SAAS,KAAK,IAAI,UAAQ,EAAE,IAAI,IAAI,WAAW,QAAQ,IAAI,UAAU,MAAM,OAAO,IAAI,IAAI,SAAS,KAAK,IAAI,WAAW,SAAS,IAAI,WAAW,WAAW,SAAS,IAAI,SAAS,QAAQ,GAAG,UAAU,KAAK,KAAK,MAAM,WAAW,YAAY,IAAI,QAAQ,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE;AAC3R;AACA,SAAS,aAAa;AAAE,QAAM,QAAQ,mBAAmB;AAAG,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,kDAAU;AAAG,SAAO;AAAO;AACnH,eAAsB,cAAc,OAAe;AACjD,MAAI,SAAS,MAAM,qBAAqB;AAExC,MAAI,OAAO,OAAO,OAAO,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM,QAAQ,MAAM,QAAQ,CAAC,GAAG;AAC/E,aAAS,MAAM,qBAAqB,EAAE,OAAO,KAAK,CAAC;AAAA,EACrD;AACA,QAAM,SAAS,MAAM,KAAK,EAAE,YAAY;AACxC,SAAO;AAAA,IACL,SAAS,OAAO,QAAQ,OAAO,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,QAAQ,MAAM;AAC/D,UAAI,wBAAwB,EAAE,EAAG,QAAO;AACxC,UAAI,CAAC,OAAQ,QAAO;AACpB,aAAO,CAAC,IAAI,SAAS,MAAM,SAAS,aAAa,SAAS,GAAG,EAAE,KAAK,CAAC,UAAU,OAAO,YAAY,EAAE,SAAS,MAAM,CAAC;AAAA,IACtH,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,QAAQ,OAAO,EAAE,IAAI,GAAG,SAAS,EAAE;AAAA,IAChD,OAAO,OAAO;AAAA,EAChB;AACF;AAOA,eAAsB,mBAAmB,IAAoC;AAC3E,MAAI,SAAS,MAAM,qBAAqB;AACxC,QAAM,SAAS,OAAO,MAAM,EAAE;AAC9B,MAAI,UAAU,CAAC,MAAM,QAAQ,OAAO,QAAQ,EAAG,UAAS,MAAM,qBAAqB,EAAE,OAAO,KAAK,CAAC;AAClG,QAAM,QAAQ,OAAO,MAAM,EAAE;AAC7B,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,aAAa,MAAM,YAAY,GAAG;AACxC,SAAO,0BAA0B,IAAI,qBAAqB,MAAM,UAAU,SAAS,CAAC;AACtF;AACA,eAAsB,SAAS,MAAgB;AAC7C,QAAM,WAAW,QAAQ,UAAU,CAAC,WAAW,GAAG,GAAG,IAAI,GAAG,IAAI;AAChE,SAAO,EAAE,SAAS,KAAK;AACzB;AACO,SAAS,WAAW,SAAiB,MAAgB,KAAa,QAAgD;AACvH,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,QAAQ,MAAM,SAAS,MAAM,EAAE,KAAK,KAAK,EAAE,GAAG,QAAQ,KAAK,WAAW,MAAM,aAAa,IAAI,GAAG,aAAa,MAAM,OAAO,CAAC,UAAU,QAAQ,MAAM,EAAE,CAAC;AAC5J,QAAI,aAAa;AACjB,eAAW,UAAU,CAAC,MAAM,QAAQ,MAAM,MAAM,EAAG,QAAO,GAAG,QAAQ,CAAC,UAAkB;AAAE,YAAM,OAAO,MAAM,SAAS;AAAG,oBAAc,aAAa,MAAM,MAAM,IAAK;AAAG,eAAS,IAAI;AAAA,IAAG,CAAC;AACzL,UAAM,GAAG,SAAS,MAAM;AAAG,UAAM,GAAG,SAAS,UAAQ,SAAS,IAAI,QAAQ,IAAI,OAAO,IAAI,MAAM,mCAAU,IAAI,MAAM,UAAU,EAAE,CAAC,CAAC;AAAA,EACnI,CAAC;AACH;AACA,eAAsB,WAAW,MAAgB,CAAC,GAAG;AACnD,QAAM,MAAM,cAAc,KAAK,KAAK,KAAK,QAAQ,WAAW,CAAC,GAAG,OAAO,mBAAmB,CAAC,EAAE;AAC7F,QAAM,MAAM,MAAM,OAAO;AACzB,SAAO,IAAI,kBAAkB,EAAE,MAAM,MAAM,IAAI,CAAC;AAClD;AACA,eAAsB,gBAAgB,KAAe;AACnD,QAAM,YAAY,KAAK,QAAQ,WAAW,CAAC;AAC3C,QAAM,MAAM,MAAM,OAAO,cAAc,KAAK,KAAK,WAAW,OAAO,mBAAmB,CAAC,EAAE;AAKzF,QAAM,WAAW,MAAM,OAAO,cAAc,WAAW,CAAC,EAAE;AAC1D,QAAM,OAAO,MAAM,IAAI,kBAAkB,EAAE,MAAM,MAAM,IAAI,CAAC;AAC5D,QAAM,SAAS,MAAM,IAAI,oBAAoB,KAAK,UAAU,EAAE,MAAM,MAAM,UAAU,KAAK,UAAU,SAAS,SAAS,uBAAuB,QAAQ,IAAI,uBAAuB,CAAC;AAChL,MAAI,OAAO,OAAO,OAAQ,OAAM,IAAI,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC;AACvE,SAAO;AACT;AAEA,MAAM,sBAAsB;AAC5B,MAAM,YAAY,OAAO,KAAK,CAAC,KAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,EAAI,CAAC;AAO9E,SAAS,cAAc,KAA4B;AACjD,QAAM,OAAO,KAAK,KAAK,KAAK,eAAe;AAC3C,MAAI;AACJ,MAAI;AAAE,WAAO,GAAG,UAAU,IAAI;AAAA,EAAG,QAAQ;AAAE,WAAO;AAAA,EAAM;AACxD,MAAI,CAAC,KAAK,OAAO,KAAK,KAAK,eAAe,KAAK,KAAK,QAAQ,KAAK,KAAK,OAAO,oBAAqB,QAAO;AACzG,SAAO,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,KAAK,OAAO,CAAC;AACjD;AAEO,SAAS,YAAY;AAC1B,QAAM,UAAU,kBAAkB;AAClC,SAAO,EAAE,OAAO,wBAAwB,QAAQ,SAAS,QAAQ,SAAS,EAAE,IAAI,UAAQ;AACtF,UAAM,YAAY,cAAc,KAAK,GAAG;AACxC,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,SAAS,KAAK,QAAQ,KAAK,GAAG;AAAA,MAC9B,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACjC,GAAI,oBAAoB,IAAI,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,IACzD;AAAA,EACF,CAAC,EAAE;AACL;AAOO,SAAS,aAAa,IAA2E;AACtG,QAAM,QAAgD,EAAE,IAAI,MAAM,MAAM,MAAM,KAAK;AACnF,QAAM,UAAU,kBAAkB;AAClC,QAAM,OAAO,wBAAwB,QAAQ,SAAS,QAAQ,SAAS,EAAE,KAAK,SAAO,IAAI,KAAK,YAAY,MAAM,GAAG,YAAY,CAAC;AAChI,MAAI,CAAC,QAAQ,CAAC,cAAc,KAAK,GAAG,EAAG,QAAO;AAC9C,QAAM,OAAO,KAAK,KAAK,KAAK,KAAK,eAAe;AAChD,MAAI;AACJ,MAAI;AAAE,WAAO,GAAG,aAAa,IAAI;AAAA,EAAG,QAAQ;AAAE,WAAO;AAAA,EAAO;AAC5D,MAAI,KAAK,SAAS,UAAU,UAAU,CAAC,KAAK,SAAS,GAAG,UAAU,MAAM,EAAE,OAAO,SAAS,KAAK,KAAK,SAAS,oBAAqB,QAAO;AACzI,SAAO,EAAE,IAAI,KAAK,MAAM,MAAM,aAAa,MAAM,KAAK,SAAS,QAAQ,EAAE;AAC3E;AAMA,eAAsB,cAAc,IAAY;AAC9C,QAAM,UAAU,kBAAkB;AAClC,QAAM,QAAQ,wBAAwB,QAAQ,SAAS,QAAQ,SAAS;AACxE,QAAM,WAAW,wBAAwB,OAAO,CAAC,EAAE,CAAC;AACpD,MAAI,SAAS,WAAW,YAAa,OAAM,IAAI,MAAM,sCAAQ;AAC7D,MAAI,SAAS,WAAW,YAAa,OAAM,IAAI,MAAM,sIAAwB;AAC7E,QAAM,QAAQ,wBAAwB,SAAS,UAAU,OAAO,KAAK;AACrE,QAAM,UAAU,MAAM,sBAAsB,OAAO,EAAE,SAAS,QAAQ,SAAS,WAAW,QAAQ,WAAW,OAAO,MAAM,CAAC;AAC3H,SAAO,EAAE,SAAS,MAAM,iBAAiB,MAAM,QAAQ;AACzD;AAKO,SAAS,iBAAiB,OAA0C;AACzE,MAAI,OAAO,UAAU,SAAU,OAAM,IAAI,MAAM,wDAA0B;AACzE,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,MAAI,MAAM,WAAW,EAAG,OAAM,IAAI,MAAM,wDAA0B;AAClE,QAAM,UAAU,MAAM,IAAI,CAAC,SAAS;AAClC,QAAI,CAAC,QAAQ,KAAK,IAAI,EAAG,OAAM,IAAI,MAAM,8DAAY;AACrD,UAAM,SAAS,OAAO,IAAI;AAC1B,QAAI,CAAC,OAAO,cAAc,MAAM,EAAG,OAAM,IAAI,MAAM,4FAAiB;AACpE,WAAO;AAAA,EACT,CAAC;AACD,QAAM,QAAQ,QAAQ,CAAC;AACvB,QAAM,QAAQ,QAAQ,CAAC;AACvB,QAAM,QAAQ,QAAQ,CAAC;AACvB,MAAI,UAAU,UAAa,UAAU,UAAa,UAAU,OAAW,OAAM,IAAI,MAAM,wDAA0B;AACjH,SAAO,CAAC,OAAO,OAAO,KAAK;AAC7B;AAOA,eAAsB,eAAe,IAAY,aAAsB;AACrE,QAAM,UAAU,iBAAiB,WAAW;AAC5C,QAAM,UAAU,kBAAkB;AAClC,QAAM,OAAO,wBAAwB,QAAQ,SAAS,QAAQ,SAAS,EAAE,KAAK,SAAO,IAAI,SAAS,EAAE;AACpG,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,sCAAQ;AACnC,MAAI,KAAK,SAAS,WAAY,OAAM,IAAI,MAAM,oEAAa;AAC3D,MAAI,KAAK,QAAQ,CAAC,MAAM,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC,MAAM,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC,MAAM,QAAQ,CAAC,GAAG;AACtG,WAAO,EAAE,SAAS,OAAO,iBAAiB,OAAO,SAAS,KAAK,QAAQ,KAAK,GAAG,EAAE;AAAA,EACnF;AACA,QAAM,OAAO,uBAAuB,KAAK,KAAK,SAAS,MAAM;AAC7D,MAAI,KAAK,SAAS;AAChB,UAAM,oBAAoB,EAAE,GAAG,SAAS,MAAM,EAAE,MAAM,KAAK,MAAM,SAAS,MAAM,MAAM,YAAY,MAAM,KAAK,KAAK,EAAE,CAAC;AAAA,EACvH;AACA,SAAO,EAAE,SAAS,MAAM,iBAAiB,MAAM,SAAS,KAAK,KAAK,GAAG,EAAE;AACzE;AAEA,eAAsB,WAAW,IAAY,SAAkB;AAC7D,QAAM,UAAU,kBAAkB;AAClC,QAAM,OAAO,wBAAwB,QAAQ,SAAS,QAAQ,SAAS,EAAE,KAAK,SAAO,IAAI,SAAS,EAAE;AACpG,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,sCAAQ;AACnC,MAAI,QAAS,OAAM,oBAAoB,EAAE,GAAG,SAAS,MAAM,EAAE,MAAM,KAAK,MAAM,SAAS,KAAK,SAAS,MAAM,KAAK,MAAM,MAAM,KAAK,KAAK,EAAE,CAAC;AAAA,MACpI,OAAM,qBAAqB,EAAE,GAAG,SAAS,MAAM,KAAK,MAAM,UAAU,KAAK,MAAM,SAAS,KAAK,QAAQ,CAAC;AAC3G,SAAO,EAAE,SAAS,MAAM,iBAAiB,KAAK;AAChD;AACO,SAAS,cAAc;AAC5B,QAAM,MAAM,kBAAkB,EAAE;AAChC,SAAO,EAAE,WAAW,KAAK,KAAK,KAAK,gBAAgB,GAAG,aAAa,KAAK,KAAK,KAAK,kBAAkB,GAAG,iBAAiB,KAAK,KAAK,MAAM,WAAW,kBAAkB,EAAE;AACzK;AACO,SAAS,sBAAsB,MAAc,SAAkB;AACpE,QAAM,QAAQ,YAAY;AAC1B,MAAI,EAAE,QAAQ,UAAU,CAAC,MAAM,QAAQ,OAAO,EAAG,OAAM,IAAI,MAAM,oEAAa;AAC9E,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,SAAS,OAAO,UAAU,SAAU,OAAM,IAAI,MAAM,wDAAW;AACpE,UAAM,MAAM;AACZ,QAAI,SAAS,gBAAgB,OAAO,IAAI,SAAS,YAAY,SAAS,KAAK,IAAI,IAAI,GAAI,OAAM,IAAI,MAAM,gFAAe;AACtH,QAAI,SAAS,kBAAkB,OAAO,IAAI,SAAS,YAAY,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,WAAW,UAAU,UAAU,EAAE,SAAS,OAAO,IAAI,UAAU,CAAC,GAAI,OAAM,IAAI,MAAM,wEAAsB;AACtM,QAAI,SAAS,sBAAsB,OAAO,IAAI,gBAAgB,YAAY,CAAC,IAAI,YAAY,KAAK,KAAK,WAAW,KAAK,IAAI,WAAW,KAAK,CAAC,OAAO,UAAU,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,IAAI,KAAK,OAAO,IAAI,KAAK,IAAI,GAAI,OAAM,IAAI,MAAM,uGAA4B;AAAA,EACxQ;AACA,aAAW,MAAM,IAA0B,GAAG,OAAO;AACrD,SAAO,EAAE,OAAO,KAAK;AACvB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -14,6 +14,14 @@ export declare function createBackup(context: TaskContext): Promise<{
|
|
|
14
14
|
export declare function restoreSnapshot(id: string, phase: TaskContext["phase"]): Promise<{
|
|
15
15
|
restored: string;
|
|
16
16
|
}>;
|
|
17
|
+
/**
|
|
18
|
+
* 删除一份已完成的备份目录。
|
|
19
|
+
* 使用场景:桌面 backups.delete。只删除 `.sfmc/backups/<id>` 这一层,且必须带 manifest.json。
|
|
20
|
+
* 不跟随符号链接,避免编号被解析到备份目录之外。
|
|
21
|
+
*/
|
|
22
|
+
export declare function deleteSnapshot(id: string): Promise<{
|
|
23
|
+
deleted: string;
|
|
24
|
+
}>;
|
|
17
25
|
/** 普通维护只负责停服与恢复;全量快照仅由手动备份任务创建。 */
|
|
18
26
|
export declare function withStoppedServices<T>(context: TaskContext, names: ServiceName[], action: () => Promise<T>): Promise<T>;
|
|
19
27
|
export declare function launchPlatformUpdate(store: TaskStore, context: TaskContext, target: string): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maintenance.d.ts","sourceRoot":"","sources":["../../src/management/maintenance.ts"],"names":[],"mappings":"AAMA,OAAO,EAAoD,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEpG,OAAO,EAAc,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAa3D,wBAAgB,eAAe,IAAI,MAAM,CASxC;AACD,wBAAsB,cAAc,CAAC,mBAAmB,UAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAaxF;AACD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAUlH;AACD,wBAAsB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,iBAOrF;AACD,wBAAsB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,iBAWvD;AAMD,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,mBAsB3E;AACD,kCAAkC;AAClC,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW;;GAatD;AACD,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC;;GAiB5E;AACD,mCAAmC;AACnC,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAa7H;AACD,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM;;GAmBhG;AACD,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,iBASxD"}
|
|
1
|
+
{"version":3,"file":"maintenance.d.ts","sourceRoot":"","sources":["../../src/management/maintenance.ts"],"names":[],"mappings":"AAMA,OAAO,EAAoD,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEpG,OAAO,EAAc,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAa3D,wBAAgB,eAAe,IAAI,MAAM,CASxC;AACD,wBAAsB,cAAc,CAAC,mBAAmB,UAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAaxF;AACD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAUlH;AACD,wBAAsB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,iBAOrF;AACD,wBAAsB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,iBAWvD;AAMD,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,mBAsB3E;AACD,kCAAkC;AAClC,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW;;GAatD;AACD,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC;;GAiB5E;AACD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM;;GAY9C;AACD,mCAAmC;AACnC,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAa7H;AACD,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM;;GAmBhG;AACD,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,iBASxD"}
|
|
@@ -136,6 +136,23 @@ async function restoreSnapshot(id, phase) {
|
|
|
136
136
|
}
|
|
137
137
|
return { restored: id };
|
|
138
138
|
}
|
|
139
|
+
async function deleteSnapshot(id) {
|
|
140
|
+
if (!/^[a-zA-Z0-9-]{1,80}$/.test(id)) throw new Error("\u975E\u6CD5\u5907\u4EFD\u7F16\u53F7");
|
|
141
|
+
const directory = path.resolve(ROOT, ".sfmc", "backups");
|
|
142
|
+
const target = path.resolve(directory, id);
|
|
143
|
+
if (path.dirname(target) !== directory) throw new Error("\u975E\u6CD5\u5907\u4EFD\u8DEF\u5F84");
|
|
144
|
+
let stat;
|
|
145
|
+
try {
|
|
146
|
+
stat = fs.lstatSync(target);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (error.code === "ENOENT") throw new Error("\u627E\u4E0D\u5230\u5907\u4EFD");
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) throw new Error("\u62D2\u7EDD\u5220\u9664\u975E\u5907\u4EFD\u76EE\u5F55");
|
|
152
|
+
if (!fs.existsSync(path.join(target, "manifest.json"))) throw new Error("\u5907\u4EFD\u4E0D\u5B8C\u6574\uFF0C\u5DF2\u62D2\u7EDD\u5220\u9664");
|
|
153
|
+
await fs.promises.rm(target, { recursive: true, force: true });
|
|
154
|
+
return { deleted: id };
|
|
155
|
+
}
|
|
139
156
|
async function withStoppedServices(context, names, action) {
|
|
140
157
|
const running = await stopForMaintenance(names, context.phase);
|
|
141
158
|
try {
|
|
@@ -188,6 +205,7 @@ export {
|
|
|
188
205
|
attachmentPlan,
|
|
189
206
|
createBackup,
|
|
190
207
|
createSnapshot,
|
|
208
|
+
deleteSnapshot,
|
|
191
209
|
launchPlatformUpdate,
|
|
192
210
|
platformVersion,
|
|
193
211
|
restoreRunning,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/management/maintenance.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { spawn } from \"node:child_process\";\nimport { fileURLToPath } from \"node:url\";\nimport { ROOT, isMonorepoLayout, isSourceCheckout } from \"../runtime.js\";\nimport { queryServicesRuntimeLocal, services, START_ORDER, type ServiceName } from \"../services.js\";\nimport { resolveBdsContext } from \"../pack-lifecycle.js\";\nimport { atomicJson, type TaskContext, type TaskStore } from \"./tasks.js\";\nimport { readJson, runProcess } from \"./domain.js\";\nimport type { AttachmentPlan } from \"@sfmc-bds/management\";\nimport { isDaemonServer } from \"../daemon/role.js\";\nimport { callDaemon } from \"../daemon/client.js\";\nimport { platformReleaseNotes } from \"@sfmc-bds/management/node\";\n\nasync function runtimeRows() {\n if (isDaemonServer()) return queryServicesRuntimeLocal();\n const result = await callDaemon(\"status\");\n if (result.kind !== \"status\") throw new Error(\"\u65E0\u6CD5\u8BFB\u53D6\u5B88\u62A4\u8FDB\u7A0B\u670D\u52A1\u72B6\u6001\");\n return result.rows;\n}\n\nconst require = createRequire(import.meta.url);\nexport function platformVersion(): string {\n if (isMonorepoLayout(ROOT)) return readJson<{ version: string }>(path.join(ROOT, \"packages\", \"meta\", \"package.json\"), { version: \"unknown\" }).version;\n if (process.env.SFMC_PLATFORM_VERSION) return process.env.SFMC_PLATFORM_VERSION;\n const active = readJson<{ version?: string }>(path.join(ROOT, \".sfmc\", \"runtime\", \"active.json\"), {});\n if (active.version) return active.version;\n const deployed = readJson<{ version?: string }>(path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"package.json\"), {});\n if (deployed.version) return deployed.version;\n try { return (require(\"@sfmc-bds/sfmc/package.json\") as { version: string }).version; }\n catch { return (readJson<{ version: string }>(path.join(fileURLToPath(new URL(\"../../..\", import.meta.url)), \"package.json\"), { version: \"unknown\" })).version; }\n}\nexport async function attachmentPlan(includeReleaseNotes = true): Promise<AttachmentPlan> {\n const development = isMonorepoLayout(ROOT) || isSourceCheckout();\n const currentVersion = platformVersion();\n let targetVersion = currentVersion;\n if (!development) {\n const response = await fetch(\"https://registry.npmjs.org/@sfmc-bds%2fsfmc/latest\", { signal: AbortSignal.timeout(15_000) });\n if (!response.ok) throw new Error(`\u5E73\u53F0\u7248\u672C\u68C0\u67E5\u5931\u8D25 (${response.status})`);\n const metadata = await response.json() as { version?: string };\n if (!metadata.version || !/^\\d+\\.\\d+\\.\\d+$/.test(metadata.version)) throw new Error(\"latest \u6CA1\u6709\u6307\u5411\u6709\u6548\u7684\u7A33\u5B9A\u5E73\u53F0\u7248\u672C\");\n targetVersion = metadata.version;\n }\n const [rows, releaseNotes] = await Promise.all([runtimeRows(), includeReleaseNotes && !development ? platformReleaseNotes(targetVersion) : undefined]);\n return { currentVersion, targetVersion, development, upgradeRequired: !development && targetVersion !== currentVersion, externalServices: rows.filter(row => row.running && row.ownership === \"external\").map(row => row.name), steps: development ? [\"\u4FDD\u7559\u6E90\u7801\u5DE5\u4F5C\u533A\uFF0C\u8FDE\u63A5\u5F53\u524D\u5F00\u53D1\u90E8\u7F72\"] : [\"\u4E0B\u8F7D\u56FA\u5B9A\u7248\u672C\u7684\u5E73\u53F0\u4F9D\u8D56\u7EC4\u5408\", \"\u505C\u6B62\u53D7\u5F71\u54CD\u670D\u52A1\u5E76\u786E\u8BA4\u8FDB\u7A0B\u9000\u51FA\", \"\u5207\u6362\u5E73\u53F0\u5E76\u9A8C\u8BC1\", \"\u6062\u590D\u6B64\u524D\u8FD0\u884C\u7684\u670D\u52A1\"], ...(releaseNotes ? { releaseNotes } : {}) };\n}\nexport async function stopForMaintenance(names: ServiceName[], phase: TaskContext[\"phase\"]): Promise<ServiceName[]> {\n const before = await queryServicesRuntimeLocal();\n const affected = before.filter(row => names.includes(row.name) && row.running);\n if (affected.some(row => row.ownership === \"external\")) throw Object.assign(new Error(\"\u5B58\u5728\u65E0\u6CD5\u901A\u8FC7\u5F53\u524D\u5B88\u62A4\u8FDB\u7A0B\u4F18\u96C5\u505C\u6B62\u7684\u5916\u90E8\u670D\u52A1\uFF1B\u8BF7\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u505C\u6B62\u540E\u91CD\u65B0\u63A5\u5165\"), { code: \"conflict\" });\n phase(\"stop-services\", \"\u4F18\u96C5\u505C\u6B62\u5E76\u786E\u8BA4\u8FDB\u7A0B\u9000\u51FA\");\n const running = affected.map(row => row.name);\n for (const name of [...START_ORDER].reverse().filter(name => names.includes(name))) await services[name].stop(false, false);\n const after = await queryServicesRuntimeLocal();\n if (after.some(row => names.includes(row.name) && row.running)) throw new Error(\"\u670D\u52A1\u672A\u5B8C\u5168\u9000\u51FA\uFF0C\u5DF2\u4E2D\u6B62\u6587\u4EF6\u64CD\u4F5C\");\n return running;\n}\nexport async function restoreRunning(names: ServiceName[], phase: TaskContext[\"phase\"]) {\n phase(\"restore\", \"\u6062\u590D\u7EF4\u62A4\u524D\u8FD0\u884C\u7684\u670D\u52A1\");\n for (const name of START_ORDER.filter(name => names.includes(name))) {\n const result = await services[name].start();\n if (result.status === \"skipped\") throw new Error(`\u6062\u590D ${name} \u5931\u8D25: ${result.reason}`);\n }\n await verifyRunning(names);\n}\nexport async function verifyRunning(names: ServiceName[]) {\n if (!names.length) return;\n await new Promise(resolve => setTimeout(resolve, 2000));\n for (const name of names) {\n if (!services[name].running || !services[name].pid) throw new Error(`${name} \u542F\u52A8\u540E\u5DF2\u9000\u51FA`);\n }\n if (names.includes(\"db\")) {\n const cfg = readJson<{ db_port?: number; http_auth?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\n const response = await fetch(`http://127.0.0.1:${cfg.db_port ?? 3001}/api/sfmc/status`, { headers: cfg.http_auth ? { authorization: `Bearer ${cfg.http_auth}` } : {}, signal: AbortSignal.timeout(5000) });\n if (!response.ok) throw new Error(`DB \u5065\u5EB7\u68C0\u67E5\u5931\u8D25 (${response.status})`);\n }\n}\nfunction snapshotTargets() {\n const db = readJson<{ dbDir?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\n const bds = resolveBdsContext().bdsRoot;\n return { configs: path.join(ROOT, \"configs\"), modules: path.join(ROOT, \"modules\"), data: path.dirname(path.resolve(ROOT, db.dbDir ?? \"data/sfmc_data.db\")), bds };\n}\nexport async function createSnapshot(id: string, phase: TaskContext[\"phase\"]) {\n if (!/^[a-zA-Z0-9-]{1,80}$/.test(id)) throw new Error(\"\u975E\u6CD5\u5907\u4EFD\u7F16\u53F7\");\n phase(\"backup\", \"\u521B\u5EFA\u5DF2\u505C\u670D\u7684\u4E00\u81F4\u5907\u4EFD\");\n const destination = path.join(ROOT, \".sfmc\", \"backups\", id);\n const targets = snapshotTargets();\n for (const target of Object.values(targets)) {\n const absolute = path.resolve(target);\n if (absolute === path.parse(absolute).root || absolute === path.resolve(ROOT) || destination.startsWith(absolute + path.sep)) throw new Error(\"\u5907\u4EFD\u76EE\u6807\u5305\u542B\u5B9E\u4F8B\u6839\u76EE\u5F55\u6216\u5907\u4EFD\u76EE\u5F55\uFF0C\u5DF2\u4E2D\u6B62\");\n }\n fs.mkdirSync(path.dirname(destination), { recursive: true });\n fs.mkdirSync(destination);\n try {\n for (const [key, target] of Object.entries(targets)) {\n if (fs.existsSync(target)) await fs.promises.cp(target, path.join(destination, key), { recursive: true, dereference: false });\n }\n atomicJson(path.join(destination, \"manifest.json\"), { createdAt: new Date().toISOString(), targets, complete: true });\n } catch (error) {\n // \u53EA\u6E05\u7406\u672C\u6B21\u521B\u5EFA\u7684\u4E0D\u5B8C\u6574\u5FEB\u7167\uFF0C\u907F\u514D\u5907\u4EFD\u5931\u8D25\u540E\u7EE7\u7EED\u5360\u7528\u7A7A\u95F4\u3002\n await fs.promises.rm(destination, { recursive: true, force: true });\n throw error;\n }\n return destination;\n}\n/** \u5907\u4EFD\u53EA\u8BFB\u53D6\u5B9E\u4F8B\u6587\u4EF6\uFF0C\u5373\u4F7F\u590D\u5236\u5931\u8D25\u4E5F\u6062\u590D\u539F\u5148\u8FD0\u884C\u7684\u670D\u52A1\u3002 */\nexport async function createBackup(context: TaskContext) {\n const running = await stopForMaintenance([...START_ORDER], context.phase);\n let completed = false;\n try {\n await createSnapshot(context.id, context.phase);\n completed = true;\n } finally {\n try { await restoreRunning(running, context.phase); }\n catch (error) {\n throw Object.assign(new Error(`\u5907\u4EFD${completed ? \"\u5DF2\u5B8C\u6210\" : \"\u672A\u5B8C\u6210\"}\uFF0C\u6062\u590D\u670D\u52A1\u8FD0\u884C\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`), { code: \"io\", details: completed ? { backupId: context.id } : undefined });\n }\n }\n return { backupId: context.id };\n}\nexport async function restoreSnapshot(id: string, phase: TaskContext[\"phase\"]) {\n if (!/^[a-zA-Z0-9-]{1,80}$/.test(id)) throw new Error(\"\u975E\u6CD5\u5907\u4EFD\u7F16\u53F7\");\n const source = path.join(ROOT, \".sfmc\", \"backups\", id);\n const manifest = readJson<{ complete: boolean; targets: Record<string, string> }>(path.join(source, \"manifest.json\"), { complete: false, targets: {} });\n if (!manifest.complete) throw new Error(\"\u5907\u4EFD\u4E0D\u5B8C\u6574\uFF0C\u7981\u6B62\u6062\u590D\");\n const targets = snapshotTargets();\n phase(\"restore-data\", \"\u6309\u7528\u6237\u660E\u786E\u9009\u62E9\u6062\u590D\u914D\u7F6E\u3001\u6A21\u5757\u3001\u6570\u636E\u5E93\u548C\u4E16\u754C\");\n for (const [key, target] of Object.entries(targets)) {\n if (path.resolve(manifest.targets[key] ?? \"\") !== path.resolve(target)) throw new Error(\"\u5907\u4EFD\u76EE\u6807\u4E0E\u5F53\u524D\u90E8\u7F72\u4E0D\u4E00\u81F4\");\n const saved = path.join(source, key);\n if (!fs.existsSync(saved)) continue;\n const absolute = path.resolve(target);\n if (absolute === path.parse(absolute).root || absolute === path.resolve(ROOT) || fs.lstatSync(saved).isSymbolicLink()) throw new Error(\"\u4E0D\u5B89\u5168\u7684\u6062\u590D\u76EE\u6807\");\n await fs.promises.rm(absolute, { recursive: true, force: true });\n await fs.promises.cp(saved, absolute, { recursive: true, dereference: false });\n }\n return { restored: id };\n}\n/** \u666E\u901A\u7EF4\u62A4\u53EA\u8D1F\u8D23\u505C\u670D\u4E0E\u6062\u590D\uFF1B\u5168\u91CF\u5FEB\u7167\u4EC5\u7531\u624B\u52A8\u5907\u4EFD\u4EFB\u52A1\u521B\u5EFA\u3002 */\nexport async function withStoppedServices<T>(context: TaskContext, names: ServiceName[], action: () => Promise<T>): Promise<T> {\n const running = await stopForMaintenance(names, context.phase);\n try {\n context.phase(\"execute\");\n const result = await action();\n context.phase(\"verify\");\n await restoreRunning(running, context.phase);\n return result;\n } catch (error) {\n // \u5931\u8D25\u540E\u4FDD\u6301\u505C\u670D\uFF0C\u4E0D\u731C\u6D4B\u672A\u77E5\u6570\u636E\u8FC1\u79FB\u662F\u5426\u53EF\u4EE5\u5B89\u5168\u6062\u590D\u8FD0\u884C\u3002\n for (const name of [...START_ORDER].reverse().filter(name => running.includes(name))) await services[name].stop(false, false).catch(() => {});\n throw Object.assign(new Error(`\u7EF4\u62A4\u5931\u8D25\uFF0C\u670D\u52A1\u4FDD\u6301\u505C\u6B62: ${error instanceof Error ? error.message : String(error)}`), { code: \"io\", details: (error as { details?: object }).details });\n }\n}\nexport async function launchPlatformUpdate(store: TaskStore, context: TaskContext, target: string) {\n if (isMonorepoLayout(ROOT)) throw new Error(\"\u6E90\u7801\u90E8\u7F72\u4E0D\u8986\u76D6\u5DE5\u4F5C\u533A\uFF1B\u8BF7\u4F7F\u7528\u6B63\u5E38\u5F00\u53D1\u53D1\u5E03\u6D41\u7A0B\");\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(target)) throw new Error(\"\u9700\u8981\u56FA\u5B9A\u7A33\u5B9A\u7248\u672C\");\n const rows = await runtimeRows();\n if (rows.some(row => row.running && row.ownership === \"external\")) throw new Error(\"\u5916\u90E8\u670D\u52A1\u5FC5\u987B\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u4F18\u96C5\u505C\u6B62\");\n const request = path.join(ROOT, \".sfmc\", \"operations\", `${context.id}.request.json`);\n const previous = readJson(path.join(ROOT, \".sfmc\", \"runtime\", \"active.json\"), { entry: fs.existsSync(path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\")) ? path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\") : process.env.SFMC_DAEMON_ENTRY, version: platformVersion() });\n atomicJson(request, { root: ROOT, id: context.id, target, running: rows.filter(row => row.running).map(row => row.name), previous });\n const entry = fileURLToPath(new URL(\"./platform-worker.js\", import.meta.url));\n const log = path.join(ROOT, \".sfmc\", \"logs\", \"maintenance.log\");\n fs.mkdirSync(path.dirname(log), { recursive: true });\n // \u4E0D\u628A\u7236\u8FDB\u7A0B\u7684\u65E5\u5FD7\u53E5\u67C4\u4EA4\u7ED9\u5B50\u8FDB\u7A0B\uFF0C\u907F\u514D\u5B88\u62A4\u8FDB\u7A0B\u9000\u51FA\u65F6\u4E2D\u65AD\u7EF4\u62A4\u8FDB\u7A0B\u3002\n const child = spawn(process.execPath, [entry, request], { cwd: ROOT, env: { ...process.env, SFMC_ROOT: ROOT, SFMC_MAINTENANCE_LOG: log }, detached: true, windowsHide: true, stdio: \"ignore\" });\n await new Promise<void>((resolve, reject) => { child.once(\"spawn\", resolve); child.once(\"error\", reject); });\n child.unref();\n const record = store.get(context.id) as ReturnType<TaskStore[\"get\"]> & { workerPid?: number };\n record.status = \"running\"; if (child.pid) record.workerPid = child.pid;\n store.save(record);\n return { detached: true };\n}\nexport async function runPnpm(args: string[], cwd: string) {\n const script = process.env.SFMC_PNPM_ENTRY;\n if (script) return runProcess(process.execPath, [script, ...args], cwd);\n const command = process.platform === \"win32\" ? \"pnpm.cmd\" : \"pnpm\";\n const crossSpawn = require(\"cross-spawn\") as typeof spawn;\n await new Promise<void>((resolve, reject) => {\n const child = crossSpawn(command, args, { cwd, env: process.env, windowsHide: true, stdio: \"ignore\" });\n child.on(\"error\", reject); child.on(\"close\", code => code === 0 ? resolve() : reject(new Error(`pnpm \u6267\u884C\u5931\u8D25 (${code})`)));\n });\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { spawn } from \"node:child_process\";\nimport { fileURLToPath } from \"node:url\";\nimport { ROOT, isMonorepoLayout, isSourceCheckout } from \"../runtime.js\";\nimport { queryServicesRuntimeLocal, services, START_ORDER, type ServiceName } from \"../services.js\";\nimport { resolveBdsContext } from \"../pack-lifecycle.js\";\nimport { atomicJson, type TaskContext, type TaskStore } from \"./tasks.js\";\nimport { readJson, runProcess } from \"./domain.js\";\nimport type { AttachmentPlan } from \"@sfmc-bds/management\";\nimport { isDaemonServer } from \"../daemon/role.js\";\nimport { callDaemon } from \"../daemon/client.js\";\nimport { platformReleaseNotes } from \"@sfmc-bds/management/node\";\n\nasync function runtimeRows() {\n if (isDaemonServer()) return queryServicesRuntimeLocal();\n const result = await callDaemon(\"status\");\n if (result.kind !== \"status\") throw new Error(\"\u65E0\u6CD5\u8BFB\u53D6\u5B88\u62A4\u8FDB\u7A0B\u670D\u52A1\u72B6\u6001\");\n return result.rows;\n}\n\nconst require = createRequire(import.meta.url);\nexport function platformVersion(): string {\n if (isMonorepoLayout(ROOT)) return readJson<{ version: string }>(path.join(ROOT, \"packages\", \"meta\", \"package.json\"), { version: \"unknown\" }).version;\n if (process.env.SFMC_PLATFORM_VERSION) return process.env.SFMC_PLATFORM_VERSION;\n const active = readJson<{ version?: string }>(path.join(ROOT, \".sfmc\", \"runtime\", \"active.json\"), {});\n if (active.version) return active.version;\n const deployed = readJson<{ version?: string }>(path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"package.json\"), {});\n if (deployed.version) return deployed.version;\n try { return (require(\"@sfmc-bds/sfmc/package.json\") as { version: string }).version; }\n catch { return (readJson<{ version: string }>(path.join(fileURLToPath(new URL(\"../../..\", import.meta.url)), \"package.json\"), { version: \"unknown\" })).version; }\n}\nexport async function attachmentPlan(includeReleaseNotes = true): Promise<AttachmentPlan> {\n const development = isMonorepoLayout(ROOT) || isSourceCheckout();\n const currentVersion = platformVersion();\n let targetVersion = currentVersion;\n if (!development) {\n const response = await fetch(\"https://registry.npmjs.org/@sfmc-bds%2fsfmc/latest\", { signal: AbortSignal.timeout(15_000) });\n if (!response.ok) throw new Error(`\u5E73\u53F0\u7248\u672C\u68C0\u67E5\u5931\u8D25 (${response.status})`);\n const metadata = await response.json() as { version?: string };\n if (!metadata.version || !/^\\d+\\.\\d+\\.\\d+$/.test(metadata.version)) throw new Error(\"latest \u6CA1\u6709\u6307\u5411\u6709\u6548\u7684\u7A33\u5B9A\u5E73\u53F0\u7248\u672C\");\n targetVersion = metadata.version;\n }\n const [rows, releaseNotes] = await Promise.all([runtimeRows(), includeReleaseNotes && !development ? platformReleaseNotes(targetVersion) : undefined]);\n return { currentVersion, targetVersion, development, upgradeRequired: !development && targetVersion !== currentVersion, externalServices: rows.filter(row => row.running && row.ownership === \"external\").map(row => row.name), steps: development ? [\"\u4FDD\u7559\u6E90\u7801\u5DE5\u4F5C\u533A\uFF0C\u8FDE\u63A5\u5F53\u524D\u5F00\u53D1\u90E8\u7F72\"] : [\"\u4E0B\u8F7D\u56FA\u5B9A\u7248\u672C\u7684\u5E73\u53F0\u4F9D\u8D56\u7EC4\u5408\", \"\u505C\u6B62\u53D7\u5F71\u54CD\u670D\u52A1\u5E76\u786E\u8BA4\u8FDB\u7A0B\u9000\u51FA\", \"\u5207\u6362\u5E73\u53F0\u5E76\u9A8C\u8BC1\", \"\u6062\u590D\u6B64\u524D\u8FD0\u884C\u7684\u670D\u52A1\"], ...(releaseNotes ? { releaseNotes } : {}) };\n}\nexport async function stopForMaintenance(names: ServiceName[], phase: TaskContext[\"phase\"]): Promise<ServiceName[]> {\n const before = await queryServicesRuntimeLocal();\n const affected = before.filter(row => names.includes(row.name) && row.running);\n if (affected.some(row => row.ownership === \"external\")) throw Object.assign(new Error(\"\u5B58\u5728\u65E0\u6CD5\u901A\u8FC7\u5F53\u524D\u5B88\u62A4\u8FDB\u7A0B\u4F18\u96C5\u505C\u6B62\u7684\u5916\u90E8\u670D\u52A1\uFF1B\u8BF7\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u505C\u6B62\u540E\u91CD\u65B0\u63A5\u5165\"), { code: \"conflict\" });\n phase(\"stop-services\", \"\u4F18\u96C5\u505C\u6B62\u5E76\u786E\u8BA4\u8FDB\u7A0B\u9000\u51FA\");\n const running = affected.map(row => row.name);\n for (const name of [...START_ORDER].reverse().filter(name => names.includes(name))) await services[name].stop(false, false);\n const after = await queryServicesRuntimeLocal();\n if (after.some(row => names.includes(row.name) && row.running)) throw new Error(\"\u670D\u52A1\u672A\u5B8C\u5168\u9000\u51FA\uFF0C\u5DF2\u4E2D\u6B62\u6587\u4EF6\u64CD\u4F5C\");\n return running;\n}\nexport async function restoreRunning(names: ServiceName[], phase: TaskContext[\"phase\"]) {\n phase(\"restore\", \"\u6062\u590D\u7EF4\u62A4\u524D\u8FD0\u884C\u7684\u670D\u52A1\");\n for (const name of START_ORDER.filter(name => names.includes(name))) {\n const result = await services[name].start();\n if (result.status === \"skipped\") throw new Error(`\u6062\u590D ${name} \u5931\u8D25: ${result.reason}`);\n }\n await verifyRunning(names);\n}\nexport async function verifyRunning(names: ServiceName[]) {\n if (!names.length) return;\n await new Promise(resolve => setTimeout(resolve, 2000));\n for (const name of names) {\n if (!services[name].running || !services[name].pid) throw new Error(`${name} \u542F\u52A8\u540E\u5DF2\u9000\u51FA`);\n }\n if (names.includes(\"db\")) {\n const cfg = readJson<{ db_port?: number; http_auth?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\n const response = await fetch(`http://127.0.0.1:${cfg.db_port ?? 3001}/api/sfmc/status`, { headers: cfg.http_auth ? { authorization: `Bearer ${cfg.http_auth}` } : {}, signal: AbortSignal.timeout(5000) });\n if (!response.ok) throw new Error(`DB \u5065\u5EB7\u68C0\u67E5\u5931\u8D25 (${response.status})`);\n }\n}\nfunction snapshotTargets() {\n const db = readJson<{ dbDir?: string }>(path.join(ROOT, \"configs\", \"db_config.json\"), {});\n const bds = resolveBdsContext().bdsRoot;\n return { configs: path.join(ROOT, \"configs\"), modules: path.join(ROOT, \"modules\"), data: path.dirname(path.resolve(ROOT, db.dbDir ?? \"data/sfmc_data.db\")), bds };\n}\nexport async function createSnapshot(id: string, phase: TaskContext[\"phase\"]) {\n if (!/^[a-zA-Z0-9-]{1,80}$/.test(id)) throw new Error(\"\u975E\u6CD5\u5907\u4EFD\u7F16\u53F7\");\n phase(\"backup\", \"\u521B\u5EFA\u5DF2\u505C\u670D\u7684\u4E00\u81F4\u5907\u4EFD\");\n const destination = path.join(ROOT, \".sfmc\", \"backups\", id);\n const targets = snapshotTargets();\n for (const target of Object.values(targets)) {\n const absolute = path.resolve(target);\n if (absolute === path.parse(absolute).root || absolute === path.resolve(ROOT) || destination.startsWith(absolute + path.sep)) throw new Error(\"\u5907\u4EFD\u76EE\u6807\u5305\u542B\u5B9E\u4F8B\u6839\u76EE\u5F55\u6216\u5907\u4EFD\u76EE\u5F55\uFF0C\u5DF2\u4E2D\u6B62\");\n }\n fs.mkdirSync(path.dirname(destination), { recursive: true });\n fs.mkdirSync(destination);\n try {\n for (const [key, target] of Object.entries(targets)) {\n if (fs.existsSync(target)) await fs.promises.cp(target, path.join(destination, key), { recursive: true, dereference: false });\n }\n atomicJson(path.join(destination, \"manifest.json\"), { createdAt: new Date().toISOString(), targets, complete: true });\n } catch (error) {\n // \u53EA\u6E05\u7406\u672C\u6B21\u521B\u5EFA\u7684\u4E0D\u5B8C\u6574\u5FEB\u7167\uFF0C\u907F\u514D\u5907\u4EFD\u5931\u8D25\u540E\u7EE7\u7EED\u5360\u7528\u7A7A\u95F4\u3002\n await fs.promises.rm(destination, { recursive: true, force: true });\n throw error;\n }\n return destination;\n}\n/** \u5907\u4EFD\u53EA\u8BFB\u53D6\u5B9E\u4F8B\u6587\u4EF6\uFF0C\u5373\u4F7F\u590D\u5236\u5931\u8D25\u4E5F\u6062\u590D\u539F\u5148\u8FD0\u884C\u7684\u670D\u52A1\u3002 */\nexport async function createBackup(context: TaskContext) {\n const running = await stopForMaintenance([...START_ORDER], context.phase);\n let completed = false;\n try {\n await createSnapshot(context.id, context.phase);\n completed = true;\n } finally {\n try { await restoreRunning(running, context.phase); }\n catch (error) {\n throw Object.assign(new Error(`\u5907\u4EFD${completed ? \"\u5DF2\u5B8C\u6210\" : \"\u672A\u5B8C\u6210\"}\uFF0C\u6062\u590D\u670D\u52A1\u8FD0\u884C\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`), { code: \"io\", details: completed ? { backupId: context.id } : undefined });\n }\n }\n return { backupId: context.id };\n}\nexport async function restoreSnapshot(id: string, phase: TaskContext[\"phase\"]) {\n if (!/^[a-zA-Z0-9-]{1,80}$/.test(id)) throw new Error(\"\u975E\u6CD5\u5907\u4EFD\u7F16\u53F7\");\n const source = path.join(ROOT, \".sfmc\", \"backups\", id);\n const manifest = readJson<{ complete: boolean; targets: Record<string, string> }>(path.join(source, \"manifest.json\"), { complete: false, targets: {} });\n if (!manifest.complete) throw new Error(\"\u5907\u4EFD\u4E0D\u5B8C\u6574\uFF0C\u7981\u6B62\u6062\u590D\");\n const targets = snapshotTargets();\n phase(\"restore-data\", \"\u6309\u7528\u6237\u660E\u786E\u9009\u62E9\u6062\u590D\u914D\u7F6E\u3001\u6A21\u5757\u3001\u6570\u636E\u5E93\u548C\u4E16\u754C\");\n for (const [key, target] of Object.entries(targets)) {\n if (path.resolve(manifest.targets[key] ?? \"\") !== path.resolve(target)) throw new Error(\"\u5907\u4EFD\u76EE\u6807\u4E0E\u5F53\u524D\u90E8\u7F72\u4E0D\u4E00\u81F4\");\n const saved = path.join(source, key);\n if (!fs.existsSync(saved)) continue;\n const absolute = path.resolve(target);\n if (absolute === path.parse(absolute).root || absolute === path.resolve(ROOT) || fs.lstatSync(saved).isSymbolicLink()) throw new Error(\"\u4E0D\u5B89\u5168\u7684\u6062\u590D\u76EE\u6807\");\n await fs.promises.rm(absolute, { recursive: true, force: true });\n await fs.promises.cp(saved, absolute, { recursive: true, dereference: false });\n }\n return { restored: id };\n}\n/**\n * \u5220\u9664\u4E00\u4EFD\u5DF2\u5B8C\u6210\u7684\u5907\u4EFD\u76EE\u5F55\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u684C\u9762 backups.delete\u3002\u53EA\u5220\u9664 `.sfmc/backups/<id>` \u8FD9\u4E00\u5C42\uFF0C\u4E14\u5FC5\u987B\u5E26 manifest.json\u3002\n * \u4E0D\u8DDF\u968F\u7B26\u53F7\u94FE\u63A5\uFF0C\u907F\u514D\u7F16\u53F7\u88AB\u89E3\u6790\u5230\u5907\u4EFD\u76EE\u5F55\u4E4B\u5916\u3002\n */\nexport async function deleteSnapshot(id: string) {\n if (!/^[a-zA-Z0-9-]{1,80}$/.test(id)) throw new Error(\"\u975E\u6CD5\u5907\u4EFD\u7F16\u53F7\");\n const directory = path.resolve(ROOT, \".sfmc\", \"backups\");\n const target = path.resolve(directory, id);\n if (path.dirname(target) !== directory) throw new Error(\"\u975E\u6CD5\u5907\u4EFD\u8DEF\u5F84\");\n let stat: fs.Stats;\n try { stat = fs.lstatSync(target); }\n catch (error) { if ((error as NodeJS.ErrnoException).code === \"ENOENT\") throw new Error(\"\u627E\u4E0D\u5230\u5907\u4EFD\"); throw error; }\n if (stat.isSymbolicLink() || !stat.isDirectory()) throw new Error(\"\u62D2\u7EDD\u5220\u9664\u975E\u5907\u4EFD\u76EE\u5F55\");\n if (!fs.existsSync(path.join(target, \"manifest.json\"))) throw new Error(\"\u5907\u4EFD\u4E0D\u5B8C\u6574\uFF0C\u5DF2\u62D2\u7EDD\u5220\u9664\");\n await fs.promises.rm(target, { recursive: true, force: true });\n return { deleted: id };\n}\n/** \u666E\u901A\u7EF4\u62A4\u53EA\u8D1F\u8D23\u505C\u670D\u4E0E\u6062\u590D\uFF1B\u5168\u91CF\u5FEB\u7167\u4EC5\u7531\u624B\u52A8\u5907\u4EFD\u4EFB\u52A1\u521B\u5EFA\u3002 */\nexport async function withStoppedServices<T>(context: TaskContext, names: ServiceName[], action: () => Promise<T>): Promise<T> {\n const running = await stopForMaintenance(names, context.phase);\n try {\n context.phase(\"execute\");\n const result = await action();\n context.phase(\"verify\");\n await restoreRunning(running, context.phase);\n return result;\n } catch (error) {\n // \u5931\u8D25\u540E\u4FDD\u6301\u505C\u670D\uFF0C\u4E0D\u731C\u6D4B\u672A\u77E5\u6570\u636E\u8FC1\u79FB\u662F\u5426\u53EF\u4EE5\u5B89\u5168\u6062\u590D\u8FD0\u884C\u3002\n for (const name of [...START_ORDER].reverse().filter(name => running.includes(name))) await services[name].stop(false, false).catch(() => {});\n throw Object.assign(new Error(`\u7EF4\u62A4\u5931\u8D25\uFF0C\u670D\u52A1\u4FDD\u6301\u505C\u6B62: ${error instanceof Error ? error.message : String(error)}`), { code: \"io\", details: (error as { details?: object }).details });\n }\n}\nexport async function launchPlatformUpdate(store: TaskStore, context: TaskContext, target: string) {\n if (isMonorepoLayout(ROOT)) throw new Error(\"\u6E90\u7801\u90E8\u7F72\u4E0D\u8986\u76D6\u5DE5\u4F5C\u533A\uFF1B\u8BF7\u4F7F\u7528\u6B63\u5E38\u5F00\u53D1\u53D1\u5E03\u6D41\u7A0B\");\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(target)) throw new Error(\"\u9700\u8981\u56FA\u5B9A\u7A33\u5B9A\u7248\u672C\");\n const rows = await runtimeRows();\n if (rows.some(row => row.running && row.ownership === \"external\")) throw new Error(\"\u5916\u90E8\u670D\u52A1\u5FC5\u987B\u5148\u901A\u8FC7\u539F\u7BA1\u7406\u5668\u4F18\u96C5\u505C\u6B62\");\n const request = path.join(ROOT, \".sfmc\", \"operations\", `${context.id}.request.json`);\n const previous = readJson(path.join(ROOT, \".sfmc\", \"runtime\", \"active.json\"), { entry: fs.existsSync(path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\")) ? path.join(ROOT, \"node_modules\", \"@sfmc-bds\", \"sfmc\", \"bin\", \"sfmc.mjs\") : process.env.SFMC_DAEMON_ENTRY, version: platformVersion() });\n atomicJson(request, { root: ROOT, id: context.id, target, running: rows.filter(row => row.running).map(row => row.name), previous });\n const entry = fileURLToPath(new URL(\"./platform-worker.js\", import.meta.url));\n const log = path.join(ROOT, \".sfmc\", \"logs\", \"maintenance.log\");\n fs.mkdirSync(path.dirname(log), { recursive: true });\n // \u4E0D\u628A\u7236\u8FDB\u7A0B\u7684\u65E5\u5FD7\u53E5\u67C4\u4EA4\u7ED9\u5B50\u8FDB\u7A0B\uFF0C\u907F\u514D\u5B88\u62A4\u8FDB\u7A0B\u9000\u51FA\u65F6\u4E2D\u65AD\u7EF4\u62A4\u8FDB\u7A0B\u3002\n const child = spawn(process.execPath, [entry, request], { cwd: ROOT, env: { ...process.env, SFMC_ROOT: ROOT, SFMC_MAINTENANCE_LOG: log }, detached: true, windowsHide: true, stdio: \"ignore\" });\n await new Promise<void>((resolve, reject) => { child.once(\"spawn\", resolve); child.once(\"error\", reject); });\n child.unref();\n const record = store.get(context.id) as ReturnType<TaskStore[\"get\"]> & { workerPid?: number };\n record.status = \"running\"; if (child.pid) record.workerPid = child.pid;\n store.save(record);\n return { detached: true };\n}\nexport async function runPnpm(args: string[], cwd: string) {\n const script = process.env.SFMC_PNPM_ENTRY;\n if (script) return runProcess(process.execPath, [script, ...args], cwd);\n const command = process.platform === \"win32\" ? \"pnpm.cmd\" : \"pnpm\";\n const crossSpawn = require(\"cross-spawn\") as typeof spawn;\n await new Promise<void>((resolve, reject) => {\n const child = crossSpawn(command, args, { cwd, env: process.env, windowsHide: true, stdio: \"ignore\" });\n child.on(\"error\", reject); child.on(\"close\", code => code === 0 ? resolve() : reject(new Error(`pnpm \u6267\u884C\u5931\u8D25 (${code})`)));\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["require", "name"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PackImportPlan, PackImportOptions } from "@sfmc-bds/management";
|
|
2
|
+
export declare function planPackImport(filename: string): Promise<PackImportPlan>;
|
|
3
|
+
/**
|
|
4
|
+
* 从管理请求取出收件箱文件名。
|
|
5
|
+
* 使用场景:桌面一次拖入或选中多个世界包时传 filenames;旧客户端仍只传 filename。
|
|
6
|
+
*/
|
|
7
|
+
export declare function readImportFilenames(params: {
|
|
8
|
+
filename?: unknown;
|
|
9
|
+
filenames?: unknown;
|
|
10
|
+
}): string[];
|
|
11
|
+
/**
|
|
12
|
+
* 按顺序导入多个收件箱文件。
|
|
13
|
+
* 使用场景:批量导入。只有一个文件时仍走 importPack,保留 force 与 revision 的原有校验。
|
|
14
|
+
* 中途失败时,前面已经安装的包保留,错误里带上已导入数量。
|
|
15
|
+
*/
|
|
16
|
+
export declare function importPacks(filenames: string[], options?: PackImportOptions): Promise<{
|
|
17
|
+
changed: boolean;
|
|
18
|
+
restartRequired: boolean;
|
|
19
|
+
imported: number;
|
|
20
|
+
} | {
|
|
21
|
+
changed: boolean;
|
|
22
|
+
restartRequired: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
/** force 必须绑定用户看过的归档及已有包版本,排队期间有变化时重新确认。 */
|
|
25
|
+
export declare function importPack(filename: string, options?: PackImportOptions): Promise<{
|
|
26
|
+
changed: boolean;
|
|
27
|
+
restartRequired: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
//# sourceMappingURL=pack-import.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack-import.d.ts","sourceRoot":"","sources":["../../src/management/pack-import.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAsD9E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAExE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,EAAE,CAOjG;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,iBAAsB;;;;;;;GAkBrF;AAED,4CAA4C;AAC5C,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB;;;GAY3E"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { decidePackInstallPlan, enableInstalledPack, installPackDirectory, readPackManifestInfo, resolvePackRoots, scanDestOccupancy, worldPackParentDir } from "@sfmc-bds/bds-tools/world-packs";
|
|
5
|
+
import { ROOT } from "../runtime.js";
|
|
6
|
+
import { resolveBdsContext } from "../pack-lifecycle.js";
|
|
7
|
+
import { identifier } from "./domain.js";
|
|
8
|
+
async function inspectImport(filename, action) {
|
|
9
|
+
const inbox = path.resolve(ROOT, "packs", "_desktop-inbox");
|
|
10
|
+
const file = path.resolve(inbox, identifier(filename));
|
|
11
|
+
if (!file.startsWith(inbox + path.sep) || !fs.existsSync(file)) throw new Error("\u4E16\u754C\u5305\u5C1A\u672A\u4E0A\u4F20\u5230\u5B9E\u4F8B\u6536\u4EF6\u7BB1");
|
|
12
|
+
const context = resolveBdsContext();
|
|
13
|
+
const resolved = await resolvePackRoots(file);
|
|
14
|
+
try {
|
|
15
|
+
if (!resolved.roots.length) throw new Error("\u5F52\u6863\u4E0D\u542B\u53EF\u8BC6\u522B\u7684\u4E16\u754C\u5305");
|
|
16
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17
|
+
const prepared = resolved.roots.map((source) => {
|
|
18
|
+
const info = readPackManifestInfo(source);
|
|
19
|
+
if (!info) throw new Error("\u4E16\u754C\u5305 manifest \u65E0\u6548");
|
|
20
|
+
const id = info.uuid.toLowerCase();
|
|
21
|
+
if (seen.has(id)) throw new Error(`\u5F52\u6863\u5305\u542B\u91CD\u590D\u7684\u4E16\u754C\u5305 UUID: ${info.uuid}`);
|
|
22
|
+
seen.add(id);
|
|
23
|
+
const destParent = worldPackParentDir(context.bdsRoot, context.levelName, info.kind);
|
|
24
|
+
const decision = decidePackInstallPlan({ incoming: info, hint: path.basename(source), occupancy: scanDestOccupancy(destParent) });
|
|
25
|
+
return { source, info, destParent, decision };
|
|
26
|
+
});
|
|
27
|
+
const hash = createHash("sha256");
|
|
28
|
+
for await (const chunk of fs.createReadStream(file)) hash.update(chunk);
|
|
29
|
+
hash.update(JSON.stringify({
|
|
30
|
+
context,
|
|
31
|
+
existing: prepared.map(({ info, decision }) => ({
|
|
32
|
+
id: info.uuid,
|
|
33
|
+
dir: decision.kind === "fresh" ? null : decision.dir,
|
|
34
|
+
manifest: decision.kind === "fresh" ? null : fs.readFileSync(path.join(decision.dir, "manifest.json"), "utf8")
|
|
35
|
+
}))
|
|
36
|
+
}));
|
|
37
|
+
const plan = {
|
|
38
|
+
revision: hash.digest("hex"),
|
|
39
|
+
packs: prepared.map(({ info, decision }) => ({
|
|
40
|
+
id: info.uuid,
|
|
41
|
+
name: info.name,
|
|
42
|
+
kind: info.kind,
|
|
43
|
+
version: info.version.join("."),
|
|
44
|
+
action: decision.kind === "fresh" ? "install" : decision.kind === "needConfirm" ? "conflict" : "update",
|
|
45
|
+
...decision.kind === "fresh" ? {} : { existing: { name: decision.existing.name, version: decision.existing.version.join(".") } }
|
|
46
|
+
}))
|
|
47
|
+
};
|
|
48
|
+
return await action(plan, async (force) => {
|
|
49
|
+
for (const { source, info, destParent } of prepared) {
|
|
50
|
+
const result = await installPackDirectory({ srcDir: source, destParent, force });
|
|
51
|
+
if (!result.ok) throw Object.assign(new Error(result.reason ?? "\u4E16\u754C\u5305\u5B89\u88C5\u5931\u8D25"), { code: result.conflict ? "conflict" : "io", details: result.conflict });
|
|
52
|
+
await enableInstalledPack({ ...context, info });
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
} finally {
|
|
56
|
+
resolved.dispose();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function planPackImport(filename) {
|
|
60
|
+
return inspectImport(filename, async (plan) => plan);
|
|
61
|
+
}
|
|
62
|
+
function readImportFilenames(params) {
|
|
63
|
+
if (Array.isArray(params.filenames)) {
|
|
64
|
+
const names = [...new Set(params.filenames.map((value) => identifier(value)))];
|
|
65
|
+
if (!names.length) throw new Error("\u6CA1\u6709\u8981\u5BFC\u5165\u7684\u4E16\u754C\u5305");
|
|
66
|
+
return names;
|
|
67
|
+
}
|
|
68
|
+
return [identifier(params.filename)];
|
|
69
|
+
}
|
|
70
|
+
async function importPacks(filenames, options = {}) {
|
|
71
|
+
if (filenames.length === 1) {
|
|
72
|
+
const only = filenames[0];
|
|
73
|
+
if (!only) throw new Error("\u6CA1\u6709\u8981\u5BFC\u5165\u7684\u4E16\u754C\u5305");
|
|
74
|
+
return importPack(only, options);
|
|
75
|
+
}
|
|
76
|
+
const imported = [];
|
|
77
|
+
for (const name of filenames) {
|
|
78
|
+
try {
|
|
79
|
+
await importPack(name);
|
|
80
|
+
imported.push(name);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
83
|
+
const code = error.code;
|
|
84
|
+
throw Object.assign(new Error(imported.length ? `\u5DF2\u5BFC\u5165 ${imported.length} \u4E2A\uFF0C\u7EE7\u7EED\u5BFC\u5165 ${name} \u5931\u8D25\uFF1A${message}` : message), typeof code === "string" ? { code } : {});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { changed: true, restartRequired: true, imported: imported.length };
|
|
88
|
+
}
|
|
89
|
+
function importPack(filename, options = {}) {
|
|
90
|
+
return inspectImport(filename, async (plan, install) => {
|
|
91
|
+
if (options.force && !options.revision || options.revision !== void 0 && options.revision !== plan.revision) {
|
|
92
|
+
throw Object.assign(new Error("\u5BFC\u5165\u6587\u4EF6\u6216\u5DF2\u5B89\u88C5\u5305\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u91CD\u65B0\u5BFC\u5165\u5E76\u786E\u8BA4"), { code: "conflict" });
|
|
93
|
+
}
|
|
94
|
+
const conflicts = plan.packs.filter((pack) => pack.action === "conflict");
|
|
95
|
+
if (conflicts.length && !options.force) {
|
|
96
|
+
throw Object.assign(new Error(`\u4E16\u754C\u5305\u9700\u8981\u786E\u8BA4\u8986\u76D6\uFF1A${conflicts.map((pack) => `${pack.name}\uFF08\u5DF2\u6709 ${pack.existing.version}\uFF0C\u5BFC\u5165 ${pack.version}\uFF09`).join("\u3001")}`), { code: "conflict", details: { conflicts } });
|
|
97
|
+
}
|
|
98
|
+
await install(options.force === true);
|
|
99
|
+
return { changed: true, restartRequired: true };
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
export {
|
|
103
|
+
importPack,
|
|
104
|
+
importPacks,
|
|
105
|
+
planPackImport,
|
|
106
|
+
readImportFilenames
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=pack-import.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/management/pack-import.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport type { PackImportPlan, PackImportOptions } from \"@sfmc-bds/management\";\nimport { decidePackInstallPlan, enableInstalledPack, installPackDirectory, readPackManifestInfo, resolvePackRoots, scanDestOccupancy, worldPackParentDir } from \"@sfmc-bds/bds-tools/world-packs\";\nimport { ROOT } from \"../runtime.js\";\nimport { resolveBdsContext } from \"../pack-lifecycle.js\";\nimport { identifier } from \"./domain.js\";\n\n/** \u4E0E REPL \u5171\u7528\u5B89\u88C5\u51B3\u7B56\uFF1B\u5148\u68C0\u67E5\u6574\u4E2A\u5F52\u6863\uFF0C\u907F\u514D\u540E\u9762\u7684\u51B2\u7A81\u5BFC\u81F4\u524D\u9762\u7684\u5305\u5DF2\u88AB\u5199\u5165\u3002 */\nasync function inspectImport<T>(filename: string, action: (plan: PackImportPlan, install: (force: boolean) => Promise<void>) => Promise<T>): Promise<T> {\n const inbox = path.resolve(ROOT, \"packs\", \"_desktop-inbox\");\n const file = path.resolve(inbox, identifier(filename));\n if (!file.startsWith(inbox + path.sep) || !fs.existsSync(file)) throw new Error(\"\u4E16\u754C\u5305\u5C1A\u672A\u4E0A\u4F20\u5230\u5B9E\u4F8B\u6536\u4EF6\u7BB1\");\n const context = resolveBdsContext();\n const resolved = await resolvePackRoots(file);\n try {\n if (!resolved.roots.length) throw new Error(\"\u5F52\u6863\u4E0D\u542B\u53EF\u8BC6\u522B\u7684\u4E16\u754C\u5305\");\n const seen = new Set<string>();\n const prepared = resolved.roots.map(source => {\n const info = readPackManifestInfo(source);\n if (!info) throw new Error(\"\u4E16\u754C\u5305 manifest \u65E0\u6548\");\n const id = info.uuid.toLowerCase();\n if (seen.has(id)) throw new Error(`\u5F52\u6863\u5305\u542B\u91CD\u590D\u7684\u4E16\u754C\u5305 UUID: ${info.uuid}`);\n seen.add(id);\n const destParent = worldPackParentDir(context.bdsRoot, context.levelName, info.kind);\n const decision = decidePackInstallPlan({ incoming: info, hint: path.basename(source), occupancy: scanDestOccupancy(destParent) });\n return { source, info, destParent, decision };\n });\n const hash = createHash(\"sha256\");\n for await (const chunk of fs.createReadStream(file)) hash.update(chunk);\n hash.update(JSON.stringify({\n context,\n existing: prepared.map(({ info, decision }) => ({\n id: info.uuid,\n dir: decision.kind === \"fresh\" ? null : decision.dir,\n manifest: decision.kind === \"fresh\" ? null : fs.readFileSync(path.join(decision.dir, \"manifest.json\"), \"utf8\"),\n })),\n }));\n const plan: PackImportPlan = {\n revision: hash.digest(\"hex\"),\n packs: prepared.map(({ info, decision }) => ({\n id: info.uuid, name: info.name, kind: info.kind, version: info.version.join(\".\"),\n action: decision.kind === \"fresh\" ? \"install\" : decision.kind === \"needConfirm\" ? \"conflict\" : \"update\",\n ...(decision.kind === \"fresh\" ? {} : { existing: { name: decision.existing.name, version: decision.existing.version.join(\".\") } }),\n })),\n };\n return await action(plan, async force => {\n for (const { source, info, destParent } of prepared) {\n const result = await installPackDirectory({ srcDir: source, destParent, force });\n if (!result.ok) throw Object.assign(new Error(result.reason ?? \"\u4E16\u754C\u5305\u5B89\u88C5\u5931\u8D25\"), { code: result.conflict ? \"conflict\" : \"io\", details: result.conflict });\n await enableInstalledPack({ ...context, info });\n }\n });\n } finally { resolved.dispose(); }\n}\n\nexport function planPackImport(filename: string): Promise<PackImportPlan> {\n return inspectImport(filename, async plan => plan);\n}\n\n/**\n * \u4ECE\u7BA1\u7406\u8BF7\u6C42\u53D6\u51FA\u6536\u4EF6\u7BB1\u6587\u4EF6\u540D\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u684C\u9762\u4E00\u6B21\u62D6\u5165\u6216\u9009\u4E2D\u591A\u4E2A\u4E16\u754C\u5305\u65F6\u4F20 filenames\uFF1B\u65E7\u5BA2\u6237\u7AEF\u4ECD\u53EA\u4F20 filename\u3002\n */\nexport function readImportFilenames(params: { filename?: unknown; filenames?: unknown }): string[] {\n if (Array.isArray(params.filenames)) {\n const names = [...new Set(params.filenames.map(value => identifier(value)))];\n if (!names.length) throw new Error(\"\u6CA1\u6709\u8981\u5BFC\u5165\u7684\u4E16\u754C\u5305\");\n return names;\n }\n return [identifier(params.filename)];\n}\n\n/**\n * \u6309\u987A\u5E8F\u5BFC\u5165\u591A\u4E2A\u6536\u4EF6\u7BB1\u6587\u4EF6\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u6279\u91CF\u5BFC\u5165\u3002\u53EA\u6709\u4E00\u4E2A\u6587\u4EF6\u65F6\u4ECD\u8D70 importPack\uFF0C\u4FDD\u7559 force \u4E0E revision \u7684\u539F\u6709\u6821\u9A8C\u3002\n * \u4E2D\u9014\u5931\u8D25\u65F6\uFF0C\u524D\u9762\u5DF2\u7ECF\u5B89\u88C5\u7684\u5305\u4FDD\u7559\uFF0C\u9519\u8BEF\u91CC\u5E26\u4E0A\u5DF2\u5BFC\u5165\u6570\u91CF\u3002\n */\nexport async function importPacks(filenames: string[], options: PackImportOptions = {}) {\n if (filenames.length === 1) {\n const only = filenames[0];\n if (!only) throw new Error(\"\u6CA1\u6709\u8981\u5BFC\u5165\u7684\u4E16\u754C\u5305\");\n return importPack(only, options);\n }\n const imported: string[] = [];\n for (const name of filenames) {\n try {\n await importPack(name);\n imported.push(name);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const code = (error as { code?: unknown }).code;\n throw Object.assign(new Error(imported.length ? `\u5DF2\u5BFC\u5165 ${imported.length} \u4E2A\uFF0C\u7EE7\u7EED\u5BFC\u5165 ${name} \u5931\u8D25\uFF1A${message}` : message), typeof code === \"string\" ? { code } : {});\n }\n }\n return { changed: true, restartRequired: true, imported: imported.length };\n}\n\n/** force \u5FC5\u987B\u7ED1\u5B9A\u7528\u6237\u770B\u8FC7\u7684\u5F52\u6863\u53CA\u5DF2\u6709\u5305\u7248\u672C\uFF0C\u6392\u961F\u671F\u95F4\u6709\u53D8\u5316\u65F6\u91CD\u65B0\u786E\u8BA4\u3002 */\nexport function importPack(filename: string, options: PackImportOptions = {}) {\n return inspectImport(filename, async (plan, install) => {\n if ((options.force && !options.revision) || (options.revision !== undefined && options.revision !== plan.revision)) {\n throw Object.assign(new Error(\"\u5BFC\u5165\u6587\u4EF6\u6216\u5DF2\u5B89\u88C5\u5305\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u91CD\u65B0\u5BFC\u5165\u5E76\u786E\u8BA4\"), { code: \"conflict\" });\n }\n const conflicts = plan.packs.filter(pack => pack.action === \"conflict\");\n if (conflicts.length && !options.force) {\n throw Object.assign(new Error(`\u4E16\u754C\u5305\u9700\u8981\u786E\u8BA4\u8986\u76D6\uFF1A${conflicts.map(pack => `${pack.name}\uFF08\u5DF2\u6709 ${pack.existing!.version}\uFF0C\u5BFC\u5165 ${pack.version}\uFF09`).join(\"\u3001\")}`), { code: \"conflict\", details: { conflicts } });\n }\n await install(options.force === true);\n return { changed: true, restartRequired: true };\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/management/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/management/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAA6C,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAO/H,OAAO,EAAE,SAAS,EAAgC,MAAM,YAAY,CAAC;AAsBrE,wBAAgB,eAAe,cAQ9B;AACD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,2BAA+E;AA4C3J,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAuNrF"}
|
|
@@ -2,23 +2,24 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import { EventEmitter } from "node:events";
|
|
5
|
-
import { MANAGEMENT_PROTOCOL_VERSION } from "@sfmc-bds/management";
|
|
5
|
+
import { LOG_TAIL_MAX, MANAGEMENT_PROTOCOL_VERSION } from "@sfmc-bds/management";
|
|
6
6
|
import { readQqBindings } from "@sfmc-bds/db-server/qq-bindings";
|
|
7
7
|
import { ROOT, isRuntimeInitialized, spawnService } from "../runtime.js";
|
|
8
8
|
import { queryServicesRuntimeLocal, services, START_ORDER, SERVICE_NAMES, refreshServices, onServiceStateChange } from "../services.js";
|
|
9
|
-
import { readDiskLogs, onLog } from "../logs.js";
|
|
9
|
+
import { readDiskLogs, deleteStoredLogs, onLog } from "../logs.js";
|
|
10
10
|
import { cmdModuleEnable, cmdModuleDisable } from "../module-commands.js";
|
|
11
11
|
import { ensureCoreConfigs } from "@sfmc-bds/sdk/node/config";
|
|
12
12
|
import { TaskStore, atomicJson } from "./tasks.js";
|
|
13
13
|
import { configFiles, readDocument, revision, saveDocument, validateDocument } from "./config.js";
|
|
14
|
-
import { listModules, searchModules, identifier, runFetch, readJson, listPacks, togglePack,
|
|
15
|
-
import { attachmentPlan, platformVersion, withStoppedServices, launchPlatformUpdate, createBackup, restoreSnapshot, verifyRunning } from "./maintenance.js";
|
|
14
|
+
import { listModules, searchModules, identifier, runFetch, readJson, listPacks, togglePack, readPackIcon, uninstallPack, setPackVersion, playerFiles, savePlayerPermissions, modulePlan, applyModulePlan, moduleInstallBlock } from "./domain.js";
|
|
15
|
+
import { attachmentPlan, platformVersion, withStoppedServices, launchPlatformUpdate, createBackup, restoreSnapshot, deleteSnapshot, verifyRunning } from "./maintenance.js";
|
|
16
16
|
import { startupPlan } from "./startup.js";
|
|
17
17
|
import { cmdPackBuild, cmdPackDeploy } from "../pack-lifecycle.js";
|
|
18
18
|
import { withMaintenanceLock } from "@sfmc-bds/management/node";
|
|
19
19
|
import { deploymentPreflight, deploymentPort } from "./deployment.js";
|
|
20
20
|
import { resolveBdsContext } from "../pack-lifecycle.js";
|
|
21
21
|
import { readRuntimeMetrics } from "./metrics-read.js";
|
|
22
|
+
import { importPacks, planPackImport, readImportFilenames } from "./pack-import.js";
|
|
22
23
|
const events = new EventEmitter();
|
|
23
24
|
function deploymentInitialized() {
|
|
24
25
|
if (isRuntimeInitialized()) return true;
|
|
@@ -49,6 +50,12 @@ function string(value, label) {
|
|
|
49
50
|
if (typeof value !== "string" || value.length > 2 * 1024 * 1024) throw new Error(`\u975E\u6CD5 ${label}`);
|
|
50
51
|
return value;
|
|
51
52
|
}
|
|
53
|
+
function timeBound(value, label) {
|
|
54
|
+
if (value === void 0) return void 0;
|
|
55
|
+
const date = new Date(string(value, label));
|
|
56
|
+
if (Number.isNaN(date.getTime())) throw new Error(`\u975E\u6CD5 ${label}`);
|
|
57
|
+
return date;
|
|
58
|
+
}
|
|
52
59
|
function service(value) {
|
|
53
60
|
if (!SERVICE_NAMES.includes(value)) throw new Error("\u672A\u77E5\u670D\u52A1");
|
|
54
61
|
return value;
|
|
@@ -93,7 +100,7 @@ async function dispatchManagement(request) {
|
|
|
93
100
|
const store = managementTasks();
|
|
94
101
|
switch (request.method) {
|
|
95
102
|
case "handshake":
|
|
96
|
-
return { protocolVersion: MANAGEMENT_PROTOCOL_VERSION, platformVersion: platformVersion(), host: { os: process.platform === "win32" ? "windows" : process.platform, arch: process.arch, release: os.release() }, root: ROOT, capabilities: ["services", "logs", "modules", "config", "packs", "players", "updates", "operations", "metrics", "manual-restart", "manual-backup"], daemonPid: process.pid, daemonStartedAt: new Date(Date.now() - process.uptime() * 1e3).toISOString(), initialized: deploymentInitialized() };
|
|
103
|
+
return { protocolVersion: MANAGEMENT_PROTOCOL_VERSION, platformVersion: platformVersion(), host: { os: process.platform === "win32" ? "windows" : process.platform, arch: process.arch, release: os.release() }, root: ROOT, capabilities: ["services", "logs", "logs-range", "modules", "config", "packs", "players", "updates", "operations", "metrics", "manual-restart", "manual-backup", "pack-import-plan", "pack-icons", "pack-uninstall", "backup-delete", "pack-import-batch", "pack-version"], daemonPid: process.pid, daemonStartedAt: new Date(Date.now() - process.uptime() * 1e3).toISOString(), initialized: deploymentInitialized() };
|
|
97
104
|
case "events.subscribe":
|
|
98
105
|
return { subscribed: true };
|
|
99
106
|
case "services.list":
|
|
@@ -141,8 +148,32 @@ async function dispatchManagement(request) {
|
|
|
141
148
|
return { delivered: true };
|
|
142
149
|
});
|
|
143
150
|
}
|
|
144
|
-
case "logs.tail":
|
|
145
|
-
|
|
151
|
+
case "logs.tail": {
|
|
152
|
+
const since = timeBound(p.since, "\u5F00\u59CB\u65F6\u95F4");
|
|
153
|
+
const until = timeBound(p.until, "\u7ED3\u675F\u65F6\u95F4");
|
|
154
|
+
if (since && until && until < since) throw new Error("\u7ED3\u675F\u65F6\u95F4\u4E0D\u80FD\u65E9\u4E8E\u5F00\u59CB\u65F6\u95F4");
|
|
155
|
+
const limit = Math.min(LOG_TAIL_MAX, Math.max(1, Number(p.limit) || 1e3));
|
|
156
|
+
const ranged = Boolean(since || until);
|
|
157
|
+
const entries = readDiskLogs({
|
|
158
|
+
...ranged ? {} : { limit },
|
|
159
|
+
...since ? { since } : {},
|
|
160
|
+
...until ? { until } : {},
|
|
161
|
+
...Array.isArray(p.sources) ? { sources: p.sources.map((value) => string(value, "\u65E5\u5FD7\u6765\u6E90")) } : {},
|
|
162
|
+
...Array.isArray(p.levels) ? { levels: p.levels } : {}
|
|
163
|
+
});
|
|
164
|
+
const truncated = entries.length > limit;
|
|
165
|
+
return { entries: (truncated ? entries.slice(entries.length - limit) : entries).map((log) => ({ ...log, time: log.time.toISOString() })), ...truncated ? { truncated: true } : {} };
|
|
166
|
+
}
|
|
167
|
+
case "logs.delete": {
|
|
168
|
+
const since = timeBound(p.since, "\u5F00\u59CB\u65F6\u95F4");
|
|
169
|
+
const until = timeBound(p.until, "\u7ED3\u675F\u65F6\u95F4");
|
|
170
|
+
if (!since || !until) throw new Error("\u5220\u9664\u65E5\u5FD7\u9700\u8981\u5F00\u59CB\u548C\u7ED3\u675F\u65F6\u95F4");
|
|
171
|
+
if (until < since) throw new Error("\u7ED3\u675F\u65F6\u95F4\u4E0D\u80FD\u65E9\u4E8E\u5F00\u59CB\u65F6\u95F4");
|
|
172
|
+
const source = p.source === void 0 ? void 0 : string(p.source, "\u65E5\u5FD7\u6765\u6E90");
|
|
173
|
+
if (source !== void 0 && (source.length > 128 || /[\r\n]/.test(source))) throw new Error("\u975E\u6CD5\u65E5\u5FD7\u6765\u6E90");
|
|
174
|
+
const text = p.text === void 0 ? void 0 : string(p.text, "\u65E5\u5FD7\u6B63\u6587");
|
|
175
|
+
return deleteStoredLogs({ since, until, ...source === void 0 ? {} : { source }, ...text === void 0 ? {} : { text } });
|
|
176
|
+
}
|
|
146
177
|
case "operations.list":
|
|
147
178
|
return { operations: store.list().filter((row) => !Array.isArray(p.statuses) || p.statuses.includes(row.status)).slice(0, Math.min(Number(p.limit) || 100, 200)) };
|
|
148
179
|
case "operations.get":
|
|
@@ -155,6 +186,8 @@ async function dispatchManagement(request) {
|
|
|
155
186
|
const id = identifier(p.id);
|
|
156
187
|
const linked = (await listModules()).modules.find((row) => row.id === id || row.folder === id)?.linked;
|
|
157
188
|
if (linked) throw new Error("\u4FDD\u7559\u672C\u5730\u94FE\u63A5\u6A21\u5757\uFF0C\u4E0D\u901A\u8FC7\u5305\u5B89\u88C5\u6216\u5378\u8F7D\u8986\u76D6\u5F00\u53D1\u76EE\u5F55");
|
|
189
|
+
const block = await moduleInstallBlock(id);
|
|
190
|
+
if (block) throw new Error(block);
|
|
158
191
|
return store.submit(request.method, async (context) => {
|
|
159
192
|
context.phase("download", "\u4E0B\u8F7D\u5E76\u5B89\u88C5\u6A21\u5757\uFF0C\u670D\u52A1\u5668\u4FDD\u6301\u8FD0\u884C");
|
|
160
193
|
const args = ["install", id];
|
|
@@ -223,16 +256,35 @@ async function dispatchManagement(request) {
|
|
|
223
256
|
}
|
|
224
257
|
case "packs.list":
|
|
225
258
|
return listPacks();
|
|
226
|
-
case "packs.
|
|
259
|
+
case "packs.icon":
|
|
260
|
+
return readPackIcon(identifier(p.id));
|
|
261
|
+
case "packs.import.plan":
|
|
262
|
+
return planPackImport(identifier(p.filename));
|
|
263
|
+
case "packs.import": {
|
|
264
|
+
const names = readImportFilenames(p);
|
|
227
265
|
return store.submit(request.method, async (context) => {
|
|
228
|
-
context.phase("execute", "\u5BFC\u5165\u4E16\u754C\u5305\uFF0C\u7B49\u5F85\u624B\u52A8\u91CD\u542F BDS");
|
|
229
|
-
return
|
|
266
|
+
context.phase("execute", names.length > 1 ? `\u5BFC\u5165 ${names.length} \u4E2A\u4E16\u754C\u5305\uFF0C\u7B49\u5F85\u624B\u52A8\u91CD\u542F BDS` : "\u5BFC\u5165\u4E16\u754C\u5305\uFF0C\u7B49\u5F85\u624B\u52A8\u91CD\u542F BDS");
|
|
267
|
+
return importPacks(names, { force: p.force === true, ...p.revision === void 0 ? {} : { revision: string(p.revision, "\u5BFC\u5165\u8BA1\u5212\u7248\u672C") } });
|
|
230
268
|
});
|
|
269
|
+
}
|
|
231
270
|
case "packs.toggle":
|
|
232
271
|
return store.submit(request.method, async (context) => {
|
|
233
272
|
context.phase("execute", "\u4FDD\u5B58\u4E16\u754C\u5305\u72B6\u6001\uFF0C\u7B49\u5F85\u624B\u52A8\u91CD\u542F BDS");
|
|
234
273
|
return togglePack(identifier(p.id), p.enabled === true);
|
|
235
274
|
});
|
|
275
|
+
case "packs.uninstall":
|
|
276
|
+
return store.submit(request.method, async (context) => {
|
|
277
|
+
context.phase("execute", "\u5378\u8F7D\u4E16\u754C\u5305\u5E76\u79FB\u5165\u56DE\u6536\u7AD9\uFF0C\u7B49\u5F85\u624B\u52A8\u91CD\u542F BDS");
|
|
278
|
+
return uninstallPack(identifier(p.id));
|
|
279
|
+
});
|
|
280
|
+
case "packs.version": {
|
|
281
|
+
const id = identifier(p.id);
|
|
282
|
+
const version = p.version;
|
|
283
|
+
return store.submit(request.method, async (context) => {
|
|
284
|
+
context.phase("execute", "\u5199\u5165\u8D44\u6E90\u5305\u7248\u672C\uFF0C\u7B49\u5F85\u624B\u52A8\u91CD\u542F BDS");
|
|
285
|
+
return setPackVersion(id, version);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
236
288
|
case "players.list":
|
|
237
289
|
return players();
|
|
238
290
|
case "metrics.read":
|
|
@@ -316,6 +368,11 @@ async function dispatchManagement(request) {
|
|
|
316
368
|
if (p.confirmDataLoss !== true) throw new Error("\u6062\u590D\u6570\u636E\u9700\u8981\u660E\u786E\u786E\u8BA4\u4E22\u5F03\u5907\u4EFD\u4E4B\u540E\u7684\u53D8\u66F4");
|
|
317
369
|
return store.submit(request.method, (context) => withStoppedServices(context, [...START_ORDER], () => restoreSnapshot(identifier(p.id), context.phase)));
|
|
318
370
|
}
|
|
371
|
+
case "backups.delete":
|
|
372
|
+
return store.submit(request.method, async (context) => {
|
|
373
|
+
context.phase("execute", "\u5220\u9664\u5907\u4EFD\u76EE\u5F55");
|
|
374
|
+
return deleteSnapshot(identifier(p.id));
|
|
375
|
+
});
|
|
319
376
|
case "startup.plan":
|
|
320
377
|
return startupPlan();
|
|
321
378
|
default:
|