@meadmin/cli 1.3.7 → 1.3.8

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.
@@ -1,8 +1,9 @@
1
1
  import { setEnv } from '../utils/env.js';
2
2
  import { addonInit } from './addon.js';
3
+ import { compressInit } from './compress.js';
3
4
  import { crudInit } from './crud.js';
4
5
  import { syncInit } from './sync.js';
5
- import { compressInit } from './compress.js';
6
+ import { updateInit } from './update.js';
6
7
  export const init = (program) => {
7
8
  program.option('-m <char>', 'env环境变量').hook('preAction', (thisCommand) => {
8
9
  setEnv(thisCommand.opts().m);
@@ -11,5 +12,6 @@ export const init = (program) => {
11
12
  crudInit(program);
12
13
  addonInit(program);
13
14
  compressInit(program);
15
+ updateInit(program);
14
16
  };
15
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbWFuZGVycy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDekMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN2QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM3QyxNQUFNLENBQUMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxPQUFnQixFQUFFLEVBQUU7SUFDdkMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFO1FBQ3ZFLE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0IsQ0FBQyxDQUFDLENBQUM7SUFDSCxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbEIsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2xCLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNuQixZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDeEIsQ0FBQyxDQUFDIn0=
17
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbWFuZGVycy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDekMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN2QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3pDLE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRyxDQUFDLE9BQWdCLEVBQUUsRUFBRTtJQUN2QyxPQUFPLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQUU7UUFDdkUsTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMvQixDQUFDLENBQUMsQ0FBQztJQUNILFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNsQixRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbEIsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ25CLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0QixVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDdEIsQ0FBQyxDQUFDIn0=
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare const databaseReminder = "\n\u540E\u7EED\u5FC5\u987B\u624B\u52A8\u5904\u7406\uFF1A\n1. \u6587\u4EF6\u5347\u7EA7\u4F1A\u5C06\u6A21\u677F\u65B0\u589E\u4F9D\u8D56\u5199\u5165\u6E05\u5355\uFF1B\u5347\u7EA7\u540E\u8BF7\u6838\u5BF9\u4EBA\u5DE5\u5408\u5E76\u9879\uFF0C\u624B\u52A8\u6267\u884C pnpm install\uFF08\u5982\u5C1A\u672A\u5B89\u88C5\uFF09\uFF0C\u518D\u66F4\u65B0\u540E\u7AEF\u7F16\u8BD1\u4EA7\u7269\u3002\n2. \u5907\u4EFD\u6570\u636E\u5E93\u540E\u624B\u52A8\u6267\u884C\uFF1Apnpm exec meadmin sync * \u540C\u6B65\u6570\u636E\u5E93\u8868\u7ED3\u6784\u3002\n3. \u8C28\u614E\u6267\u884C update.sql\uFF01\u5EFA\u8BAE\u81EA\u884C\u6BD4\u8F83\u7248\u672CSQL\u3001update.sql\u4E0E\u73B0\u6709\u6570\u636E\u5E93\u540E\u518D\u6267\u884C\uFF0C\u5148\u5728\u6D4B\u8BD5\u73AF\u5883\u9A8C\u8BC1\u3002\n4. \u6570\u636E\u5904\u7406\u5B8C\u6210\u540E\uFF0C\u624B\u52A8\u4F9D\u6B21\u6267\u884C\u83DC\u5355\u3001\u7EC4\u7EC7\u3001\u89D2\u8272\u7684\u201C\u4FEE\u590D\u6811\u5173\u7CFB\u201D\u3002\n5. \u5237\u65B0/\u91CD\u65B0\u767B\u5F55\u5E76\u6838\u5BF9\u83DC\u5355\u6388\u6743\u3001\u7EC4\u7EC7\u6570\u636E\u8303\u56F4\u548C\u4E1A\u52A1\u529F\u80FD\u3002\n\u672C\u5DE5\u5177\u4E0D\u81EA\u52A8\u540C\u6B65\u8868\u7ED3\u6784\u3001\u6267\u884CSQL\u6216\u4FEE\u590D\u6811\u5173\u7CFB\u3002\u539F\u59CB\u7248\u672CSQL\u4E0D\u80FD\u76F4\u63A5\u5B8C\u6574\u5BFC\u5165\u5DF2\u6709\u4E1A\u52A1\u5E93\u3002\n\u6587\u4EF6\u56DE\u6EDA\u4E0D\u56DE\u6EDA\u6570\u636E\u5E93\u3002\u65B0\u589E\u6388\u6743\u5173\u8054\u4E5F\u53EF\u80FD\u5F71\u54CD\u5DF2\u6709\u89D2\u8272\u6743\u9650\u3002\n";
3
+ export declare function updateInit(program: Command): void;
@@ -0,0 +1,132 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { basename, join, resolve } from 'node:path';
5
+ import { stdin, stdout } from 'node:process';
6
+ import { createInterface } from 'node:readline/promises';
7
+ import { applyPlan, rollback, saveRecord } from '../update/backup.js';
8
+ import { makePlan } from '../update/planner.js';
9
+ import { validateConfig } from '../update/rules.js';
10
+ import { compareVersions, currentVersion, downloadTemplate, registryManifest, selectVersion } from '../update/template.js';
11
+ import { Log } from '../utils/log.js';
12
+ async function confirm(message) {
13
+ if (!stdin.isTTY || !stdout.isTTY)
14
+ throw new Error('需要交互式终端确认;非交互场景请使用 --dry-run');
15
+ const prompt = createInterface({ input: stdin, output: stdout });
16
+ try {
17
+ return (await prompt.question(message + ' [y/N] ')).trim().toLowerCase() === 'y';
18
+ }
19
+ finally {
20
+ prompt.close();
21
+ }
22
+ }
23
+ export const databaseReminder = `
24
+ 后续必须手动处理:
25
+ 1. 文件升级会将模板新增依赖写入清单;升级后请核对人工合并项,手动执行 pnpm install(如尚未安装),再更新后端编译产物。
26
+ 2. 备份数据库后手动执行:pnpm exec meadmin sync * 同步数据库表结构。
27
+ 3. 谨慎执行 update.sql!建议自行比较版本SQL、update.sql与现有数据库后再执行,先在测试环境验证。
28
+ 4. 数据处理完成后,手动依次执行菜单、组织、角色的“修复树关系”。
29
+ 5. 刷新/重新登录并核对菜单授权、组织数据范围和业务功能。
30
+ 本工具不自动同步表结构、执行SQL或修复树关系。原始版本SQL不能直接完整导入已有业务库。
31
+ 文件回滚不回滚数据库。新增授权关联也可能影响已有角色权限。
32
+ `;
33
+ export function updateInit(program) {
34
+ program
35
+ .command('update')
36
+ .description('基于官方模板升级框架(需确认覆盖,不自动操作数据库)')
37
+ .option('--version <version>', '指定准确的目标稳定版本')
38
+ .option('--config <path>', '自定义跳过规则文件')
39
+ .option('--registry <url>', 'npm registry 地址')
40
+ .option('--dry-run', '仅预览,不写入项目')
41
+ .option('--rollback <id>', '恢复升级批次的文件(不恢复数据库)')
42
+ .action(async (options) => {
43
+ try {
44
+ const root = process.cwd();
45
+ if (!existsSync(join(root, 'package.json')))
46
+ throw new Error('请在目标项目根目录运行');
47
+ if (options.rollback) {
48
+ if (options.version || options.config || options.dryRun)
49
+ throw new Error('--rollback 不能与升级选项组合');
50
+ if (!/^[a-f0-9-]{36}$/.test(options.rollback))
51
+ throw new Error('备份ID无效');
52
+ if (await confirm('将恢复本批次文件,数据库不会恢复,是否继续?'))
53
+ rollback(root, join(root, '.meadmin/updates', options.rollback));
54
+ return;
55
+ }
56
+ const from = currentVersion(root);
57
+ const updates = join(root, '.meadmin/updates');
58
+ if (existsSync(updates))
59
+ for (const id of readdirSync(updates)) {
60
+ const file = join(updates, id, 'record.json');
61
+ if (!existsSync(file))
62
+ continue;
63
+ const record = JSON.parse(readFileSync(file, 'utf8'));
64
+ if (record.phase !== 'rolled-back' && (record.phase !== 'files-complete' || compareVersions(record.to, from) > 0 || ['failed', 'running'].includes(record.installation)))
65
+ throw new Error(`存在待处理升级批次 ${id},请先按报告完成依赖/人工处理或回滚`);
66
+ }
67
+ const npmRegistry = spawnSync(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['config', 'get', 'registry'], { encoding: 'utf8', shell: process.platform === 'win32' });
68
+ const registry = options.registry || process.env.npm_config_registry || (npmRegistry.status === 0 ? npmRegistry.stdout.trim() : '') || 'https://registry.npmjs.org';
69
+ const manifest = await registryManifest(registry);
70
+ const to = selectVersion(from, manifest.versions, options.version);
71
+ if (from === to) {
72
+ console.log(`已是目标版本 ${to},不重置本地文件`);
73
+ return;
74
+ }
75
+ const rulePath = options.config ? resolve(root, options.config) : join(root, 'meadmin.update.json');
76
+ if (options.config && !existsSync(rulePath))
77
+ throw new Error('指定规则文件不存在');
78
+ const config = existsSync(rulePath) ? validateConfig(JSON.parse(readFileSync(rulePath, 'utf8'))) : { skipExisting: {}, mergeSource: {} };
79
+ const rules = config.skipExisting;
80
+ const sourceRules = config.mergeSource;
81
+ const workspace = mkdtempSync(join(tmpdir(), 'meadmin-update-'));
82
+ const [oldTemplate, targetTemplate] = await Promise.all([downloadTemplate(manifest, from, join(workspace, 'old')), downloadTemplate(manifest, to, join(workspace, 'target'))]);
83
+ const plan = makePlan(root, oldTemplate, targetTemplate, to, rules, sourceRules);
84
+ const git = spawnSync('git', ['status', '--porcelain'], { cwd: root, encoding: 'utf8' });
85
+ Log.log(`升级 ${from} → ${to}${from.split('.')[0] !== to.split('.')[0] ? '(跨主版本)' : ''}`);
86
+ if (git.status === 0 && git.stdout.trim())
87
+ console.warn('工作区存在未提交修改,请先审查或提交。');
88
+ for (const item of plan.changes)
89
+ console.log(`${item.action}${item.conflict ? ' [本地冲突]' : ''}: ${item.path}`);
90
+ for (const item of plan.skipped)
91
+ console.log('跳过: ' + item);
92
+ for (const item of plan.manual)
93
+ console.warn('人工处理: ' + item);
94
+ console.log('SQL候选插入(不代表数据库实际新增):', plan.sqlTables);
95
+ Log.log(`参考模板保留于:${workspace}`);
96
+ Log.log(databaseReminder);
97
+ if (options.dryRun)
98
+ return;
99
+ if (!(await confirm('警告:将覆盖上述文件,可能丢失业务修改;特殊文件仅按规则合并。是否继续?')))
100
+ return;
101
+ const directory = applyPlan(root, plan, from, to);
102
+ Log.log(`文件处理完成${plan.manual.length ? ',存在人工处理项' : ''}。备份:${directory};批次:${basename(directory)}`);
103
+ Log.log('依赖清单已合并(包含目标模板新增依赖),请执行 pnpm install 安装。');
104
+ if (await confirm('是否现在执行 pnpm install?可能运行生命周期脚本;选择否后请手动执行。')) {
105
+ const record = JSON.parse(readFileSync(join(directory, 'record.json'), 'utf8'));
106
+ const installBackup = join(directory, 'before-install');
107
+ mkdirSync(installBackup, { recursive: true });
108
+ for (const name of new Set(['pnpm-lock.yaml', 'package.json', ...plan.changes.filter((change) => change.path.endsWith('/package.json')).map((change) => change.path)])) {
109
+ if (existsSync(join(root, name))) {
110
+ mkdirSync(join(installBackup, name, '..'), { recursive: true });
111
+ copyFileSync(join(root, name), join(installBackup, name));
112
+ }
113
+ }
114
+ record.installation = 'running';
115
+ saveRecord(directory, record);
116
+ const install = spawnSync(process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm', ['install'], { cwd: root, stdio: 'inherit', shell: process.platform === 'win32' });
117
+ record.installation = install.status === 0 ? 'completed' : 'failed';
118
+ saveRecord(directory, record);
119
+ if (install.status !== 0) {
120
+ console.warn('依赖安装失败,请手动处理,文件备份仍保留');
121
+ process.exitCode = 1;
122
+ }
123
+ }
124
+ Log.success(databaseReminder);
125
+ }
126
+ catch (error) {
127
+ Log.error(error instanceof Error ? error.message : '', error);
128
+ process.exitCode = 1;
129
+ }
130
+ });
131
+ }
132
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRlcnMvdXBkYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMvQyxPQUFPLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsV0FBVyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDdEcsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNqQyxPQUFPLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDcEQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDN0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBc0IsTUFBTSxxQkFBcUIsQ0FBQztBQUMxRixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLGFBQWEsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzNILE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV0QyxLQUFLLFVBQVUsT0FBTyxDQUFDLE9BQWU7SUFDcEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSztRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQztJQUNuRixNQUFNLE1BQU0sR0FBRyxlQUFlLENBQUMsRUFBRSxLQUFLLEVBQUUs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
@@ -0,0 +1,21 @@
1
+ import { type Plan } from './planner.js';
2
+ type RecordFile = {
3
+ path: string;
4
+ before: string | null;
5
+ after: string;
6
+ state: 'pending' | 'writing' | 'written';
7
+ };
8
+ export type UpgradeRecord = {
9
+ root: string;
10
+ from: string;
11
+ to: string;
12
+ phase: string;
13
+ files: RecordFile[];
14
+ manual: string[];
15
+ installation: string;
16
+ };
17
+ export declare function safePath(root: string, path: string): string;
18
+ export declare function saveRecord(directory: string, record: UpgradeRecord): void;
19
+ export declare function applyPlan(root: string, plan: Plan, from: string, to: string): string;
20
+ export declare function rollback(root: string, directory: string): void;
21
+ export {};
@@ -0,0 +1,120 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { existsSync, lstatSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
3
+ import { dirname, join, relative, resolve } from 'node:path';
4
+ import { hash, readLocal } from './planner.js';
5
+ export function safePath(root, path) {
6
+ if (!path || path.includes('\\') || path.includes(':') || path.startsWith('/') || path.split('/').some((x) => x === '..' || x === '.' || !x || ['.git', 'node_modules', '.meadmin', '.workbuddy'].includes(x.toLowerCase())))
7
+ throw new Error('恢复清单路径无效');
8
+ readLocal(root, path);
9
+ return join(root, path);
10
+ }
11
+ function atomic(file, content) {
12
+ mkdirSync(dirname(file), { recursive: true });
13
+ const temporary = file + '.meadmin-' + randomUUID();
14
+ try {
15
+ writeFileSync(temporary, content, { mode: 0o600 });
16
+ renameSync(temporary, file);
17
+ }
18
+ finally {
19
+ if (existsSync(temporary))
20
+ unlinkSync(temporary);
21
+ }
22
+ }
23
+ export function saveRecord(directory, record) {
24
+ atomic(join(directory, 'record.json'), JSON.stringify(record, null, 2));
25
+ }
26
+ export function applyPlan(root, plan, from, to) {
27
+ for (const part of ['.meadmin', '.meadmin/updates']) {
28
+ const location = join(root, part);
29
+ if (existsSync(location) && (lstatSync(location).isSymbolicLink() || !lstatSync(location).isDirectory()))
30
+ throw new Error('升级备份目录不安全');
31
+ }
32
+ for (const change of plan.changes) {
33
+ const before = readLocal(root, change.path);
34
+ if ((before ? hash(before) : null) !== change.previous)
35
+ throw new Error(`预览后文件发生变化:${change.path}`);
36
+ }
37
+ const directory = join(root, '.meadmin/updates', randomUUID());
38
+ mkdirSync(directory, { recursive: true });
39
+ const record = { root: resolve(root), from, to, phase: 'prepared', files: [], manual: plan.manual, installation: 'not-run' };
40
+ for (const change of plan.changes) {
41
+ const before = readLocal(root, change.path);
42
+ if ((before ? hash(before) : null) !== change.previous)
43
+ throw new Error(`备份时文件发生变化:${change.path}`);
44
+ if (before)
45
+ atomic(join(directory, 'original', change.path), before);
46
+ atomic(join(directory, 'target', change.path), change.content);
47
+ record.files.push({ path: change.path, before: change.previous, after: hash(change.content), state: 'pending' });
48
+ }
49
+ saveRecord(directory, record);
50
+ try {
51
+ for (const [index, change] of plan.changes.entries()) {
52
+ const current = readLocal(root, change.path);
53
+ if ((current ? hash(current) : null) !== change.previous)
54
+ throw new Error(`写入前文件发生变化:${change.path}`);
55
+ record.files[index].state = 'writing';
56
+ saveRecord(directory, record);
57
+ atomic(safePath(root, change.path), change.content);
58
+ record.files[index].state = 'written';
59
+ saveRecord(directory, record);
60
+ }
61
+ record.phase = 'files-complete';
62
+ saveRecord(directory, record);
63
+ }
64
+ catch (error) {
65
+ record.phase = 'failed';
66
+ try {
67
+ saveRecord(directory, record);
68
+ }
69
+ catch {
70
+ /* 日志写入失败也必须尝试恢复。 */
71
+ }
72
+ try {
73
+ rollback(root, directory);
74
+ }
75
+ catch (recovery) {
76
+ throw new Error(`${String(error)};恢复未完成:${String(recovery)}。备份:${directory}`, { cause: recovery });
77
+ }
78
+ throw error;
79
+ }
80
+ return directory;
81
+ }
82
+ export function rollback(root, directory) {
83
+ const rel = relative(resolve(root), resolve(directory)).replaceAll('\\', '/');
84
+ if (!/^\.meadmin\/updates\/[a-f0-9-]{36}$/.test(rel))
85
+ throw new Error('备份路径不在项目升级目录');
86
+ let currentDirectory = resolve(root);
87
+ for (const part of rel.split('/')) {
88
+ currentDirectory = join(currentDirectory, part);
89
+ if (!existsSync(currentDirectory) || lstatSync(currentDirectory).isSymbolicLink() || !lstatSync(currentDirectory).isDirectory())
90
+ throw new Error('备份路径不安全');
91
+ }
92
+ readLocal(directory, 'record.json');
93
+ const record = JSON.parse(readFileSync(join(directory, 'record.json'), 'utf8'));
94
+ if (record.root !== resolve(root))
95
+ throw new Error('备份所属项目不匹配');
96
+ if (record.installation !== 'not-run')
97
+ console.warn('安装已执行:仅恢复内容未被再次修改的升级文件;锁文件、node_modules及生命周期脚本影响需人工恢复并重新安装依赖。');
98
+ const candidates = record.files.filter((file) => file.state !== 'pending');
99
+ for (const file of candidates) {
100
+ safePath(root, file.path);
101
+ const current = readLocal(root, file.path), currentHash = current ? hash(current) : null;
102
+ if (currentHash !== file.after && currentHash !== file.before)
103
+ throw new Error(`升级后文件已被修改,拒绝覆盖:${file.path}`);
104
+ if (file.before) {
105
+ const backup = readLocal(directory, 'original/' + file.path);
106
+ if (!backup || hash(backup) !== file.before)
107
+ throw new Error(`备份不完整:${file.path}`);
108
+ }
109
+ }
110
+ for (const file of [...candidates].reverse()) {
111
+ const destination = safePath(root, file.path);
112
+ if (file.before)
113
+ atomic(destination, readFileSync(join(directory, 'original', file.path)));
114
+ else if (existsSync(destination))
115
+ unlinkSync(destination);
116
+ }
117
+ record.phase = 'rolled-back';
118
+ saveRecord(directory, record);
119
+ }
120
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja3VwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3VwZGF0ZS9iYWNrdXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN6QyxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsYUFBYSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ2hILE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDN0QsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQWEsTUFBTSxjQUFjLENBQUM7QUFJMUQsTUFBTSxVQUFVLFFBQVEsQ0FBQyxJQUFZLEVBQUUsSUFBWTtJQUNqRCxJQUFJLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsY0FBYyxFQUFFLFVBQVUsRUFBRSxZQUFZLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzFQLFNBQVMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDdEIsT0FBTyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQzFCLENBQUM7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
@@ -0,0 +1,7 @@
1
+ export type MergeResult = {
2
+ content: string;
3
+ manual: string[];
4
+ };
5
+ export declare function mergePackage(local: string, target: string, base?: string): MergeResult;
6
+ export declare function mergeConfig(local: string, target: string, base?: string): MergeResult;
7
+ export declare function mergeEntity(local: string, target: string, base?: string): MergeResult;