@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.
Files changed (126) hide show
  1. package/dist/commonjs/Connection.js +50 -51
  2. package/dist/commonjs/Connection.js.map +1 -1
  3. package/dist/commonjs/InMemoryStorage.js +13 -32
  4. package/dist/commonjs/InMemoryStorage.js.map +1 -1
  5. package/dist/commonjs/IndexedDBStorage.js +193 -217
  6. package/dist/commonjs/IndexedDBStorage.js.map +1 -1
  7. package/dist/commonjs/InstantError.js +1 -0
  8. package/dist/commonjs/InstantError.js.map +1 -1
  9. package/dist/commonjs/Reactor.js +566 -610
  10. package/dist/commonjs/Reactor.js.map +1 -1
  11. package/dist/commonjs/StorageAPI.js +51 -70
  12. package/dist/commonjs/StorageAPI.js.map +1 -1
  13. package/dist/commonjs/SyncTable.js +68 -81
  14. package/dist/commonjs/SyncTable.js.map +1 -1
  15. package/dist/commonjs/WindowNetworkListener.js +2 -13
  16. package/dist/commonjs/WindowNetworkListener.js.map +1 -1
  17. package/dist/commonjs/__types__/fieldsTypeTest.js +8 -16
  18. package/dist/commonjs/__types__/fieldsTypeTest.js.map +1 -1
  19. package/dist/commonjs/__types__/useDatesTypeTest.js +3 -6
  20. package/dist/commonjs/__types__/useDatesTypeTest.js.map +1 -1
  21. package/dist/commonjs/authAPI.js +62 -79
  22. package/dist/commonjs/authAPI.js.map +1 -1
  23. package/dist/commonjs/createRouteHandler.js +5 -15
  24. package/dist/commonjs/createRouteHandler.js.map +1 -1
  25. package/dist/commonjs/datalog.js +1 -1
  26. package/dist/commonjs/datalog.js.map +1 -1
  27. package/dist/commonjs/devtool.js +26 -8
  28. package/dist/commonjs/devtool.js.map +1 -1
  29. package/dist/commonjs/framework.d.ts.map +1 -1
  30. package/dist/commonjs/framework.js +142 -152
  31. package/dist/commonjs/framework.js.map +1 -1
  32. package/dist/commonjs/index.js +204 -190
  33. package/dist/commonjs/index.js.map +1 -1
  34. package/dist/commonjs/instaml.js +44 -30
  35. package/dist/commonjs/instaml.js.map +1 -1
  36. package/dist/commonjs/instaql.js +25 -33
  37. package/dist/commonjs/instaql.js.map +1 -1
  38. package/dist/commonjs/parseSchemaFromJSON.js +6 -7
  39. package/dist/commonjs/parseSchemaFromJSON.js.map +1 -1
  40. package/dist/commonjs/presence.js +7 -8
  41. package/dist/commonjs/presence.js.map +1 -1
  42. package/dist/commonjs/queryValidation.js +1 -2
  43. package/dist/commonjs/queryValidation.js.map +1 -1
  44. package/dist/commonjs/schema.js +8 -6
  45. package/dist/commonjs/schema.js.map +1 -1
  46. package/dist/commonjs/schemaTypes.js +22 -3
  47. package/dist/commonjs/schemaTypes.js.map +1 -1
  48. package/dist/commonjs/store.js +29 -38
  49. package/dist/commonjs/store.js.map +1 -1
  50. package/dist/commonjs/transactionValidation.js +1 -2
  51. package/dist/commonjs/transactionValidation.js.map +1 -1
  52. package/dist/commonjs/utils/Deferred.js +3 -0
  53. package/dist/commonjs/utils/Deferred.js.map +1 -1
  54. package/dist/commonjs/utils/PersistedObject.js +216 -233
  55. package/dist/commonjs/utils/PersistedObject.js.map +1 -1
  56. package/dist/commonjs/utils/fetch.js +9 -19
  57. package/dist/commonjs/utils/fetch.js.map +1 -1
  58. package/dist/commonjs/utils/linkIndex.js +2 -4
  59. package/dist/commonjs/utils/linkIndex.js.map +1 -1
  60. package/dist/commonjs/utils/object.js +1 -1
  61. package/dist/commonjs/utils/object.js.map +1 -1
  62. package/dist/esm/Connection.js +50 -51
  63. package/dist/esm/Connection.js.map +1 -1
  64. package/dist/esm/InMemoryStorage.js +13 -32
  65. package/dist/esm/InMemoryStorage.js.map +1 -1
  66. package/dist/esm/IndexedDBStorage.js +193 -217
  67. package/dist/esm/IndexedDBStorage.js.map +1 -1
  68. package/dist/esm/InstantError.js +1 -0
  69. package/dist/esm/InstantError.js.map +1 -1
  70. package/dist/esm/Reactor.js +566 -610
  71. package/dist/esm/Reactor.js.map +1 -1
  72. package/dist/esm/StorageAPI.js +51 -70
  73. package/dist/esm/StorageAPI.js.map +1 -1
  74. package/dist/esm/SyncTable.js +68 -81
  75. package/dist/esm/SyncTable.js.map +1 -1
  76. package/dist/esm/WindowNetworkListener.js +2 -13
  77. package/dist/esm/WindowNetworkListener.js.map +1 -1
  78. package/dist/esm/__types__/fieldsTypeTest.js +8 -16
  79. package/dist/esm/__types__/fieldsTypeTest.js.map +1 -1
  80. package/dist/esm/__types__/useDatesTypeTest.js +3 -6
  81. package/dist/esm/__types__/useDatesTypeTest.js.map +1 -1
  82. package/dist/esm/authAPI.js +62 -79
  83. package/dist/esm/authAPI.js.map +1 -1
  84. package/dist/esm/createRouteHandler.js +5 -15
  85. package/dist/esm/createRouteHandler.js.map +1 -1
  86. package/dist/esm/datalog.js +1 -1
  87. package/dist/esm/datalog.js.map +1 -1
  88. package/dist/esm/devtool.js +26 -8
  89. package/dist/esm/devtool.js.map +1 -1
  90. package/dist/esm/framework.d.ts.map +1 -1
  91. package/dist/esm/framework.js +142 -152
  92. package/dist/esm/framework.js.map +1 -1
  93. package/dist/esm/index.js +204 -190
  94. package/dist/esm/index.js.map +1 -1
  95. package/dist/esm/instaml.js +44 -30
  96. package/dist/esm/instaml.js.map +1 -1
  97. package/dist/esm/instaql.js +25 -33
  98. package/dist/esm/instaql.js.map +1 -1
  99. package/dist/esm/parseSchemaFromJSON.js +6 -7
  100. package/dist/esm/parseSchemaFromJSON.js.map +1 -1
  101. package/dist/esm/presence.js +7 -8
  102. package/dist/esm/presence.js.map +1 -1
  103. package/dist/esm/queryValidation.js +1 -2
  104. package/dist/esm/queryValidation.js.map +1 -1
  105. package/dist/esm/schema.js +8 -6
  106. package/dist/esm/schema.js.map +1 -1
  107. package/dist/esm/schemaTypes.js +22 -3
  108. package/dist/esm/schemaTypes.js.map +1 -1
  109. package/dist/esm/store.js +29 -38
  110. package/dist/esm/store.js.map +1 -1
  111. package/dist/esm/transactionValidation.js +1 -2
  112. package/dist/esm/transactionValidation.js.map +1 -1
  113. package/dist/esm/utils/Deferred.js +3 -0
  114. package/dist/esm/utils/Deferred.js.map +1 -1
  115. package/dist/esm/utils/PersistedObject.js +216 -233
  116. package/dist/esm/utils/PersistedObject.js.map +1 -1
  117. package/dist/esm/utils/fetch.js +9 -19
  118. package/dist/esm/utils/fetch.js.map +1 -1
  119. package/dist/esm/utils/linkIndex.js +2 -4
  120. package/dist/esm/utils/linkIndex.js.map +1 -1
  121. package/dist/esm/utils/object.js +1 -1
  122. package/dist/esm/utils/object.js.map +1 -1
  123. package/dist/standalone/index.js +2610 -2367
  124. package/dist/standalone/index.umd.cjs +3 -3
  125. package/package.json +2 -2
  126. 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 = (_a = opts.saveThrottleMs) !== null && _a !== void 0 ? _a : 100;
