@fairfox/polly 0.62.0 → 0.64.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/dist/src/background/index.js +29 -16
- package/dist/src/background/index.js.map +3 -3
- package/dist/src/background/message-router.js +29 -16
- package/dist/src/background/message-router.js.map +3 -3
- package/dist/src/index.js +29 -16
- package/dist/src/index.js.map +3 -3
- package/dist/src/mesh.d.ts +2 -2
- package/dist/src/mesh.js +187 -46
- package/dist/src/mesh.js.map +6 -6
- package/dist/src/peer.js +88 -20
- package/dist/src/peer.js.map +3 -3
- package/dist/src/shared/adapters/index.js +29 -16
- package/dist/src/shared/adapters/index.js.map +3 -3
- package/dist/src/shared/lib/context-helpers.js +29 -16
- package/dist/src/shared/lib/context-helpers.js.map +3 -3
- package/dist/src/shared/lib/crdt-state.d.ts +14 -0
- package/dist/src/shared/lib/idb-helpers.d.ts +22 -2
- package/dist/src/shared/lib/mesh-state.d.ts +79 -1
- package/dist/src/shared/lib/message-bus.js +29 -16
- package/dist/src/shared/lib/message-bus.js.map +3 -3
- package/dist/src/shared/lib/resource.js +29 -16
- package/dist/src/shared/lib/resource.js.map +3 -3
- package/dist/src/shared/lib/state.js +29 -16
- package/dist/src/shared/lib/state.js.map +3 -3
- package/dist/src/shared/state/app-state.js +29 -16
- package/dist/src/shared/state/app-state.js.map +3 -3
- package/package.json +1 -1
package/dist/src/mesh.js
CHANGED
|
@@ -70,25 +70,22 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
// src/shared/lib/idb-helpers.ts
|
|
73
|
-
function openIDB(options) {
|
|
73
|
+
function openIDB(options, openFn = defaultOpenFn) {
|
|
74
74
|
return new Promise((resolve, reject) => {
|
|
75
75
|
const start = Date.now();
|
|
76
|
-
const request =
|
|
76
|
+
const request = openFn(options.name, options.version);
|
|
77
77
|
let settled = false;
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
return;
|
|
81
|
-
settled = true;
|
|
82
|
-
const elapsedMs = Date.now() - start;
|
|
83
|
-
reject(new Error(`Polly IndexedDB open of '${options.name}' timed out after ${elapsedMs}ms (cross-tab lock or zombie connection?)`));
|
|
84
|
-
}, IDB_OPEN_TIMEOUT_MS);
|
|
85
|
-
request.onerror = () => {
|
|
78
|
+
const elapsed = () => Date.now() - start;
|
|
79
|
+
const rejectWith = (reason, cause) => {
|
|
86
80
|
if (settled)
|
|
87
81
|
return;
|
|
88
82
|
settled = true;
|
|
89
83
|
clearTimeout(timer);
|
|
90
|
-
reject(
|
|
84
|
+
reject(new IDBOpenError(reason, options.name, elapsed(), cause));
|
|
91
85
|
};
|
|
86
|
+
const timer = setTimeout(() => rejectWith("timeout"), IDB_OPEN_TIMEOUT_MS);
|
|
87
|
+
request.onerror = () => rejectWith("error", request.error);
|
|
88
|
+
request.onblocked = () => rejectWith("blocked");
|
|
92
89
|
request.onsuccess = () => {
|
|
93
90
|
if (settled)
|
|
94
91
|
return;
|
|
@@ -102,10 +99,10 @@ function openIDB(options) {
|
|
|
102
99
|
};
|
|
103
100
|
});
|
|
104
101
|
}
|
|
105
|
-
function cachedOpen(ref, options) {
|
|
102
|
+
function cachedOpen(ref, options, openFn) {
|
|
106
103
|
if (ref.promise)
|
|
107
104
|
return ref.promise;
|
|
108
|
-
const pending = openIDB(options);
|
|
105
|
+
const pending = openIDB(options, openFn);
|
|
109
106
|
pending.catch(() => {
|
|
110
107
|
if (ref.promise === pending)
|
|
111
108
|
ref.promise = null;
|
|
@@ -151,7 +148,21 @@ function iterateCursor(db, storeName, visit) {
|
|
|
151
148
|
request.onerror = () => reject(request.error);
|
|
152
149
|
});
|
|
153
150
|
}
|
|
154
|
-
var IDB_OPEN_TIMEOUT_MS = 5000;
|
|
151
|
+
var IDB_OPEN_TIMEOUT_MS = 5000, IDBOpenError, defaultOpenFn = (name, version) => indexedDB.open(name, version);
|
|
152
|
+
var init_idb_helpers = __esm(() => {
|
|
153
|
+
IDBOpenError = class IDBOpenError extends Error {
|
|
154
|
+
reason;
|
|
155
|
+
dbName;
|
|
156
|
+
elapsedMs;
|
|
157
|
+
constructor(reason, dbName, elapsedMs, cause) {
|
|
158
|
+
super(`Polly IndexedDB open of '${dbName}' ${reason} after ${elapsedMs}ms`, cause === undefined ? undefined : { cause });
|
|
159
|
+
this.name = "IDBOpenError";
|
|
160
|
+
this.reason = reason;
|
|
161
|
+
this.dbName = dbName;
|
|
162
|
+
this.elapsedMs = elapsedMs;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
});
|
|
155
166
|
|
|
156
167
|
// src/shared/lib/encryption.ts
|
|
157
168
|
var exports_encryption = {};
|
|
@@ -253,6 +264,8 @@ var wasmUrl = new URL(wasmPath, import.meta.url).href;
|
|
|
253
264
|
await initializeWasm(wasmUrl);
|
|
254
265
|
|
|
255
266
|
// src/shared/lib/blob-cache.ts
|
|
267
|
+
init_idb_helpers();
|
|
268
|
+
|
|
256
269
|
class MemoryBlobCache {
|
|
257
270
|
store = new Map;
|
|
258
271
|
pinned = new Set;
|
|
@@ -1716,25 +1729,10 @@ function $crdtState(options) {
|
|
|
1716
1729
|
const inner = signal2(options.initialValue);
|
|
1717
1730
|
let updating = false;
|
|
1718
1731
|
let currentHandle;
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
if (options.schemaVersion !== undefined) {
|
|
1724
|
-
const targetVersion = options.schemaVersion;
|
|
1725
|
-
const migrations = options.migrations ?? {};
|
|
1726
|
-
handle.change((doc) => {
|
|
1727
|
-
runMigrations(doc, targetVersion, migrations);
|
|
1728
|
-
setDocVersion(doc, targetVersion);
|
|
1729
|
-
});
|
|
1730
|
-
}
|
|
1731
|
-
updating = true;
|
|
1732
|
-
try {
|
|
1733
|
-
inner.value = cloneDoc(handle.doc());
|
|
1734
|
-
} finally {
|
|
1735
|
-
updating = false;
|
|
1736
|
-
}
|
|
1737
|
-
handle.on("change", (payload) => {
|
|
1732
|
+
let detachChangeListener;
|
|
1733
|
+
let swapping = false;
|
|
1734
|
+
function attachChangeListener(handle) {
|
|
1735
|
+
const listener = (payload) => {
|
|
1738
1736
|
if (updating)
|
|
1739
1737
|
return;
|
|
1740
1738
|
updating = true;
|
|
@@ -1743,7 +1741,75 @@ function $crdtState(options) {
|
|
|
1743
1741
|
} finally {
|
|
1744
1742
|
updating = false;
|
|
1745
1743
|
}
|
|
1744
|
+
if (options.resolveRedirect && !swapping) {
|
|
1745
|
+
maybeRebind(handle, payload.doc);
|
|
1746
|
+
}
|
|
1747
|
+
};
|
|
1748
|
+
handle.on("change", listener);
|
|
1749
|
+
detachChangeListener = () => {
|
|
1750
|
+
handle.off("change", listener);
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
async function maybeRebind(fromHandle, doc) {
|
|
1754
|
+
if (!options.resolveRedirect)
|
|
1755
|
+
return;
|
|
1756
|
+
if (swapping)
|
|
1757
|
+
return;
|
|
1758
|
+
swapping = true;
|
|
1759
|
+
try {
|
|
1760
|
+
const next = await options.resolveRedirect(fromHandle, doc);
|
|
1761
|
+
if (!next)
|
|
1762
|
+
return;
|
|
1763
|
+
if (next === currentHandle)
|
|
1764
|
+
return;
|
|
1765
|
+
if (next.documentId === fromHandle.documentId)
|
|
1766
|
+
return;
|
|
1767
|
+
detachChangeListener?.();
|
|
1768
|
+
detachChangeListener = undefined;
|
|
1769
|
+
currentHandle = next;
|
|
1770
|
+
attachChangeListener(next);
|
|
1771
|
+
updating = true;
|
|
1772
|
+
try {
|
|
1773
|
+
inner.value = cloneDoc(next.doc());
|
|
1774
|
+
} finally {
|
|
1775
|
+
updating = false;
|
|
1776
|
+
}
|
|
1777
|
+
} finally {
|
|
1778
|
+
swapping = false;
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
async function followInitialRedirects(start) {
|
|
1782
|
+
if (!options.resolveRedirect)
|
|
1783
|
+
return start;
|
|
1784
|
+
let handle = start;
|
|
1785
|
+
const seen = new Set([handle.documentId]);
|
|
1786
|
+
for (;; ) {
|
|
1787
|
+
const doc = handle.doc();
|
|
1788
|
+
if (!doc)
|
|
1789
|
+
break;
|
|
1790
|
+
const next = await options.resolveRedirect(handle, doc);
|
|
1791
|
+
if (!next || next === handle)
|
|
1792
|
+
break;
|
|
1793
|
+
const nextIdString = next.documentId;
|
|
1794
|
+
if (seen.has(nextIdString))
|
|
1795
|
+
break;
|
|
1796
|
+
seen.add(nextIdString);
|
|
1797
|
+
handle = next;
|
|
1798
|
+
await handle.whenReady();
|
|
1799
|
+
}
|
|
1800
|
+
return handle;
|
|
1801
|
+
}
|
|
1802
|
+
function applyPendingMigrations(handle) {
|
|
1803
|
+
if (options.schemaVersion === undefined)
|
|
1804
|
+
return;
|
|
1805
|
+
const targetVersion = options.schemaVersion;
|
|
1806
|
+
const migrations = options.migrations ?? {};
|
|
1807
|
+
handle.change((doc) => {
|
|
1808
|
+
runMigrations(doc, targetVersion, migrations);
|
|
1809
|
+
setDocVersion(doc, targetVersion);
|
|
1746
1810
|
});
|
|
1811
|
+
}
|
|
1812
|
+
function bindSignalToHandle() {
|
|
1747
1813
|
effect2(() => {
|
|
1748
1814
|
const value = inner.value;
|
|
1749
1815
|
if (updating)
|
|
@@ -1759,6 +1825,21 @@ function $crdtState(options) {
|
|
|
1759
1825
|
updating = false;
|
|
1760
1826
|
}
|
|
1761
1827
|
});
|
|
1828
|
+
}
|
|
1829
|
+
const loaded = (async () => {
|
|
1830
|
+
const initialHandle = await options.getHandle();
|
|
1831
|
+
await initialHandle.whenReady();
|
|
1832
|
+
const handle = await followInitialRedirects(initialHandle);
|
|
1833
|
+
currentHandle = handle;
|
|
1834
|
+
applyPendingMigrations(handle);
|
|
1835
|
+
updating = true;
|
|
1836
|
+
try {
|
|
1837
|
+
inner.value = cloneDoc(handle.doc());
|
|
1838
|
+
} finally {
|
|
1839
|
+
updating = false;
|
|
1840
|
+
}
|
|
1841
|
+
attachChangeListener(handle);
|
|
1842
|
+
bindSignalToHandle();
|
|
1762
1843
|
})();
|
|
1763
1844
|
return {
|
|
1764
1845
|
key: options.key,
|
|
@@ -1822,6 +1903,7 @@ function resetMeshState() {
|
|
|
1822
1903
|
lastLoadedRejection = undefined;
|
|
1823
1904
|
lastStorageOpenError = undefined;
|
|
1824
1905
|
lazyWrappers = [];
|
|
1906
|
+
docIdResolver = undefined;
|
|
1825
1907
|
}
|
|
1826
1908
|
function isMeshStateConfigured() {
|
|
1827
1909
|
return defaultRepo !== undefined;
|
|
@@ -1927,8 +2009,25 @@ function deriveDocumentId(key) {
|
|
|
1927
2009
|
const bytes = digest.slice(0, 16);
|
|
1928
2010
|
return interpretAsDocumentId(bytes);
|
|
1929
2011
|
}
|
|
2012
|
+
var docIdResolver;
|
|
2013
|
+
function registerDocIdResolver(resolver) {
|
|
2014
|
+
docIdResolver = resolver;
|
|
2015
|
+
}
|
|
2016
|
+
function getDocIdResolver() {
|
|
2017
|
+
return docIdResolver;
|
|
2018
|
+
}
|
|
2019
|
+
function resolveDocumentId(key) {
|
|
2020
|
+
return docIdResolver?.(key) ?? deriveDocumentId(key);
|
|
2021
|
+
}
|
|
2022
|
+
var redirectDetector;
|
|
2023
|
+
function registerRedirectDetector(detector) {
|
|
2024
|
+
redirectDetector = detector;
|
|
2025
|
+
}
|
|
2026
|
+
function getRedirectDetector() {
|
|
2027
|
+
return redirectDetector;
|
|
2028
|
+
}
|
|
1930
2029
|
function buildHandleFactory(repo, key, initialDoc) {
|
|
1931
|
-
const documentId =
|
|
2030
|
+
const documentId = resolveDocumentId(key);
|
|
1932
2031
|
return async () => {
|
|
1933
2032
|
lazyInvocations++;
|
|
1934
2033
|
let exitReason = "threw";
|
|
@@ -1937,23 +2036,22 @@ function buildHandleFactory(repo, key, initialDoc) {
|
|
|
1937
2036
|
const cached = repo.handles[documentId];
|
|
1938
2037
|
lazyReachedRepo++;
|
|
1939
2038
|
const docIdString = documentId;
|
|
2039
|
+
let handle;
|
|
1940
2040
|
if (cached) {
|
|
1941
2041
|
await withStorageTimeout("whenReady", docIdString, cached.whenReady(["ready", "unavailable"]));
|
|
1942
2042
|
if (cached.state === "ready") {
|
|
1943
2043
|
exitReason = "returned-cached";
|
|
1944
|
-
|
|
2044
|
+
handle = cached;
|
|
2045
|
+
} else {
|
|
2046
|
+
handle = await loadOrSeed(repo, documentId, initialDoc, docIdString, (r) => {
|
|
2047
|
+
exitReason = r;
|
|
2048
|
+
});
|
|
1945
2049
|
}
|
|
2050
|
+
} else {
|
|
2051
|
+
handle = await loadOrSeed(repo, documentId, initialDoc, docIdString, (r) => {
|
|
2052
|
+
exitReason = r;
|
|
2053
|
+
});
|
|
1946
2054
|
}
|
|
1947
|
-
const loadPromise = repo.storageSubsystem?.loadDoc(documentId);
|
|
1948
|
-
const stored = loadPromise ? await withStorageTimeout("loadDoc", docIdString, loadPromise) : undefined;
|
|
1949
|
-
if (stored) {
|
|
1950
|
-
exitReason = "loaded-from-storage";
|
|
1951
|
-
return repo.find(documentId, { allowableStates: ["ready"] });
|
|
1952
|
-
}
|
|
1953
|
-
const seeded = Automerge.save(Automerge.from(initialDoc));
|
|
1954
|
-
const handle = repo.import(seeded, { docId: documentId });
|
|
1955
|
-
handle.doneLoading();
|
|
1956
|
-
exitReason = "seeded-and-imported";
|
|
1957
2055
|
return handle;
|
|
1958
2056
|
} catch (err) {
|
|
1959
2057
|
errorMessage = err instanceof Error ? err.message : String(err);
|
|
@@ -1973,6 +2071,19 @@ function buildHandleFactory(repo, key, initialDoc) {
|
|
|
1973
2071
|
}
|
|
1974
2072
|
};
|
|
1975
2073
|
}
|
|
2074
|
+
async function loadOrSeed(repo, documentId, initialDoc, docIdString, setExitReason) {
|
|
2075
|
+
const loadPromise = repo.storageSubsystem?.loadDoc(documentId);
|
|
2076
|
+
const stored = loadPromise ? await withStorageTimeout("loadDoc", docIdString, loadPromise) : undefined;
|
|
2077
|
+
if (stored) {
|
|
2078
|
+
setExitReason("loaded-from-storage");
|
|
2079
|
+
return repo.find(documentId, { allowableStates: ["ready"] });
|
|
2080
|
+
}
|
|
2081
|
+
const seeded = Automerge.save(Automerge.from(initialDoc));
|
|
2082
|
+
const handle = repo.import(seeded, { docId: documentId });
|
|
2083
|
+
handle.doneLoading();
|
|
2084
|
+
setExitReason("seeded-and-imported");
|
|
2085
|
+
return handle;
|
|
2086
|
+
}
|
|
1976
2087
|
function attachLoadedRejectionSink(primitive) {
|
|
1977
2088
|
primitive.loaded.catch((err) => {
|
|
1978
2089
|
recordLoadedRejection(err);
|
|
@@ -1986,11 +2097,35 @@ function $meshState(key, initialValue, options = {}) {
|
|
|
1986
2097
|
primitive: "meshState",
|
|
1987
2098
|
initialValue,
|
|
1988
2099
|
getHandle: buildHandleFactory(repo, key, initialValue),
|
|
2100
|
+
resolveRedirect: buildRedirectResolver(repo),
|
|
1989
2101
|
schemaVersion: options.schemaVersion,
|
|
1990
2102
|
migrations: options.migrations,
|
|
1991
2103
|
access: options.access
|
|
1992
2104
|
}));
|
|
1993
2105
|
}
|
|
2106
|
+
function buildRedirectResolver(repo) {
|
|
2107
|
+
if (!redirectDetector) {}
|
|
2108
|
+
return async (_handle, doc) => {
|
|
2109
|
+
const detector = redirectDetector;
|
|
2110
|
+
if (!detector)
|
|
2111
|
+
return;
|
|
2112
|
+
let nextId;
|
|
2113
|
+
try {
|
|
2114
|
+
nextId = detector(doc);
|
|
2115
|
+
} catch {
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
if (!nextId)
|
|
2119
|
+
return;
|
|
2120
|
+
try {
|
|
2121
|
+
return await repo.find(nextId, {
|
|
2122
|
+
allowableStates: ["ready", "unavailable"]
|
|
2123
|
+
});
|
|
2124
|
+
} catch {
|
|
2125
|
+
return;
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
}
|
|
1994
2129
|
function $meshText(key, initialValue, options = {}) {
|
|
1995
2130
|
const repo = resolveRepo(options.repo);
|
|
1996
2131
|
return attachLoadedRejectionSink($crdtText(key, initialValue, {
|
|
@@ -3604,25 +3739,31 @@ export {
|
|
|
3604
3739
|
serialisePairingToken,
|
|
3605
3740
|
serialiseKeyring,
|
|
3606
3741
|
revokePeerLocally,
|
|
3742
|
+
resolveDocumentId,
|
|
3607
3743
|
resetMeshState,
|
|
3744
|
+
registerRedirectDetector,
|
|
3745
|
+
registerDocIdResolver,
|
|
3608
3746
|
parsePairingToken,
|
|
3609
3747
|
memoryKeyringStorage,
|
|
3610
3748
|
isPairingTokenExpired,
|
|
3611
3749
|
isMeshStateConfigured,
|
|
3612
3750
|
isBlobRef,
|
|
3613
3751
|
getStorageOpenError,
|
|
3752
|
+
getRedirectDetector,
|
|
3614
3753
|
getMeshStateModuleId,
|
|
3615
3754
|
getLazyWrappers,
|
|
3616
3755
|
getLazyReachedRepo,
|
|
3617
3756
|
getLazyInvocations,
|
|
3618
3757
|
getLastLoadedRejection,
|
|
3619
3758
|
getLastConfiguredRepoPeerId,
|
|
3759
|
+
getDocIdResolver,
|
|
3620
3760
|
generateSigningKeyPair,
|
|
3621
3761
|
generateDocumentKey,
|
|
3622
3762
|
encrypt,
|
|
3623
3763
|
encodeRevocation,
|
|
3624
3764
|
encodePairingToken,
|
|
3625
3765
|
deserialiseKeyring,
|
|
3766
|
+
deriveDocumentId,
|
|
3626
3767
|
decryptOrThrow,
|
|
3627
3768
|
decrypt,
|
|
3628
3769
|
decodeRevocation,
|
|
@@ -3666,4 +3807,4 @@ export {
|
|
|
3666
3807
|
$meshCounter
|
|
3667
3808
|
};
|
|
3668
3809
|
|
|
3669
|
-
//# debugId=
|
|
3810
|
+
//# debugId=32FAEA2DE6283FD764756E2164756E21
|