dsh-config-manager 0.2.3 → 0.3.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.
Files changed (132) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/lib/adapters/self.d.ts +44 -4
  4. package/lib/adapters/self.js +63 -3
  5. package/lib/client.d.ts +11 -6
  6. package/lib/client.js +1256 -1185
  7. package/lib/core/analyzer.d.ts +3 -0
  8. package/lib/core/analyzer.js +32 -56
  9. package/lib/core/backup.d.ts +36 -0
  10. package/lib/core/backup.js +125 -3
  11. package/lib/core/import-defaults.d.ts +13 -0
  12. package/lib/core/import-defaults.js +14 -0
  13. package/lib/core/importer.d.ts +10 -1
  14. package/lib/core/importer.js +7 -1
  15. package/lib/core/messages.d.ts +4 -0
  16. package/lib/core/messages.js +8 -0
  17. package/lib/core/model-tools.js +19 -3
  18. package/lib/index.d.ts +1 -1
  19. package/lib/index.js +12 -22
  20. package/lib/routes/import.js +3 -1
  21. package/lib/routes/recovery.js +226 -2
  22. package/lib/routes/sync.js +26 -7
  23. package/lib/security/integrity.d.ts +24 -0
  24. package/lib/security/integrity.js +30 -0
  25. package/lib/security/unverified-file-blocks.d.ts +73 -0
  26. package/lib/security/unverified-file-blocks.js +151 -0
  27. package/lib/sync/autosync-config.d.ts +8 -4
  28. package/lib/sync/autosync-config.js +2 -2
  29. package/lib/sync/autosync-scheduler.d.ts +61 -3
  30. package/lib/sync/autosync-scheduler.js +87 -10
  31. package/lib/sync/config-issue-reporting.d.ts +32 -0
  32. package/lib/sync/config-issue-reporting.js +63 -0
  33. package/lib/sync/gc-skip.d.ts +42 -0
  34. package/lib/sync/gc-skip.js +57 -0
  35. package/lib/sync/git/git-transport.d.ts +56 -2
  36. package/lib/sync/git/git-transport.js +344 -73
  37. package/lib/sync/merge-preview-text.d.ts +11 -0
  38. package/lib/sync/merge-preview-text.js +38 -0
  39. package/lib/sync/s3/s3-transport.d.ts +8 -1
  40. package/lib/sync/s3/s3-transport.js +19 -5
  41. package/lib/sync/session-tombstones.d.ts +53 -0
  42. package/lib/sync/session-tombstones.js +52 -0
  43. package/lib/sync/sync-config.d.ts +55 -5
  44. package/lib/sync/sync-config.js +188 -15
  45. package/lib/sync/sync-engine.d.ts +21 -7
  46. package/lib/sync/sync-engine.js +63 -85
  47. package/lib/sync/webdav/webdav-transport.d.ts +11 -1
  48. package/lib/sync/webdav/webdav-transport.js +22 -6
  49. package/lib/ui/i18n.js +56 -36
  50. package/lib/ui/import-wizard.d.ts +1 -1
  51. package/lib/ui/import-wizard.js +2 -1
  52. package/lib/ui/overview-view.d.ts +6 -2
  53. package/lib/ui/overview-view.js +8 -1
  54. package/lib/ui/report.js +2 -1
  55. package/lib/utils/git-fast-forward.d.ts +7 -2
  56. package/lib/utils/git-fast-forward.js +8 -3
  57. package/package.json +2 -2
  58. package/src/adapters/self.test.ts +126 -85
  59. package/src/adapters/self.ts +73 -6
  60. package/src/client/ConfigManagerSection.tsx +0 -3
  61. package/src/client/common/Icon.tsx +3 -0
  62. package/src/client/common/SectionComposition.tsx +6 -1
  63. package/src/client/common/info-hint-guard.test.ts +7 -5
  64. package/src/client/config-manager.module.css +254 -13
  65. package/src/client/environment/EnvironmentPanel.tsx +57 -47
  66. package/src/client/environment/maintenance/DiskUsageCard.tsx +3 -1
  67. package/src/client/export/ExportView.tsx +3 -1
  68. package/src/client/home/HomePanel.tsx +25 -5
  69. package/src/client/import/ImportWizardView.tsx +1 -3
  70. package/src/client/import/import-wizard-steps.tsx +1 -17
  71. package/src/client/library/ArtifactRow.tsx +13 -2
  72. package/src/client/library/LibraryPanel.tsx +12 -2
  73. package/src/client/locales.ts +53 -34
  74. package/src/client/lucide-icons.d.ts +2 -0
  75. package/src/client/market/MarketPanel.tsx +12 -11
  76. package/src/client/market/market-locales.ts +16 -16
  77. package/src/client/recovery/RollbackCard.tsx +4 -2
  78. package/src/client/recovery/recovery-locales.test.ts +4 -2
  79. package/src/client/recovery/recovery-locales.ts +23 -23
  80. package/src/client/sync/AutosyncCard.tsx +36 -10
  81. package/src/client/sync/SyncChannelEntryCard.tsx +18 -19
  82. package/src/client/sync/SyncPanel.tsx +32 -33
  83. package/src/client/sync/SyncProbeRow.tsx +23 -6
  84. package/src/client/sync/SyncSectionPickerDialog.tsx +2 -2
  85. package/src/client/sync/sync-locales.ts +24 -24
  86. package/src/core/analyzer.ts +37 -56
  87. package/src/core/backup.test.ts +139 -1
  88. package/src/core/backup.ts +145 -4
  89. package/src/core/import-defaults.ts +13 -0
  90. package/src/core/importer.ts +12 -2
  91. package/src/core/integrity-extra-entries.test.ts +205 -0
  92. package/src/core/messages.test.ts +3 -1
  93. package/src/core/messages.ts +8 -0
  94. package/src/core/model-tools.test.ts +33 -0
  95. package/src/core/model-tools.ts +20 -4
  96. package/src/index.ts +12 -21
  97. package/src/routes/import.ts +4 -1
  98. package/src/routes/recovery.test.ts +198 -1
  99. package/src/routes/recovery.ts +194 -1
  100. package/src/routes/sync.ts +27 -8
  101. package/src/security/integrity.ts +37 -0
  102. package/src/security/unverified-file-blocks.ts +192 -0
  103. package/src/sync/autosync-config.ts +9 -5
  104. package/src/sync/autosync-scheduler.test.ts +133 -6
  105. package/src/sync/autosync-scheduler.ts +118 -14
  106. package/src/sync/config-issue-reporting.test.ts +148 -0
  107. package/src/sync/config-issue-reporting.ts +75 -0
  108. package/src/sync/gc-skip.test.ts +66 -0
  109. package/src/sync/gc-skip.ts +64 -0
  110. package/src/sync/git/git-probe.test.ts +6 -1
  111. package/src/sync/git/git-transport.test.ts +351 -14
  112. package/src/sync/git/git-transport.ts +343 -79
  113. package/src/sync/merge-preview-text.ts +37 -0
  114. package/src/sync/s3/s3-delete-index-404.test.ts +26 -1
  115. package/src/sync/s3/s3-transport.ts +23 -4
  116. package/src/sync/session-tombstones.ts +90 -0
  117. package/src/sync/sync-config.test.ts +170 -1
  118. package/src/sync/sync-config.ts +184 -14
  119. package/src/sync/sync-engine.test.ts +238 -0
  120. package/src/sync/sync-engine.ts +79 -83
  121. package/src/sync/webdav/webdav-delete-index-404.test.ts +29 -1
  122. package/src/sync/webdav/webdav-transport.ts +26 -5
  123. package/src/ui/disk-usage-view.test.ts +2 -1
  124. package/src/ui/i18n.test.ts +47 -0
  125. package/src/ui/i18n.ts +58 -38
  126. package/src/ui/import-wizard.test.ts +18 -1
  127. package/src/ui/import-wizard.ts +3 -2
  128. package/src/ui/overview-view.test.ts +9 -0
  129. package/src/ui/overview-view.ts +9 -2
  130. package/src/ui/report.test.ts +4 -3
  131. package/src/ui/report.ts +2 -1
  132. package/src/utils/git-fast-forward.ts +8 -3
