zen-fs-config 0.3.23 → 0.3.25

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
@@ -222,7 +222,7 @@ declare class ConfigRepo implements IConfigRepo {
222
222
  private onConflictCallback?;
223
223
  private disposed;
224
224
  private configCache;
225
- constructor(appId: string, nodeId: string, cachedFS: MinimalAsyncFS, serializer: PathAwareSerializer, onConflict?: (conflict: ConflictInfo) => Promise<unknown | null>);
225
+ constructor(appId: string, nodeId: string, primaryBackendId: string, cachedFS: MinimalAsyncFS, serializer: PathAwareSerializer, onConflict?: (conflict: ConflictInfo) => Promise<unknown | null>);
226
226
  /** Full path to this node's directory on the primary backend. */
227
227
  get nodePath(): string;
228
228
  load(rawConfig?: string): Promise<void>;
@@ -244,9 +244,6 @@ declare class ConfigRepo implements IConfigRepo {
244
244
  * Called automatically by createConfigRepo() after setupSync().
245
245
  */
246
246
  syncMetaToReplicas(): Promise<void>;
247
- /** Compare two file contents (handles Uint8Array, ArrayBuffer, string, Buffer). */
248
- private bufferEqual;
249
- private toUint8Array;
250
247
  getSyncStatuses(): Map<string, SyncPairStatus>;
251
248
  resolveConflict(conflictId: string, mergedContent: unknown): Promise<void>;
252
249
  listConflicts(): Promise<ConflictArchive[]>;
package/dist/index.d.ts CHANGED
@@ -222,7 +222,7 @@ declare class ConfigRepo implements IConfigRepo {
222
222
  private onConflictCallback?;
223
223
  private disposed;
224
224
  private configCache;
225
- constructor(appId: string, nodeId: string, cachedFS: MinimalAsyncFS, serializer: PathAwareSerializer, onConflict?: (conflict: ConflictInfo) => Promise<unknown | null>);
225
+ constructor(appId: string, nodeId: string, primaryBackendId: string, cachedFS: MinimalAsyncFS, serializer: PathAwareSerializer, onConflict?: (conflict: ConflictInfo) => Promise<unknown | null>);
226
226
  /** Full path to this node's directory on the primary backend. */
227
227
  get nodePath(): string;
228
228
  load(rawConfig?: string): Promise<void>;
@@ -244,9 +244,6 @@ declare class ConfigRepo implements IConfigRepo {
244
244
  * Called automatically by createConfigRepo() after setupSync().
245
245
  */
246
246
  syncMetaToReplicas(): Promise<void>;
247
- /** Compare two file contents (handles Uint8Array, ArrayBuffer, string, Buffer). */
248
- private bufferEqual;
249
- private toUint8Array;
250
247
  getSyncStatuses(): Map<string, SyncPairStatus>;
251
248
  resolveConflict(conflictId: string, mergedContent: unknown): Promise<void>;
252
249
  listConflicts(): Promise<ConflictArchive[]>;
package/dist/index.js CHANGED
@@ -225,8 +225,8 @@ async function ensureParentDir(absolutePath) {
225
225
  }
226
226
 
227
227
  // src/adapters.ts
228
- function backendToSyncableFS(backend) {
229
- return {
228
+ function backendToSyncableFS(backend, name) {
229
+ const syncable = {
230
230
  async readdir(path) {
231
231
  return backend.readdir(path);
232
232
  },
@@ -265,9 +265,17 @@ function backendToSyncableFS(backend) {
265
265
  return backend.exists(path);
266
266
  }
267
267
  };
268
+ if (name) {
269
+ syncable.backendName = name;
270
+ } else if (backend.backendName) {
271
+ syncable.backendName = backend.backendName;
272
+ } else {
273
+ syncable.backendName = backend.constructor.name || "Backend";
274
+ }
275
+ return syncable;
268
276
  }
269
- function cachedFSToSyncableFS(cached) {
270
- return {
277
+ function cachedFSToSyncableFS(cached, name) {
278
+ const syncable = {
271
279
  async readdir(path) {
272
280
  return cached.readdir(path);
273
281
  },
@@ -306,6 +314,8 @@ function cachedFSToSyncableFS(cached) {
306
314
  return cached.exists(path);
307
315
  }
308
316
  };
317
+ syncable.backendName = name || "CachedFS";
318
+ return syncable;
309
319
  }
310
320
 
311
321
  // src/backend-registry.ts
@@ -502,7 +512,7 @@ var ConfigRepo = class {
502
512
  onConflictCallback;
503
513
  disposed = false;
504
514
  configCache = /* @__PURE__ */ new Map();
505
- constructor(appId, nodeId, cachedFS, serializer, onConflict) {
515
+ constructor(appId, nodeId, primaryBackendId, cachedFS, serializer, onConflict) {
506
516
  this.appId = appId;
507
517
  this.nodeId = nodeId;
508
518
  this.cachedFS = cachedFS;
@@ -510,7 +520,7 @@ var ConfigRepo = class {
510
520
  this.syncEngine = new import_zen_fs_sync.ZenFSSync();
511
521
  this.replicaBackends = /* @__PURE__ */ new Map();
512
522
  this.onConflictCallback = onConflict;
513
- this.fullFS = cachedFSToSyncableFS(cachedFS);
523
+ this.fullFS = cachedFSToSyncableFS(cachedFS, `CachedFS(${primaryBackendId})`);
514
524
  this.fs = createChrootFS(cachedFS, `/${appId}`);
515
525
  this.rootFS = createChrootFS(cachedFS, "/");
516
526
  }
@@ -667,59 +677,12 @@ var ConfigRepo = class {
667
677
  */
668
678
  async syncMetaToReplicas() {
669
679
  this.assertNotDisposed();
670
- try {
671
- const content = await this.cachedFS.readFile(BACKENDS_FILE);
672
- const vPath = versionPathFor(BACKENDS_FILE);
673
- let vContent;
674
- try {
675
- vContent = await this.cachedFS.readFile(vPath);
676
- } catch {
677
- }
678
- for (const [id, replica] of this.replicaBackends) {
679
- try {
680
- let needWrite = true;
681
- try {
682
- const existing = await replica.syncable.readFile(BACKENDS_FILE);
683
- if (this.bufferEqual(content, existing)) {
684
- needWrite = false;
685
- console.log(`[ConfigRepo] ${BACKENDS_FILE} already up-to-date on ${id}, skipping`);
686
- }
687
- } catch {
688
- }
689
- if (needWrite) {
690
- await replica.syncable.writeFile(BACKENDS_FILE, content);
691
- console.log(`[ConfigRepo] Synced ${BACKENDS_FILE} to replica ${id}`);
692
- }
693
- if (vContent) {
694
- try {
695
- await replica.syncable.writeFile(vPath, vContent);
696
- } catch (err) {
697
- console.error(`[ConfigRepo] Failed to sync ${vPath} to ${id}:`, err.message);
698
- }
699
- }
700
- } catch (err) {
701
- console.error(`[ConfigRepo] Failed to sync ${BACKENDS_FILE} to ${id}:`, err.message);
702
- }
703
- }
704
- } catch {
705
- }
706
- }
707
- /** Compare two file contents (handles Uint8Array, ArrayBuffer, string, Buffer). */
708
- bufferEqual(a, b) {
709
- const ua = this.toUint8Array(a);
710
- const ub = this.toUint8Array(b);
711
- if (ua.length !== ub.length) return false;
712
- for (let i = 0; i < ua.length; i++) {
713
- if (ua[i] !== ub[i]) return false;
680
+ const results = await this.flush();
681
+ for (const result of results) {
682
+ console.log(
683
+ `[ConfigRepo] syncMetaToReplicas: ${result.pairId} +${result.filesCreated}/~${result.filesUpdated}/-${result.filesDeleted} skip:${result.filesSkipped} ${result.durationMs}ms`
684
+ );
714
685
  }
715
- return true;
716
- }
717
- toUint8Array(raw) {
718
- if (raw instanceof ArrayBuffer) return new Uint8Array(raw);
719
- if (raw instanceof Uint8Array) return raw;
720
- if (typeof raw === "string") return new TextEncoder().encode(raw);
721
- if (Buffer.isBuffer(raw)) return new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
722
- return new Uint8Array(raw);
723
686
  }
724
687
  getSyncStatuses() {
725
688
  this.assertNotDisposed();
@@ -816,7 +779,7 @@ var ConfigRepo = class {
816
779
  console.log(`[ConfigRepo] Creating replica backend: id=${desc.id}, type=${desc.type}`);
817
780
  try {
818
781
  const instance = await createBackend(desc);
819
- const syncable = backendToSyncableFS(instance);
782
+ const syncable = backendToSyncableFS(instance, `${desc.type}(${desc.id})`);
820
783
  this.replicaBackends.set(desc.id, { instance, syncable });
821
784
  console.log(`[ConfigRepo] Replica ${desc.id} created successfully`);
822
785
  } catch (err) {
@@ -1062,6 +1025,7 @@ async function createConfigRepo(appId, options) {
1062
1025
  const tempRepo = new ConfigRepo(
1063
1026
  appId,
1064
1027
  "",
1028
+ options.primaryBackendId,
1065
1029
  cachedFS,
1066
1030
  createSerializerChain(),
1067
1031
  void 0
@@ -1118,6 +1082,7 @@ async function createConfigRepo(appId, options) {
1118
1082
  const repo = new ConfigRepo(
1119
1083
  appId,
1120
1084
  nodeId,
1085
+ options.primaryBackendId,
1121
1086
  cachedFS,
1122
1087
  serializer,
1123
1088
  options.onConflict
package/dist/index.mjs CHANGED
@@ -176,8 +176,8 @@ async function ensureParentDir(absolutePath) {
176
176
  }
177
177
 
178
178
  // src/adapters.ts
179
- function backendToSyncableFS(backend) {
180
- return {
179
+ function backendToSyncableFS(backend, name) {
180
+ const syncable = {
181
181
  async readdir(path) {
182
182
  return backend.readdir(path);
183
183
  },
@@ -216,9 +216,17 @@ function backendToSyncableFS(backend) {
216
216
  return backend.exists(path);
217
217
  }
218
218
  };
219
+ if (name) {
220
+ syncable.backendName = name;
221
+ } else if (backend.backendName) {
222
+ syncable.backendName = backend.backendName;
223
+ } else {
224
+ syncable.backendName = backend.constructor.name || "Backend";
225
+ }
226
+ return syncable;
219
227
  }
220
- function cachedFSToSyncableFS(cached) {
221
- return {
228
+ function cachedFSToSyncableFS(cached, name) {
229
+ const syncable = {
222
230
  async readdir(path) {
223
231
  return cached.readdir(path);
224
232
  },
@@ -257,6 +265,8 @@ function cachedFSToSyncableFS(cached) {
257
265
  return cached.exists(path);
258
266
  }
259
267
  };
268
+ syncable.backendName = name || "CachedFS";
269
+ return syncable;
260
270
  }
261
271
 
262
272
  // src/backend-registry.ts
@@ -453,7 +463,7 @@ var ConfigRepo = class {
453
463
  onConflictCallback;
454
464
  disposed = false;
455
465
  configCache = /* @__PURE__ */ new Map();
456
- constructor(appId, nodeId, cachedFS, serializer, onConflict) {
466
+ constructor(appId, nodeId, primaryBackendId, cachedFS, serializer, onConflict) {
457
467
  this.appId = appId;
458
468
  this.nodeId = nodeId;
459
469
  this.cachedFS = cachedFS;
@@ -461,7 +471,7 @@ var ConfigRepo = class {
461
471
  this.syncEngine = new ZenFSSync();
462
472
  this.replicaBackends = /* @__PURE__ */ new Map();
463
473
  this.onConflictCallback = onConflict;
464
- this.fullFS = cachedFSToSyncableFS(cachedFS);
474
+ this.fullFS = cachedFSToSyncableFS(cachedFS, `CachedFS(${primaryBackendId})`);
465
475
  this.fs = createChrootFS(cachedFS, `/${appId}`);
466
476
  this.rootFS = createChrootFS(cachedFS, "/");
467
477
  }
@@ -618,59 +628,12 @@ var ConfigRepo = class {
618
628
  */
619
629
  async syncMetaToReplicas() {
620
630
  this.assertNotDisposed();
621
- try {
622
- const content = await this.cachedFS.readFile(BACKENDS_FILE);
623
- const vPath = versionPathFor(BACKENDS_FILE);
624
- let vContent;
625
- try {
626
- vContent = await this.cachedFS.readFile(vPath);
627
- } catch {
628
- }
629
- for (const [id, replica] of this.replicaBackends) {
630
- try {
631
- let needWrite = true;
632
- try {
633
- const existing = await replica.syncable.readFile(BACKENDS_FILE);
634
- if (this.bufferEqual(content, existing)) {
635
- needWrite = false;
636
- console.log(`[ConfigRepo] ${BACKENDS_FILE} already up-to-date on ${id}, skipping`);
637
- }
638
- } catch {
639
- }
640
- if (needWrite) {
641
- await replica.syncable.writeFile(BACKENDS_FILE, content);
642
- console.log(`[ConfigRepo] Synced ${BACKENDS_FILE} to replica ${id}`);
643
- }
644
- if (vContent) {
645
- try {
646
- await replica.syncable.writeFile(vPath, vContent);
647
- } catch (err) {
648
- console.error(`[ConfigRepo] Failed to sync ${vPath} to ${id}:`, err.message);
649
- }
650
- }
651
- } catch (err) {
652
- console.error(`[ConfigRepo] Failed to sync ${BACKENDS_FILE} to ${id}:`, err.message);
653
- }
654
- }
655
- } catch {
656
- }
657
- }
658
- /** Compare two file contents (handles Uint8Array, ArrayBuffer, string, Buffer). */
659
- bufferEqual(a, b) {
660
- const ua = this.toUint8Array(a);
661
- const ub = this.toUint8Array(b);
662
- if (ua.length !== ub.length) return false;
663
- for (let i = 0; i < ua.length; i++) {
664
- if (ua[i] !== ub[i]) return false;
631
+ const results = await this.flush();
632
+ for (const result of results) {
633
+ console.log(
634
+ `[ConfigRepo] syncMetaToReplicas: ${result.pairId} +${result.filesCreated}/~${result.filesUpdated}/-${result.filesDeleted} skip:${result.filesSkipped} ${result.durationMs}ms`
635
+ );
665
636
  }
666
- return true;
667
- }
668
- toUint8Array(raw) {
669
- if (raw instanceof ArrayBuffer) return new Uint8Array(raw);
670
- if (raw instanceof Uint8Array) return raw;
671
- if (typeof raw === "string") return new TextEncoder().encode(raw);
672
- if (Buffer.isBuffer(raw)) return new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
673
- return new Uint8Array(raw);
674
637
  }
675
638
  getSyncStatuses() {
676
639
  this.assertNotDisposed();
@@ -767,7 +730,7 @@ var ConfigRepo = class {
767
730
  console.log(`[ConfigRepo] Creating replica backend: id=${desc.id}, type=${desc.type}`);
768
731
  try {
769
732
  const instance = await createBackend(desc);
770
- const syncable = backendToSyncableFS(instance);
733
+ const syncable = backendToSyncableFS(instance, `${desc.type}(${desc.id})`);
771
734
  this.replicaBackends.set(desc.id, { instance, syncable });
772
735
  console.log(`[ConfigRepo] Replica ${desc.id} created successfully`);
773
736
  } catch (err) {
@@ -1013,6 +976,7 @@ async function createConfigRepo(appId, options) {
1013
976
  const tempRepo = new ConfigRepo(
1014
977
  appId,
1015
978
  "",
979
+ options.primaryBackendId,
1016
980
  cachedFS,
1017
981
  createSerializerChain(),
1018
982
  void 0
@@ -1069,6 +1033,7 @@ async function createConfigRepo(appId, options) {
1069
1033
  const repo = new ConfigRepo(
1070
1034
  appId,
1071
1035
  nodeId,
1036
+ options.primaryBackendId,
1072
1037
  cachedFS,
1073
1038
  serializer,
1074
1039
  options.onConflict
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zen-fs-config",
3
- "version": "0.3.23",
3
+ "version": "0.3.25",
4
4
  "description": "Distributed config management library built on ZenFS, zen-fs-cache, and zen-fs-sync",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",