zen-fs-config 0.3.2 → 0.3.4
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.js +54 -23
- package/dist/index.mjs +54 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -319,40 +319,54 @@ function listBackends() {
|
|
|
319
319
|
async function wrapZenFSFileSystem(config) {
|
|
320
320
|
const zenfs = await import("@zenfs/core");
|
|
321
321
|
const isolatedFS = await zenfs.resolveMountConfig(config);
|
|
322
|
-
const pfs = isolatedFS.promises;
|
|
323
322
|
return {
|
|
324
323
|
async readFile(path, ...args) {
|
|
325
|
-
|
|
324
|
+
const st = await isolatedFS.stat(path);
|
|
325
|
+
const size = st.size;
|
|
326
|
+
const buf = new Uint8Array(size);
|
|
327
|
+
await isolatedFS.read(path, buf, 0, size);
|
|
328
|
+
if (args[0] === "utf-8") return new TextDecoder().decode(buf);
|
|
329
|
+
return buf;
|
|
326
330
|
},
|
|
327
|
-
async writeFile(path, data,
|
|
328
|
-
|
|
331
|
+
async writeFile(path, data, _options) {
|
|
332
|
+
const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data instanceof Uint8Array ? data : new TextEncoder().encode(data);
|
|
333
|
+
const parts = path.split("/").filter(Boolean);
|
|
334
|
+
parts.pop();
|
|
335
|
+
let dir = "";
|
|
336
|
+
for (const p of parts) {
|
|
337
|
+
dir += "/" + p;
|
|
338
|
+
if (!await isolatedFS.exists(dir)) {
|
|
339
|
+
await isolatedFS.mkdir(dir, { uid: 0, gid: 0, mode: 493 });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
await isolatedFS.write(path, bytes, 0);
|
|
329
343
|
},
|
|
330
344
|
async readdir(path) {
|
|
331
|
-
|
|
332
|
-
return entries.map((e) => typeof e === "string" ? e : e.name);
|
|
345
|
+
return isolatedFS.readdir(path);
|
|
333
346
|
},
|
|
334
|
-
async stat(path, ...
|
|
335
|
-
|
|
347
|
+
async stat(path, ..._args) {
|
|
348
|
+
const st = await isolatedFS.stat(path);
|
|
349
|
+
return {
|
|
350
|
+
isFile: () => st.isDirectory?.() === false || st.mode !== void 0 && (st.mode & 61440) === 32768,
|
|
351
|
+
isDirectory: () => st.isDirectory?.() === true || st.mode !== void 0 && (st.mode & 61440) === 16384,
|
|
352
|
+
size: st.size,
|
|
353
|
+
mtime: st.mtimeMs ?? st.mtime
|
|
354
|
+
};
|
|
336
355
|
},
|
|
337
356
|
async exists(path) {
|
|
338
|
-
|
|
339
|
-
await pfs.stat(path);
|
|
340
|
-
return true;
|
|
341
|
-
} catch {
|
|
342
|
-
return false;
|
|
343
|
-
}
|
|
357
|
+
return isolatedFS.exists(path);
|
|
344
358
|
},
|
|
345
359
|
async mkdir(path, options) {
|
|
346
|
-
return
|
|
360
|
+
return isolatedFS.mkdir(path, options ?? { uid: 0, gid: 0, mode: 493 });
|
|
347
361
|
},
|
|
348
362
|
async unlink(path) {
|
|
349
|
-
return
|
|
363
|
+
return isolatedFS.unlink(path);
|
|
350
364
|
},
|
|
351
365
|
async rmdir(path) {
|
|
352
|
-
return
|
|
366
|
+
return isolatedFS.rmdir(path);
|
|
353
367
|
},
|
|
354
368
|
async rename(oldPath, newPath) {
|
|
355
|
-
return
|
|
369
|
+
return isolatedFS.rename(oldPath, newPath);
|
|
356
370
|
}
|
|
357
371
|
};
|
|
358
372
|
}
|
|
@@ -1047,20 +1061,35 @@ var ConfigRepo = class {
|
|
|
1047
1061
|
// Internal — Setup
|
|
1048
1062
|
// -----------------------------------------------------------------------
|
|
1049
1063
|
async setupSync(rules, backends, primaryBackendId) {
|
|
1064
|
+
console.log(`[ConfigRepo] setupSync: ${backends.length} backends, primary=${primaryBackendId}`);
|
|
1065
|
+
console.log(`[ConfigRepo] setupSync: rules=`, JSON.stringify(rules, null, 2));
|
|
1050
1066
|
for (const desc of backends) {
|
|
1051
1067
|
if (desc.id === primaryBackendId) continue;
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1068
|
+
console.log(`[ConfigRepo] Creating replica backend: id=${desc.id}, type=${desc.type}`);
|
|
1069
|
+
try {
|
|
1070
|
+
const instance = await createBackend(desc);
|
|
1071
|
+
const syncable = backendToSyncableFS(instance);
|
|
1072
|
+
this.replicaBackends.set(desc.id, { instance, syncable });
|
|
1073
|
+
console.log(`[ConfigRepo] Replica ${desc.id} created successfully`);
|
|
1074
|
+
} catch (err) {
|
|
1075
|
+
console.error(`[ConfigRepo] Failed to create replica ${desc.id} (${desc.type}):`, err);
|
|
1076
|
+
}
|
|
1055
1077
|
}
|
|
1078
|
+
console.log(`[ConfigRepo] Available replicas:`, Array.from(this.replicaBackends.keys()));
|
|
1056
1079
|
for (const rule of rules) {
|
|
1057
1080
|
if (rule.direction === "none") continue;
|
|
1058
|
-
if (!rule.replicas?.length)
|
|
1081
|
+
if (!rule.replicas?.length) {
|
|
1082
|
+
console.log(`[ConfigRepo] Skipping rule ${rule.prefix}: no replicas`);
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1059
1085
|
const zenSyncDirection = rule.direction === "bi-directional" ? import_zen_fs_sync.SyncDirection.BiDirectional : import_zen_fs_sync.SyncDirection.OneWay;
|
|
1060
1086
|
for (const replicaId of rule.replicas) {
|
|
1061
1087
|
if (replicaId === primaryBackendId) continue;
|
|
1062
1088
|
const replica = this.replicaBackends.get(replicaId);
|
|
1063
|
-
if (!replica)
|
|
1089
|
+
if (!replica) {
|
|
1090
|
+
console.warn(`[ConfigRepo] Skipping pair ${replicaId}: replica not found (available: ${Array.from(this.replicaBackends.keys()).join(", ")})`);
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1064
1093
|
const pair = this.syncEngine.addPair(
|
|
1065
1094
|
this.fullFS,
|
|
1066
1095
|
replica.syncable,
|
|
@@ -1073,6 +1102,7 @@ var ConfigRepo = class {
|
|
|
1073
1102
|
},
|
|
1074
1103
|
"/"
|
|
1075
1104
|
);
|
|
1105
|
+
console.log(`[ConfigRepo] Sync pair added: pairId=${pair.pairId}, prefix=${rule.prefix}, dir=${rule.direction}, replica=${replicaId}`);
|
|
1076
1106
|
const conflictHandler = (event) => {
|
|
1077
1107
|
this.handleConflict(event, rule);
|
|
1078
1108
|
};
|
|
@@ -1080,6 +1110,7 @@ var ConfigRepo = class {
|
|
|
1080
1110
|
this.syncEngine.watch(pair.pairId);
|
|
1081
1111
|
}
|
|
1082
1112
|
}
|
|
1113
|
+
console.log(`[ConfigRepo] setupSync complete. Sync statuses:`, this.getSyncStatuses());
|
|
1083
1114
|
}
|
|
1084
1115
|
// -----------------------------------------------------------------------
|
|
1085
1116
|
// Internal — Persistence
|
package/dist/index.mjs
CHANGED
|
@@ -272,40 +272,54 @@ function listBackends() {
|
|
|
272
272
|
async function wrapZenFSFileSystem(config) {
|
|
273
273
|
const zenfs = await import("@zenfs/core");
|
|
274
274
|
const isolatedFS = await zenfs.resolveMountConfig(config);
|
|
275
|
-
const pfs = isolatedFS.promises;
|
|
276
275
|
return {
|
|
277
276
|
async readFile(path, ...args) {
|
|
278
|
-
|
|
277
|
+
const st = await isolatedFS.stat(path);
|
|
278
|
+
const size = st.size;
|
|
279
|
+
const buf = new Uint8Array(size);
|
|
280
|
+
await isolatedFS.read(path, buf, 0, size);
|
|
281
|
+
if (args[0] === "utf-8") return new TextDecoder().decode(buf);
|
|
282
|
+
return buf;
|
|
279
283
|
},
|
|
280
|
-
async writeFile(path, data,
|
|
281
|
-
|
|
284
|
+
async writeFile(path, data, _options) {
|
|
285
|
+
const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data instanceof Uint8Array ? data : new TextEncoder().encode(data);
|
|
286
|
+
const parts = path.split("/").filter(Boolean);
|
|
287
|
+
parts.pop();
|
|
288
|
+
let dir = "";
|
|
289
|
+
for (const p of parts) {
|
|
290
|
+
dir += "/" + p;
|
|
291
|
+
if (!await isolatedFS.exists(dir)) {
|
|
292
|
+
await isolatedFS.mkdir(dir, { uid: 0, gid: 0, mode: 493 });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
await isolatedFS.write(path, bytes, 0);
|
|
282
296
|
},
|
|
283
297
|
async readdir(path) {
|
|
284
|
-
|
|
285
|
-
return entries.map((e) => typeof e === "string" ? e : e.name);
|
|
298
|
+
return isolatedFS.readdir(path);
|
|
286
299
|
},
|
|
287
|
-
async stat(path, ...
|
|
288
|
-
|
|
300
|
+
async stat(path, ..._args) {
|
|
301
|
+
const st = await isolatedFS.stat(path);
|
|
302
|
+
return {
|
|
303
|
+
isFile: () => st.isDirectory?.() === false || st.mode !== void 0 && (st.mode & 61440) === 32768,
|
|
304
|
+
isDirectory: () => st.isDirectory?.() === true || st.mode !== void 0 && (st.mode & 61440) === 16384,
|
|
305
|
+
size: st.size,
|
|
306
|
+
mtime: st.mtimeMs ?? st.mtime
|
|
307
|
+
};
|
|
289
308
|
},
|
|
290
309
|
async exists(path) {
|
|
291
|
-
|
|
292
|
-
await pfs.stat(path);
|
|
293
|
-
return true;
|
|
294
|
-
} catch {
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
310
|
+
return isolatedFS.exists(path);
|
|
297
311
|
},
|
|
298
312
|
async mkdir(path, options) {
|
|
299
|
-
return
|
|
313
|
+
return isolatedFS.mkdir(path, options ?? { uid: 0, gid: 0, mode: 493 });
|
|
300
314
|
},
|
|
301
315
|
async unlink(path) {
|
|
302
|
-
return
|
|
316
|
+
return isolatedFS.unlink(path);
|
|
303
317
|
},
|
|
304
318
|
async rmdir(path) {
|
|
305
|
-
return
|
|
319
|
+
return isolatedFS.rmdir(path);
|
|
306
320
|
},
|
|
307
321
|
async rename(oldPath, newPath) {
|
|
308
|
-
return
|
|
322
|
+
return isolatedFS.rename(oldPath, newPath);
|
|
309
323
|
}
|
|
310
324
|
};
|
|
311
325
|
}
|
|
@@ -1000,20 +1014,35 @@ var ConfigRepo = class {
|
|
|
1000
1014
|
// Internal — Setup
|
|
1001
1015
|
// -----------------------------------------------------------------------
|
|
1002
1016
|
async setupSync(rules, backends, primaryBackendId) {
|
|
1017
|
+
console.log(`[ConfigRepo] setupSync: ${backends.length} backends, primary=${primaryBackendId}`);
|
|
1018
|
+
console.log(`[ConfigRepo] setupSync: rules=`, JSON.stringify(rules, null, 2));
|
|
1003
1019
|
for (const desc of backends) {
|
|
1004
1020
|
if (desc.id === primaryBackendId) continue;
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1021
|
+
console.log(`[ConfigRepo] Creating replica backend: id=${desc.id}, type=${desc.type}`);
|
|
1022
|
+
try {
|
|
1023
|
+
const instance = await createBackend(desc);
|
|
1024
|
+
const syncable = backendToSyncableFS(instance);
|
|
1025
|
+
this.replicaBackends.set(desc.id, { instance, syncable });
|
|
1026
|
+
console.log(`[ConfigRepo] Replica ${desc.id} created successfully`);
|
|
1027
|
+
} catch (err) {
|
|
1028
|
+
console.error(`[ConfigRepo] Failed to create replica ${desc.id} (${desc.type}):`, err);
|
|
1029
|
+
}
|
|
1008
1030
|
}
|
|
1031
|
+
console.log(`[ConfigRepo] Available replicas:`, Array.from(this.replicaBackends.keys()));
|
|
1009
1032
|
for (const rule of rules) {
|
|
1010
1033
|
if (rule.direction === "none") continue;
|
|
1011
|
-
if (!rule.replicas?.length)
|
|
1034
|
+
if (!rule.replicas?.length) {
|
|
1035
|
+
console.log(`[ConfigRepo] Skipping rule ${rule.prefix}: no replicas`);
|
|
1036
|
+
continue;
|
|
1037
|
+
}
|
|
1012
1038
|
const zenSyncDirection = rule.direction === "bi-directional" ? SyncDirection.BiDirectional : SyncDirection.OneWay;
|
|
1013
1039
|
for (const replicaId of rule.replicas) {
|
|
1014
1040
|
if (replicaId === primaryBackendId) continue;
|
|
1015
1041
|
const replica = this.replicaBackends.get(replicaId);
|
|
1016
|
-
if (!replica)
|
|
1042
|
+
if (!replica) {
|
|
1043
|
+
console.warn(`[ConfigRepo] Skipping pair ${replicaId}: replica not found (available: ${Array.from(this.replicaBackends.keys()).join(", ")})`);
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1017
1046
|
const pair = this.syncEngine.addPair(
|
|
1018
1047
|
this.fullFS,
|
|
1019
1048
|
replica.syncable,
|
|
@@ -1026,6 +1055,7 @@ var ConfigRepo = class {
|
|
|
1026
1055
|
},
|
|
1027
1056
|
"/"
|
|
1028
1057
|
);
|
|
1058
|
+
console.log(`[ConfigRepo] Sync pair added: pairId=${pair.pairId}, prefix=${rule.prefix}, dir=${rule.direction}, replica=${replicaId}`);
|
|
1029
1059
|
const conflictHandler = (event) => {
|
|
1030
1060
|
this.handleConflict(event, rule);
|
|
1031
1061
|
};
|
|
@@ -1033,6 +1063,7 @@ var ConfigRepo = class {
|
|
|
1033
1063
|
this.syncEngine.watch(pair.pairId);
|
|
1034
1064
|
}
|
|
1035
1065
|
}
|
|
1066
|
+
console.log(`[ConfigRepo] setupSync complete. Sync statuses:`, this.getSyncStatuses());
|
|
1036
1067
|
}
|
|
1037
1068
|
// -----------------------------------------------------------------------
|
|
1038
1069
|
// Internal — Persistence
|