zen-fs-config 0.3.19 → 0.3.20

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
@@ -170,6 +170,11 @@ interface IConfigRepo {
170
170
  getSyncRules(): Promise<SyncRulesMeta | null>;
171
171
  /** Write .meta/sync-rules.json. */
172
172
  updateSyncRules(meta: SyncRulesMeta): Promise<void>;
173
+ /**
174
+ * Sync .meta/ files (backends.json, sync-rules.json) to all replica backends.
175
+ * Called automatically by createConfigRepo() after setupSync().
176
+ */
177
+ syncMetaToReplicas(): Promise<void>;
173
178
  /** Dispose: stop all sync, release cache FS and resources. */
174
179
  dispose(): Promise<void>;
175
180
  }
@@ -254,6 +259,16 @@ declare class ConfigRepo implements IConfigRepo {
254
259
  }): Promise<SyncResult>;
255
260
  peekNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
256
261
  flush(): Promise<SyncResult[]>;
262
+ /**
263
+ * Sync .meta/ files (backends.json, sync-rules.json) to all replica backends.
264
+ *
265
+ * This ensures the backend topology is available on every replica, enabling
266
+ * any program that connects to any backend to discover the full topology.
267
+ *
268
+ * Called automatically by createConfigRepo() after setupSync().
269
+ * Can also be called manually after updateBackends() / updateSyncRules().
270
+ */
271
+ syncMetaToReplicas(): Promise<void>;
257
272
  getSyncStatuses(): Map<string, SyncPairStatus>;
258
273
  resolveConflict(conflictId: string, mergedContent: unknown): Promise<void>;
259
274
  listConflicts(): Promise<ConflictArchive[]>;
package/dist/index.d.ts CHANGED
@@ -170,6 +170,11 @@ interface IConfigRepo {
170
170
  getSyncRules(): Promise<SyncRulesMeta | null>;
171
171
  /** Write .meta/sync-rules.json. */
172
172
  updateSyncRules(meta: SyncRulesMeta): Promise<void>;
173
+ /**
174
+ * Sync .meta/ files (backends.json, sync-rules.json) to all replica backends.
175
+ * Called automatically by createConfigRepo() after setupSync().
176
+ */
177
+ syncMetaToReplicas(): Promise<void>;
173
178
  /** Dispose: stop all sync, release cache FS and resources. */
174
179
  dispose(): Promise<void>;
175
180
  }
@@ -254,6 +259,16 @@ declare class ConfigRepo implements IConfigRepo {
254
259
  }): Promise<SyncResult>;
255
260
  peekNodeConfig<T = unknown>(nodeId: string, path: string): Promise<T>;
256
261
  flush(): Promise<SyncResult[]>;
262
+ /**
263
+ * Sync .meta/ files (backends.json, sync-rules.json) to all replica backends.
264
+ *
265
+ * This ensures the backend topology is available on every replica, enabling
266
+ * any program that connects to any backend to discover the full topology.
267
+ *
268
+ * Called automatically by createConfigRepo() after setupSync().
269
+ * Can also be called manually after updateBackends() / updateSyncRules().
270
+ */
271
+ syncMetaToReplicas(): Promise<void>;
257
272
  getSyncStatuses(): Map<string, SyncPairStatus>;
258
273
  resolveConflict(conflictId: string, mergedContent: unknown): Promise<void>;
259
274
  listConflicts(): Promise<ConflictArchive[]>;
package/dist/index.js CHANGED
@@ -665,6 +665,32 @@ var ConfigRepo = class {
665
665
  const resultsMap = await this.syncEngine.syncAll();
666
666
  return Array.from(resultsMap.values());
667
667
  }
