zen-fs-config 0.5.19 → 0.5.21

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 CHANGED
@@ -1,192 +1,197 @@
1
1
  # zen-fs-config
2
2
 
3
- 基于 ZenFS 的分布式配置管理库。以 IndexedDB 为本地主后端(offline-first),用户提供的远程后端作为副本自动同步。支持应用隔离、共享空间、节点本地配置和冲突安全。
3
+ Distributed configuration management library built on [ZenFS](https://github.com/weijia/zen-fs), with IndexedDB as the offline-first local primary backend and user-provided remote backends as replicas that sync automatically. Supports app isolation, shared spaces, node-local config, and conflict-safe operations.
4
4
 
5
5
  **GitHub**: https://github.com/weijia/zen-fs-config
6
6
  **NPM**: `zen-fs-config`
7
- **设计文档**: [DESIGN.md](./DESIGN.md)
7
+ **Design doc**: [DESIGN.md](./DESIGN.md)
8
8
 
9
- ## 安装
9
+ ## Features
10
+
11
+ - **Offline-first** — IndexedDB is always the primary backend; reads and writes work without network
12
+ - **Multi-backend sync** — Add any number of remote replicas (Gitee, GitHub, RemoteStorage, WebDAV, etc.) with automatic bi-directional sync
13
+ - **App isolation** — Each app gets its own namespace under `/{appId}/`
14
+ - **Shared spaces** — Cross-app shared config under `/shared/`
15
+ - **Node-local config** — Per-device settings under `/nodes/{nodeId}/` that never sync
16
+ - **Self-describing topology** — Backend configuration is stored as files in `.meta/backends/`, so re-opening a repo restores everything automatically
17
+ - **Conflict safety** — Conflicts are archived instead of silently overwritten; JSON deep-merge is available as a strategy
18
+ - **Version tracking** — Every config file has a version sidecar with version number and SHA-256 hash
19
+ - **Caching layer** — Optional ETag/TTL caching via `zen-fs-cache` to reduce remote API calls
20
+
21
+ ## Installation
10
22
 
11
23
  ```bash
12
24
  npm install zen-fs-config @zenfs/core @zenfs/dom zen-fs-sync
13
25
  ```
14
26
 
15
- > `@zenfs/dom` 提供 IndexedDB 后端(浏览器环境必需)。`zen-fs-cache` 为可选依赖。
27
+ > `@zenfs/dom` provides the IndexedDB backend (required in browser environments). `zen-fs-cache` is an optional dependency for remote request caching.
16
28
 
17
- ## 快速开始
29
+ ## Quick Start
18
30
 
19
- ### 1. 初始化(零参数)
31
+ ### 1. Initialize (zero-configuration)
20
32
 
21
33
  ```typescript
22
34
  import { createConfigRepo } from 'zen-fs-config';
23
35
 
24
- // 不传任何后端参数,自动创建 IndexedDB 本地主后端
36
+ // Creates an IndexedDB primary backend automatically
25
37
  const repo = await createConfigRepo('my-app');
26
38
 
27
- // 读写配置(同步 API,从 IndexedDB 读取)
39
+ // Read/write config (synchronous API, served from IndexedDB)
28
40
  repo.setConfig('/database', { host: 'localhost', port: 5432 });
29
41
  const db = repo.getConfig<{ host: string; port: number }>('/database');
30
42
  ```
31
43
 
32
- ### 2. 设置新的配置
33
-
34
- ```typescript
35
- repo.setConfig('/cache', { ttl: 3600, maxSize: '100MB' });
36
- repo.setConfig('/feature-flags', { newUI: true, beta: false });
37
- ```
38
-
39
- ### 3. 增加数据后端(副本)
44
+ ### 2. Add a remote replica backend
40
45
 
41
46
  ```typescript
42
47
  import { registerBackend } from 'zen-fs-config';
43
48
  import { Gitee } from 'zen-fs-gitee';
44
49
 
45
- // 注册后端类型
50
+ // Register the backend type first
46
51
  registerBackend('Gitee', async (options) => {
47
52
  return Gitee.create(options);
48
53
  });
49
54
 
50
- // 动态添加副本后端,自动与本地 IndexedDB 双向同步
55
+ // Dynamically add a replica — auto-syncs bi-directionally with local IndexedDB
51
56
  await repo.addBackend('gitee-prod', 'Gitee', {
52
57
  token: 'your-token',
53
58
  owner: 'your-name',
54
59
  repo: 'config-repo',
55
60
  branch: 'main',
56
- }, '生产环境 Gitee 配置仓库');
61
+ }, 'Production Gitee config repo');
57
62
  ```
58
63
 
59
- ### 4. 自动同步
64
+ ### 3. Automatic sync
60
65
 
61
66
  ```typescript
62
- // setConfig 写入 IndexedDB 后,自动同步到所有副本后端
67
+ // Writing to IndexedDB triggers auto-sync to all replicas
63
68
  repo.setConfig('/database', { host: 'new-host', port: 5432 });
64
69
 
65
- // 手动触发同步(通常不需要,同步是自动的)
70
+ // Manual flush (usually not needed — sync is automatic)
66
71
  await repo.flush();
67
72
  ```
68
73
 
69
- ### 5. 再次打开时初始化
74
+ ### 4. Re-open on next page load
70
75
 
71
76
  ```typescript
72
- // 重新打开页面时,只需传入 appId
73
- // IndexedDB 中的配置和后端拓扑会自动恢复
77
+ // Just pass the appId — IndexedDB restores everything
74
78
  const repo = await createConfigRepo('my-app');
75
79
 
76
- // 配置直接从 IndexedDB 读取(离线可用)
80
+ // Config is readable immediately (offline)
77
81
  const db = repo.getConfig<{ host: string; port: number }>('/database');
78
82
 
79
- // 已注册的副本后端会自动重新连接并同步
83
+ // Registered replicas reconnect and sync automatically
80
84
  const backends = await repo.getBackends();
81
85
  console.log(backends?.backends.map(b => b.id)); // ['local-idb', 'gitee-prod', ...]
82
86
  ```
83
87
 
84
- ### 带初始后端初始化
88
+ ### Initialize with a backend from the start
85
89
 
86
90
  ```typescript
87
- // 首次初始化时可以直接传入远程后端
88
91
  const repo = await createConfigRepo('my-app', {
89
- primaryBackendId: 'gitee-prod', // 副本后端 ID
92
+ primaryBackendId: 'gitee-prod',
90
93
  backendInfo: {
91
94
  type: 'Gitee',
92
95
  options: { token: 'xxx', owner: 'xxx', repo: 'xxx', branch: 'main' },
93
96
  },
94
- idbStoreName: 'my-app-config', // 自定义 IndexedDB store 名称
97
+ idbStoreName: 'my-app-config', // custom IndexedDB store name
95
98
  });
96
99
 
97
- // 之后重新打开时不需要再传后端参数
100
+ // Next time you don't need to pass backend info again
98
101
  const repo2 = await createConfigRepo('my-app');
99
102
  ```
100
103
 
101
- ## 目录结构
104
+ ## Directory Structure
102
105
 
103
106
  ```
104
107
  /
105
- ├── {appId}/ # 应用私有配置(自动同步到副本)
106
- ├── shared/ # 跨应用共享配置(双向同步)
107
- ├── nodes/{nodeId}/ # 节点本地配置(不同步)
108
+ ├── {appId}/ # App-private config (auto-synced to replicas)
109
+ ├── shared/ # Cross-app shared config (bi-directional sync)
110
+ ├── nodes/{nodeId}/ # Node-local config (never synced)
108
111
  └── .meta/
109
- ├── backends/ # 后端拓扑(每个后端一个文件)
112
+ ├── backends/ # Backend topology (one file per backend)
110
113
  │ ├── local-idb.json
111
114
  │ ├── gitee-prod.json
112
115
  │ └── ...
113
- ├── .deleted/ # 删除墓碑(跨后端删除传播)
114
- └── .conflicts/ # 冲突归档(双方内容都保存)
116
+ ├── .deleted/ # Deletion tombstones (propagate deletes across backends)
117
+ └── .conflicts/ # Conflict archives (both sides preserved)
115
118
  ```
116
119
 
117
- 每个配置文件有 sidecar 版本文件:`db.json` → `.db.json.version`(版本号 + SHA-256 哈希)。
120
+ Each config file has a sidecar version file: `db.json` → `.db.json.version` (version number + SHA-256 hash).
121
+
122
+ ## Core API
118
123
 
119
- ## 核心 API
124
+ ### ConfigRepo
120
125
 
121
- | 方法 | 说明 |
122
- |---|---|
123
- | `createConfigRepo(appId, options?)` | 创建配置仓库。IndexedDB 始终为主后端,`backendInfo` 作为副本 |
124
- | `getConfig<T>(path)` | 同步读取应用配置(从 IndexedDB) |
125
- | `setConfig(path, data)` | 同步写入应用配置(异步持久化 + 自动同步) |
126
- | `addBackend(id, type, options, desc?)` | 动态添加副本后端,自动建立双向同步 |
127
- | `removeBackend(id)` | 移除副本后端,停止同步 |
128
- | `getBackends()` | 读取所有后端拓扑(从 `.meta/backends/*.json` 聚合) |
129
- | `getNodeConfig<T>(nodeId, path)` | 异步读取节点本地配置 |
130
- | `setNodeConfig(nodeId, path, data)` | 异步写入节点本地配置(不同步) |
131
- | `publishNodeConfig(nodeId)` | 将节点配置一次性同步到所有后端 |
132
- | `peekNodeConfig<T>(nodeId, path)` | 只读查看其他节点的已发布配置 |
133
- | `flush()` | 手动触发所有同步 |
134
- | `listConflicts()` | 列出所有冲突归档 |
135
- | `resolveConflict(id, merged)` | 用合并内容解决冲突 |
136
- | `fs.promises.*` | 标准 fs API,chroot 隔离到 `/{appId}/` |
137
- | `dispose()` | 停止同步、释放资源 |
126
+ | Method | Description |
127
+ |--------|-------------|
128
+ | `createConfigRepo(appId, options?)` | Create a config repo. IndexedDB is always primary; `backendInfo` becomes a replica. |
129
+ | `getConfig<T>(path)` | Synchronously read app config (from IndexedDB) |
130
+ | `setConfig(path, data)` | Synchronously write app config (async persistence + auto-sync) |
131
+ | `addBackend(id, type, options, desc?)` | Dynamically add a replica backend with auto bi-directional sync |
132
+ | `removeBackend(id)` | Remove a replica backend and stop syncing |
133
+ | `getBackends()` | Read backend topology (aggregated from `.meta/backends/*.json`) |
134
+ | `getNodeConfig<T>(nodeId, path)` | Asynchronously read node-local config |
135
+ | `setNodeConfig(nodeId, path, data)` | Asynchronously write node-local config (not synced) |
136
+ | `publishNodeConfig(nodeId)` | One-time push of node config to all backends |
137
+ | `peekNodeConfig<T>(nodeId, path)` | Read-only view of another node's published config |
138
+ | `flush()` | Manually trigger all pending syncs |
139
+ | `listConflicts()` | List all archived conflicts |
140
+ | `resolveConflict(id, merged)` | Resolve a conflict with merged content |
141
+ | `fs.promises.*` | Standard fs API, chrooted to `/{appId}/` |
142
+ | `dispose()` | Stop syncing and release resources |
138
143
 
139
- ## 后端注册
144
+ ### Backend Registration
140
145
 
141
- zen-fs-config 内置两个后端:
142
- - **IndexedDB** — 本地主后端(基于 `@zenfs/dom`),无需注册
143
- - **InMemory** — 内存后端(基于 `@zenfs/core`),用于测试
146
+ zen-fs-config includes two built-in backends:
147
+ - **IndexedDB** — local primary backend (based on `@zenfs/dom`), no registration needed
148
+ - **InMemory** — in-memory backend (based on `@zenfs/core`), useful for testing
144
149
 
145
- 注册自定义后端:
150
+ Register custom backends:
146
151
 
147
152
  ```typescript
148
153
  import { registerBackend } from 'zen-fs-config';
149
154
 
150
- // 注册 Gitee 后端
155
+ // Register Gitee backend
151
156
  registerBackend('Gitee', async (options) => {
152
157
  const { Gitee } = await import('zen-fs-gitee');
153
158
  return Gitee.create(options);
154
159
  });
155
160
 
156
- // 注册 S3 后端
157
- registerBackend('S3Bucket', async (options) => {
158
- const { S3Bucket } = await import('@zenfs/core');
159
- return S3Bucket.create(options);
161
+ // Register RemoteStorage backend
162
+ registerBackend('RemoteStorage', async (options) => {
163
+ const { createRemoteStorageFileSystem } = await import('zen-fs-remotestoragejs');
164
+ return createRemoteStorageFileSystem(options);
160
165
  });
161
166
  ```
162
167
 
163
- ## 架构概览
168
+ ## Architecture
164
169
 
165
170
  ```
166
171
  Application code
167
172
  ↓ (reads/writes via standard fs API)
168
- ConfigRepo (this library)
173
+ ConfigRepo
169
174
  ├─ IndexedDB (local primary, always)
170
175
  │ └─ All config operations target IndexedDB first
171
176
  └─ zen-fs-sync → Bi-directional sync
172
- ├─ Replica X (e.g., Gitee)
173
- ├─ Replica Y (e.g., S3)
174
- └─ Replica Z (e.g., RemoteStorage)
177
+ ├─ Replica 1 (e.g. Gitee)
178
+ ├─ Replica 2 (e.g. RemoteStorage)
179
+ └─ Replica 3 (e.g. GitHub)
175
180
  ```
176
181
 
177
- - **IndexedDB 是唯一的主后端**:所有读写操作直接操作 IndexedDB,保证离线可用
178
- - **远程后端是副本**:通过 `addBackend()` 或 `createConfigRepo({ backendInfo })` 添加
179
- - **自动同步**:对 IndexedDB 的修改会自动同步到所有副本后端
180
- - **自描述拓扑**:后端配置存储在 `.meta/backends/` 目录中,每个后端一个 JSON 文件
182
+ - **IndexedDB is the only primary backend** — all reads and writes go directly to IndexedDB, guaranteeing offline availability
183
+ - **Remote backends are replicas** — added via `addBackend()` or `createConfigRepo({ backendInfo })`
184
+ - **Auto-sync** — changes to IndexedDB automatically propagate to all replicas
185
+ - **Self-describing topology** — backend configuration lives in `.meta/backends/`, one JSON file per backend
181
186
 
182
- ## 依赖
187
+ ## Dependencies
183
188
 
184
- | 包 | 说明 | 必需 |
185
- |---|---|---|
186
- | `@zenfs/core >=2.3.0` | ZenFS 虚拟文件系统 | 是 |
187
- | `@zenfs/dom >=1.0.0` | IndexedDB 后端(浏览器) | 是(浏览器) |
188
- | `zen-fs-sync >=0.1.0` | 跨后端同步引擎 | 是 |
189
- | `zen-fs-cache >=1.0.0` | ETag/TTL 缓存层 | 否(可选) |
189
+ | Package | Description | Required |
190
+ |---------|-------------|----------|
191
+ | `@zenfs/core >=2.3.0` | ZenFS virtual file system | Yes |
192
+ | `@zenfs/dom >=1.0.0` | IndexedDB backend (browser) | Yes (browser) |
193
+ | `zen-fs-sync >=0.4.7` | Cross-backend sync engine | Yes |
194
+ | `zen-fs-cache >=1.0.0` | ETag/TTL caching layer | No (optional) |
190
195
 
191
196
  ## License
192
197
 
@@ -0,0 +1,193 @@
1
+ # zen-fs-config
2
+
3
+ 基于 ZenFS 的分布式配置管理库。以 IndexedDB 为本地主后端(offline-first),用户提供的远程后端作为副本自动同步。支持应用隔离、共享空间、节点本地配置和冲突安全。
4
+
5
+ **GitHub**: https://github.com/weijia/zen-fs-config
6
+ **NPM**: `zen-fs-config`
7
+ **设计文档**: [DESIGN.md](./DESIGN.md)
8
+
9
+ ## 安装
10
+
11
+ ```bash
12
+ npm install zen-fs-config @zenfs/core @zenfs/dom zen-fs-sync
13
+ ```
14
+
15
+ > `@zenfs/dom` 提供 IndexedDB 后端(浏览器环境必需)。`zen-fs-cache` 为可选依赖。
16
+
17
+ ## 快速开始
18
+
19
+ ### 1. 初始化(零参数)
20
+
21
+ ```typescript
22
+ import { createConfigRepo } from 'zen-fs-config';
23
+
24
+ // 不传任何后端参数,自动创建 IndexedDB 本地主后端
25
+ const repo = await createConfigRepo('my-app');
26
+
27
+ // 读写配置(同步 API,从 IndexedDB 读取)
28
+ repo.setConfig('/database', { host: 'localhost', port: 5432 });
29
+ const db = repo.getConfig<{ host: string; port: number }>('/database');
30
+ ```
31
+
32
+ ### 2. 设置新的配置
33
+
34
+ ```typescript
35
+ repo.setConfig('/cache', { ttl: 3600, maxSize: '100MB' });
36
+ repo.setConfig('/feature-flags', { newUI: true, beta: false });
37
+ ```
38
+
39
+ ### 3. 增加数据后端(副本)
40
+
41
+ ```typescript
42
+ import { registerBackend } from 'zen-fs-config';
43
+ import { Gitee } from 'zen-fs-gitee';
44
+
45
+ // 注册后端类型
46
+ registerBackend('Gitee', async (options) => {
47
+ return Gitee.create(options);
48
+ });
49
+
50
+ // 动态添加副本后端,自动与本地 IndexedDB 双向同步
51
+ await repo.addBackend('gitee-prod', 'Gitee', {
52
+ token: 'your-token',
53
+ owner: 'your-name',
54
+ repo: 'config-repo',
55
+ branch: 'main',
56
+ }, '生产环境 Gitee 配置仓库');
57
+ ```
58
+
59
+ ### 4. 自动同步
60
+
61
+ ```typescript
62
+ // setConfig 写入 IndexedDB 后,自动同步到所有副本后端
63
+ repo.setConfig('/database', { host: 'new-host', port: 5432 });
64
+
65
+ // 手动触发同步(通常不需要,同步是自动的)
66
+ await repo.flush();
67
+ ```
68
+
69
+ ### 5. 再次打开时初始化
70
+
71
+ ```typescript
72
+ // 重新打开页面时,只需传入 appId
73
+ // IndexedDB 中的配置和后端拓扑会自动恢复
74
+ const repo = await createConfigRepo('my-app');
75
+
76
+ // 配置直接从 IndexedDB 读取(离线可用)
77
+ const db = repo.getConfig<{ host: string; port: number }>('/database');
78
+
79
+ // 已注册的副本后端会自动重新连接并同步
80
+ const backends = await repo.getBackends();
81
+ console.log(backends?.backends.map(b => b.id)); // ['local-idb', 'gitee-prod', ...]
82
+ ```
83
+
84
+ ### 带初始后端初始化
85
+
86
+ ```typescript
87
+ // 首次初始化时可以直接传入远程后端
88
+ const repo = await createConfigRepo('my-app', {
89
+ primaryBackendId: 'gitee-prod', // 副本后端 ID
90
+ backendInfo: {
91
+ type: 'Gitee',
92
+ options: { token: 'xxx', owner: 'xxx', repo: 'xxx', branch: 'main' },
93
+ },
94
+ idbStoreName: 'my-app-config', // 自定义 IndexedDB store 名称
95
+ });
96
+
97
+ // 之后重新打开时不需要再传后端参数
98
+ const repo2 = await createConfigRepo('my-app');
99
+ ```
100
+
101
+ ## 目录结构
102
+
103
+ ```
104
+ /
105
+ ├── {appId}/ # 应用私有配置(自动同步到副本)
106
+ ├── shared/ # 跨应用共享配置(双向同步)
107
+ ├── nodes/{nodeId}/ # 节点本地配置(不同步)
108
+ └── .meta/
109
+ ├── backends/ # 后端拓扑(每个后端一个文件)
110
+ │ ├── local-idb.json
111
+ │ ├── gitee-prod.json
112
+ │ └── ...
113
+ ├── .deleted/ # 删除墓碑(跨后端删除传播)
114
+ └── .conflicts/ # 冲突归档(双方内容都保存)
115
+ ```
116
+
117
+ 每个配置文件有 sidecar 版本文件:`db.json` → `.db.json.version`(版本号 + SHA-256 哈希)。
118
+
119
+ ## 核心 API
120
+
121
+ | 方法 | 说明 |
122
+ |---|---|
123
+ | `createConfigRepo(appId, options?)` | 创建配置仓库。IndexedDB 始终为主后端,`backendInfo` 作为副本 |
124
+ | `getConfig<T>(path)` | 同步读取应用配置(从 IndexedDB) |
125
+ | `setConfig(path, data)` | 同步写入应用配置(异步持久化 + 自动同步) |
126
+ | `addBackend(id, type, options, desc?)` | 动态添加副本后端,自动建立双向同步 |
127
+ | `removeBackend(id)` | 移除副本后端,停止同步 |
128
+ | `getBackends()` | 读取所有后端拓扑(从 `.meta/backends/*.json` 聚合) |
129
+ | `getNodeConfig<T>(nodeId, path)` | 异步读取节点本地配置 |
130
+ | `setNodeConfig(nodeId, path, data)` | 异步写入节点本地配置(不同步) |
131
+ | `publishNodeConfig(nodeId)` | 将节点配置一次性同步到所有后端 |
132
+ | `peekNodeConfig<T>(nodeId, path)` | 只读查看其他节点的已发布配置 |
133
+ | `flush()` | 手动触发所有同步 |
134
+ | `listConflicts()` | 列出所有冲突归档 |
135
+ | `resolveConflict(id, merged)` | 用合并内容解决冲突 |
136
+ | `fs.promises.*` | 标准 fs API,chroot 隔离到 `/{appId}/` |
137
+ | `dispose()` | 停止同步、释放资源 |
138
+
139
+ ## 后端注册
140
+
141
+ zen-fs-config 内置两个后端:
142
+ - **IndexedDB** — 本地主后端(基于 `@zenfs/dom`),无需注册
143
+ - **InMemory** — 内存后端(基于 `@zenfs/core`),用于测试
144
+
145
+ 注册自定义后端:
146
+
147
+ ```typescript
148
+ import { registerBackend } from 'zen-fs-config';
149
+
150
+ // 注册 Gitee 后端
151
+ registerBackend('Gitee', async (options) => {
152
+ const { Gitee } = await import('zen-fs-gitee');
153
+ return Gitee.create(options);
154
+ });
155
+
156
+ // 注册 S3 后端
157
+ registerBackend('S3Bucket', async (options) => {
158
+ const { S3Bucket } = await import('@zenfs/core');
159
+ return S3Bucket.create(options);
160
+ });
161
+ ```
162
+
163
+ ## 架构概览
164
+
165
+ ```
166
+ Application code
167
+ ↓ (reads/writes via standard fs API)
168
+ ConfigRepo (this library)
169
+ ├─ IndexedDB (local primary, always)
170
+ │ └─ All config operations target IndexedDB first
171
+ └─ zen-fs-sync → Bi-directional sync
172
+ ├─ Replica X (e.g., Gitee)
173
+ ├─ Replica Y (e.g., S3)
174
+ └─ Replica Z (e.g., RemoteStorage)
175
+ ```
176
+
177
+ - **IndexedDB 是唯一的主后端**:所有读写操作直接操作 IndexedDB,保证离线可用
178
+ - **远程后端是副本**:通过 `addBackend()` 或 `createConfigRepo({ backendInfo })` 添加
179
+ - **自动同步**:对 IndexedDB 的修改会自动同步到所有副本后端
180
+ - **自描述拓扑**:后端配置存储在 `.meta/backends/` 目录中,每个后端一个 JSON 文件
181
+
182
+ ## 依赖
183
+
184
+ | 包 | 说明 | 必需 |
185
+ |---|---|---|
186
+ | `@zenfs/core >=2.3.0` | ZenFS 虚拟文件系统 | 是 |
187
+ | `@zenfs/dom >=1.0.0` | IndexedDB 后端(浏览器) | 是(浏览器) |
188
+ | `zen-fs-sync >=0.1.0` | 跨后端同步引擎 | 是 |
189
+ | `zen-fs-cache >=1.0.0` | ETag/TTL 缓存层 | 否(可选) |
190
+
191
+ ## License
192
+
193
+ MIT