@@ -0,0 +1,57 @@
1
+ /**
2
+ * 本轮 blob GC 的放弃码(SYN-04)。**机器可判定**,文案由上层按码翻译(字典键由 Lead 统一加):
3
+ * 通道没有 logger,`delete()` 还会吞掉 GC 抛出的异常,所以「本轮为什么没回收」只能靠这个码如实外露。
4
+ * 三态同义:拿不到引用者内容 = 无法证明「没人引用」⇒ 本轮整轮放弃,绝不按残集删除。
5
+ *
6
+ * 单一来源:webdav / s3 两个通道都从这里导入(此前各写一份同名常量,改一侧不炸另一侧 =
7
+ * 静默漂移;本模块不 import 任何 transport,所以不存在环)。
8
+ */
9
+ export const GC_SKIP_REFERENCE_MISSING = 'gc-skip-reference-missing';
10
+ export const GC_SKIP_REFERENCE_UNREADABLE = 'gc-skip-reference-unreadable';
11
+ export const GC_SKIP_SNAPSHOT_UNPARSABLE = 'gc-skip-snapshot-unparsable';
12
+ /**
13
+ * SYN-04b:通道「本轮 GC 放弃码」的读取与冒泡(从 sync-engine.ts 下沉,行为逐字不变)。
14
+ *
15
+ * 为什么放在独立模块:SYN-04 之后 webdav/s3 遇到「引用快照 404 / 读不出」会**放弃本轮 blob GC**
16
+ * (绝不在「证明不了没人引用」时删 blob),而通道层没有 logger、delete() 又把 GC 异常吃掉
17
+ * ⇒ 放弃只能靠 transport 的只读字段外露。字段形态是 getter(见 webdav/s3 transport 的
18
+ * `get lastGcSkip()`),这里按 unknown 读、只接受非空字符串,getter 抛错也不影响 push。
19
+ *
20
+ * 判据(缺一不可,全部当「没有放弃码」):字段缺失 / null / 非字符串 / 空串 / getter 抛错。
21
+ * 读不到 ≠ 没有放弃:通道没这个能力时本来就不该冒泡告警,所以两者在调用侧合并处理。
22
+ */
23
+ export function readGcSkipCode(transport) {
24
+ try {
25
+ const raw = transport?.lastGcSkip;
26
+ return typeof raw === 'string' && raw !== '' ? raw : null;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ /**
33
+ * SYN-04b:放弃码 → 一条 warning 文本。
34
+ *
35
+ * 码必须同时以**明文**出现:core 目录的翻译器对未知键回退键名本身({code} 插值随之丢失),
36
+ * 而文案键由上层统一补字典 —— 在补键之前,只发出裸键名等于「报了但看不出来」,日志也无法 grep。
37
+ */
38
+ export function gcSkipWarning(msg, code) {
39
+ const text = msg('sync.gcSkipped', { code });
40
+ return text.includes(code) ? text : text + ': ' + code;
41
+ }
42
+ /**
43
+ * SYN-04b:把通道的 GC 放弃码冒泡成一条 warning(`state` 保证同一轮只报一次)。
44
+ *
45
+ * 语义边界:放弃 GC **不是** push 失败 —— 快照本身已上传/已删除,只是这一轮的孤儿 blob
46
+ * 没被回收(磁盘/远端会多留几份文件)。所以它进 warnings、不进 ok,与 prune 既有语义一致。
47
+ */
48
+ export function reportGcSkipOnce(transport, msg, warnings, state) {
49
+ if (state.done)
50
+ return;
51
+ const code = readGcSkipCode(transport);
52
+ if (code === null)
53
+ return;
54
+ state.done = true;
55
+ warnings.push(gcSkipWarning(msg, code));
56
+ }
57
+ //# sourceMappingURL=gc-skip.js.map
@@ -7,7 +7,7 @@ export interface GitExecResult {
7
7
  stderr: string;
8
8
  code: number;
9
9
  }
10
- /** 可注入的 git 执行器(测试 mock 用);默认实现 = child_process.execFile promise 封装 */
10
+ /** 可注入的 git 执行器(测试 mock 用);默认实现 = child_process.spawn promise 封装(超时杀进程树) */
11
11
  export type GitExecFn = (cmd: string, args: string[], opts: {
12
12
  cwd?: string;
13
13
  timeoutMs?: number;
@@ -59,7 +59,7 @@ export interface GitTransportOptions {
59
59
  timeoutMs?: number;
60
60
  /** 幂等读操作(list/download 的 clone/pull)的网络重试参数;缺省 attempts=3、250ms 起指数退避 */
61
61
  retry?: SyncRetryOptions;
62
- /** 注入 exec(测试 mock 用);缺省 = execFile 封装 */
62
+ /** 注入 exec(测试 mock 用);缺省 = spawn 封装(超时杀进程树) */
63
63
  exec?: GitExecFn;
64
64
  /** 提交作者(写入远端历史),默认 DSH Config Sync <sync@dsh.local> */
65
65
  author?: GitAuthor;
@@ -75,11 +75,26 @@ export interface GitTransportOptions {
75
75
  export declare class GitTransportError extends SyncTransportError {
76
76
  constructor(message: string, opts?: SyncTransportErrorOptions);
77
77
  }
78
+ /**
79
+ * 默认 git 执行器:spawn + **进程树** kill(issue #122)。
80
+ *
81
+ * 为什么不再用 execFile:它的 timeout 只对 git.exe 自己发 SIGTERM,而真正在下包的是 git.exe 的子进程
82
+ * (git-remote-https / git index-pack)。父进程被杀、孙进程继续写 tmp_pack_*,管道不关闭 ⇒ execFile 的
83
+ * promise 连超时错误都可能不返回 ⇒ 上层「正在检查远端变更...」永久挂起,下一轮重试再起一份,最终 N 份
84
+ * 并发下载同一个 pack。
85
+ * 这里改为:POSIX 上 detached 起独立进程组,超时对**整组**发 SIGKILL;Windows 上 `taskkill /T /F`;
86
+ * 无论 kill 是否成功,宽限期到点都带着已收集输出收尾 —— 绝不把「管道没关」变成上层无限等待。
87
+ *
88
+ * 导出仅供测试直接验证「超时 + 进程树 kill + 有界收尾」(issue #122 的验收面)。
89
+ */
90
+ export declare const defaultGitExec: GitExecFn;
78
91
  /** 实现 SyncTransport 的 git 通道。所有操作前 ensureRepo() 保证工作副本就绪,网络命令带凭据。 */
79
92
  export declare class GitTransport implements SyncTransport {
80
93
  readonly type = "git";
81
94
  private readonly o;
82
95
  private repoReady;
96
+ /** 该工作副本是否 partial clone(remote.origin.promisor);null = 尚未判定(issue #122) */
97
+ private partialClone;
83
98
  /**
84
99
  * 工作副本锁的可重入深度:list/upload/download/delete 都会经 ensureRepo → reconcileOrigin,
85
100
  * rebuildWorkDir → adoptRemoteHistory 也各自嵌套;外层入口持锁,内层直接跑。
@@ -94,6 +109,8 @@ export declare class GitTransport implements SyncTransport {
94
109
  */
95
110
  private readErrors;
96
111
  private readonly msg;
112
+ /** repoUrl 是否为网络地址(本地目录仓库 == false):决定要不要额外禁 file 传输(SEC-12)。 */
113
+ private readonly networkRepo;
97
114
  constructor(options: GitTransportOptions);
98
115
  /** 最近一次 checkIsPrivate() 的结果;null = 尚未检查 */
99
116
  get isPrivateHint(): boolean | null;
@@ -151,6 +168,30 @@ export declare class GitTransport implements SyncTransport {
151
168
  */
152
169
  private withWorkdir;
153
170
  private ensureRepo;
171
+ /**
172
+ * 首次 clone(issue #122):partial clone + sparse-checkout,只落地同步内容。
173
+ *
174
+ * 为什么:同步仓库可能比同步内容大几个数量级(报告者现场 1.8 GB 仓库 / 6 MB 内容)。此前 `git clone`
175
+ * 全量落地,之后每次 fetch 还要拉完整对象图 ⇒ 一次「检查远端变更」就下几百 MB。
176
+ * `--filter=blob:none` 只取 commit+tree,`--no-checkout` 先不落地任何文件,
177
+ * `sparse-checkout set --cone <三个目录>` 之后 checkout 只 materialize 这三个目录的 blob。
178
+ *
179
+ * 老 git 不认这些选项(unknown option)时回落全量 clone —— 行为与修复前完全一致,绝不因优化失败。
180
+ */
181
+ private cloneIntoWorkDir;
182
+ /**
183
+ * 该工作副本是不是 partial clone(`remote.origin.promisor=true`)。
184
+ *
185
+ * 只有 partial clone 才能给 fetch 加 `--filter=blob:none`:对普通全量副本加过滤会让后续 checkout
186
+ * 拿到缺失的 blob。存量副本(1.8 GB 那种)因此只受益于 ls-remote 短路与 `--no-tags`,不会被改坏。
187
+ */
188
+ private isPartialClone;
189
+ /** 拉取姿态:partial clone 保持 blob 过滤;同步仓库不需要 tag(issue #122) */
190
+ private fetchOptionFlags;
191
+ /** 远端分支当前的 sha(ls-remote 只取一行 refs);读不到 → null(短路是优化,失败一律回落正常 fetch) */
192
+ private lsRemoteBranchSha;
193
+ /** 解析引用指向的 sha;读不到 / 不是 sha → null */
194
+ private revParseSha;
154
195
  /**
155
196
  * 让工作副本的 origin 与配置的 repoUrl 保持一致(issue #79)。
156
197
  *
@@ -229,6 +270,11 @@ export declare class GitTransport implements SyncTransport {
229
270
  * 还会在本地留下一个已提交却推不上去的快照。
230
271
  */
231
272
  private runGit;
273
+ /**
274
+ * 把「git 退出非零」归一成可操作错误(runGit 与 clone 回落共用同一套文案与分类)。
275
+ * token 只用于脱敏,绝不进 message。
276
+ */
277
+ private raiseGitFailure;
232
278
  /**
233
279
  * 为网络命令构造 credential helper 参数:
234
280
  * 仅 http(s) 远端需要 token;本地路径 / ssh 走 git 原生认证(密钥),不调用 provider。
@@ -239,6 +285,14 @@ export declare class GitTransport implements SyncTransport {
239
285
  private repoHost;
240
286
  /** 读取一次 token(错误消息脱敏用);非 http(s) 场景返回空 */
241
287
  private readTokenOnce;
288
+ /**
289
+ * 回传体里的地址(工作副本自检的 origin / pushUrl)脱敏:只剥「凭据段」,其余原样保留。
290
+ *
291
+ * 为什么不整串换占位符:状态面板要显示「工作副本现在指向哪个远端」,用户靠 host/path 判断是否
292
+ * 已跟随配置。为什么不一律剥 userinfo:`ssh://git@host` 里的 `git` 是 ssh 登录名(标准写法),
293
+ * 剥掉会让用户认不出自己的远端 —— 与 validateRepoUrl 的口径保持一致(只有 password 位是凭据)。
294
+ */
295
+ private bareUrl;
242
296
  /** 错误/日志脱敏:token(原文与 URL 编码两种形态)与 repoUrl 一律替换 */
243
297
  private mask;
244
298
  /**