66
- this._idleCallbackMaxWaitMs = (_b = opts.idleCallbackMaxWaitMs) !== null && _b !== void 0 ? _b : 1000;
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
- return __awaiter(this, void 0, void 0, function* () {
78
- var _a, _b, _c;
79
- if (this._meta.loadingPromise) {
80
- yield this._meta.loadingPromise;
81
- }
82
- try {
83
- const p = this._persister.getItem(exports.META_KEY);
84
- this._meta.loadingPromise = p;
85
- const v = yield p;
86
- this._meta.isLoading = false;
87
- this._meta.error = null;
88
- this._meta.loadingPromise = null;
89
- this._meta.attempts = 0;
90
- const existingObjects = (_b = (_a = this._meta.value) === null || _a === void 0 ? void 0 : _a.objects) !== null && _b !== void 0 ? _b : {};
91
- const value = v !== null && v !== void 0 ? v : {};
92
- const objects = (_c = value.objects) !== null && _c !== void 0 ? _c : {};
93
- // Merge the values from storage with in-memory values
94
- this._meta.value = Object.assign(Object.assign({}, value), { objects: Object.assign(Object.assign({}, existingObjects), objects) });
95
- }
96
- catch (e) {
97
- this._meta.error = e;
98
- this._meta.attempts++;
99
- this._meta.loadingPromise = null;
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
- return __awaiter(this, void 0, void 0, function* () {
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
- _refreshMeta() {
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
- _preloadEntries(n) {
124
- return __awaiter(this, void 0, void 0, function* () {
125
- const meta = yield this.waitForMetaToLoad();
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
- _getFromStorage(key) {
138
- return __awaiter(this, void 0, void 0, function* () {
139
- try {
140
- const data = yield this._persister.getItem(key);
141
- if (!data) {
142
- return data;
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
- waitForKeyToLoad(k) {
154
- return __awaiter(this, void 0, void 0, function* () {
155
- if (this._loadedKeys.has(k)) {
156
- return this.currentValue[k];
133
+ async _getFromStorage(key) {
134
+ try {
135
+ const data = await this._persister.getItem(key);
136
+ if (!data) {
137
+ return data;
157
138
  }
158
- yield (this._loadingKeys[k] || this._loadKey(k));
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 __awaiter(this, void 0, void 0, function* () {
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
- return __awaiter(this, void 0, void 0, function* () {
177
- if (this._loadedKeys.has(k) || k in this._loadingKeys)
178
- return;
179
- const p = this._getFromStorage(k);
180
- this._loadingKeys[k] = p;
181
- const value = yield p;
182
- delete this._loadingKeys[k];
183
- this._loadedKeys.add(k);
184
- if (value) {
185
- const merged = this._merge(k, value, this.currentValue[k]);
186
- if (merged) {
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
- this.onKeyLoaded && this.onKeyLoaded(k);
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 === null || opts === void 0 ? void 0 : opts.skipGc;
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
- ? Object.assign(Object.assign({}, opts), { attempts: (opts.attempts || 0) + 1 }) : { attempts: 1 })
193
+ ? { ...opts, attempts: (opts.attempts || 0) + 1 }
194
+ : { attempts: 1 })
208
195
  .then(resolve)
209
- .catch(reject), 10 + ((_a = opts === null || opts === void 0 ? void 0 : opts.attempts) !== null && _a !== void 0 ? _a : 0) * 1000);
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 = (_a = metaValue.objects) !== null && _a !== void 0 ? _a : {};
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 = (_b = metaObjects[k]) !== null && _b !== void 0 ? _b : {
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
- return __awaiter(this, void 0, void 0, function* () {
280
- if (!this._nextSave) {
281
- return;
282
- }
283
- clearTimeout(this._nextSave);
284
- this._nextSave = null;
285
- const p = this._writeToStorage();
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
- return __awaiter(this, void 0, void 0, function* () {
291
- if (!this._gcOpts) {
292
- return;
293
- }
294
- const keys = new Set(yield this._persister.getAllKeys());
295
- keys.delete(exports.META_KEY);
296
- // Keys we can't delete
297
- const sacredKeys = new Set(Object.keys(this.currentValue));
298
- for (const k of Object.keys(this._loadingKeys)) {
299
- sacredKeys.add(k);
300
- }
301
- for (const k of this._loadedKeys) {
302
- sacredKeys.add(k);
303
- }
304
- // Refresh meta from the store so that we're less likely to
305
- // clobber data from other tabs
306
- const meta = yield this._refreshMeta();
307
- if (!meta) {
308
- this._log.info('Could not gc because we were not able to load meta');
309
- return;
310
- }
311
- const promises = [];
312
- const deets = {
313
- gcOpts: this._gcOpts,
314
- keys,
315
- sacredKeys,
316
- removed: [],
317
- metaRemoved: [],
318
- removedMissingCount: 0,
319
- removedOldCount: 0,
320
- removedThresholdCount: 0,
321
- removedSizeCount: 0,
322
- };
323
- // First, remove all keys we don't know about
324
- for (const key of keys) {
325
- if (sacredKeys.has(key) || key in meta.objects) {
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
- // Remove oldest entries until we are under max size
359
- const delEntries = Object.entries(meta.objects);
360
- delEntries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
361
- return a_meta.updatedAt - b_meta.updatedAt;
362
- });
363
- const deletableDelEntries = delEntries.filter(([x]) => !sacredKeys.has(x));
364
- let currentSize = delEntries.reduce((acc, [_k, m]) => {
365
- return acc + m.size;
366
- }, 0);
367
- while (currentSize > 0 &&
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.removedSizeCount++;
325
+ deets.removedOldCount++;
376
326
  }
377
- // Update meta to remove keys that are no longer in the store
378
- for (const k of Object.keys(meta.objects)) {
379
- if (!keys.has(k) && !sacredKeys.has(k)) {
380
- delete meta.objects[k];
381
- }
382
- }
383
- if (deets.removed.length || deets.metaRemoved.length) {
384
- // Trigger a flush of the meta
385
- promises.push(this._enqueuePersist({ skipGc: true }));
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
- this._log.info('Completed GC', deets);
388
- yield Promise.all(promises);
389
- return deets;
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() {