668
+ /**
669
+ * Sync .meta/ files (backends.json, sync-rules.json) to all replica backends.
670
+ *
671
+ * This ensures the backend topology is available on every replica, enabling
672
+ * any program that connects to any backend to discover the full topology.
673
+ *
674
+ * Called automatically by createConfigRepo() after setupSync().
675
+ * Can also be called manually after updateBackends() / updateSyncRules().
676
+ */
677
+ async syncMetaToReplicas() {
678
+ this.assertNotDisposed();
679
+ for (const metaFile of [BACKENDS_FILE, SYNC_RULES_FILE]) {
680
+ try {
681
+ const content = await this.cachedFS.readFile(metaFile);
682
+ for (const [id, replica] of this.replicaBackends) {
683
+ try {
684
+ await replica.syncable.writeFile(metaFile, content);
685
+ console.log(`[ConfigRepo] Synced ${metaFile} to replica ${id}`);
686
+ } catch (err) {
687
+ console.error(`[ConfigRepo] Failed to sync ${metaFile} to ${id}:`, err.message);
688
+ }
689
+ }
690
+ } catch {
691
+ }
692
+ }
693
+ }
668
694
  getSyncStatuses() {
669
695
  this.assertNotDisposed();
670
696
  return this.syncEngine.getStatusAll();
@@ -1052,7 +1078,12 @@ async function createConfigRepo(appId, options) {
1052
1078
  replicas: backendsMeta.backends.map((b) => b.id)
1053
1079
  },
1054
1080
  { prefix: `${NODES_DIR}/`, direction: "none" },
1055
- { prefix: `${META_DIR}/`, direction: "none" }
1081
+ {
1082
+ prefix: `${META_DIR}/`,
1083
+ direction: "one-way",
1084
+ conflictStrategy: "source-wins",
1085
+ replicas: backendsMeta.backends.map((b) => b.id)
1086
+ }
1056
1087
  ]
1057
1088
  };
1058
1089
  }
@@ -1094,6 +1125,7 @@ async function createConfigRepo(appId, options) {
1094
1125
  backendsMeta.backends,
1095
1126
  options.primaryBackendId
1096
1127
  );
1128
+ await repo.syncMetaToReplicas();
1097
1129
  await repo.load();
1098
1130
  return repo;
1099
1131
  }
package/dist/index.mjs CHANGED
@@ -616,6 +616,32 @@ var ConfigRepo = class {
616
616
  const resultsMap = await this.syncEngine.syncAll();
617
617
  return Array.from(resultsMap.values());
618
618
  }
619
+ /**
620
+ * Sync .meta/ files (backends.json, sync-rules.json) to all replica backends.
621
+ *
622
+ * This ensures the backend topology is available on every replica, enabling
623
+ * any program that connects to any backend to discover the full topology.
624
+ *
625
+ * Called automatically by createConfigRepo() after setupSync().
626
+ * Can also be called manually after updateBackends() / updateSyncRules().
627
+ */
628
+ async syncMetaToReplicas() {
629
+ this.assertNotDisposed();
630
+ for (const metaFile of [BACKENDS_FILE, SYNC_RULES_FILE]) {
631
+ try {
632
+ const content = await this.cachedFS.readFile(metaFile);
633
+ for (const [id, replica] of this.replicaBackends) {
634
+ try {
635
+ await replica.syncable.writeFile(metaFile, content);
636
+ console.log(`[ConfigRepo] Synced ${metaFile} to replica ${id}`);
637
+ } catch (err) {
638
+ console.error(`[ConfigRepo] Failed to sync ${metaFile} to ${id}:`, err.message);
639
+ }
640
+ }
641
+ } catch {
642
+ }
643
+ }
644
+ }
619
645
  getSyncStatuses() {
620
646
  this.assertNotDisposed();
621
647
  return this.syncEngine.getStatusAll();
@@ -1003,7 +1029,12 @@ async function createConfigRepo(appId, options) {
1003
1029
  replicas: backendsMeta.backends.map((b) => b.id)
1004
1030
  },
1005
1031
  { prefix: `${NODES_DIR}/`, direction: "none" },
1006
- { prefix: `${META_DIR}/`, direction: "none" }
1032
+ {
1033
+ prefix: `${META_DIR}/`,
1034
+ direction: "one-way",
1035
+ conflictStrategy: "source-wins",
1036
+ replicas: backendsMeta.backends.map((b) => b.id)
1037
+ }
1007
1038
  ]
1008
1039
  };
1009
1040
  }
@@ -1045,6 +1076,7 @@ async function createConfigRepo(appId, options) {
1045
1076
  backendsMeta.backends,
1046
1077
  options.primaryBackendId
1047
1078
  );
1079
+ await repo.syncMetaToReplicas();
1048
1080
  await repo.load();
1049
1081
  return repo;
1050
1082
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zen-fs-config",
3
- "version": "0.3.19",
3
+ "version": "0.3.20",
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",