@fairfox/polly 0.60.0 → 0.62.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 +114 -42
- package/dist/src/background/index.js.map +5 -4
- package/dist/src/background/message-router.js +114 -42
- package/dist/src/background/message-router.js.map +5 -4
- package/dist/src/index.js +115 -42
- package/dist/src/index.js.map +5 -4
- package/dist/src/mesh.d.ts +3 -3
- package/dist/src/mesh.js +181 -77
- package/dist/src/mesh.js.map +8 -7
- package/dist/src/shared/adapters/index.js +114 -42
- package/dist/src/shared/adapters/index.js.map +5 -4
- package/dist/src/shared/lib/blob-cache.d.ts +1 -1
- package/dist/src/shared/lib/context-helpers.js +114 -42
- package/dist/src/shared/lib/context-helpers.js.map +5 -4
- package/dist/src/shared/lib/idb-helpers.d.ts +38 -0
- package/dist/src/shared/lib/mesh-client.d.ts +45 -1
- package/dist/src/shared/lib/mesh-state.d.ts +37 -0
- package/dist/src/shared/lib/message-bus.js +114 -42
- package/dist/src/shared/lib/message-bus.js.map +5 -4
- package/dist/src/shared/lib/resource.js +109 -38
- package/dist/src/shared/lib/resource.js.map +5 -4
- package/dist/src/shared/lib/state.js +109 -38
- package/dist/src/shared/lib/state.js.map +5 -4
- package/dist/src/shared/lib/storage-adapter.d.ts +3 -3
- package/dist/src/shared/state/app-state.js +109 -38
- package/dist/src/shared/state/app-state.js.map +5 -4
- package/package.json +1 -1
package/dist/src/mesh.js
CHANGED
|
@@ -69,6 +69,90 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
69
69
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
+
// src/shared/lib/idb-helpers.ts
|
|
73
|
+
function openIDB(options) {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const start = Date.now();
|
|
76
|
+
const request = indexedDB.open(options.name, options.version);
|
|
77
|
+
let settled = false;
|
|
78
|
+
const timer = setTimeout(() => {
|
|
79
|
+
if (settled)
|
|
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 = () => {
|
|
86
|
+
if (settled)
|
|
87
|
+
return;
|
|
88
|
+
settled = true;
|
|
89
|
+
clearTimeout(timer);
|
|
90
|
+
reject(request.error);
|
|
91
|
+
};
|
|
92
|
+
request.onsuccess = () => {
|
|
93
|
+
if (settled)
|
|
94
|
+
return;
|
|
95
|
+
settled = true;
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
resolve(request.result);
|
|
98
|
+
};
|
|
99
|
+
request.onupgradeneeded = (event) => {
|
|
100
|
+
const db = event.target.result;
|
|
101
|
+
options.upgrade(db, event);
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function cachedOpen(ref, options) {
|
|
106
|
+
if (ref.promise)
|
|
107
|
+
return ref.promise;
|
|
108
|
+
const pending = openIDB(options);
|
|
109
|
+
pending.catch(() => {
|
|
110
|
+
if (ref.promise === pending)
|
|
111
|
+
ref.promise = null;
|
|
112
|
+
});
|
|
113
|
+
ref.promise = pending;
|
|
114
|
+
return pending;
|
|
115
|
+
}
|
|
116
|
+
function runRequest(request) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
request.onsuccess = () => resolve(request.result);
|
|
119
|
+
request.onerror = () => reject(request.error);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function runTx(db, storeName, mode, fn) {
|
|
123
|
+
return new Promise((resolve, reject) => {
|
|
124
|
+
const tx = db.transaction(storeName, mode);
|
|
125
|
+
const store = tx.objectStore(storeName);
|
|
126
|
+
tx.oncomplete = () => resolve();
|
|
127
|
+
tx.onerror = () => reject(tx.error);
|
|
128
|
+
tx.onabort = () => reject(tx.error);
|
|
129
|
+
try {
|
|
130
|
+
fn(store);
|
|
131
|
+
} catch (err) {
|
|
132
|
+
try {
|
|
133
|
+
tx.abort();
|
|
134
|
+
} catch {}
|
|
135
|
+
reject(err);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function iterateCursor(db, storeName, visit) {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const tx = db.transaction(storeName, "readonly");
|
|
142
|
+
const store = tx.objectStore(storeName);
|
|
143
|
+
const request = store.openCursor();
|
|
144
|
+
request.onsuccess = () => {
|
|
145
|
+
const cursor = request.result;
|
|
146
|
+
if (!cursor)
|
|
147
|
+
return resolve();
|
|
148
|
+
visit(cursor.key, cursor.value);
|
|
149
|
+
cursor.continue();
|
|
150
|
+
};
|
|
151
|
+
request.onerror = () => reject(request.error);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
var IDB_OPEN_TIMEOUT_MS = 5000;
|
|
155
|
+
|
|
72
156
|
// src/shared/lib/encryption.ts
|
|
73
157
|
var exports_encryption = {};
|
|
74
158
|
__export(exports_encryption, {
|
|
@@ -255,42 +339,28 @@ class IndexedDBBlobCache {
|
|
|
255
339
|
static DB_NAME = "polly-blobs";
|
|
256
340
|
static DB_VERSION = 1;
|
|
257
341
|
static STORE_NAME = "blobs";
|
|
258
|
-
|
|
342
|
+
dbRef = { promise: null };
|
|
259
343
|
urls = new Map;
|
|
260
344
|
openDB() {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
request.onerror = () => reject(request.error);
|
|
266
|
-
request.onsuccess = () => resolve(request.result);
|
|
267
|
-
request.onupgradeneeded = (event) => {
|
|
268
|
-
const db = event.target.result;
|
|
345
|
+
return cachedOpen(this.dbRef, {
|
|
346
|
+
name: IndexedDBBlobCache.DB_NAME,
|
|
347
|
+
version: IndexedDBBlobCache.DB_VERSION,
|
|
348
|
+
upgrade: (db) => {
|
|
269
349
|
if (!db.objectStoreNames.contains(IndexedDBBlobCache.STORE_NAME)) {
|
|
270
350
|
db.createObjectStore(IndexedDBBlobCache.STORE_NAME);
|
|
271
351
|
}
|
|
272
|
-
}
|
|
352
|
+
}
|
|
273
353
|
});
|
|
274
|
-
return this.dbPromise;
|
|
275
354
|
}
|
|
276
355
|
async getRecord(hash) {
|
|
277
356
|
const db = await this.openDB();
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const store = tx.objectStore(IndexedDBBlobCache.STORE_NAME);
|
|
281
|
-
const request = store.get(hash);
|
|
282
|
-
request.onsuccess = () => resolve(request.result);
|
|
283
|
-
request.onerror = () => reject(request.error);
|
|
284
|
-
});
|
|
357
|
+
const tx = db.transaction(IndexedDBBlobCache.STORE_NAME, "readonly");
|
|
358
|
+
return runRequest(tx.objectStore(IndexedDBBlobCache.STORE_NAME).get(hash));
|
|
285
359
|
}
|
|
286
360
|
async putRecord(hash, record) {
|
|
287
361
|
const db = await this.openDB();
|
|
288
|
-
|
|
289
|
-
const tx = db.transaction(IndexedDBBlobCache.STORE_NAME, "readwrite");
|
|
290
|
-
const store = tx.objectStore(IndexedDBBlobCache.STORE_NAME);
|
|
362
|
+
await runTx(db, IndexedDBBlobCache.STORE_NAME, "readwrite", (store) => {
|
|
291
363
|
store.put(record, hash);
|
|
292
|
-
tx.oncomplete = () => resolve();
|
|
293
|
-
tx.onerror = () => reject(tx.error);
|
|
294
364
|
});
|
|
295
365
|
}
|
|
296
366
|
async get(hash) {
|
|
@@ -311,13 +381,9 @@ class IndexedDBBlobCache {
|
|
|
311
381
|
}
|
|
312
382
|
async has(hash) {
|
|
313
383
|
const db = await this.openDB();
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const request = store.count(hash);
|
|
318
|
-
request.onsuccess = () => resolve(request.result > 0);
|
|
319
|
-
request.onerror = () => reject(request.error);
|
|
320
|
-
});
|
|
384
|
+
const tx = db.transaction(IndexedDBBlobCache.STORE_NAME, "readonly");
|
|
385
|
+
const count = await runRequest(tx.objectStore(IndexedDBBlobCache.STORE_NAME).count(hash));
|
|
386
|
+
return count > 0;
|
|
321
387
|
}
|
|
322
388
|
async delete(hash) {
|
|
323
389
|
const url = this.urls.get(hash);
|
|
@@ -326,12 +392,8 @@ class IndexedDBBlobCache {
|
|
|
326
392
|
this.urls.delete(hash);
|
|
327
393
|
}
|
|
328
394
|
const db = await this.openDB();
|
|
329
|
-
|
|
330
|
-
const tx = db.transaction(IndexedDBBlobCache.STORE_NAME, "readwrite");
|
|
331
|
-
const store = tx.objectStore(IndexedDBBlobCache.STORE_NAME);
|
|
395
|
+
await runTx(db, IndexedDBBlobCache.STORE_NAME, "readwrite", (store) => {
|
|
332
396
|
store.delete(hash);
|
|
333
|
-
tx.oncomplete = () => resolve();
|
|
334
|
-
tx.onerror = () => reject(tx.error);
|
|
335
397
|
});
|
|
336
398
|
}
|
|
337
399
|
async pin(hash) {
|
|
@@ -348,50 +410,25 @@ class IndexedDBBlobCache {
|
|
|
348
410
|
}
|
|
349
411
|
async size() {
|
|
350
412
|
const db = await this.openDB();
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const request = store.openCursor();
|
|
355
|
-
let total = 0;
|
|
356
|
-
request.onsuccess = () => {
|
|
357
|
-
const cursor = request.result;
|
|
358
|
-
if (cursor) {
|
|
359
|
-
const value = cursor.value;
|
|
360
|
-
total += value.size;
|
|
361
|
-
cursor.continue();
|
|
362
|
-
} else {
|
|
363
|
-
resolve(total);
|
|
364
|
-
}
|
|
365
|
-
};
|
|
366
|
-
request.onerror = () => reject(request.error);
|
|
413
|
+
let total = 0;
|
|
414
|
+
await iterateCursor(db, IndexedDBBlobCache.STORE_NAME, (_key, value) => {
|
|
415
|
+
total += value.size;
|
|
367
416
|
});
|
|
417
|
+
return total;
|
|
368
418
|
}
|
|
369
419
|
async evict(maxBytes) {
|
|
370
420
|
const db = await this.openDB();
|
|
371
421
|
const candidates = [];
|
|
372
422
|
let totalSize = 0;
|
|
373
|
-
await
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
if (!value.pinned) {
|
|
383
|
-
candidates.push({
|
|
384
|
-
hash: cursor.key,
|
|
385
|
-
accessedAt: value.accessedAt,
|
|
386
|
-
size: value.size
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
cursor.continue();
|
|
390
|
-
} else {
|
|
391
|
-
resolve();
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
request.onerror = () => reject(request.error);
|
|
423
|
+
await iterateCursor(db, IndexedDBBlobCache.STORE_NAME, (key, value) => {
|
|
424
|
+
totalSize += value.size;
|
|
425
|
+
if (!value.pinned) {
|
|
426
|
+
candidates.push({
|
|
427
|
+
hash: key,
|
|
428
|
+
accessedAt: value.accessedAt,
|
|
429
|
+
size: value.size
|
|
430
|
+
});
|
|
431
|
+
}
|
|
395
432
|
});
|
|
396
433
|
if (totalSize <= maxBytes)
|
|
397
434
|
return 0;
|
|
@@ -1783,6 +1820,7 @@ function resetMeshState() {
|
|
|
1783
1820
|
lazyInvocations = 0;
|
|
1784
1821
|
lazyReachedRepo = 0;
|
|
1785
1822
|
lastLoadedRejection = undefined;
|
|
1823
|
+
lastStorageOpenError = undefined;
|
|
1786
1824
|
lazyWrappers = [];
|
|
1787
1825
|
}
|
|
1788
1826
|
function isMeshStateConfigured() {
|
|
@@ -1813,6 +1851,47 @@ function recordLoadedRejection(thrown) {
|
|
|
1813
1851
|
at: Date.now()
|
|
1814
1852
|
};
|
|
1815
1853
|
}
|
|
1854
|
+
var STORAGE_OP_TIMEOUT_MS = 5000;
|
|
1855
|
+
var lastStorageOpenError;
|
|
1856
|
+
function getStorageOpenError() {
|
|
1857
|
+
return lastStorageOpenError;
|
|
1858
|
+
}
|
|
1859
|
+
function recordStorageOpenError(error) {
|
|
1860
|
+
lastStorageOpenError = error;
|
|
1861
|
+
}
|
|
1862
|
+
async function withStorageTimeout(operation, documentId, promise, timeoutMs = STORAGE_OP_TIMEOUT_MS) {
|
|
1863
|
+
const start = Date.now();
|
|
1864
|
+
let timer;
|
|
1865
|
+
let timedOut = false;
|
|
1866
|
+
try {
|
|
1867
|
+
return await new Promise((resolve, reject) => {
|
|
1868
|
+
timer = setTimeout(() => {
|
|
1869
|
+
timedOut = true;
|
|
1870
|
+
const elapsedMs = Date.now() - start;
|
|
1871
|
+
const message = `Polly $meshState: storage operation '${operation}' on document '${documentId}' timed out after ${timeoutMs}ms`;
|
|
1872
|
+
recordStorageOpenError({
|
|
1873
|
+
operation,
|
|
1874
|
+
documentId,
|
|
1875
|
+
timeoutMs,
|
|
1876
|
+
elapsedMs,
|
|
1877
|
+
message,
|
|
1878
|
+
at: Date.now()
|
|
1879
|
+
});
|
|
1880
|
+
reject(new Error(message));
|
|
1881
|
+
}, timeoutMs);
|
|
1882
|
+
promise.then((value) => {
|
|
1883
|
+
if (!timedOut)
|
|
1884
|
+
resolve(value);
|
|
1885
|
+
}, (err) => {
|
|
1886
|
+
if (!timedOut)
|
|
1887
|
+
reject(err);
|
|
1888
|
+
});
|
|
1889
|
+
});
|
|
1890
|
+
} finally {
|
|
1891
|
+
if (timer !== undefined)
|
|
1892
|
+
clearTimeout(timer);
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1816
1895
|
var LAZY_WRAPPER_LOG_CAP = 64;
|
|
1817
1896
|
var lazyWrappers = [];
|
|
1818
1897
|
function getLazyWrappers() {
|
|
@@ -1857,14 +1936,16 @@ function buildHandleFactory(repo, key, initialDoc) {
|
|
|
1857
1936
|
try {
|
|
1858
1937
|
const cached = repo.handles[documentId];
|
|
1859
1938
|
lazyReachedRepo++;
|
|
1939
|
+
const docIdString = documentId;
|
|
1860
1940
|
if (cached) {
|
|
1861
|
-
await cached.whenReady(["ready", "unavailable"]);
|
|
1941
|
+
await withStorageTimeout("whenReady", docIdString, cached.whenReady(["ready", "unavailable"]));
|
|
1862
1942
|
if (cached.state === "ready") {
|
|
1863
1943
|
exitReason = "returned-cached";
|
|
1864
1944
|
return cached;
|
|
1865
1945
|
}
|
|
1866
1946
|
}
|
|
1867
|
-
const
|
|
1947
|
+
const loadPromise = repo.storageSubsystem?.loadDoc(documentId);
|
|
1948
|
+
const stored = loadPromise ? await withStorageTimeout("loadDoc", docIdString, loadPromise) : undefined;
|
|
1868
1949
|
if (stored) {
|
|
1869
1950
|
exitReason = "loaded-from-storage";
|
|
1870
1951
|
return repo.find(documentId, { allowableStates: ["ready"] });
|
|
@@ -2987,6 +3068,7 @@ function getReevaluateDocumentShare(repo) {
|
|
|
2987
3068
|
return () => fn.call(sync);
|
|
2988
3069
|
}
|
|
2989
3070
|
function buildMeshStateModuleDiagnostics() {
|
|
3071
|
+
const lazyWrappers2 = getLazyWrappers();
|
|
2990
3072
|
return {
|
|
2991
3073
|
moduleId: getMeshStateModuleId(),
|
|
2992
3074
|
configured: isMeshStateConfigured(),
|
|
@@ -2995,9 +3077,30 @@ function buildMeshStateModuleDiagnostics() {
|
|
|
2995
3077
|
lazyInvocations: getLazyInvocations(),
|
|
2996
3078
|
lazyReachedRepo: getLazyReachedRepo(),
|
|
2997
3079
|
lastLoadedRejection: getLastLoadedRejection(),
|
|
2998
|
-
|
|
3080
|
+
storageOpenError: getStorageOpenError(),
|
|
3081
|
+
lazyWrappers: lazyWrappers2,
|
|
3082
|
+
lazyWrapperDuplicateDocIds: findLazyWrapperDocIdDuplicates(lazyWrappers2)
|
|
2999
3083
|
};
|
|
3000
3084
|
}
|
|
3085
|
+
function findLazyWrapperDocIdDuplicates(records) {
|
|
3086
|
+
const byDocId = new Map;
|
|
3087
|
+
for (const record of records) {
|
|
3088
|
+
let entry = byDocId.get(record.docId);
|
|
3089
|
+
if (!entry) {
|
|
3090
|
+
entry = { keys: new Set, count: 0 };
|
|
3091
|
+
byDocId.set(record.docId, entry);
|
|
3092
|
+
}
|
|
3093
|
+
entry.keys.add(record.key);
|
|
3094
|
+
entry.count++;
|
|
3095
|
+
}
|
|
3096
|
+
const duplicates = [];
|
|
3097
|
+
for (const [docId, entry] of byDocId) {
|
|
3098
|
+
if (entry.count > 1) {
|
|
3099
|
+
duplicates.push({ docId, keys: [...entry.keys], recordCount: entry.count });
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
return duplicates;
|
|
3103
|
+
}
|
|
3001
3104
|
function installPolly107SyncReevaluation(networkAdapter, repo) {
|
|
3002
3105
|
const disable = typeof process !== "undefined" && process.env?.["POLLY_107_DISABLE_FIX"] === "1";
|
|
3003
3106
|
if (disable)
|
|
@@ -3507,6 +3610,7 @@ export {
|
|
|
3507
3610
|
isPairingTokenExpired,
|
|
3508
3611
|
isMeshStateConfigured,
|
|
3509
3612
|
isBlobRef,
|
|
3613
|
+
getStorageOpenError,
|
|
3510
3614
|
getMeshStateModuleId,
|
|
3511
3615
|
getLazyWrappers,
|
|
3512
3616
|
getLazyReachedRepo,
|
|
@@ -3562,4 +3666,4 @@ export {
|
|
|
3562
3666
|
$meshCounter
|
|
3563
3667
|
};
|
|
3564
3668
|
|
|
3565
|
-
//# debugId=
|
|
3669
|
+
//# debugId=EFE12C3DC2653D4B64756E2164756E21
|