zen-fs-config 0.1.0 → 0.1.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/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import * as node_fs from 'node:fs';
2
- import { ConflictStrategy, SyncResult, SyncPairStatus } from 'zen-fs-sync';
1
+ import { ConflictStrategy, SyncResult, SyncPairStatus, SyncableFS } from 'zen-fs-sync';
3
2
  export { SyncPairStatus, SyncResult } from 'zen-fs-sync';
3
+ import * as node_fs from 'node:fs';
4
4
 
5
5
  /** A single backend in the topology. */
6
6
  interface BackendDescriptor {
@@ -143,15 +143,15 @@ interface IConfigRepo {
143
143
  /** Write a config value (auto-synced). */
144
144
  setConfig(path: string, data: unknown): void;
145
145
  /** Read node-local config. */
146
- getNodeConfig<T = unknown>(nodeId: string, path: string): T;
146
+ getNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
147
147
  /** Write node-local config (no auto-sync). */
148
- setNodeConfig(nodeId: string, path: string, data: unknown): void;
148
+ setNodeConfig(nodeId: string, path: string, data: unknown): Promise<void>;
149
149
  /** Publish node-local config to sync backends (one-time, for debugging). */
150
150
  publishNodeConfig(nodeId: string, options?: {
151
151
  paths?: string[];
152
152
  }): Promise<SyncResult>;
153
153
  /** Peek at another node's published config (read-only). */
154
- peekNodeConfig<T = unknown>(nodeId: string, path: string): T;
154
+ peekNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
155
155
  /** Manually flush all pending sync operations. */
156
156
  flush(): Promise<SyncResult[]>;
157
157
  /** Get sync status for all registered sync pairs. */
@@ -164,4 +164,189 @@ interface IConfigRepo {
164
164
  dispose(): Promise<void>;
165
165
  }
166
166
 
167
- export type { BackendDescriptor, BackendsMeta, BootstrapData, CacheOptions, ConfigRepoOptions, ConfigSerializer, ConflictArchive, ConflictInfo, IConfigRepo, SyncRule, SyncRulesMeta, VersionMeta };
167
+ /**
168
+ * zen-fs-config — Config Serializers
169
+ *
170
+ * Handles serialization/deserialization between JS values and file bytes.
171
+ * The default serializer handles .json, .txt, and unknown extensions.
172
+ * Users can provide a custom ConfigSerializer via ConfigRepoOptions.
173
+ */
174
+
175
+ /**
176
+ * Extended serializer that also accepts an optional path hint for routing.
177
+ * The core ConfigSerializer interface only takes `data`, but internally
178
+ * we use the path to pick the right serializer.
179
+ */
180
+ interface PathAwareSerializer extends ConfigSerializer {
181
+ serialize(data: unknown, path?: string): Uint8Array;
182
+ deserialize(raw: Uint8Array, path?: string): unknown;
183
+ }
184
+ /**
185
+ * Create a serializer chain from a user-provided serializer + defaults.
186
+ * The first serializer whose `canHandle()` returns true wins.
187
+ */
188
+ declare function createSerializerChain(custom?: ConfigSerializer): PathAwareSerializer;
189
+
190
+ /**
191
+ * Map a config key to a file path.
192
+ *
193
+ * - `/db/host` → `/db/host.json` (append .json if no extension)
194
+ * - `/readme.md` → `/readme.md` (preserve existing extension)
195
+ */
196
+ declare function configKeyToFilePath(configPath: string): string;
197
+ /**
198
+ * Extract the file extension (including the dot), or empty string.
199
+ */
200
+ declare function getExtension(path: string): string;
201
+
202
+ /**
203
+ * zen-fs-config — ConfigRepo Implementation
204
+ *
205
+ * Core implementation of IConfigRepo and the createConfigRepo factory.
206
+ */
207
+
208
+ interface MinimalAsyncFS {
209
+ readFile(path: string, ...args: any[]): Promise<any>;
210
+ writeFile(path: string, data: any, options?: any): Promise<void>;
211
+ readdir(path: string): Promise<string[]>;
212
+ stat(path: string): Promise<any>;
213
+ exists(path: string): Promise<boolean>;
214
+ mkdir(path: string, options?: any): Promise<any>;
215
+ unlink(path: string): Promise<void>;
216
+ rmdir?(path: string): Promise<void>;
217
+ rename?(oldPath: string, newPath: string): Promise<void>;
218
+ }
219
+ declare class ConfigRepo implements IConfigRepo {
220
+ readonly appId: string;
221
+ readonly nodeId: string;
222
+ /** Chroot-isolated fs for app-facing API. Typed as `any` to match `typeof import('node:fs')` duck-typically. */
223
+ readonly fs: any;
224
+ private cachedFS;
225
+ private fullFS;
226
+ private serializer;
227
+ private syncEngine;
228
+ private replicaBackends;
229
+ private onConflictCallback?;
230
+ private disposed;
231
+ private configCache;
232
+ constructor(appId: string, nodeId: string, cachedFS: MinimalAsyncFS, serializer: PathAwareSerializer, onConflict?: (conflict: ConflictInfo) => Promise<unknown | null>);
233
+ load(rawConfig?: string): Promise<void>;
234
+ getConfig<T = unknown>(path: string): T;
235
+ setConfig(path: string, data: unknown): void;
236
+ getNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
237
+ setNodeConfig(nodeId: string, path: string, data: unknown): Promise<void>;
238
+ publishNodeConfig(nodeId: string, options?: {
239
+ paths?: string[];
240
+ }): Promise<SyncResult>;
241
+ peekNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
242
+ flush(): Promise<SyncResult[]>;
243
+ getSyncStatuses(): Map<string, SyncPairStatus>;
244
+ resolveConflict(conflictId: string, mergedContent: unknown): Promise<void>;
245
+ listConflicts(): Promise<ConflictArchive[]>;
246
+ dispose(): Promise<void>;
247
+ setupSync(rules: SyncRule[], backends: BackendDescriptor[], primaryBackendId: string): Promise<void>;
248
+ private persistConfig;
249
+ private reloadConfigCache;
250
+ private handleConflict;
251
+ private ensureDir;
252
+ private walkDir;
253
+ writeMetaFile(path: string, data: BackendsMeta | SyncRulesMeta): Promise<void>;
254
+ readMetaFile<T>(path: string): Promise<T | null>;
255
+ private tryParse;
256
+ private assertNotDisposed;
257
+ }
258
+ declare function createConfigRepo(appId: string, options: ConfigRepoOptions): Promise<IConfigRepo>;
259
+
260
+ /**
261
+ * zen-fs-config — Backend Registry
262
+ *
263
+ * A pluggable registry that maps backend type names to factory functions.
264
+ * Built-in support for ZenFS backends (InMemory, IndexedDB, etc.)
265
+ * loaded from @zenfs/core.
266
+ *
267
+ * Users can register custom backends via `registerBackend()`.
268
+ */
269
+
270
+ /**
271
+ * A factory function that creates a file system instance from options.
272
+ * The returned value must satisfy SyncableFS (and ideally CacheableFileSystem).
273
+ */
274
+ type BackendFactory = (options: Record<string, unknown>) => Promise<BackendInstance>;
275
+ /**
276
+ * The minimal interface a backend instance must satisfy.
277
+ * Combines SyncableFS (from zen-fs-sync) with the write signature
278
+ * needed by CachedFileSystem.
279
+ */
280
+ interface BackendInstance {
281
+ readFile(path: string, ...args: any[]): Promise<any>;
282
+ writeFile(path: string, data: string | Uint8Array | ArrayBuffer, options?: any): Promise<void>;
283
+ readdir(path: string): Promise<string[]>;
284
+ stat(path: string, ...args: any[]): Promise<any>;
285
+ exists(path: string): Promise<boolean>;
286
+ mkdir(path: string, options?: any): Promise<any>;
287
+ unlink(path: string): Promise<void>;
288
+ rmdir?(path: string): Promise<void>;
289
+ rename?(oldPath: string, newPath: string): Promise<void>;
290
+ readFileMeta?(path: string, opts?: any): Promise<any>;
291
+ getRevision?(path: string): Promise<string | number | undefined>;
292
+ }
293
+ /**
294
+ * Register a backend factory by type name.
295
+ */
296
+ declare function registerBackend(type: string, factory: BackendFactory): void;
297
+ /**
298
+ * Create a backend instance from a descriptor.
299
+ */
300
+ declare function createBackend(descriptor: Pick<BackendDescriptor, 'type' | 'options'>): Promise<BackendInstance>;
301
+ /**
302
+ * Check if a backend type is registered.
303
+ */
304
+ declare function hasBackend(type: string): boolean;
305
+ /**
306
+ * List all registered backend type names.
307
+ */
308
+ declare function listBackends(): string[];
309
+
310
+ /**
311
+ * zen-fs-config — Sidecar Version File Management
312
+ *
313
+ * Each config file has a companion .version file for version-based change
314
+ * detection and conflict resolution.
315
+ *
316
+ * Config file: /app-a/db.json
317
+ * Version file: /app-a/.db.json.version
318
+ */
319
+
320
+ /**
321
+ * Compute the sidecar version file path from a config file path.
322
+ *
323
+ * /app-a/db.json → /app-a/.db.json.version
324
+ * /shared/flags.json → /shared/.flags.json.version
325
+ * /nodes/s1/env.json → /nodes/s1/.env.json.version
326
+ */
327
+ declare function versionPathFor(configFilePath: string): string;
328
+ /**
329
+ * Compute SHA-256 hash of a Uint8Array.
330
+ * Returns "sha256:" prefix + hex digest.
331
+ */
332
+ declare function sha256(data: Uint8Array): Promise<string>;
333
+ /**
334
+ * Read and parse a version file. Returns null if it doesn't exist or is invalid.
335
+ */
336
+ declare function readVersion(fs: SyncableFS, versionFilePath: string): Promise<VersionMeta | null>;
337
+ /**
338
+ * Write a version file.
339
+ */
340
+ declare function writeVersion(fs: SyncableFS, versionFilePath: string, meta: VersionMeta): Promise<void>;
341
+ /**
342
+ * Increment version for a config file write.
343
+ */
344
+ declare function incrementVersion(fs: SyncableFS, configFilePath: string, newContent: Uint8Array, author: string): Promise<VersionMeta>;
345
+ /**
346
+ * Verify that the version file's hash matches the actual file content.
347
+ * If mismatch, auto-increment version and return updated meta.
348
+ * If version file doesn't exist, return null.
349
+ */
350
+ declare function verifyOrRepairVersion(fs: SyncableFS, configFilePath: string, author: string): Promise<VersionMeta | null>;
351
+
352
+ export { type BackendDescriptor, type BackendFactory, type BackendInstance, type BackendsMeta, type BootstrapData, type CacheOptions, ConfigRepo, type ConfigRepoOptions, type ConfigSerializer, type ConflictArchive, type ConflictInfo, type IConfigRepo, type SyncRule, type SyncRulesMeta, type VersionMeta, configKeyToFilePath, createBackend, createConfigRepo, createSerializerChain, getExtension, hasBackend, incrementVersion, listBackends, readVersion, registerBackend, sha256, verifyOrRepairVersion, versionPathFor, writeVersion };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import * as node_fs from 'node:fs';
2
- import { ConflictStrategy, SyncResult, SyncPairStatus } from 'zen-fs-sync';
1
+ import { ConflictStrategy, SyncResult, SyncPairStatus, SyncableFS } from 'zen-fs-sync';
3
2
  export { SyncPairStatus, SyncResult } from 'zen-fs-sync';
3
+ import * as node_fs from 'node:fs';
4
4
 
5
5
  /** A single backend in the topology. */
6
6
  interface BackendDescriptor {
@@ -143,15 +143,15 @@ interface IConfigRepo {
143
143
  /** Write a config value (auto-synced). */
144
144
  setConfig(path: string, data: unknown): void;
145
145
  /** Read node-local config. */
146
- getNodeConfig<T = unknown>(nodeId: string, path: string): T;
146
+ getNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
147
147
  /** Write node-local config (no auto-sync). */
148
- setNodeConfig(nodeId: string, path: string, data: unknown): void;
148
+ setNodeConfig(nodeId: string, path: string, data: unknown): Promise<void>;
149
149
  /** Publish node-local config to sync backends (one-time, for debugging). */
150
150
  publishNodeConfig(nodeId: string, options?: {
151
151
  paths?: string[];
152
152
  }): Promise<SyncResult>;
153
153
  /** Peek at another node's published config (read-only). */
154
- peekNodeConfig<T = unknown>(nodeId: string, path: string): T;
154
+ peekNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
155
155
  /** Manually flush all pending sync operations. */
156
156
  flush(): Promise<SyncResult[]>;
157
157
  /** Get sync status for all registered sync pairs. */
@@ -164,4 +164,189 @@ interface IConfigRepo {
164
164
  dispose(): Promise<void>;
165
165
  }
166
166
 
167
- export type { BackendDescriptor, BackendsMeta, BootstrapData, CacheOptions, ConfigRepoOptions, ConfigSerializer, ConflictArchive, ConflictInfo, IConfigRepo, SyncRule, SyncRulesMeta, VersionMeta };
167
+ /**
168
+ * zen-fs-config — Config Serializers
169
+ *
170
+ * Handles serialization/deserialization between JS values and file bytes.
171
+ * The default serializer handles .json, .txt, and unknown extensions.
172
+ * Users can provide a custom ConfigSerializer via ConfigRepoOptions.
173
+ */
174
+
175
+ /**
176
+ * Extended serializer that also accepts an optional path hint for routing.
177
+ * The core ConfigSerializer interface only takes `data`, but internally
178
+ * we use the path to pick the right serializer.
179
+ */
180
+ interface PathAwareSerializer extends ConfigSerializer {
181
+ serialize(data: unknown, path?: string): Uint8Array;
182
+ deserialize(raw: Uint8Array, path?: string): unknown;
183
+ }
184
+ /**
185
+ * Create a serializer chain from a user-provided serializer + defaults.
186
+ * The first serializer whose `canHandle()` returns true wins.
187
+ */
188
+ declare function createSerializerChain(custom?: ConfigSerializer): PathAwareSerializer;
189
+
190
+ /**
191
+ * Map a config key to a file path.
192
+ *
193
+ * - `/db/host` → `/db/host.json` (append .json if no extension)
194
+ * - `/readme.md` → `/readme.md` (preserve existing extension)
195
+ */
196
+ declare function configKeyToFilePath(configPath: string): string;
197
+ /**
198
+ * Extract the file extension (including the dot), or empty string.
199
+ */
200
+ declare function getExtension(path: string): string;
201
+
202
+ /**
203
+ * zen-fs-config — ConfigRepo Implementation
204
+ *
205
+ * Core implementation of IConfigRepo and the createConfigRepo factory.
206
+ */
207
+
208
+ interface MinimalAsyncFS {
209
+ readFile(path: string, ...args: any[]): Promise<any>;
210
+ writeFile(path: string, data: any, options?: any): Promise<void>;
211
+ readdir(path: string): Promise<string[]>;
212
+ stat(path: string): Promise<any>;
213
+ exists(path: string): Promise<boolean>;
214
+ mkdir(path: string, options?: any): Promise<any>;
215
+ unlink(path: string): Promise<void>;
216
+ rmdir?(path: string): Promise<void>;
217
+ rename?(oldPath: string, newPath: string): Promise<void>;
218
+ }
219
+ declare class ConfigRepo implements IConfigRepo {
220
+ readonly appId: string;
221
+ readonly nodeId: string;
222
+ /** Chroot-isolated fs for app-facing API. Typed as `any` to match `typeof import('node:fs')` duck-typically. */
223
+ readonly fs: any;
224
+ private cachedFS;
225
+ private fullFS;
226
+ private serializer;
227
+ private syncEngine;
228
+ private replicaBackends;
229
+ private onConflictCallback?;
230
+ private disposed;
231
+ private configCache;
232
+ constructor(appId: string, nodeId: string, cachedFS: MinimalAsyncFS, serializer: PathAwareSerializer, onConflict?: (conflict: ConflictInfo) => Promise<unknown | null>);
233
+ load(rawConfig?: string): Promise<void>;
234
+ getConfig<T = unknown>(path: string): T;
235
+ setConfig(path: string, data: unknown): void;
236
+ getNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
237
+ setNodeConfig(nodeId: string, path: string, data: unknown): Promise<void>;
238
+ publishNodeConfig(nodeId: string, options?: {
239
+ paths?: string[];
240
+ }): Promise<SyncResult>;
241
+ peekNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
242
+ flush(): Promise<SyncResult[]>;
243
+ getSyncStatuses(): Map<string, SyncPairStatus>;
244
+ resolveConflict(conflictId: string, mergedContent: unknown): Promise<void>;
245
+ listConflicts(): Promise<ConflictArchive[]>;
246
+ dispose(): Promise<void>;
247
+ setupSync(rules: SyncRule[], backends: BackendDescriptor[], primaryBackendId: string): Promise<void>;
248
+ private persistConfig;
249
+ private reloadConfigCache;
250
+ private handleConflict;
251
+ private ensureDir;
252
+ private walkDir;
253
+ writeMetaFile(path: string, data: BackendsMeta | SyncRulesMeta): Promise<void>;
254
+ readMetaFile<T>(path: string): Promise<T | null>;
255
+ private tryParse;
256
+ private assertNotDisposed;
257
+ }
258
+ declare function createConfigRepo(appId: string, options: ConfigRepoOptions): Promise<IConfigRepo>;
259
+
260
+ /**
261
+ * zen-fs-config — Backend Registry
262
+ *
263
+ * A pluggable registry that maps backend type names to factory functions.
264
+ * Built-in support for ZenFS backends (InMemory, IndexedDB, etc.)
265
+ * loaded from @zenfs/core.
266
+ *
267
+ * Users can register custom backends via `registerBackend()`.
268
+ */
269
+
270
+ /**
271
+ * A factory function that creates a file system instance from options.
272
+ * The returned value must satisfy SyncableFS (and ideally CacheableFileSystem).
273
+ */
274
+ type BackendFactory = (options: Record<string, unknown>) => Promise<BackendInstance>;
275
+ /**
276
+ * The minimal interface a backend instance must satisfy.
277
+ * Combines SyncableFS (from zen-fs-sync) with the write signature
278
+ * needed by CachedFileSystem.
279
+ */
280
+ interface BackendInstance {
281
+ readFile(path: string, ...args: any[]): Promise<any>;
282
+ writeFile(path: string, data: string | Uint8Array | ArrayBuffer, options?: any): Promise<void>;
283
+ readdir(path: string): Promise<string[]>;
284
+ stat(path: string, ...args: any[]): Promise<any>;
285
+ exists(path: string): Promise<boolean>;
286
+ mkdir(path: string, options?: any): Promise<any>;
287
+ unlink(path: string): Promise<void>;
288
+ rmdir?(path: string): Promise<void>;
289
+ rename?(oldPath: string, newPath: string): Promise<void>;
290
+ readFileMeta?(path: string, opts?: any): Promise<any>;
291
+ getRevision?(path: string): Promise<string | number | undefined>;
292
+ }
293
+ /**
294
+ * Register a backend factory by type name.
295
+ */
296
+ declare function registerBackend(type: string, factory: BackendFactory): void;
297
+ /**
298
+ * Create a backend instance from a descriptor.
299
+ */
300
+ declare function createBackend(descriptor: Pick<BackendDescriptor, 'type' | 'options'>): Promise<BackendInstance>;
301
+ /**
302
+ * Check if a backend type is registered.
303
+ */
304
+ declare function hasBackend(type: string): boolean;
305
+ /**
306
+ * List all registered backend type names.
307
+ */
308
+ declare function listBackends(): string[];
309
+
310
+ /**
311
+ * zen-fs-config — Sidecar Version File Management
312
+ *
313
+ * Each config file has a companion .version file for version-based change
314
+ * detection and conflict resolution.
315
+ *
316
+ * Config file: /app-a/db.json
317
+ * Version file: /app-a/.db.json.version
318
+ */
319
+
320
+ /**
321
+ * Compute the sidecar version file path from a config file path.
322
+ *
323
+ * /app-a/db.json → /app-a/.db.json.version
324
+ * /shared/flags.json → /shared/.flags.json.version
325
+ * /nodes/s1/env.json → /nodes/s1/.env.json.version
326
+ */
327
+ declare function versionPathFor(configFilePath: string): string;
328
+ /**
329
+ * Compute SHA-256 hash of a Uint8Array.
330
+ * Returns "sha256:" prefix + hex digest.
331
+ */
332
+ declare function sha256(data: Uint8Array): Promise<string>;
333
+ /**
334
+ * Read and parse a version file. Returns null if it doesn't exist or is invalid.
335
+ */
336
+ declare function readVersion(fs: SyncableFS, versionFilePath: string): Promise<VersionMeta | null>;
337
+ /**
338
+ * Write a version file.
339
+ */
340
+ declare function writeVersion(fs: SyncableFS, versionFilePath: string, meta: VersionMeta): Promise<void>;
341
+ /**
342
+ * Increment version for a config file write.
343
+ */
344
+ declare function incrementVersion(fs: SyncableFS, configFilePath: string, newContent: Uint8Array, author: string): Promise<VersionMeta>;
345
+ /**
346
+ * Verify that the version file's hash matches the actual file content.
347
+ * If mismatch, auto-increment version and return updated meta.
348
+ * If version file doesn't exist, return null.
349
+ */
350
+ declare function verifyOrRepairVersion(fs: SyncableFS, configFilePath: string, author: string): Promise<VersionMeta | null>;
351
+
352
+ export { type BackendDescriptor, type BackendFactory, type BackendInstance, type BackendsMeta, type BootstrapData, type CacheOptions, ConfigRepo, type ConfigRepoOptions, type ConfigSerializer, type ConflictArchive, type ConflictInfo, type IConfigRepo, type SyncRule, type SyncRulesMeta, type VersionMeta, configKeyToFilePath, createBackend, createConfigRepo, createSerializerChain, getExtension, hasBackend, incrementVersion, listBackends, readVersion, registerBackend, sha256, verifyOrRepairVersion, versionPathFor, writeVersion };