@deepseek-ai/dsh-atomic-write 0.1.5-rc.1 → 0.1.6-alpha.1
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.i18n.yaml +1 -1
- package/README.zh.md +7 -7
- package/package.json +1 -1
package/README.i18n.yaml
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/util/atomic-write/README.md
|
|
5
5
|
README.md: c3ce840f79c38fb7fac404786f0e5a7e41138d57
|
|
6
|
-
README.zh.md:
|
|
6
|
+
README.zh.md: 9cc1f271f70e113637b88b7e3984d431e84c647f
|
package/README.zh.md
CHANGED
|
@@ -9,7 +9,7 @@ kind: "package-library"
|
|
|
9
9
|
|
|
10
10
|
## 概述
|
|
11
11
|
|
|
12
|
-
使用 `dsh-atomic-write`
|
|
12
|
+
使用 `dsh-atomic-write` 替换文件时,不会暴露部分内容,也不会跟随临时路径上的符号链接。它的写锁会跨进程串行化读-修改-写入循环,因此并发写入方不会用陈旧状态相互覆盖。每次替换都会在全新 inode 上使用调用方选择的权限位,从而安全地收窄现有文件的权限。这个零依赖库只接受字符串;它不提供 `cordis.yml` 插件,也不保证崩溃持久性,因为它不调用 `fsync`。
|
|
13
13
|
|
|
14
14
|
## 目录
|
|
15
15
|
|
|
@@ -25,7 +25,7 @@ kind: "package-library"
|
|
|
25
25
|
<a id="use-this-package"></a>
|
|
26
26
|
## 使用本包
|
|
27
27
|
|
|
28
|
-
当文件型存储必须替换一份已渲染好的字符串、且绝不允许暴露部分写入、符号链接劫持或权限过宽状态时,使用 `writeFileAtomic
|
|
28
|
+
当文件型存储必须替换一份已渲染好的字符串、且绝不允许暴露部分写入、符号链接劫持或权限过宽状态时,使用 `writeFileAtomic`;当多个进程对同一文件执行读-修改-写入循环时,使用 `withFileLock`。最小路径是一次调用,传入最终内容与替换 inode 的权限位。
|
|
29
29
|
|
|
30
30
|
### 原子写入文件
|
|
31
31
|
|
|
@@ -54,7 +54,7 @@ await withFileLock('/home/u/.dsh/settings.yaml', async () => {
|
|
|
54
54
|
})
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
只有写入方会竞争——读取方从不取锁——竞争者按指数退避,超时后报错,而不是无限阻塞。竞争者等待多久由每次调用经 `waitMs` 声明:默认值只按纯文件工作量级选定,因此持锁方循环若包含一次网络往返——例如刷新过期 token 的凭据变更——就应声明更长的值,否则该文件的其他写入方在这段时间内都会失败。退避节奏保持固定。竞争者绝不移除已有锁,因为文件存续时间无法证明其持有者已经停止。
|
|
58
58
|
|
|
59
59
|
### 需要规划的失败
|
|
60
60
|
|
|
@@ -68,18 +68,18 @@ await withFileLock('/home/u/.dsh/settings.yaml', async () => {
|
|
|
68
68
|
<details>
|
|
69
69
|
<summary>实现细节——点击展开</summary>
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
本包遵循一项职责分离:原子提交负责交换,写锁负责跨进程排序。
|
|
72
72
|
|
|
73
73
|
### 源码地图
|
|
74
74
|
|
|
75
75
|
| 文件 | 职责 |
|
|
76
76
|
|---|---|
|
|
77
77
|
| [`src/index.ts`](src/index.ts) | `writeFileAtomic` 与 `withFileLock`,即本包的全部接口 |
|
|
78
|
-
| — |
|
|
78
|
+
| — | 不发布运行时不变式伴生入口;这个纯文件系统原语不维护事件流或可变运行时数据;其替换约定由单元测试覆盖。 |
|
|
79
79
|
|
|
80
80
|
### 写入路径
|
|
81
81
|
|
|
82
|
-
`writeFileAtomic` 先以独占创建(`wx`)打开一个随机后缀的同级文件并写入内容,然后 rename 到目标上。独占打开拒绝跟随预先埋在可猜测临时路径上的符号链接;同目录兄弟文件保证 rename 落在同一文件系统上;rename
|
|
82
|
+
`writeFileAtomic` 先以独占创建(`wx`)打开一个随机后缀的同级文件并写入内容,然后 rename 到目标上。独占打开拒绝跟随预先埋在可猜测临时路径上的符号链接;同目录兄弟文件保证 rename 落在同一文件系统上;rename 替换的是目标位置的符号链接本身,绝不写穿到该链接指向的文件。Windows 重试会保留同一份完整的兄弟文件,并采用有界指数退避,因此协作式写锁之外的软件瞬时占用目标时,不会让安全替换立即失败;已归档的[重试决策记录](../../../.agents/notes/archived/bug-fix/2026-08-29-windows-atomic-replace-retry.md)记录了最初的理由与被拒绝的替代方案。
|
|
83
83
|
|
|
84
84
|
`withFileLock` 以 `wx` 创建 `<filename>.lock` 同级文件。`EEXIST` 直接表示竞争;只有一次新的 `lstat` 确认锁路径存在时,`EPERM` 才表示竞争,从而兼容 Windows 的独占创建行为,又不掩盖无关的权限故障。锁记录创建者的 PID,由持有者在 `finally` 中移除;竞争按指数退避,在每次调用声明的 `waitMs` 期限(默认两秒)过后失败。
|
|
85
85
|
|
|
@@ -96,7 +96,7 @@ await withFileLock('/home/u/.dsh/settings.yaml', async () => {
|
|
|
96
96
|
<a id="further-exploration"></a>
|
|
97
97
|
## 进一步探索
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
当你需要了解使用本原语的存储或它所属的工具家族时,阅读以下页面。
|
|
100
100
|
|
|
101
101
|
- [用户设置文件存储](../../settings/settings-file/README.zh.md)——每次写入都通过本包替换的设置文档。
|
|
102
102
|
- [凭据存储](../../credentials/credentials-local/README.zh.md)——本包加锁并替换的凭据文件。
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-atomic-write",
|
|
3
3
|
"description": "Zero-dependency atomic file replacement: exclusive-create random-suffix temp + rename carrying the caller-stated permissions (writeFileAtomic)",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.6-alpha.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|