@sfmc-bds/bds-tools 0.1.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/README.md +18 -0
- package/dist/bds-manager.d.ts +27 -0
- package/dist/bds-manager.d.ts.map +1 -0
- package/dist/bds-manager.js +294 -0
- package/dist/bds-manager.js.map +1 -0
- package/dist/changelog.d.ts +9 -0
- package/dist/changelog.d.ts.map +1 -0
- package/dist/changelog.js +59 -0
- package/dist/changelog.js.map +1 -0
- package/dist/check-update.d.ts +12 -0
- package/dist/check-update.d.ts.map +1 -0
- package/dist/check-update.js +442 -0
- package/dist/check-update.js.map +1 -0
- package/dist/cli-pack-manager.d.ts +19 -0
- package/dist/cli-pack-manager.d.ts.map +1 -0
- package/dist/cli-pack-manager.js +154 -0
- package/dist/cli-pack-manager.js.map +1 -0
- package/dist/fsx.d.ts +25 -0
- package/dist/fsx.d.ts.map +1 -0
- package/dist/fsx.js +117 -0
- package/dist/fsx.js.map +1 -0
- package/dist/http.d.ts +37 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +203 -0
- package/dist/http.js.map +1 -0
- package/dist/log.d.ts +13 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +22 -0
- package/dist/log.js.map +1 -0
- package/dist/logger.d.ts +10 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +10 -0
- package/dist/logger.js.map +1 -0
- package/dist/pack-manager.d.ts +136 -0
- package/dist/pack-manager.d.ts.map +1 -0
- package/dist/pack-manager.js +264 -0
- package/dist/pack-manager.js.map +1 -0
- package/dist/paths.d.ts +28 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +47 -0
- package/dist/paths.js.map +1 -0
- package/dist/qqutil.d.ts +13 -0
- package/dist/qqutil.d.ts.map +1 -0
- package/dist/qqutil.js +101 -0
- package/dist/qqutil.js.map +1 -0
- package/dist/recovery.d.ts +8 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +45 -0
- package/dist/recovery.js.map +1 -0
- package/dist/rollback.d.ts +36 -0
- package/dist/rollback.d.ts.map +1 -0
- package/dist/rollback.js +87 -0
- package/dist/rollback.js.map +1 -0
- package/dist/taskbar.d.ts +42 -0
- package/dist/taskbar.d.ts.map +1 -0
- package/dist/taskbar.js +94 -0
- package/dist/taskbar.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/upstream.d.ts +20 -0
- package/dist/upstream.d.ts.map +1 -0
- package/dist/upstream.js +126 -0
- package/dist/upstream.js.map +1 -0
- package/dist/version.d.ts +20 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +97 -0
- package/dist/version.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pack-manager.ts — Bedrock 行为包/资源包 装配 + 部署到 BDS 根。
|
|
3
|
+
*
|
|
4
|
+
* 这是 SEA 与 npm 两条用户路径共用的纯函数库:
|
|
5
|
+
*
|
|
6
|
+
* - SEA:用户在 REPL/wizard 里跑 `sfmc behavior-pack build/deploy`
|
|
7
|
+
* → sfmc 通过 spawnService 启 `bds-tools/dist/pack-manager.js`,
|
|
8
|
+
* SEA 自己跑 esbuild 把脚本 bundle 写到 <modulesDir>/build/sfmc-modules-bp/scripts/main.js,
|
|
9
|
+
* 然后调 pack-manager#assembleBehaviorPack 装配。
|
|
10
|
+
* - npm: 用户跑 `sfmc behavior-pack build`,
|
|
11
|
+
* 同一 spawnService 路径。或者直接在同进程 import 这个库。
|
|
12
|
+
*
|
|
13
|
+
* 关键约束:本文件不允许引 esbuild / 任何 npm-only 包 — SEA 要把它打成 SEA
|
|
14
|
+
* 的一部分内嵌起来,而 SEA 是个单 exe (除 Node 内置 + bds-tools 已有依赖外)。
|
|
15
|
+
*
|
|
16
|
+
* 已有依赖 (bds-tools/package.json):
|
|
17
|
+
* - cli-progress: 进度条
|
|
18
|
+
* - node-html-parser: changelog 抓取 (本文件用不到)
|
|
19
|
+
* - jszip: zip 解压(模块 zip / BDS server.zip),与 sfmc/wizard 共享同一个库
|
|
20
|
+
*
|
|
21
|
+
* 没有外部依赖意味着:SEA 静态把 `bds-tools/dist/*` 解压到 exe 旁边即可,
|
|
22
|
+
*不需把 npm 整棵树带进去。
|
|
23
|
+
*/
|
|
24
|
+
import fs from "node:fs";
|
|
25
|
+
import path from "node:path";
|
|
26
|
+
import { copyDirAsync, copyFileAsync } from "./fsx.js";
|
|
27
|
+
/* ── 路径常量 ─────────────────────────────────────────────────────────── */
|
|
28
|
+
/** SFMC 合成 BP 的固定 @minecraft/* permissions,所有用到的命名空间都打开。 */
|
|
29
|
+
export const SFMC_PERMISSIONS = [
|
|
30
|
+
"@minecraft/server",
|
|
31
|
+
"@minecraft/server-ui",
|
|
32
|
+
"@minecraft/server-admin",
|
|
33
|
+
"@minecraft/server-gametest",
|
|
34
|
+
"@minecraft/server-net",
|
|
35
|
+
"@minecraft/server-editor",
|
|
36
|
+
"@minecraft/diagnostics",
|
|
37
|
+
];
|
|
38
|
+
/** 随机生成 BP/RP manifest.json header.uuid (RFC 4122 v4) */
|
|
39
|
+
export function randomUuid() {
|
|
40
|
+
/* crypto.randomUUID 是 Node 19+ 内置,SEA 走 Node 22+,这里直接用 */
|
|
41
|
+
return crypto.randomUUID();
|
|
42
|
+
}
|
|
43
|
+
/* ── 骨架函数 (Commit 5 实现) ──────────────────────────────────────────── */
|
|
44
|
+
/**
|
|
45
|
+
* Assemble a Bedrock behavior pack directory at `outDir` from a prebuilt
|
|
46
|
+
* `srcDir` (which must already contain `scripts/main.js` plus whatever else
|
|
47
|
+
* was bundled by esbuild) and write a fresh `manifest.json` + `permissions.json`.
|
|
48
|
+
*
|
|
49
|
+
* The caller is responsible for running esbuild first; pack-manager does not
|
|
50
|
+
* bundle scripts. That decoupling is what lets the SEA ship without esbuild.
|
|
51
|
+
*/
|
|
52
|
+
export async function assembleBehaviorPack(opts) {
|
|
53
|
+
const version = opts.version ?? [1, 0, 0];
|
|
54
|
+
const bpUuid = randomUuid();
|
|
55
|
+
await fs.promises.rm(opts.outDir, { recursive: true, force: true });
|
|
56
|
+
await fs.promises.mkdir(opts.outDir, { recursive: true });
|
|
57
|
+
if (fs.existsSync(opts.srcDir)) {
|
|
58
|
+
await copyDirAsync(opts.srcDir, opts.outDir);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
await fs.promises.mkdir(path.join(opts.outDir, "scripts"), { recursive: true });
|
|
62
|
+
await fs.promises.writeFile(path.join(opts.outDir, "scripts", "main.js"), "/* no scripts */\n", "utf8");
|
|
63
|
+
}
|
|
64
|
+
await writeBehaviorPackManifest(opts.outDir, {
|
|
65
|
+
name: opts.projectName,
|
|
66
|
+
uuid: bpUuid,
|
|
67
|
+
version,
|
|
68
|
+
description: opts.description,
|
|
69
|
+
});
|
|
70
|
+
if (opts.iconSrc && fs.existsSync(opts.iconSrc)) {
|
|
71
|
+
await copyFileAsync(opts.iconSrc, path.join(opts.outDir, "pack_icon.png"));
|
|
72
|
+
}
|
|
73
|
+
await writePermissionsJson(opts.outDir);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Merge every enabled module's `resource_pack/**` tree into one RP directory
|
|
77
|
+
* at `outDir`, with a single fresh `manifest.json`. Per-module subfolders are
|
|
78
|
+
* preserved so resource pack authors can disambiguate (e.g. `peace/textures/...`).
|
|
79
|
+
*/
|
|
80
|
+
export async function assembleResourcePack(opts) {
|
|
81
|
+
const version = opts.version ?? [1, 0, 0];
|
|
82
|
+
const rpUuid = randomUuid();
|
|
83
|
+
await fs.promises.rm(opts.outDir, { recursive: true, force: true });
|
|
84
|
+
await fs.promises.mkdir(opts.outDir, { recursive: true });
|
|
85
|
+
for (const [moduleId, rpDir] of Object.entries(opts.moduleResourceDirs)) {
|
|
86
|
+
if (!fs.existsSync(rpDir))
|
|
87
|
+
continue;
|
|
88
|
+
const dst = path.join(opts.outDir, moduleId);
|
|
89
|
+
await fs.promises.mkdir(dst, { recursive: true });
|
|
90
|
+
await copyDirAsync(rpDir, dst);
|
|
91
|
+
}
|
|
92
|
+
await writeResourcePackManifest(opts.outDir, {
|
|
93
|
+
name: opts.projectName,
|
|
94
|
+
uuid: rpUuid,
|
|
95
|
+
version,
|
|
96
|
+
description: opts.description,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Read the `level-name=` value from `<bdsRoot>/server.properties`.
|
|
101
|
+
* Falls back to "Bedrock level" (BDS default) when the file is missing or
|
|
102
|
+
* the key is absent.
|
|
103
|
+
*/
|
|
104
|
+
export async function readLevelName(bdsRoot) {
|
|
105
|
+
const file = path.join(bdsRoot, "server.properties");
|
|
106
|
+
if (!fs.existsSync(file))
|
|
107
|
+
return "Bedrock level";
|
|
108
|
+
const text = await fs.promises.readFile(file, "utf8");
|
|
109
|
+
for (const line of text.split(/\r?\n/)) {
|
|
110
|
+
const m = /^\s*level-name\s*=\s*(.+?)\s*$/.exec(line);
|
|
111
|
+
if (m && m[1])
|
|
112
|
+
return m[1];
|
|
113
|
+
}
|
|
114
|
+
return "Bedrock level";
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Copy BP/RP source dirs into the world's behavior_packs/ + resource_packs/
|
|
118
|
+
* folders, and write a fresh `permissions.json` into the BP target.
|
|
119
|
+
*
|
|
120
|
+
* Does NOT edit world_behavior_packs.json — that's a separate step the caller
|
|
121
|
+
* must invoke after restart, because BDS only reads that file at startup.
|
|
122
|
+
*/
|
|
123
|
+
export async function deployToBDS(opts) {
|
|
124
|
+
const worldsDir = path.join(opts.bdsRoot, "worlds", opts.levelName);
|
|
125
|
+
const bpDst = path.join(worldsDir, "behavior_packs", opts.bpName);
|
|
126
|
+
const rpDst = path.join(worldsDir, "resource_packs", opts.rpName ?? `${opts.bpName}-rp`);
|
|
127
|
+
await fs.promises.mkdir(worldsDir, { recursive: true });
|
|
128
|
+
await fs.promises.rm(bpDst, { recursive: true, force: true });
|
|
129
|
+
await copyDirAsync(opts.behaviorPackSrc, bpDst);
|
|
130
|
+
await writePermissionsJson(bpDst);
|
|
131
|
+
if (opts.resourcePackSrc && fs.existsSync(opts.resourcePackSrc)) {
|
|
132
|
+
await fs.promises.rm(rpDst, { recursive: true, force: true });
|
|
133
|
+
await copyDirAsync(opts.resourcePackSrc, rpDst);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Write the seven `@minecraft/*` allowed_modules into a behavior pack's
|
|
138
|
+
* `permissions.json`. Idempotent: rewrites any pre-existing file.
|
|
139
|
+
*/
|
|
140
|
+
export async function writePermissionsJson(bpDir) {
|
|
141
|
+
const payload = { allowed_modules: [...SFMC_PERMISSIONS] };
|
|
142
|
+
await fs.promises.mkdir(bpDir, { recursive: true });
|
|
143
|
+
const tmp = path.join(bpDir, `.permissions.${process.pid}.tmp`);
|
|
144
|
+
await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
145
|
+
await fs.promises.rename(tmp, path.join(bpDir, "permissions.json"));
|
|
146
|
+
void copyDirAsync;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Add `{ pack_id, version }` to `worlds/<level>/world_behavior_packs.json`
|
|
150
|
+
* (or `world_resource_packs.json`). If the pack_id already exists, replace its
|
|
151
|
+
* version. File missing → initialize as `[]`.
|
|
152
|
+
*/
|
|
153
|
+
export async function enablePackInWorld(opts) {
|
|
154
|
+
await editWorldPackList(opts, "enable");
|
|
155
|
+
}
|
|
156
|
+
/** Remove a pack_id from the world's enable-list JSON. */
|
|
157
|
+
export async function disablePackInWorld(opts) {
|
|
158
|
+
await editWorldPackList(opts, "disable");
|
|
159
|
+
}
|
|
160
|
+
async function editWorldPackList(opts, mode) {
|
|
161
|
+
const file = path.join(opts.worldsDir, opts.levelName, opts.kind === "behavior" ? "world_behavior_packs.json" : "world_resource_packs.json");
|
|
162
|
+
let entries = [];
|
|
163
|
+
try {
|
|
164
|
+
const raw = await fs.promises.readFile(file, "utf8");
|
|
165
|
+
const parsed = JSON.parse(raw);
|
|
166
|
+
if (Array.isArray(parsed))
|
|
167
|
+
entries = parsed;
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
/* missing / corrupt → start with [] */
|
|
171
|
+
entries = [];
|
|
172
|
+
}
|
|
173
|
+
const idx = entries.findIndex((e) => e.pack_id === opts.packUuid);
|
|
174
|
+
if (mode === "enable") {
|
|
175
|
+
const next = { pack_id: opts.packUuid, version: opts.version };
|
|
176
|
+
if (idx >= 0)
|
|
177
|
+
entries[idx] = next;
|
|
178
|
+
else
|
|
179
|
+
entries.push(next);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
if (idx >= 0)
|
|
183
|
+
entries.splice(idx, 1);
|
|
184
|
+
}
|
|
185
|
+
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
|
186
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
187
|
+
await fs.promises.writeFile(tmp, JSON.stringify(entries, null, 2) + "\n", "utf8");
|
|
188
|
+
await fs.promises.rename(tmp, file);
|
|
189
|
+
}
|
|
190
|
+
/* ── 低层 helpers (Commit 5 实现) ──────────────────────────────────────── */
|
|
191
|
+
export async function writeBehaviorPackManifest(outDir, header) {
|
|
192
|
+
const manifest = {
|
|
193
|
+
format_version: 2,
|
|
194
|
+
header: {
|
|
195
|
+
name: header.name,
|
|
196
|
+
uuid: header.uuid,
|
|
197
|
+
version: header.version,
|
|
198
|
+
description: header.description ? `${header.description} (behavior pack)` : "SFMC behavior pack",
|
|
199
|
+
min_engine_version: [1, 21, 0],
|
|
200
|
+
},
|
|
201
|
+
modules: [
|
|
202
|
+
{
|
|
203
|
+
type: "script",
|
|
204
|
+
language: "javascript",
|
|
205
|
+
entry: "scripts/main.js",
|
|
206
|
+
uuid: crypto.randomUUID(),
|
|
207
|
+
version: header.version,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
dependencies: [
|
|
211
|
+
{ module_name: "@minecraft/server", version: "1.18.0" },
|
|
212
|
+
],
|
|
213
|
+
};
|
|
214
|
+
const file = path.join(outDir, "manifest.json");
|
|
215
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
216
|
+
await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
217
|
+
}
|
|
218
|
+
export async function writeResourcePackManifest(outDir, header) {
|
|
219
|
+
const manifest = {
|
|
220
|
+
format_version: 2,
|
|
221
|
+
header: {
|
|
222
|
+
name: header.name,
|
|
223
|
+
uuid: header.uuid,
|
|
224
|
+
version: header.version,
|
|
225
|
+
description: header.description ? `${header.description} (resource pack)` : "SFMC resource pack",
|
|
226
|
+
min_engine_version: [1, 21, 0],
|
|
227
|
+
},
|
|
228
|
+
modules: [
|
|
229
|
+
{
|
|
230
|
+
type: "resources",
|
|
231
|
+
uuid: crypto.randomUUID(),
|
|
232
|
+
version: header.version,
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
};
|
|
236
|
+
const file = path.join(outDir, "manifest.json");
|
|
237
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
238
|
+
await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
239
|
+
}
|
|
240
|
+
/* Re-export copyFileAsync so callers (e.g. SEA bundle) can copy icon without
|
|
241
|
+
* pulling in the full fsx surface area. */
|
|
242
|
+
export { copyFileAsync, copyDirAsync };
|
|
243
|
+
/* ── Discovery ─────────────────────────────────────────────────────────── */
|
|
244
|
+
/**
|
|
245
|
+
* Walk `<modulesDir>/<id>/resource_pack/` for every installed module and
|
|
246
|
+
* return a map { id: absoluteDir }. Modules without a resource_pack folder
|
|
247
|
+
* are silently skipped. Used by `assemble-rp` and the sfmc CLI to know which
|
|
248
|
+
* modules to merge into the resource pack output.
|
|
249
|
+
*/
|
|
250
|
+
export function scanModuleResourcePacks(modulesDir) {
|
|
251
|
+
const out = {};
|
|
252
|
+
if (!fs.existsSync(modulesDir))
|
|
253
|
+
return out;
|
|
254
|
+
for (const entry of fs.readdirSync(modulesDir, { withFileTypes: true })) {
|
|
255
|
+
if (!entry.isDirectory())
|
|
256
|
+
continue;
|
|
257
|
+
const rpDir = path.join(modulesDir, entry.name, "resource_pack");
|
|
258
|
+
if (fs.existsSync(rpDir)) {
|
|
259
|
+
out[entry.name] = rpDir;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return out;
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=pack-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack-manager.js","sourceRoot":"","sources":["../src/pack-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* paths.ts — 路径常量 & 加载 bds_updater.json
|
|
3
|
+
*
|
|
4
|
+
* ROOT_DIR = 项目根,通过 SDK 统一解析(env SFMC_ROOT > __dirname 上溯)。
|
|
5
|
+
* SCRIPT_DIR = bds-tools/ 内部 dist 目录,bds 的 PID / log / cache 文件落盘处。
|
|
6
|
+
*/
|
|
7
|
+
import { type BdsUpdaterConfig } from "@sfmc-bds/sdk/node/config";
|
|
8
|
+
/** 项目根目录:bds-tools 的上一级。统一通过 SDK 解析,SEA / npm 一致。 */
|
|
9
|
+
export declare const ROOT_DIR: string;
|
|
10
|
+
export declare const CFG_PATH: string;
|
|
11
|
+
export declare const LOG_PATH: string;
|
|
12
|
+
export declare const VERSION_CACHE: string;
|
|
13
|
+
export declare const PID_FILE: string;
|
|
14
|
+
export declare const ROLLBACK_MARKER: string;
|
|
15
|
+
/** 加载并解析 bds_updater.json。
|
|
16
|
+
* 启动时 ensure 文件存在,避免 wizard 没跑时 bds_updater.json 缺失导致 loadConfig 抛错。 */
|
|
17
|
+
export declare function loadConfig(): BdsUpdaterConfig;
|
|
18
|
+
/** 解析后的 BDS 路径 / 备份目录 */
|
|
19
|
+
export interface BdsPaths {
|
|
20
|
+
bds_path: string;
|
|
21
|
+
backup_dir: string;
|
|
22
|
+
preserve: string[];
|
|
23
|
+
cfg: BdsUpdaterConfig;
|
|
24
|
+
}
|
|
25
|
+
export declare function resolvePaths(cfg: BdsUpdaterConfig): BdsPaths;
|
|
26
|
+
/** 删除 PID 文件 */
|
|
27
|
+
export declare function clearPid(): void;
|
|
28
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAOnC,qDAAqD;AACrD,eAAO,MAAM,QAAQ,EAAE,MAAiE,CAAC;AACzF,eAAO,MAAM,QAAQ,EAAE,MAAiD,CAAC;AACzE,eAAO,MAAM,QAAQ,EAAE,MAA4C,CAAC;AACpE,eAAO,MAAM,aAAa,EAAE,MAAqD,CAAC;AAClF,eAAO,MAAM,QAAQ,EAAE,MAA0C,CAAC;AAClE,eAAO,MAAM,eAAe,EAAE,MAA4D,CAAC;AAE3F;yEACyE;AACzE,wBAAgB,UAAU,IAAI,gBAAgB,CAQ7C;AAED,yBAAyB;AACzB,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,gBAAgB,CAAC;CACvB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,GAAG,QAAQ,CAS5D;AAED,gBAAgB;AAChB,wBAAgB,QAAQ,IAAI,IAAI,CAM/B"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* paths.ts — 路径常量 & 加载 bds_updater.json
|
|
3
|
+
*
|
|
4
|
+
* ROOT_DIR = 项目根,通过 SDK 统一解析(env SFMC_ROOT > __dirname 上溯)。
|
|
5
|
+
* SCRIPT_DIR = bds-tools/ 内部 dist 目录,bds 的 PID / log / cache 文件落盘处。
|
|
6
|
+
*/
|
|
7
|
+
import { configPath, ensureJsonConfig, resolveRuntimeRoot, } from "@sfmc-bds/sdk/node/config";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const SCRIPT_DIR = path.dirname(__filename);
|
|
13
|
+
/** 项目根目录:bds-tools 的上一级。统一通过 SDK 解析,SEA / npm 一致。 */
|
|
14
|
+
export const ROOT_DIR = resolveRuntimeRoot(path.resolve(SCRIPT_DIR, "..", ".."));
|
|
15
|
+
export const CFG_PATH = configPath(ROOT_DIR, "bds_updater.json");
|
|
16
|
+
export const LOG_PATH = path.join(SCRIPT_DIR, "update.log");
|
|
17
|
+
export const VERSION_CACHE = path.join(SCRIPT_DIR, ".version_cache.json");
|
|
18
|
+
export const PID_FILE = path.join(SCRIPT_DIR, ".bds.pid");
|
|
19
|
+
export const ROLLBACK_MARKER = path.join(SCRIPT_DIR, ".last_update_rollback.json");
|
|
20
|
+
/** 加载并解析 bds_updater.json。
|
|
21
|
+
* 启动时 ensure 文件存在,避免 wizard 没跑时 bds_updater.json 缺失导致 loadConfig 抛错。 */
|
|
22
|
+
export function loadConfig() {
|
|
23
|
+
const cfg = ensureJsonConfig(ROOT_DIR, "bds_updater.json", {});
|
|
24
|
+
delete cfg._comment;
|
|
25
|
+
return cfg;
|
|
26
|
+
}
|
|
27
|
+
export function resolvePaths(cfg) {
|
|
28
|
+
const bds_path = path.resolve(cfg.bds_path || process.cwd());
|
|
29
|
+
const backup_dir = path.resolve(cfg.backup_dir || path.join(bds_path, "..", "backups"));
|
|
30
|
+
const relativeBackup = path.relative(bds_path, backup_dir);
|
|
31
|
+
if (relativeBackup === "" || (!relativeBackup.startsWith("..") && !path.isAbsolute(relativeBackup))) {
|
|
32
|
+
throw new Error("backup_dir must be outside bds_path so deployment cannot delete the backup");
|
|
33
|
+
}
|
|
34
|
+
const preserve = Array.isArray(cfg.preserve) ? cfg.preserve : [];
|
|
35
|
+
return { bds_path, backup_dir, preserve, cfg };
|
|
36
|
+
}
|
|
37
|
+
/** 删除 PID 文件 */
|
|
38
|
+
export function clearPid() {
|
|
39
|
+
try {
|
|
40
|
+
if (fs.existsSync(PID_FILE))
|
|
41
|
+
fs.unlinkSync(PID_FILE);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
/* ignore */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,kBAAkB,GAEnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,UAAU,GAAW,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AACpD,qDAAqD;AACrD,MAAM,CAAC,MAAM,QAAQ,GAAW,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AACzF,MAAM,CAAC,MAAM,QAAQ,GAAW,UAAU,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,QAAQ,GAAW,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AACpE,MAAM,CAAC,MAAM,aAAa,GAAW,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC;AAClF,MAAM,CAAC,MAAM,QAAQ,GAAW,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,eAAe,GAAW,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,4BAA4B,CAAC,CAAC;AAE3F;yEACyE;AACzE,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,gBAAgB,CAC1B,QAAQ,EACR,kBAAkB,EAClB,EAAE,CACH,CAAC;IACF,OAAO,GAAG,CAAC,QAAQ,CAAC;IACpB,OAAO,GAAG,CAAC;AACb,CAAC;AAUD,MAAM,UAAU,YAAY,CAAC,GAAqB;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IACxF,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC3D,IAAI,cAAc,KAAK,EAAE,IAAI,CAAC,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC;QACpG,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAChG,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AACjD,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC"}
|
package/dist/qqutil.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* qqutil.ts — QQ 通知工具 (基于 LLBot HTTP OneBot 11)
|
|
3
|
+
*
|
|
4
|
+
* 改进:
|
|
5
|
+
* - sendTimeout 提供总超时,避免通知发送挂死主流程
|
|
6
|
+
* - 静默模式 (失败不抛出),保证主流程不被通知干扰
|
|
7
|
+
*/
|
|
8
|
+
/** 检查 qq-bridge 模块是否启用 */
|
|
9
|
+
export declare function isQqBridgeEnabled(): boolean;
|
|
10
|
+
export declare function sendText(text: string): Promise<void>;
|
|
11
|
+
export declare function sendMixed(segments: unknown[]): Promise<void>;
|
|
12
|
+
export declare function sendWithImage(text: string, base64Img: string): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=qqutil.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qqutil.d.ts","sourceRoot":"","sources":["../src/qqutil.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,0BAA0B;AAC1B,wBAAgB,iBAAiB,IAAI,OAAO,CAQ3C;AA6CD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY1D;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAYlE;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlF"}
|
package/dist/qqutil.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* qqutil.ts — QQ 通知工具 (基于 LLBot HTTP OneBot 11)
|
|
3
|
+
*
|
|
4
|
+
* 改进:
|
|
5
|
+
* - sendTimeout 提供总超时,避免通知发送挂死主流程
|
|
6
|
+
* - 静默模式 (失败不抛出),保证主流程不被通知干扰
|
|
7
|
+
*/
|
|
8
|
+
import http from "node:http";
|
|
9
|
+
import { configPath, modulePath, readJson } from "@sfmc-bds/sdk/node/config";
|
|
10
|
+
import { ROOT_DIR } from "./paths.js";
|
|
11
|
+
import { log } from "./log.js";
|
|
12
|
+
let cachedCfg = null;
|
|
13
|
+
function getConfig() {
|
|
14
|
+
if (cachedCfg)
|
|
15
|
+
return cachedCfg;
|
|
16
|
+
cachedCfg = (readJson(configPath(ROOT_DIR, "qq_config.json")) ?? {});
|
|
17
|
+
return cachedCfg;
|
|
18
|
+
}
|
|
19
|
+
/** 检查 qq-bridge 模块是否启用 */
|
|
20
|
+
export function isQqBridgeEnabled() {
|
|
21
|
+
const catalog = readJson(modulePath(ROOT_DIR, "catalog.json"));
|
|
22
|
+
const lock = readJson(modulePath(ROOT_DIR, "module-lock.json"));
|
|
23
|
+
if (!catalog || !lock)
|
|
24
|
+
return true; // 模块目录缺失则保守视为可用
|
|
25
|
+
const mod = catalog.modules?.find((m) => m.id === "qq-bridge" || m.configKey === "qq_bridge");
|
|
26
|
+
return mod ? lock.modules?.[mod.id ?? ""]?.enabled === true : false;
|
|
27
|
+
}
|
|
28
|
+
function sendToLLBot(payload, timeoutMs = 5_000) {
|
|
29
|
+
const cfg = getConfig();
|
|
30
|
+
const url = new URL(cfg.llbot_http || "http://127.0.0.1:3000");
|
|
31
|
+
const data = JSON.stringify(payload);
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const req = http.request({
|
|
34
|
+
hostname: url.hostname,
|
|
35
|
+
port: url.port || 3000,
|
|
36
|
+
path: "/send_group_msg",
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers: {
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
"Content-Length": Buffer.byteLength(data),
|
|
41
|
+
},
|
|
42
|
+
timeout: timeoutMs,
|
|
43
|
+
}, (res) => {
|
|
44
|
+
let body = "";
|
|
45
|
+
res.on("data", (c) => (body += c));
|
|
46
|
+
res.on("end", () => {
|
|
47
|
+
if (res.statusCode === 200)
|
|
48
|
+
resolve();
|
|
49
|
+
else
|
|
50
|
+
reject(new Error(`LLBot HTTP ${res.statusCode}: ${body.slice(0, 200)}`));
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
req.on("timeout", () => {
|
|
54
|
+
req.destroy(new Error(`LLBot 超时 ${timeoutMs}ms`));
|
|
55
|
+
});
|
|
56
|
+
req.on("error", reject);
|
|
57
|
+
req.write(data);
|
|
58
|
+
req.end();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async function safeSend(label, fn) {
|
|
62
|
+
try {
|
|
63
|
+
await fn();
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
log.warn(`[QQ] ${label} 失败: ${e.message}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export async function sendText(text) {
|
|
70
|
+
const cfg = getConfig();
|
|
71
|
+
if (!isQqBridgeEnabled() || !cfg.qq_group_id) {
|
|
72
|
+
log.warn("[QQ] qq-bridge 未启用或 qq_group_id 缺失");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
await safeSend("sendText", () => sendToLLBot({
|
|
76
|
+
group_id: parseInt(cfg.qq_group_id ?? "0", 10),
|
|
77
|
+
message: [{ type: "text", data: { text } }],
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
export async function sendMixed(segments) {
|
|
81
|
+
const cfg = getConfig();
|
|
82
|
+
if (!isQqBridgeEnabled() || !cfg.qq_group_id) {
|
|
83
|
+
log.warn("[QQ] qq-bridge 未启用或 qq_group_id 缺失");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
await safeSend("sendMixed", () => sendToLLBot({
|
|
87
|
+
group_id: parseInt(cfg.qq_group_id ?? "0", 10),
|
|
88
|
+
message: segments,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
export async function sendWithImage(text, base64Img) {
|
|
92
|
+
const segments = [];
|
|
93
|
+
if (text)
|
|
94
|
+
segments.push({ type: "text", data: { text } });
|
|
95
|
+
if (base64Img)
|
|
96
|
+
segments.push({ type: "image", data: { file: `base64://${base64Img}` } });
|
|
97
|
+
if (segments.length === 0)
|
|
98
|
+
return;
|
|
99
|
+
await sendMixed(segments);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=qqutil.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qqutil.js","sourceRoot":"","sources":["../src/qqutil.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
package/dist/recovery.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recovery.ts — 手动触发回滚
|
|
3
|
+
*
|
|
4
|
+
* 用法: node recovery.js
|
|
5
|
+
* 读取 ROLLBACK_MARKER,然后从备份恢复 preserve 项。
|
|
6
|
+
*/
|
|
7
|
+
import { readRollbackMarker, rollbackFromBackup } from "./rollback.js";
|
|
8
|
+
import { log, closeLog } from "./log.js";
|
|
9
|
+
import { clearPid } from "./paths.js";
|
|
10
|
+
async function run() {
|
|
11
|
+
const m = readRollbackMarker();
|
|
12
|
+
if (!m) {
|
|
13
|
+
log.warn("未发现回滚标记,无需恢复。");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
log.info(`发现回滚标记: 时间 ${new Date(m.timestamp).toISOString()}`);
|
|
17
|
+
log.info(`目标: 从 ${m.backup_dir} 恢复 ${m.preserve.length} 项到 ${m.bds_path}`);
|
|
18
|
+
const result = rollbackFromBackup(m);
|
|
19
|
+
if (!result.ok) {
|
|
20
|
+
log.error(`回滚失败: ${result.reason}`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
// 清理 pid 文件
|
|
24
|
+
clearPid();
|
|
25
|
+
log.info("回滚完成,请手动检查并启动 BDS。");
|
|
26
|
+
}
|
|
27
|
+
function isMain() {
|
|
28
|
+
if (require.main === module)
|
|
29
|
+
return true;
|
|
30
|
+
const entry = process.argv[1] ?? "";
|
|
31
|
+
return entry.endsWith("recovery.js") || entry.endsWith("recovery.ts");
|
|
32
|
+
}
|
|
33
|
+
if (isMain()) {
|
|
34
|
+
run()
|
|
35
|
+
.then(() => {
|
|
36
|
+
closeLog();
|
|
37
|
+
process.exit(0);
|
|
38
|
+
})
|
|
39
|
+
.catch((e) => {
|
|
40
|
+
log.error(`未捕获错误: ${e.message}`);
|
|
41
|
+
closeLog();
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.js","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,KAAK,UAAU,GAAG;IAChB,MAAM,CAAC,GAAG,kBAAkB,EAAE,CAAC;IAC/B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC1B,OAAO;IACT,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,UAAU,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE3E,MAAM,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,YAAY;IACZ,QAAQ,EAAE,CAAC;IACX,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,MAAM;IACb,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,OAAO,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;AACxE,CAAC;AAED,IAAI,MAAM,EAAE,EAAE,CAAC;IACb,GAAG,EAAE;SACF,IAAI,CAAC,GAAG,EAAE;QACT,QAAQ,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QACX,GAAG,CAAC,KAAK,CAAC,UAAW,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5C,QAAQ,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rollback.ts — 回滚支持
|
|
3
|
+
*
|
|
4
|
+
* 在更新开始前记录: 当前 BDS 目录 + 备份目录。
|
|
5
|
+
* 主流程任意阶段失败时,尝试反向恢复 preserves 到 BDS_PATH,
|
|
6
|
+
* 然后从备份重新放回 preserve 内容,恢复旧配置。
|
|
7
|
+
*
|
|
8
|
+
* 持久化: ROLLBACK_MARKER (BDSTools/.last_update_rollback.json) 用于跨进程记录。
|
|
9
|
+
*/
|
|
10
|
+
import { getDirSize } from "./fsx.js";
|
|
11
|
+
export interface RollbackMarker {
|
|
12
|
+
timestamp: number;
|
|
13
|
+
bds_path: string;
|
|
14
|
+
backup_dir: string;
|
|
15
|
+
preserve: string[];
|
|
16
|
+
previous_version: string;
|
|
17
|
+
}
|
|
18
|
+
/** 在备份完成后调用: 记录快照指示符。 */
|
|
19
|
+
export declare function writeRollbackMarker(marker: RollbackMarker): void;
|
|
20
|
+
export declare function clearRollbackMarker(): void;
|
|
21
|
+
export declare function readRollbackMarker(): RollbackMarker | null;
|
|
22
|
+
/**
|
|
23
|
+
* 紧急回滚: 把 preserve 项从 backup_dir 拷回 bds_path。
|
|
24
|
+
* 用法: 在 catch 分支调用,如果主流程失败导致 BDS 目录破坏。
|
|
25
|
+
*/
|
|
26
|
+
export declare function rollbackFromBackup(marker: RollbackMarker): {
|
|
27
|
+
ok: boolean;
|
|
28
|
+
reason?: string;
|
|
29
|
+
};
|
|
30
|
+
/** 检查 BDS_PATH 中关键文件是否都还在 (更新后完整性 sanity check) */
|
|
31
|
+
export declare function verifyBdsInstall(bds_path: string, expected: string[]): {
|
|
32
|
+
ok: boolean;
|
|
33
|
+
missing: string[];
|
|
34
|
+
};
|
|
35
|
+
export { getDirSize };
|
|
36
|
+
//# sourceMappingURL=rollback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../src/rollback.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAAe,UAAU,EAAgB,MAAM,UAAU,CAAC;AAGjE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,yBAAyB;AACzB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAOhE;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAM1C;AAED,wBAAgB,kBAAkB,IAAI,cAAc,GAAG,IAAI,CAE1D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA8B3F;AAED,mDAAmD;AACnD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAMzG;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
|