zen-fs-config 0.5.0 → 0.5.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.js +39 -3
- package/dist/index.mjs +39 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -533,6 +533,22 @@ var LOCAL_IDB_BACKEND_ID = "local-idb";
|
|
|
533
533
|
function tombstoneFileName(filePath) {
|
|
534
534
|
return filePath.replace(/^\//, "").replace(/\//g, "__").replace(/\./g, "++") + ".json";
|
|
535
535
|
}
|
|
536
|
+
function stableOptionsKey(options) {
|
|
537
|
+
if (!options || typeof options !== "object") return "{}";
|
|
538
|
+
return JSON.stringify(sortKeysDeep(options));
|
|
539
|
+
}
|
|
540
|
+
function sortKeysDeep(obj) {
|
|
541
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
542
|
+
if (Array.isArray(obj)) return obj.map(sortKeysDeep);
|
|
543
|
+
const sorted = {};
|
|
544
|
+
for (const key of Object.keys(obj).sort()) {
|
|
545
|
+
sorted[key] = sortKeysDeep(obj[key]);
|
|
546
|
+
}
|
|
547
|
+
return sorted;
|
|
548
|
+
}
|
|
549
|
+
function backendDedupKey(desc) {
|
|
550
|
+
return `${desc.type}:${stableOptionsKey(desc.options)}`;
|
|
551
|
+
}
|
|
536
552
|
var ConfigRepo = class {
|
|
537
553
|
appId;
|
|
538
554
|
nodeId;
|
|
@@ -1163,7 +1179,7 @@ var ConfigRepo = class {
|
|
|
1163
1179
|
const seen = /* @__PURE__ */ new Map();
|
|
1164
1180
|
const duplicates = [];
|
|
1165
1181
|
for (const item of items) {
|
|
1166
|
-
const key =
|
|
1182
|
+
const key = backendDedupKey(item.desc);
|
|
1167
1183
|
const existing = seen.get(key);
|
|
1168
1184
|
if (existing) {
|
|
1169
1185
|
if (item.mtime < existing.mtime) {
|
|
@@ -1181,7 +1197,12 @@ var ConfigRepo = class {
|
|
|
1181
1197
|
`[ConfigRepo] readAllBackendDescriptors: removing ${duplicates.length} duplicate(s): ${duplicates.join(", ")}`
|
|
1182
1198
|
);
|
|
1183
1199
|
for (const dupId of duplicates) {
|
|
1184
|
-
|
|
1200
|
+
const descPath = this.backendFilePath(dupId);
|
|
1201
|
+
try {
|
|
1202
|
+
await this.deleteFile(descPath);
|
|
1203
|
+
} catch {
|
|
1204
|
+
await this.removeBackendDescriptor(dupId);
|
|
1205
|
+
}
|
|
1185
1206
|
}
|
|
1186
1207
|
}
|
|
1187
1208
|
return Array.from(seen.values()).map((i) => i.desc);
|
|
@@ -1260,6 +1281,13 @@ var ConfigRepo = class {
|
|
|
1260
1281
|
if (existing.some((b) => b.id === id)) {
|
|
1261
1282
|
throw new Error(`Backend "${id}" already exists. Use removeBackend() first.`);
|
|
1262
1283
|
}
|
|
1284
|
+
const newKey = backendDedupKey({ id, type, options });
|
|
1285
|
+
const dup = existing.find((b) => backendDedupKey(b) === newKey);
|
|
1286
|
+
if (dup) {
|
|
1287
|
+
throw new Error(
|
|
1288
|
+
`Backend "${id}" has the same configuration as existing backend "${dup.id}" (type=${type}). Use removeBackend("${dup.id}") first, or connect with the existing backend's ID.`
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1263
1291
|
console.log(`[ConfigRepo] addBackend: creating ${id} (${type})...`);
|
|
1264
1292
|
const instance = await createBackend({ type, options });
|
|
1265
1293
|
const syncable = backendToSyncableFS(instance, `${type}(${id})`);
|
|
@@ -1655,13 +1683,21 @@ async function createConfigRepo(appId, options = {}) {
|
|
|
1655
1683
|
const replicaId = options.primaryBackendId || `${options.backendInfo.type}-replica`;
|
|
1656
1684
|
const allBackends2 = await tempRepo.readAllBackendDescriptors();
|
|
1657
1685
|
const hasReplica = allBackends2.some((b) => b.id === replicaId);
|
|
1658
|
-
|
|
1686
|
+
const newKey = backendDedupKey({
|
|
1687
|
+
id: replicaId,
|
|
1688
|
+
type: options.backendInfo.type,
|
|
1689
|
+
options: options.backendInfo.options
|
|
1690
|
+
});
|
|
1691
|
+
const dupConfig = allBackends2.find((b) => backendDedupKey(b) === newKey);
|
|
1692
|
+
if (!hasReplica && !dupConfig) {
|
|
1659
1693
|
await tempRepo.writeBackendDescriptor({
|
|
1660
1694
|
id: replicaId,
|
|
1661
1695
|
type: options.backendInfo.type,
|
|
1662
1696
|
options: options.backendInfo.options
|
|
1663
1697
|
});
|
|
1664
1698
|
console.log(`[createConfigRepo] Added replica backend: ${replicaId} (${options.backendInfo.type})`);
|
|
1699
|
+
} else if (dupConfig) {
|
|
1700
|
+
console.log(`[createConfigRepo] Replica with same config already registered as "${dupConfig.id}", skipping`);
|
|
1665
1701
|
} else {
|
|
1666
1702
|
console.log(`[createConfigRepo] Replica ${replicaId} already registered`);
|
|
1667
1703
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -476,6 +476,22 @@ var LOCAL_IDB_BACKEND_ID = "local-idb";
|
|
|
476
476
|
function tombstoneFileName(filePath) {
|
|
477
477
|
return filePath.replace(/^\//, "").replace(/\//g, "__").replace(/\./g, "++") + ".json";
|
|
478
478
|
}
|
|
479
|
+
function stableOptionsKey(options) {
|
|
480
|
+
if (!options || typeof options !== "object") return "{}";
|
|
481
|
+
return JSON.stringify(sortKeysDeep(options));
|
|
482
|
+
}
|
|
483
|
+
function sortKeysDeep(obj) {
|
|
484
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
485
|
+
if (Array.isArray(obj)) return obj.map(sortKeysDeep);
|
|
486
|
+
const sorted = {};
|
|
487
|
+
for (const key of Object.keys(obj).sort()) {
|
|
488
|
+
sorted[key] = sortKeysDeep(obj[key]);
|
|
489
|
+
}
|
|
490
|
+
return sorted;
|
|
491
|
+
}
|
|
492
|
+
function backendDedupKey(desc) {
|
|
493
|
+
return `${desc.type}:${stableOptionsKey(desc.options)}`;
|
|
494
|
+
}
|
|
479
495
|
var ConfigRepo = class {
|
|
480
496
|
appId;
|
|
481
497
|
nodeId;
|
|
@@ -1106,7 +1122,7 @@ var ConfigRepo = class {
|
|
|
1106
1122
|
const seen = /* @__PURE__ */ new Map();
|
|
1107
1123
|
const duplicates = [];
|
|
1108
1124
|
for (const item of items) {
|
|
1109
|
-
const key =
|
|
1125
|
+
const key = backendDedupKey(item.desc);
|
|
1110
1126
|
const existing = seen.get(key);
|
|
1111
1127
|
if (existing) {
|
|
1112
1128
|
if (item.mtime < existing.mtime) {
|
|
@@ -1124,7 +1140,12 @@ var ConfigRepo = class {
|
|
|
1124
1140
|
`[ConfigRepo] readAllBackendDescriptors: removing ${duplicates.length} duplicate(s): ${duplicates.join(", ")}`
|
|
1125
1141
|
);
|
|
1126
1142
|
for (const dupId of duplicates) {
|
|
1127
|
-
|
|
1143
|
+
const descPath = this.backendFilePath(dupId);
|
|
1144
|
+
try {
|
|
1145
|
+
await this.deleteFile(descPath);
|
|
1146
|
+
} catch {
|
|
1147
|
+
await this.removeBackendDescriptor(dupId);
|
|
1148
|
+
}
|
|
1128
1149
|
}
|
|
1129
1150
|
}
|
|
1130
1151
|
return Array.from(seen.values()).map((i) => i.desc);
|
|
@@ -1203,6 +1224,13 @@ var ConfigRepo = class {
|
|
|
1203
1224
|
if (existing.some((b) => b.id === id)) {
|
|
1204
1225
|
throw new Error(`Backend "${id}" already exists. Use removeBackend() first.`);
|
|
1205
1226
|
}
|
|
1227
|
+
const newKey = backendDedupKey({ id, type, options });
|
|
1228
|
+
const dup = existing.find((b) => backendDedupKey(b) === newKey);
|
|
1229
|
+
if (dup) {
|
|
1230
|
+
throw new Error(
|
|
1231
|
+
`Backend "${id}" has the same configuration as existing backend "${dup.id}" (type=${type}). Use removeBackend("${dup.id}") first, or connect with the existing backend's ID.`
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1206
1234
|
console.log(`[ConfigRepo] addBackend: creating ${id} (${type})...`);
|
|
1207
1235
|
const instance = await createBackend({ type, options });
|
|
1208
1236
|
const syncable = backendToSyncableFS(instance, `${type}(${id})`);
|
|
@@ -1598,13 +1626,21 @@ async function createConfigRepo(appId, options = {}) {
|
|
|
1598
1626
|
const replicaId = options.primaryBackendId || `${options.backendInfo.type}-replica`;
|
|
1599
1627
|
const allBackends2 = await tempRepo.readAllBackendDescriptors();
|
|
1600
1628
|
const hasReplica = allBackends2.some((b) => b.id === replicaId);
|
|
1601
|
-
|
|
1629
|
+
const newKey = backendDedupKey({
|
|
1630
|
+
id: replicaId,
|
|
1631
|
+
type: options.backendInfo.type,
|
|
1632
|
+
options: options.backendInfo.options
|
|
1633
|
+
});
|
|
1634
|
+
const dupConfig = allBackends2.find((b) => backendDedupKey(b) === newKey);
|
|
1635
|
+
if (!hasReplica && !dupConfig) {
|
|
1602
1636
|
await tempRepo.writeBackendDescriptor({
|
|
1603
1637
|
id: replicaId,
|
|
1604
1638
|
type: options.backendInfo.type,
|
|
1605
1639
|
options: options.backendInfo.options
|
|
1606
1640
|
});
|
|
1607
1641
|
console.log(`[createConfigRepo] Added replica backend: ${replicaId} (${options.backendInfo.type})`);
|
|
1642
|
+
} else if (dupConfig) {
|
|
1643
|
+
console.log(`[createConfigRepo] Replica with same config already registered as "${dupConfig.id}", skipping`);
|
|
1608
1644
|
} else {
|
|
1609
1645
|
console.log(`[createConfigRepo] Replica ${replicaId} already registered`);
|
|
1610
1646
|
}
|