@instantdb/core 0.22.97 → 0.22.98-experimental.drewh-ts-target.20762041587.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/commonjs/Connection.js +50 -51
- package/dist/commonjs/Connection.js.map +1 -1
- package/dist/commonjs/InMemoryStorage.js +13 -32
- package/dist/commonjs/InMemoryStorage.js.map +1 -1
- package/dist/commonjs/IndexedDBStorage.js +193 -217
- package/dist/commonjs/IndexedDBStorage.js.map +1 -1
- package/dist/commonjs/InstantError.js +1 -0
- package/dist/commonjs/InstantError.js.map +1 -1
- package/dist/commonjs/Reactor.js +566 -610
- package/dist/commonjs/Reactor.js.map +1 -1
- package/dist/commonjs/StorageAPI.js +51 -70
- package/dist/commonjs/StorageAPI.js.map +1 -1
- package/dist/commonjs/SyncTable.js +68 -81
- package/dist/commonjs/SyncTable.js.map +1 -1
- package/dist/commonjs/WindowNetworkListener.js +2 -13
- package/dist/commonjs/WindowNetworkListener.js.map +1 -1
- package/dist/commonjs/__types__/fieldsTypeTest.js +8 -16
- package/dist/commonjs/__types__/fieldsTypeTest.js.map +1 -1
- package/dist/commonjs/__types__/useDatesTypeTest.js +3 -6
- package/dist/commonjs/__types__/useDatesTypeTest.js.map +1 -1
- package/dist/commonjs/authAPI.js +62 -79
- package/dist/commonjs/authAPI.js.map +1 -1
- package/dist/commonjs/createRouteHandler.js +5 -15
- package/dist/commonjs/createRouteHandler.js.map +1 -1
- package/dist/commonjs/datalog.js +1 -1
- package/dist/commonjs/datalog.js.map +1 -1
- package/dist/commonjs/devtool.js +26 -8
- package/dist/commonjs/devtool.js.map +1 -1
- package/dist/commonjs/framework.d.ts.map +1 -1
- package/dist/commonjs/framework.js +142 -152
- package/dist/commonjs/framework.js.map +1 -1
- package/dist/commonjs/index.js +204 -190
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/instaml.js +44 -30
- package/dist/commonjs/instaml.js.map +1 -1
- package/dist/commonjs/instaql.js +25 -33
- package/dist/commonjs/instaql.js.map +1 -1
- package/dist/commonjs/parseSchemaFromJSON.js +6 -7
- package/dist/commonjs/parseSchemaFromJSON.js.map +1 -1
- package/dist/commonjs/presence.js +7 -8
- package/dist/commonjs/presence.js.map +1 -1
- package/dist/commonjs/queryValidation.js +1 -2
- package/dist/commonjs/queryValidation.js.map +1 -1
- package/dist/commonjs/schema.js +8 -6
- package/dist/commonjs/schema.js.map +1 -1
- package/dist/commonjs/schemaTypes.js +22 -3
- package/dist/commonjs/schemaTypes.js.map +1 -1
- package/dist/commonjs/store.js +29 -38
- package/dist/commonjs/store.js.map +1 -1
- package/dist/commonjs/transactionValidation.js +1 -2
- package/dist/commonjs/transactionValidation.js.map +1 -1
- package/dist/commonjs/utils/Deferred.js +3 -0
- package/dist/commonjs/utils/Deferred.js.map +1 -1
- package/dist/commonjs/utils/PersistedObject.js +216 -233
- package/dist/commonjs/utils/PersistedObject.js.map +1 -1
- package/dist/commonjs/utils/fetch.js +9 -19
- package/dist/commonjs/utils/fetch.js.map +1 -1
- package/dist/commonjs/utils/linkIndex.js +2 -4
- package/dist/commonjs/utils/linkIndex.js.map +1 -1
- package/dist/commonjs/utils/object.js +1 -1
- package/dist/commonjs/utils/object.js.map +1 -1
- package/dist/esm/Connection.js +50 -51
- package/dist/esm/Connection.js.map +1 -1
- package/dist/esm/InMemoryStorage.js +13 -32
- package/dist/esm/InMemoryStorage.js.map +1 -1
- package/dist/esm/IndexedDBStorage.js +193 -217
- package/dist/esm/IndexedDBStorage.js.map +1 -1
- package/dist/esm/InstantError.js +1 -0
- package/dist/esm/InstantError.js.map +1 -1
- package/dist/esm/Reactor.js +566 -610
- package/dist/esm/Reactor.js.map +1 -1
- package/dist/esm/StorageAPI.js +51 -70
- package/dist/esm/StorageAPI.js.map +1 -1
- package/dist/esm/SyncTable.js +68 -81
- package/dist/esm/SyncTable.js.map +1 -1
- package/dist/esm/WindowNetworkListener.js +2 -13
- package/dist/esm/WindowNetworkListener.js.map +1 -1
- package/dist/esm/__types__/fieldsTypeTest.js +8 -16
- package/dist/esm/__types__/fieldsTypeTest.js.map +1 -1
- package/dist/esm/__types__/useDatesTypeTest.js +3 -6
- package/dist/esm/__types__/useDatesTypeTest.js.map +1 -1
- package/dist/esm/authAPI.js +62 -79
- package/dist/esm/authAPI.js.map +1 -1
- package/dist/esm/createRouteHandler.js +5 -15
- package/dist/esm/createRouteHandler.js.map +1 -1
- package/dist/esm/datalog.js +1 -1
- package/dist/esm/datalog.js.map +1 -1
- package/dist/esm/devtool.js +26 -8
- package/dist/esm/devtool.js.map +1 -1
- package/dist/esm/framework.d.ts.map +1 -1
- package/dist/esm/framework.js +142 -152
- package/dist/esm/framework.js.map +1 -1
- package/dist/esm/index.js +204 -190
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/instaml.js +44 -30
- package/dist/esm/instaml.js.map +1 -1
- package/dist/esm/instaql.js +25 -33
- package/dist/esm/instaql.js.map +1 -1
- package/dist/esm/parseSchemaFromJSON.js +6 -7
- package/dist/esm/parseSchemaFromJSON.js.map +1 -1
- package/dist/esm/presence.js +7 -8
- package/dist/esm/presence.js.map +1 -1
- package/dist/esm/queryValidation.js +1 -2
- package/dist/esm/queryValidation.js.map +1 -1
- package/dist/esm/schema.js +8 -6
- package/dist/esm/schema.js.map +1 -1
- package/dist/esm/schemaTypes.js +22 -3
- package/dist/esm/schemaTypes.js.map +1 -1
- package/dist/esm/store.js +29 -38
- package/dist/esm/store.js.map +1 -1
- package/dist/esm/transactionValidation.js +1 -2
- package/dist/esm/transactionValidation.js.map +1 -1
- package/dist/esm/utils/Deferred.js +3 -0
- package/dist/esm/utils/Deferred.js.map +1 -1
- package/dist/esm/utils/PersistedObject.js +216 -233
- package/dist/esm/utils/PersistedObject.js.map +1 -1
- package/dist/esm/utils/fetch.js +9 -19
- package/dist/esm/utils/fetch.js.map +1 -1
- package/dist/esm/utils/linkIndex.js +2 -4
- package/dist/esm/utils/linkIndex.js.map +1 -1
- package/dist/esm/utils/object.js +1 -1
- package/dist/esm/utils/object.js.map +1 -1
- package/dist/standalone/index.js +2610 -2367
- package/dist/standalone/index.umd.cjs +3 -3
- package/package.json +2 -2
- package/src/framework.ts +0 -1
|
@@ -13,15 +13,6 @@
|
|
|
13
13
|
// Each PersistedObject provides it's own `onMerge`
|
|
14
14
|
// function to handle the merge of data from storage and memory
|
|
15
15
|
// on load
|
|
16
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
17
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
18
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
19
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
20
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
21
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
22
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23
|
-
});
|
|
24
|
-
};
|
|
25
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
17
|
exports.PersistedObject = exports.StorageInterface = exports.META_KEY = void 0;
|
|
27
18
|
// Uses `requestIdleCallback` if available, otherwise calls the
|
|
@@ -41,29 +32,40 @@ class StorageInterface {
|
|
|
41
32
|
}
|
|
42
33
|
exports.StorageInterface = StorageInterface;
|
|
43
34
|
class PersistedObject {
|
|
35
|
+
currentValue;
|
|
36
|
+
_subs = [];
|
|
37
|
+
_persister;
|
|
38
|
+
_merge;
|
|
39
|
+
serialize;
|
|
40
|
+
parse;
|
|
41
|
+
_saveThrottleMs;
|
|
42
|
+
_idleCallbackMaxWaitMs;
|
|
43
|
+
_nextSave = null;
|
|
44
|
+
_nextGc = null;
|
|
45
|
+
_pendingSaveKeys = new Set();
|
|
46
|
+
_loadedKeys = new Set();
|
|
47
|
+
_loadingKeys;
|
|
48
|
+
_objectSize;
|
|
49
|
+
_log;
|
|
50
|
+
onKeyLoaded;
|
|
51
|
+
_version = 0;
|
|
52
|
+
_meta = {
|
|
53
|
+
isLoading: true,
|
|
54
|
+
onLoadCbs: [],
|
|
55
|
+
value: null,
|
|
56
|
+
error: null,
|
|
57
|
+
attempts: 0,
|
|
58
|
+
};
|
|
59
|
+
_gcOpts;
|
|
44
60
|
constructor(opts) {
|
|
45
|
-
var _a, _b;
|
|
46
|
-
this._subs = [];
|
|
47
|
-
this._nextSave = null;
|
|
48
|
-
this._nextGc = null;
|
|
49
|
-
this._pendingSaveKeys = new Set();
|
|
50
|
-
this._loadedKeys = new Set();
|
|
51
|
-
this._version = 0;
|
|
52
|
-
this._meta = {
|
|
53
|
-
isLoading: true,
|
|
54
|
-
onLoadCbs: [],
|
|
55
|
-
value: null,
|
|
56
|
-
error: null,
|
|
57
|
-
attempts: 0,
|
|
58
|
-
};
|
|
59
61
|
this._persister = opts.persister;
|
|
60
62
|
this._merge = opts.merge;
|
|
61
63
|
this.serialize = opts.serialize;
|
|
62
64
|
this.parse = opts.parse;
|
|
63
65
|
this._objectSize = opts.objectSize;
|
|
64
66
|
this._log = opts.logger;
|
|
65
|
-
this._saveThrottleMs =
|
|
66
|
-
this._idleCallbackMaxWaitMs =
|
|
67
|
+
this._saveThrottleMs = opts.saveThrottleMs ?? 100;
|
|
68
|
+
this._idleCallbackMaxWaitMs = opts.idleCallbackMaxWaitMs ?? 1000;
|
|
67
69
|
this._gcOpts = opts.gc;
|
|
68
70
|
this.currentValue = {};
|
|
69
71
|
this._loadedKeys = new Set();
|
|
@@ -73,97 +75,85 @@ class PersistedObject {
|
|
|
73
75
|
this._preloadEntries(opts.preloadEntryCount);
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
|
-
_initMeta() {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
78
|
+
async _initMeta() {
|
|
79
|
+
if (this._meta.loadingPromise) {
|
|
80
|
+
await this._meta.loadingPromise;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const p = this._persister.getItem(exports.META_KEY);
|
|
84
|
+
this._meta.loadingPromise = p;
|
|
85
|
+
const v = await p;
|
|
86
|
+
this._meta.isLoading = false;
|
|
87
|
+
this._meta.error = null;
|
|
88
|
+
this._meta.loadingPromise = null;
|
|
89
|
+
this._meta.attempts = 0;
|
|
90
|
+
const existingObjects = this._meta.value?.objects ?? {};
|
|
91
|
+
const value = v ?? {};
|
|
92
|
+
const objects = value.objects ?? {};
|
|
93
|
+
// Merge the values from storage with in-memory values
|
|
94
|
+
this._meta.value = {
|
|
95
|
+
...value,
|
|
96
|
+
objects: { ...existingObjects, ...objects },
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
this._meta.error = e;
|
|
101
|
+
this._meta.attempts++;
|
|
102
|
+
this._meta.loadingPromise = null;
|
|
103
|
+
}
|
|
102
104
|
}
|
|
103
|
-
_getMeta() {
|
|
104
|
-
|
|
105
|
-
if (this._meta.value) {
|
|
106
|
-
return this._meta.value;
|
|
107
|
-
}
|
|
108
|
-
if (this._meta.loadingPromise) {
|
|
109
|
-
yield this._meta.loadingPromise;
|
|
110
|
-
return this._meta.value;
|
|
111
|
-
}
|
|
112
|
-
this._initMeta();
|
|
113
|
-
yield this._meta.loadingPromise;
|
|
105
|
+
async _getMeta() {
|
|
106
|
+
if (this._meta.value) {
|
|
114
107
|
return this._meta.value;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
-
yield this._initMeta();
|
|
108
|
+
}
|
|
109
|
+
if (this._meta.loadingPromise) {
|
|
110
|
+
await this._meta.loadingPromise;
|
|
120
111
|
return this._meta.value;
|
|
121
|
-
}
|
|
112
|
+
}
|
|
113
|
+
this._initMeta();
|
|
114
|
+
await this._meta.loadingPromise;
|
|
115
|
+
return this._meta.value;
|
|
122
116
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (!meta)
|
|
127
|
-
return;
|
|
128
|
-
const entries = Object.entries(meta.objects);
|
|
129
|
-
entries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
130
|
-
return b_meta.updatedAt - a_meta.updatedAt;
|
|
131
|
-
});
|
|
132
|
-
for (const [k] of entries.slice(0, n)) {
|
|
133
|
-
this._loadKey(k);
|
|
134
|
-
}
|
|
135
|
-
});
|
|
117
|
+
async _refreshMeta() {
|
|
118
|
+
await this._initMeta();
|
|
119
|
+
return this._meta.value;
|
|
136
120
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const parsed = this.parse(key, data);
|
|
145
|
-
return parsed;
|
|
146
|
-
}
|
|
147
|
-
catch (e) {
|
|
148
|
-
console.error(`Unable to read from storage for key=${key}`, e);
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
121
|
+
async _preloadEntries(n) {
|
|
122
|
+
const meta = await this.waitForMetaToLoad();
|
|
123
|
+
if (!meta)
|
|
124
|
+
return;
|
|
125
|
+
const entries = Object.entries(meta.objects);
|
|
126
|
+
entries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
127
|
+
return b_meta.updatedAt - a_meta.updatedAt;
|
|
151
128
|
});
|
|
129
|
+
for (const [k] of entries.slice(0, n)) {
|
|
130
|
+
this._loadKey(k);
|
|
131
|
+
}
|
|
152
132
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
133
|
+
async _getFromStorage(key) {
|
|
134
|
+
try {
|
|
135
|
+
const data = await this._persister.getItem(key);
|
|
136
|
+
if (!data) {
|
|
137
|
+
return data;
|
|
157
138
|
}
|
|
158
|
-
|
|
139
|
+
const parsed = this.parse(key, data);
|
|
140
|
+
return parsed;
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
console.error(`Unable to read from storage for key=${key}`, e);
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async waitForKeyToLoad(k) {
|
|
148
|
+
if (this._loadedKeys.has(k)) {
|
|
159
149
|
return this.currentValue[k];
|
|
160
|
-
}
|
|
150
|
+
}
|
|
151
|
+
await (this._loadingKeys[k] || this._loadKey(k));
|
|
152
|
+
return this.currentValue[k];
|
|
161
153
|
}
|
|
162
154
|
// Used for tests
|
|
163
|
-
waitForMetaToLoad() {
|
|
164
|
-
return
|
|
165
|
-
return this._getMeta();
|
|
166
|
-
});
|
|
155
|
+
async waitForMetaToLoad() {
|
|
156
|
+
return this._getMeta();
|
|
167
157
|
}
|
|
168
158
|
// Unloads the key so that it can be garbage collected, but does not
|
|
169
159
|
// delete it. Removes the key from currentValue.
|
|
@@ -172,41 +162,38 @@ class PersistedObject {
|
|
|
172
162
|
delete this._loadingKeys[k];
|
|
173
163
|
delete this.currentValue[k];
|
|
174
164
|
}
|
|
175
|
-
_loadKey(k) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
this.currentValue[k] = merged;
|
|
188
|
-
}
|
|
165
|
+
async _loadKey(k) {
|
|
166
|
+
if (this._loadedKeys.has(k) || k in this._loadingKeys)
|
|
167
|
+
return;
|
|
168
|
+
const p = this._getFromStorage(k);
|
|
169
|
+
this._loadingKeys[k] = p;
|
|
170
|
+
const value = await p;
|
|
171
|
+
delete this._loadingKeys[k];
|
|
172
|
+
this._loadedKeys.add(k);
|
|
173
|
+
if (value) {
|
|
174
|
+
const merged = this._merge(k, value, this.currentValue[k]);
|
|
175
|
+
if (merged) {
|
|
176
|
+
this.currentValue[k] = merged;
|
|
189
177
|
}
|
|
190
|
-
|
|
191
|
-
|
|
178
|
+
}
|
|
179
|
+
this.onKeyLoaded && this.onKeyLoaded(k);
|
|
192
180
|
}
|
|
193
181
|
// Returns a promise with a number so that we can wait for flush
|
|
194
182
|
// to finish in the tests. The number is the number of operations
|
|
195
183
|
// it performed, but it's mostly there so that typescript will warn
|
|
196
184
|
// us if we forget to retun the promise from the function.
|
|
197
185
|
_writeToStorage(opts) {
|
|
198
|
-
var _a, _b;
|
|
199
186
|
const promises = [];
|
|
200
|
-
const skipGc = opts
|
|
187
|
+
const skipGc = opts?.skipGc;
|
|
201
188
|
if (this._meta.isLoading) {
|
|
202
189
|
// Wait for meta to load and try again, give it a delay so that
|
|
203
190
|
// we don't spend too much time retrying
|
|
204
191
|
const p = new Promise((resolve, reject) => {
|
|
205
|
-
var _a;
|
|
206
192
|
setTimeout(() => this._enqueuePersist(opts
|
|
207
|
-
?
|
|
193
|
+
? { ...opts, attempts: (opts.attempts || 0) + 1 }
|
|
194
|
+
: { attempts: 1 })
|
|
208
195
|
.then(resolve)
|
|
209
|
-
.catch(reject), 10 + (
|
|
196
|
+
.catch(reject), 10 + (opts?.attempts ?? 0) * 1000);
|
|
210
197
|
});
|
|
211
198
|
promises.push(p);
|
|
212
199
|
return Promise.all(promises).then((vs) => vs.reduce((acc, x) => acc + x, 0));
|
|
@@ -237,14 +224,14 @@ class PersistedObject {
|
|
|
237
224
|
}
|
|
238
225
|
const keysToLoad = [];
|
|
239
226
|
const kvPairs = [[exports.META_KEY, metaValue]];
|
|
240
|
-
const metaObjects =
|
|
227
|
+
const metaObjects = metaValue.objects ?? {};
|
|
241
228
|
metaValue.objects = metaObjects;
|
|
242
229
|
for (const k of keysToUpdate) {
|
|
243
230
|
if (this._loadedKeys.has(k)) {
|
|
244
231
|
const serializedV = this.serialize(k, this.currentValue[k]);
|
|
245
232
|
kvPairs.push([k, serializedV]);
|
|
246
233
|
const size = this._objectSize(serializedV);
|
|
247
|
-
const m =
|
|
234
|
+
const m = metaObjects[k] ?? {
|
|
248
235
|
createdAt: Date.now(),
|
|
249
236
|
updatedAt: Date.now(),
|
|
250
237
|
size,
|
|
@@ -275,119 +262,115 @@ class PersistedObject {
|
|
|
275
262
|
return vs.reduce((acc, x) => acc + x, 0);
|
|
276
263
|
});
|
|
277
264
|
}
|
|
278
|
-
flush() {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
return p;
|
|
287
|
-
});
|
|
265
|
+
async flush() {
|
|
266
|
+
if (!this._nextSave) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
clearTimeout(this._nextSave);
|
|
270
|
+
this._nextSave = null;
|
|
271
|
+
const p = this._writeToStorage();
|
|
272
|
+
return p;
|
|
288
273
|
}
|
|
289
|
-
_gc() {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
continue;
|
|
327
|
-
}
|
|
328
|
-
this._log.info('Lost track of key in meta', key);
|
|
329
|
-
promises.push(this._persister.removeItem(key));
|
|
330
|
-
deets.removed.push(key);
|
|
331
|
-
deets.removedMissingCount++;
|
|
332
|
-
}
|
|
333
|
-
// Remove anything over the max age
|
|
334
|
-
const now = Date.now();
|
|
335
|
-
for (const [k, m] of Object.entries(meta.objects)) {
|
|
336
|
-
if (!sacredKeys.has(k) &&
|
|
337
|
-
m.updatedAt < now - this._gcOpts.maxAgeMs) {
|
|
338
|
-
promises.push(this._persister.removeItem(k));
|
|
339
|
-
delete meta.objects[k];
|
|
340
|
-
deets.removed.push(k);
|
|
341
|
-
deets.removedOldCount++;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
// Keep queries under max queries
|
|
345
|
-
const maxEntries = Object.entries(meta.objects);
|
|
346
|
-
maxEntries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
347
|
-
return a_meta.updatedAt - b_meta.updatedAt;
|
|
348
|
-
});
|
|
349
|
-
const deletableMaxEntries = maxEntries.filter(([x]) => !sacredKeys.has(x));
|
|
350
|
-
if (maxEntries.length > this._gcOpts.maxEntries) {
|
|
351
|
-
for (const [k] of deletableMaxEntries.slice(0, maxEntries.length - this._gcOpts.maxEntries)) {
|
|
352
|
-
promises.push(this._persister.removeItem(k));
|
|
353
|
-
delete meta.objects[k];
|
|
354
|
-
deets.removed.push(k);
|
|
355
|
-
deets.removedThresholdCount++;
|
|
356
|
-
}
|
|
274
|
+
async _gc() {
|
|
275
|
+
if (!this._gcOpts) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const keys = new Set(await this._persister.getAllKeys());
|
|
279
|
+
keys.delete(exports.META_KEY);
|
|
280
|
+
// Keys we can't delete
|
|
281
|
+
const sacredKeys = new Set(Object.keys(this.currentValue));
|
|
282
|
+
for (const k of Object.keys(this._loadingKeys)) {
|
|
283
|
+
sacredKeys.add(k);
|
|
284
|
+
}
|
|
285
|
+
for (const k of this._loadedKeys) {
|
|
286
|
+
sacredKeys.add(k);
|
|
287
|
+
}
|
|
288
|
+
// Refresh meta from the store so that we're less likely to
|
|
289
|
+
// clobber data from other tabs
|
|
290
|
+
const meta = await this._refreshMeta();
|
|
291
|
+
if (!meta) {
|
|
292
|
+
this._log.info('Could not gc because we were not able to load meta');
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const promises = [];
|
|
296
|
+
const deets = {
|
|
297
|
+
gcOpts: this._gcOpts,
|
|
298
|
+
keys,
|
|
299
|
+
sacredKeys,
|
|
300
|
+
removed: [],
|
|
301
|
+
metaRemoved: [],
|
|
302
|
+
removedMissingCount: 0,
|
|
303
|
+
removedOldCount: 0,
|
|
304
|
+
removedThresholdCount: 0,
|
|
305
|
+
removedSizeCount: 0,
|
|
306
|
+
};
|
|
307
|
+
// First, remove all keys we don't know about
|
|
308
|
+
for (const key of keys) {
|
|
309
|
+
if (sacredKeys.has(key) || key in meta.objects) {
|
|
310
|
+
continue;
|
|
357
311
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
currentSize > this._gcOpts.maxSize &&
|
|
369
|
-
deletableDelEntries.length) {
|
|
370
|
-
const [[k, m]] = deletableDelEntries.splice(0, 1);
|
|
371
|
-
currentSize -= m.size;
|
|
312
|
+
this._log.info('Lost track of key in meta', key);
|
|
313
|
+
promises.push(this._persister.removeItem(key));
|
|
314
|
+
deets.removed.push(key);
|
|
315
|
+
deets.removedMissingCount++;
|
|
316
|
+
}
|
|
317
|
+
// Remove anything over the max age
|
|
318
|
+
const now = Date.now();
|
|
319
|
+
for (const [k, m] of Object.entries(meta.objects)) {
|
|
320
|
+
if (!sacredKeys.has(k) &&
|
|
321
|
+
m.updatedAt < now - this._gcOpts.maxAgeMs) {
|
|
372
322
|
promises.push(this._persister.removeItem(k));
|
|
373
323
|
delete meta.objects[k];
|
|
374
324
|
deets.removed.push(k);
|
|
375
|
-
deets.
|
|
325
|
+
deets.removedOldCount++;
|
|
376
326
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
327
|
+
}
|
|
328
|
+
// Keep queries under max queries
|
|
329
|
+
const maxEntries = Object.entries(meta.objects);
|
|
330
|
+
maxEntries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
331
|
+
return a_meta.updatedAt - b_meta.updatedAt;
|
|
332
|
+
});
|
|
333
|
+
const deletableMaxEntries = maxEntries.filter(([x]) => !sacredKeys.has(x));
|
|
334
|
+
if (maxEntries.length > this._gcOpts.maxEntries) {
|
|
335
|
+
for (const [k] of deletableMaxEntries.slice(0, maxEntries.length - this._gcOpts.maxEntries)) {
|
|
336
|
+
promises.push(this._persister.removeItem(k));
|
|
337
|
+
delete meta.objects[k];
|
|
338
|
+
deets.removed.push(k);
|
|
339
|
+
deets.removedThresholdCount++;
|
|
386
340
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
341
|
+
}
|
|
342
|
+
// Remove oldest entries until we are under max size
|
|
343
|
+
const delEntries = Object.entries(meta.objects);
|
|
344
|
+
delEntries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
345
|
+
return a_meta.updatedAt - b_meta.updatedAt;
|
|
390
346
|
});
|
|
347
|
+
const deletableDelEntries = delEntries.filter(([x]) => !sacredKeys.has(x));
|
|
348
|
+
let currentSize = delEntries.reduce((acc, [_k, m]) => {
|
|
349
|
+
return acc + m.size;
|
|
350
|
+
}, 0);
|
|
351
|
+
while (currentSize > 0 &&
|
|
352
|
+
currentSize > this._gcOpts.maxSize &&
|
|
353
|
+
deletableDelEntries.length) {
|
|
354
|
+
const [[k, m]] = deletableDelEntries.splice(0, 1);
|
|
355
|
+
currentSize -= m.size;
|
|
356
|
+
promises.push(this._persister.removeItem(k));
|
|
357
|
+
delete meta.objects[k];
|
|
358
|
+
deets.removed.push(k);
|
|
359
|
+
deets.removedSizeCount++;
|
|
360
|
+
}
|
|
361
|
+
// Update meta to remove keys that are no longer in the store
|
|
362
|
+
for (const k of Object.keys(meta.objects)) {
|
|
363
|
+
if (!keys.has(k) && !sacredKeys.has(k)) {
|
|
364
|
+
delete meta.objects[k];
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (deets.removed.length || deets.metaRemoved.length) {
|
|
368
|
+
// Trigger a flush of the meta
|
|
369
|
+
promises.push(this._enqueuePersist({ skipGc: true }));
|
|
370
|
+
}
|
|
371
|
+
this._log.info('Completed GC', deets);
|
|
372
|
+
await Promise.all(promises);
|
|
373
|
+
return deets;
|
|
391
374
|
}
|
|
392
375
|
// Schedules a GC to run in one minute (unless it is already scheduled)
|
|
393
376
|
gc() {
|