selfstore 1.0.0 → 1.1.0
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/README.md +4 -0
- package/dist/advanced.d.ts +5 -5
- package/dist/advanced.js +7 -7
- package/dist/backups.d.ts +1 -1
- package/dist/backups.js +1 -1
- package/dist/backups.js.map +1 -1
- package/dist/{cache-lock-LZILZNLP.js → cache-lock-NXIR6JRB.js} +3 -3
- package/dist/{cache-lock-LZILZNLP.js.map → cache-lock-NXIR6JRB.js.map} +1 -1
- package/dist/{chunk-SGISYMT5.js → chunk-43BJDRPT.js} +2 -2
- package/dist/{chunk-SGISYMT5.js.map → chunk-43BJDRPT.js.map} +1 -1
- package/dist/{chunk-FDPAKHQS.js → chunk-6746AL4I.js} +9 -4
- package/dist/chunk-6746AL4I.js.map +1 -0
- package/dist/{chunk-ATUPHVLG.js → chunk-CUFKME4S.js} +5 -5
- package/dist/chunk-CUFKME4S.js.map +1 -0
- package/dist/{chunk-OWLX6PNT.js → chunk-KHER6MWR.js} +26 -8
- package/dist/chunk-KHER6MWR.js.map +1 -0
- package/dist/{chunk-IBIEKK36.js → chunk-SKWHKM25.js} +24 -5
- package/dist/chunk-SKWHKM25.js.map +1 -0
- package/dist/{chunk-JB4JHM7V.js → chunk-SRKUHFRG.js} +17 -8
- package/dist/chunk-SRKUHFRG.js.map +1 -0
- package/dist/{chunk-CUWB5EWF.js → chunk-TEIAFKFS.js} +63 -22
- package/dist/chunk-TEIAFKFS.js.map +1 -0
- package/dist/{chunk-BJ3RUMGI.js → chunk-UWVAKBU4.js} +3 -3
- package/dist/{chunk-BJ3RUMGI.js.map → chunk-UWVAKBU4.js.map} +1 -1
- package/dist/{chunk-N4RPMX3Y.js → chunk-XI3MGK4M.js} +120 -30
- package/dist/chunk-XI3MGK4M.js.map +1 -0
- package/dist/{drive-Bv94UM8b.d.ts → drive-DNiDXBDe.d.ts} +7 -2
- package/dist/flows.d.ts +2 -2
- package/dist/flows.js +7 -7
- package/dist/flows.js.map +1 -1
- package/dist/groups.js +3 -3
- package/dist/groups.js.map +1 -1
- package/dist/households.d.ts +1 -1
- package/dist/households.js +10 -4
- package/dist/households.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +14 -11
- package/dist/index.js.map +1 -1
- package/dist/{local-2py_vGGy.d.ts → local-DsXG7QW7.d.ts} +2 -2
- package/dist/local-KIP25T7I.js +7 -0
- package/dist/{local-AM22RWRR.js.map → local-KIP25T7I.js.map} +1 -1
- package/dist/{store-ChIGEOph.d.ts → store-2RnED1Vq.d.ts} +5 -0
- package/dist/sync.js +1 -1
- package/dist/widgets.d.ts +2 -2
- package/dist/widgets.js +445 -86
- package/dist/widgets.js.map +1 -1
- package/package.json +129 -97
- package/dist/chunk-ATUPHVLG.js.map +0 -1
- package/dist/chunk-CUWB5EWF.js.map +0 -1
- package/dist/chunk-FDPAKHQS.js.map +0 -1
- package/dist/chunk-IBIEKK36.js.map +0 -1
- package/dist/chunk-JB4JHM7V.js.map +0 -1
- package/dist/chunk-N4RPMX3Y.js.map +0 -1
- package/dist/chunk-OWLX6PNT.js.map +0 -1
- package/dist/local-AM22RWRR.js +0 -7
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createNode, createMeta, gcTombstones, stamp, merge, unsyncableCounts, idPathFor, detectConflicts, changes } from './chunk-
|
|
2
|
-
import { inspect, checkPasswordPolicy, writeBox, BACKUP_MIME, readBoxWithSync, asBytes } from './chunk-
|
|
3
|
-
import { openManifest, GROUP_KEYING } from './chunk-
|
|
1
|
+
import { createNode, createMeta, gcTombstones, stamp, merge, unsyncableCounts, idPathFor, detectConflicts, changes } from './chunk-SKWHKM25.js';
|
|
2
|
+
import { inspect, checkPasswordPolicy, writeBox, BACKUP_MIME, readBoxWithSync, asBytes } from './chunk-SRKUHFRG.js';
|
|
3
|
+
import { openManifest, GROUP_KEYING } from './chunk-KHER6MWR.js';
|
|
4
4
|
import { seal, isEnvelope, unseal, newDeviceKey } from './chunk-QBCU7OOP.js';
|
|
5
|
-
import { mintSlot, MAX_KEY_SLOTS, mintExternalSlot, openSlot } from './chunk-
|
|
5
|
+
import { mintSlot, MAX_KEY_SLOTS, mintExternalSlot, openSlot } from './chunk-6746AL4I.js';
|
|
6
6
|
import { SelfstoreError, isAuthExpired, errorLabelKey, isSelfstoreError } from './chunk-VBFMMR7Q.js';
|
|
7
7
|
import { openDB } from 'idb';
|
|
8
8
|
|
|
@@ -86,9 +86,40 @@ var KEY = {
|
|
|
86
86
|
groupSeqIds: "groupSeqIds"
|
|
87
87
|
};
|
|
88
88
|
var JOURNAL_MAX = 20;
|
|
89
|
+
var BOOT_NET_MS = 25e3;
|
|
90
|
+
var BootTimeout = class extends Error {
|
|
91
|
+
constructor(what) {
|
|
92
|
+
super(`${what} timed out at boot`);
|
|
93
|
+
this.name = "BootTimeout";
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
function bootDeadline(work, what, ms = BOOT_NET_MS) {
|
|
97
|
+
return new Promise((resolve, reject) => {
|
|
98
|
+
const timer = setTimeout(() => reject(new BootTimeout(what)), ms);
|
|
99
|
+
work.then(
|
|
100
|
+
(v) => {
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
resolve(v);
|
|
103
|
+
},
|
|
104
|
+
(e) => {
|
|
105
|
+
clearTimeout(timer);
|
|
106
|
+
reject(e instanceof Error ? e : new Error(String(e)));
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
89
111
|
var STALE_CHECK_MS = 2e4;
|
|
90
112
|
function createLocalStore(opts) {
|
|
91
|
-
const {
|
|
113
|
+
const {
|
|
114
|
+
app,
|
|
115
|
+
schemaVersion: version,
|
|
116
|
+
appVersion,
|
|
117
|
+
gather,
|
|
118
|
+
apply,
|
|
119
|
+
cache,
|
|
120
|
+
readme,
|
|
121
|
+
debounceMs = 800
|
|
122
|
+
} = opts;
|
|
92
123
|
const logger = opts.logger ?? console;
|
|
93
124
|
const requireEncryption = opts.requireEncryption ?? false;
|
|
94
125
|
const passwordPolicy = opts.passwordPolicy;
|
|
@@ -96,7 +127,10 @@ function createLocalStore(opts) {
|
|
|
96
127
|
if (!passwordPolicy) return;
|
|
97
128
|
const { ok, unmet } = checkPasswordPolicy(pw, passwordPolicy);
|
|
98
129
|
if (!ok) {
|
|
99
|
-
throw new SelfstoreError(
|
|
130
|
+
throw new SelfstoreError(
|
|
131
|
+
"WEAK_PASSWORD",
|
|
132
|
+
`Password does not meet the policy: ${unmet.join(", ")}.`
|
|
133
|
+
);
|
|
100
134
|
}
|
|
101
135
|
}
|
|
102
136
|
const journalSilent = new Set(opts.journalSilent ?? []);
|
|
@@ -446,7 +480,7 @@ function createLocalStore(opts) {
|
|
|
446
480
|
}
|
|
447
481
|
}
|
|
448
482
|
async function requireReady(where) {
|
|
449
|
-
let ok
|
|
483
|
+
let ok;
|
|
450
484
|
try {
|
|
451
485
|
ok = await durable.isReady();
|
|
452
486
|
} catch (e) {
|
|
@@ -469,7 +503,10 @@ function createLocalStore(opts) {
|
|
|
469
503
|
}
|
|
470
504
|
function redactForStorage(entries) {
|
|
471
505
|
return entries.map(
|
|
472
|
-
(e) => e.conflicts ? {
|
|
506
|
+
(e) => e.conflicts ? {
|
|
507
|
+
...e,
|
|
508
|
+
conflicts: e.conflicts.map(({ collection, id, kept }) => ({ collection, id, kept }))
|
|
509
|
+
} : e
|
|
473
510
|
);
|
|
474
511
|
}
|
|
475
512
|
function recordJournal(delta, source, conflicts = []) {
|
|
@@ -716,7 +753,12 @@ function createLocalStore(opts) {
|
|
|
716
753
|
);
|
|
717
754
|
continue;
|
|
718
755
|
}
|
|
719
|
-
const {
|
|
756
|
+
const {
|
|
757
|
+
snapshot,
|
|
758
|
+
sidecar,
|
|
759
|
+
author,
|
|
760
|
+
envelope: peerEnv
|
|
761
|
+
} = await readBoxWithSync(
|
|
720
762
|
await asBytes(remote),
|
|
721
763
|
p.password ?? pass ?? void 0,
|
|
722
764
|
peerGroupRead(),
|
|
@@ -824,7 +866,9 @@ function createLocalStore(opts) {
|
|
|
824
866
|
}
|
|
825
867
|
await cache.requestPersistent?.();
|
|
826
868
|
}
|
|
827
|
-
async function dropDurable({
|
|
869
|
+
async function dropDurable({
|
|
870
|
+
keepSession = false
|
|
871
|
+
} = {}) {
|
|
828
872
|
if (durable && !keepSession) await durable.disconnect();
|
|
829
873
|
durable = null;
|
|
830
874
|
label = null;
|
|
@@ -947,7 +991,10 @@ function createLocalStore(opts) {
|
|
|
947
991
|
let t = null;
|
|
948
992
|
let restoreThrew = false;
|
|
949
993
|
try {
|
|
950
|
-
t = opts.restoreTarget ? await
|
|
994
|
+
t = opts.restoreTarget ? await bootDeadline(
|
|
995
|
+
Promise.resolve(opts.restoreTarget(savedKind)),
|
|
996
|
+
"destination restore"
|
|
997
|
+
) : null;
|
|
951
998
|
} catch (e) {
|
|
952
999
|
restoreThrew = true;
|
|
953
1000
|
lastError = transient("Could not restore the destination; will retry.");
|
|
@@ -959,14 +1006,19 @@ function createLocalStore(opts) {
|
|
|
959
1006
|
label = t.label;
|
|
960
1007
|
let ok = false;
|
|
961
1008
|
try {
|
|
962
|
-
ok = await t.isReady();
|
|
963
|
-
} catch {
|
|
964
|
-
|
|
1009
|
+
ok = await bootDeadline(t.isReady(), "destination check");
|
|
1010
|
+
} catch (e) {
|
|
1011
|
+
if (e instanceof BootTimeout) {
|
|
1012
|
+
lastError = transient("Destination is slow to answer; will retry.");
|
|
1013
|
+
logger.error("[selfstore] boot destination check stalled", e);
|
|
1014
|
+
} else {
|
|
1015
|
+
raiseGate("AUTH_EXPIRED", "Access to the destination expired or was revoked.");
|
|
1016
|
+
}
|
|
965
1017
|
}
|
|
966
1018
|
needsAttention = needsAttention || locked();
|
|
967
1019
|
if (ok && !locked()) {
|
|
968
1020
|
try {
|
|
969
|
-
await pull("boot");
|
|
1021
|
+
await bootDeadline(pull("boot"), "boot sync");
|
|
970
1022
|
} catch (e) {
|
|
971
1023
|
lastError = transient("Boot sync failed; will retry.");
|
|
972
1024
|
logger.error("[selfstore] boot sync failed", e);
|
|
@@ -982,7 +1034,7 @@ function createLocalStore(opts) {
|
|
|
982
1034
|
}
|
|
983
1035
|
if (!durable && peerList.length > 0) {
|
|
984
1036
|
try {
|
|
985
|
-
await pull("boot");
|
|
1037
|
+
await bootDeadline(pull("boot"), "boot sync");
|
|
986
1038
|
} catch (e) {
|
|
987
1039
|
lastError = transient("Boot sync failed; will retry.");
|
|
988
1040
|
logger.error("[selfstore] boot sync failed", e);
|
|
@@ -1115,7 +1167,7 @@ function createLocalStore(opts) {
|
|
|
1115
1167
|
async inspectTarget(target) {
|
|
1116
1168
|
const blob = await target.load();
|
|
1117
1169
|
if (!blob || blob.size === 0) return { hasBackup: false, date: null, encrypted: false };
|
|
1118
|
-
let marker
|
|
1170
|
+
let marker;
|
|
1119
1171
|
try {
|
|
1120
1172
|
marker = target.stat ? await target.stat() : null;
|
|
1121
1173
|
} catch {
|
|
@@ -1158,6 +1210,7 @@ function createLocalStore(opts) {
|
|
|
1158
1210
|
return false;
|
|
1159
1211
|
},
|
|
1160
1212
|
detachTarget(opts2) {
|
|
1213
|
+
durable?.abortInFlight?.();
|
|
1161
1214
|
return serialize(async () => {
|
|
1162
1215
|
await dropDurable({ keepSession: opts2?.keepSession });
|
|
1163
1216
|
targetKind = "device";
|
|
@@ -1252,7 +1305,13 @@ function createLocalStore(opts) {
|
|
|
1252
1305
|
if (replicaList.some((r) => r.id === id)) {
|
|
1253
1306
|
throw new TypeError(`attachReplica(): a replica with id "${id}" is already attached`);
|
|
1254
1307
|
}
|
|
1255
|
-
replicaList.push({
|
|
1308
|
+
replicaList.push({
|
|
1309
|
+
id,
|
|
1310
|
+
target,
|
|
1311
|
+
label: target.label ?? id,
|
|
1312
|
+
lastPublishAt: null,
|
|
1313
|
+
lastError: null
|
|
1314
|
+
});
|
|
1256
1315
|
notify();
|
|
1257
1316
|
if (ready) {
|
|
1258
1317
|
void serialize(publishReplicas).catch(
|
|
@@ -1359,7 +1418,10 @@ function createLocalStore(opts) {
|
|
|
1359
1418
|
}
|
|
1360
1419
|
assertPasswordPolicy(password);
|
|
1361
1420
|
if (!durable) {
|
|
1362
|
-
throw new SelfstoreError(
|
|
1421
|
+
throw new SelfstoreError(
|
|
1422
|
+
"NOT_CONNECTED",
|
|
1423
|
+
"addEncryptionKey(): no destination is connected."
|
|
1424
|
+
);
|
|
1363
1425
|
}
|
|
1364
1426
|
if (locked() || needsAttention) {
|
|
1365
1427
|
throw new SelfstoreError(
|
|
@@ -1389,7 +1451,9 @@ function createLocalStore(opts) {
|
|
|
1389
1451
|
envelope = { dataKey, slots: [await mintSlot(pass, dataKey)] };
|
|
1390
1452
|
}
|
|
1391
1453
|
if (envelope.slots.length >= MAX_KEY_SLOTS) {
|
|
1392
|
-
throw new TypeError(
|
|
1454
|
+
throw new TypeError(
|
|
1455
|
+
`addEncryptionKey(): this backup already has ${MAX_KEY_SLOTS} key slots.`
|
|
1456
|
+
);
|
|
1393
1457
|
}
|
|
1394
1458
|
if (id && envelope.slots.some((s) => s.id === id)) {
|
|
1395
1459
|
throw new TypeError(`addEncryptionKey(): a key slot named "${id}" already exists.`);
|
|
@@ -1422,7 +1486,10 @@ function createLocalStore(opts) {
|
|
|
1422
1486
|
);
|
|
1423
1487
|
}
|
|
1424
1488
|
if (!durable) {
|
|
1425
|
-
throw new SelfstoreError(
|
|
1489
|
+
throw new SelfstoreError(
|
|
1490
|
+
"NOT_CONNECTED",
|
|
1491
|
+
"removeEncryptionKey(): no destination is connected."
|
|
1492
|
+
);
|
|
1426
1493
|
}
|
|
1427
1494
|
if (locked() || needsAttention) {
|
|
1428
1495
|
throw new SelfstoreError(
|
|
@@ -1499,7 +1566,10 @@ function createLocalStore(opts) {
|
|
|
1499
1566
|
);
|
|
1500
1567
|
}
|
|
1501
1568
|
if (!durable) {
|
|
1502
|
-
throw new SelfstoreError(
|
|
1569
|
+
throw new SelfstoreError(
|
|
1570
|
+
"NOT_CONNECTED",
|
|
1571
|
+
"setExternalEncryption(): no destination is connected."
|
|
1572
|
+
);
|
|
1503
1573
|
}
|
|
1504
1574
|
if (locked() || needsAttention) {
|
|
1505
1575
|
throw new SelfstoreError(
|
|
@@ -1532,7 +1602,13 @@ function createLocalStore(opts) {
|
|
|
1532
1602
|
await persistLocal();
|
|
1533
1603
|
pendingEdit = false;
|
|
1534
1604
|
const blob = await buildBlob();
|
|
1535
|
-
await readBoxWithSync(
|
|
1605
|
+
await readBoxWithSync(
|
|
1606
|
+
await asBytes(blob),
|
|
1607
|
+
void 0,
|
|
1608
|
+
void 0,
|
|
1609
|
+
void 0,
|
|
1610
|
+
async () => secret
|
|
1611
|
+
);
|
|
1536
1612
|
const written = await durable.save(blob);
|
|
1537
1613
|
await setRemoteVersion(typeof written === "string" ? written : await statRemote());
|
|
1538
1614
|
lastError = null;
|
|
@@ -1592,7 +1668,9 @@ function createLocalStore(opts) {
|
|
|
1592
1668
|
throw new TypeError("addExternalKey(): no data key in hand - unlock the backup first.");
|
|
1593
1669
|
}
|
|
1594
1670
|
if (envelope.slots.length >= MAX_KEY_SLOTS) {
|
|
1595
|
-
throw new TypeError(
|
|
1671
|
+
throw new TypeError(
|
|
1672
|
+
`addExternalKey(): this backup already has ${MAX_KEY_SLOTS} key slots.`
|
|
1673
|
+
);
|
|
1596
1674
|
}
|
|
1597
1675
|
if (id && envelope.slots.some((s) => s.id === id)) {
|
|
1598
1676
|
throw new TypeError(`addExternalKey(): a key slot named "${id}" already exists.`);
|
|
@@ -1602,7 +1680,13 @@ function createLocalStore(opts) {
|
|
|
1602
1680
|
envelope = { dataKey: envelope.dataKey, slots: [...envelope.slots, slot] };
|
|
1603
1681
|
try {
|
|
1604
1682
|
const blob = await buildBlob();
|
|
1605
|
-
await readBoxWithSync(
|
|
1683
|
+
await readBoxWithSync(
|
|
1684
|
+
await asBytes(blob),
|
|
1685
|
+
void 0,
|
|
1686
|
+
void 0,
|
|
1687
|
+
void 0,
|
|
1688
|
+
async () => secret
|
|
1689
|
+
);
|
|
1606
1690
|
const written = await durable.save(blob);
|
|
1607
1691
|
await setRemoteVersion(typeof written === "string" ? written : await statRemote());
|
|
1608
1692
|
lastError = null;
|
|
@@ -1697,7 +1781,10 @@ function indexedDbCache(name, opts) {
|
|
|
1697
1781
|
function key() {
|
|
1698
1782
|
if (lockMode) {
|
|
1699
1783
|
return sealKey ? Promise.resolve(sealKey) : Promise.reject(
|
|
1700
|
-
new SelfstoreError(
|
|
1784
|
+
new SelfstoreError(
|
|
1785
|
+
"PASSWORD_REQUIRED",
|
|
1786
|
+
"The local cache is locked - unlock() it first."
|
|
1787
|
+
)
|
|
1701
1788
|
);
|
|
1702
1789
|
}
|
|
1703
1790
|
return _key ??= loadOrCreateKey();
|
|
@@ -1737,7 +1824,10 @@ function indexedDbCache(name, opts) {
|
|
|
1737
1824
|
const rawCollections = await d.get("kv", COLLECTIONS_KEY);
|
|
1738
1825
|
if (rawCollections === void 0) return null;
|
|
1739
1826
|
if (!isEnvelope(rawCollections)) {
|
|
1740
|
-
throw new SelfstoreError(
|
|
1827
|
+
throw new SelfstoreError(
|
|
1828
|
+
"BAD_FORMAT",
|
|
1829
|
+
"Unrecognized cache record (not a sealed envelope)."
|
|
1830
|
+
);
|
|
1741
1831
|
}
|
|
1742
1832
|
const collections = JSON.parse(
|
|
1743
1833
|
new TextDecoder().decode(await unseal(await key(), rawCollections))
|
|
@@ -1797,7 +1887,7 @@ function indexedDbCache(name, opts) {
|
|
|
1797
1887
|
sealKey = null;
|
|
1798
1888
|
},
|
|
1799
1889
|
async unlock(secret) {
|
|
1800
|
-
const { keyFromPassword, freshCacheKdf, opens } = await import('./cache-lock-
|
|
1890
|
+
const { keyFromPassword, freshCacheKdf, opens } = await import('./cache-lock-NXIR6JRB.js');
|
|
1801
1891
|
const d = await db();
|
|
1802
1892
|
let candidate;
|
|
1803
1893
|
if (typeof secret === "string") {
|
|
@@ -1904,5 +1994,5 @@ function gisDriveAuth(opts) {
|
|
|
1904
1994
|
}
|
|
1905
1995
|
|
|
1906
1996
|
export { RESERVED_STORE_MODES, createLocalStore, deriveStatus, gisDriveAuth, indexedDbCache, isLockableCache, isReservedStoreMode, memoryCache };
|
|
1907
|
-
//# sourceMappingURL=chunk-
|
|
1908
|
-
//# sourceMappingURL=chunk-
|
|
1997
|
+
//# sourceMappingURL=chunk-XI3MGK4M.js.map
|
|
1998
|
+
//# sourceMappingURL=chunk-XI3MGK4M.js.map
|