@verdant-web/store 3.7.0 → 3.8.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 (64) hide show
  1. package/LICENSE +650 -21
  2. package/dist/bundle/index.js +12 -12
  3. package/dist/bundle/index.js.map +4 -4
  4. package/dist/esm/DocumentManager.d.ts +1 -0
  5. package/dist/esm/DocumentManager.js +8 -3
  6. package/dist/esm/DocumentManager.js.map +1 -1
  7. package/dist/esm/__tests__/documents.test.js +16 -0
  8. package/dist/esm/__tests__/documents.test.js.map +1 -1
  9. package/dist/esm/client/Client.d.ts +3 -3
  10. package/dist/esm/client/Client.js +5 -5
  11. package/dist/esm/client/Client.js.map +1 -1
  12. package/dist/esm/client/ClientDescriptor.d.ts +1 -0
  13. package/dist/esm/client/ClientDescriptor.js +6 -3
  14. package/dist/esm/client/ClientDescriptor.js.map +1 -1
  15. package/dist/esm/context.d.ts +1 -0
  16. package/dist/esm/entities/EntityStore.d.ts +3 -3
  17. package/dist/esm/entities/EntityStore.js +5 -0
  18. package/dist/esm/entities/EntityStore.js.map +1 -1
  19. package/dist/esm/idb.d.ts +6 -0
  20. package/dist/esm/idb.js +17 -1
  21. package/dist/esm/idb.js.map +1 -1
  22. package/dist/esm/migration/db.d.ts +9 -3
  23. package/dist/esm/migration/db.js +23 -11
  24. package/dist/esm/migration/db.js.map +1 -1
  25. package/dist/esm/migration/engine.d.ts +15 -0
  26. package/dist/esm/migration/engine.js +159 -0
  27. package/dist/esm/migration/engine.js.map +1 -0
  28. package/dist/esm/migration/migrations.d.ts +17 -0
  29. package/dist/esm/migration/migrations.js +242 -0
  30. package/dist/esm/migration/migrations.js.map +1 -0
  31. package/dist/esm/migration/openQueryDatabase.d.ts +10 -0
  32. package/dist/esm/migration/openQueryDatabase.js +27 -0
  33. package/dist/esm/migration/openQueryDatabase.js.map +1 -0
  34. package/dist/esm/migration/openWIPDatabase.d.ts +11 -0
  35. package/dist/esm/migration/openWIPDatabase.js +65 -0
  36. package/dist/esm/migration/openWIPDatabase.js.map +1 -0
  37. package/dist/esm/migration/types.d.ts +3 -0
  38. package/dist/esm/migration/types.js +2 -0
  39. package/dist/esm/migration/types.js.map +1 -0
  40. package/dist/esm/queries/QueryableStorage.js +1 -1
  41. package/dist/esm/queries/QueryableStorage.js.map +1 -1
  42. package/dist/esm/sync/PushPullSync.d.ts +3 -2
  43. package/dist/esm/sync/PushPullSync.js +7 -1
  44. package/dist/esm/sync/PushPullSync.js.map +1 -1
  45. package/package.json +4 -3
  46. package/src/DocumentManager.ts +11 -2
  47. package/src/__tests__/documents.test.ts +19 -0
  48. package/src/client/Client.ts +6 -8
  49. package/src/client/ClientDescriptor.ts +7 -6
  50. package/src/context.ts +1 -0
  51. package/src/entities/EntityStore.ts +8 -2
  52. package/src/idb.ts +20 -1
  53. package/src/migration/db.ts +62 -20
  54. package/src/migration/engine.ts +248 -0
  55. package/src/migration/migrations.ts +347 -0
  56. package/src/migration/openQueryDatabase.ts +63 -0
  57. package/src/migration/openWIPDatabase.ts +97 -0
  58. package/src/migration/types.ts +4 -0
  59. package/src/queries/QueryableStorage.ts +1 -1
  60. package/src/sync/PushPullSync.ts +10 -0
  61. package/dist/esm/migration/openDatabase.d.ts +0 -20
  62. package/dist/esm/migration/openDatabase.js +0 -463
  63. package/dist/esm/migration/openDatabase.js.map +0 -1
  64. package/src/migration/openDatabase.ts +0 -749
@@ -0,0 +1,65 @@
1
+ import { copyAll, getDatabaseVersion, openDatabase } from './db.js';
2
+ import { runMigrations } from './migrations.js';
3
+ import { getMigrationPath } from './paths.js';
4
+ const globalIDB = typeof window !== 'undefined' ? window.indexedDB : undefined;
5
+ export async function openWIPDatabase({ version, indexedDB = globalIDB, migrations, meta, context, wipNamespace, }) {
6
+ context.log('debug', 'Opening WIP database', wipNamespace);
7
+ const currentWIPVersion = await getDatabaseVersion(indexedDB, wipNamespace, version, context.log);
8
+ if (currentWIPVersion === version) {
9
+ context.log('info', `WIP schema is up-to-date; not refreshing database`);
10
+ }
11
+ else {
12
+ context.log('info', `WIP schema is out-of-date; refreshing database`);
13
+ // first we need to copy the data from the production database to the WIP database
14
+ // at the current (non-wip) version.
15
+ const initialToRun = getMigrationPath({
16
+ currentVersion: currentWIPVersion,
17
+ targetVersion: version - 1,
18
+ migrations,
19
+ });
20
+ if (initialToRun.length > 0) {
21
+ await runMigrations({
22
+ context,
23
+ toRun: initialToRun,
24
+ meta,
25
+ indexedDB,
26
+ namespace: wipNamespace,
27
+ });
28
+ // now, we copy the data from the main database.
29
+ const mainDatabase = await openDatabase({
30
+ indexedDB,
31
+ namespace: context.namespace,
32
+ version: version - 1,
33
+ context,
34
+ });
35
+ const wipDatabase = await openDatabase({
36
+ indexedDB,
37
+ namespace: wipNamespace,
38
+ version: version - 1,
39
+ context,
40
+ });
41
+ await copyAll(mainDatabase, wipDatabase);
42
+ }
43
+ const toRun = getMigrationPath({
44
+ currentVersion: version - 1,
45
+ targetVersion: version,
46
+ migrations,
47
+ });
48
+ if (toRun.length > 0) {
49
+ await runMigrations({
50
+ context,
51
+ toRun,
52
+ meta,
53
+ indexedDB,
54
+ namespace: wipNamespace,
55
+ });
56
+ }
57
+ }
58
+ return openDatabase({
59
+ indexedDB,
60
+ namespace: wipNamespace,
61
+ version,
62
+ context,
63
+ });
64
+ }
65
+ //# sourceMappingURL=openWIPDatabase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openWIPDatabase.js","sourceRoot":"","sources":["../../../src/migration/openWIPDatabase.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9C,MAAM,SAAS,GACd,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAE,SAAiB,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EACrC,OAAO,EACP,SAAS,GAAG,SAAS,EACrB,UAAU,EACV,IAAI,EACJ,OAAO,EACP,YAAY,GAQZ;IACA,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,sBAAsB,EAAE,YAAY,CAAC,CAAC;IAC3D,MAAM,iBAAiB,GAAG,MAAM,kBAAkB,CACjD,SAAS,EACT,YAAY,EACZ,OAAO,EACP,OAAO,CAAC,GAAG,CACX,CAAC;IAEF,IAAI,iBAAiB,KAAK,OAAO,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mDAAmD,CAAC,CAAC;IAC1E,CAAC;SAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gDAAgD,CAAC,CAAC;QAEtE,kFAAkF;QAClF,oCAAoC;QAEpC,MAAM,YAAY,GAAG,gBAAgB,CAAC;YACrC,cAAc,EAAE,iBAAiB;YACjC,aAAa,EAAE,OAAO,GAAG,CAAC;YAC1B,UAAU;SACV,CAAC,CAAC;QAEH,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,aAAa,CAAC;gBACnB,OAAO;gBACP,KAAK,EAAE,YAAY;gBACnB,IAAI;gBACJ,SAAS;gBACT,SAAS,EAAE,YAAY;aACvB,CAAC,CAAC;YAEH,gDAAgD;YAChD,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC;gBACvC,SAAS;gBACT,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,OAAO,EAAE,OAAO,GAAG,CAAC;gBACpB,OAAO;aACP,CAAC,CAAC;YAEH,MAAM,WAAW,GAAG,MAAM,YAAY,CAAC;gBACtC,SAAS;gBACT,SAAS,EAAE,YAAY;gBACvB,OAAO,EAAE,OAAO,GAAG,CAAC;gBACpB,OAAO;aACP,CAAC,CAAC;YACH,MAAM,OAAO,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAC1C,CAAC;QAED,MAAM,KAAK,GAAG,gBAAgB,CAAC;YAC9B,cAAc,EAAE,OAAO,GAAG,CAAC;YAC3B,aAAa,EAAE,OAAO;YACtB,UAAU;SACV,CAAC,CAAC;QAEH,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,aAAa,CAAC;gBACnB,OAAO;gBACP,KAAK;gBACL,IAAI;gBACJ,SAAS;gBACT,SAAS,EAAE,YAAY;aACvB,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED,OAAO,YAAY,CAAC;QACnB,SAAS;QACT,SAAS,EAAE,YAAY;QACvB,OAAO;QACP,OAAO;KACP,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Context } from '../context.js';
2
+ /** During migration, only a partial context is available */
3
+ export type OpenDocumentDbContext = Omit<Context, 'documentDb'>;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/migration/types.ts"],"names":[],"mappings":""}
@@ -9,7 +9,7 @@ export class QueryableStorage extends IDBService {
9
9
  */
10
10
  this.reset = async () => {
11
11
  const allCollections = Object.keys(this.ctx.schema.collections);
12
- const tx = this.ctx.documentDb.transaction(allCollections, 'readwrite');
12
+ const tx = this.createTransaction(allCollections, { mode: 'readwrite' });
13
13
  await Promise.all(allCollections.map((collection) => {
14
14
  const store = tx.objectStore(collection);
15
15
  return storeRequestPromise(store.clear());
@@ -1 +1 @@
1
- {"version":3,"file":"QueryableStorage.js","sourceRoot":"","sources":["../../../src/queries/QueryableStorage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"QueryableStorage.js","sourceRoot":"","sources":["../../../src/queries/QueryableStorage.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ClientMessage, EventSubscriber } from '@verdant-web/common';
1
+ import { ClientMessage, EventSubscriber, PresenceUpdateMessage } from '@verdant-web/common';
2
2
  import { Metadata } from '../metadata/Metadata.js';
3
3
  import { PresenceManager } from './PresenceManager.js';
4
4
  import { ServerSyncEndpointProvider } from './ServerSyncEndpointProvider.js';
@@ -26,7 +26,8 @@ export declare class PushPullSync extends EventSubscriber<SyncTransportEvents> i
26
26
  get interval(): number;
27
27
  private sendRequest;
28
28
  private handleServerMessage;
29
- send: (message: ClientMessage) => Promise<void> | undefined;
29
+ throttledPresenceUpdate: (message: PresenceUpdateMessage) => void;
30
+ send: (message: ClientMessage) => void | Promise<void>;
30
31
  start(): void;
31
32
  stop(): void;
32
33
  destroy: () => void;
@@ -1,4 +1,4 @@
1
- import { EventSubscriber, VerdantErrorCode, isVerdantErrorResponse, } from '@verdant-web/common';
1
+ import { EventSubscriber, VerdantErrorCode, isVerdantErrorResponse, throttle, } from '@verdant-web/common';
2
2
  import { Heartbeat } from './Heartbeat.js';
3
3
  export class PushPullSync extends EventSubscriber {
4
4
  constructor({ endpointProvider, meta, presence, interval = 15 * 1000, log = () => { }, fetch = window.fetch.bind(window), }) {
@@ -81,10 +81,16 @@ export class PushPullSync extends EventSubscriber {
81
81
  }
82
82
  this.emit('message', message);
83
83
  };
84
+ // reduce rate of presence messages sent; each one would trigger an HTTP
85
+ // request, which is not ideal if presence is updating rapidly.
86
+ this.throttledPresenceUpdate = throttle((message) => {
87
+ this.sendRequest([message]);
88
+ }, 3000);
84
89
  this.send = (message) => {
85
90
  // only certain messages are sent for pull-based sync.
86
91
  switch (message.type) {
87
92
  case 'presence-update':
93
+ return this.throttledPresenceUpdate(message);
88
94
  case 'sync':
89
95
  case 'heartbeat':
90
96
  return this.sendRequest([message]);
@@ -1 +1 @@
1
- {"version":3,"file":"PushPullSync.js","sourceRoot":"","sources":["../../../src/sync/PushPullSync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PushPullSync.js","sourceRoot":"","sources":["../../../src/sync/PushPullSync.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdant-web/store",
3
- "version": "3.7.0",
3
+ "version": "3.8.1",
4
4
  "access": "public",
5
5
  "type": "module",
6
6
  "exports": {
@@ -27,7 +27,7 @@
27
27
  "jwt-decode": "^3.1.2",
28
28
  "kysely": "^0.27.3",
29
29
  "weak-event": "^2.0.5",
30
- "@verdant-web/common": "2.3.2"
30
+ "@verdant-web/common": "2.3.4"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "20.10.5",
@@ -49,6 +49,7 @@
49
49
  "link": "pnpm link --global",
50
50
  "typecheck": "tsc --noEmit",
51
51
  "perf:build": "esbuild perf/perfTest.ts --bundle --format=cjs --outfile=perf/perfTest.js --sourcemap --platform=browser",
52
- "perf": "pnpm perf:build && node ./perf/run.mjs"
52
+ "perf": "pnpm perf:build && node ./perf/run.mjs",
53
+ "changeset": "cd ../../ && pnpm changeset"
53
54
  }
54
55
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  addFieldDefaults,
3
+ constrainEntity,
3
4
  assert,
4
5
  createOid,
5
6
  SchemaCollection,
@@ -45,15 +46,23 @@ export class DocumentManager<Schema extends StorageSchema<any>> {
45
46
  return addFieldDefaults(collection, init);
46
47
  };
47
48
 
49
+ private validate = (collectionName: string, init: any) => {
50
+ const collection = this.schema.collections[
51
+ collectionName
52
+ ] as StorageCollectionSchema;
53
+ return constrainEntity(collection.fields, init);
54
+ };
55
+
48
56
  create = (
49
57
  collection: string,
50
58
  init: any,
51
59
  options: { undoable?: boolean } = {},
52
60
  ) => {
53
61
  const defaulted = this.addDefaults(collection, init);
54
- const oid = this.getOid(collection, defaulted);
62
+ const validated = this.validate(collection, defaulted);
63
+ const oid = this.getOid(collection, validated);
55
64
  // documents are always objects at the root
56
- return this.entities.create(defaulted, oid, options) as any;
65
+ return this.entities.create(validated, oid, options) as any;
57
66
  };
58
67
 
59
68
  delete = async (
@@ -620,4 +620,23 @@ describe('storage documents', () => {
620
620
  await storage.weirds.delete(weird.get('id'));
621
621
  expect(true).toBe(true);
622
622
  });
623
+
624
+ it('should ignore unknown keys in initialization', async () => {
625
+ const storage = await createTestStorage();
626
+ const item = await storage.todos.put({
627
+ content: 'item',
628
+ unknown: 'key',
629
+ });
630
+
631
+ expect(item.get('content')).toBe('item');
632
+ });
633
+
634
+ it('should error on invalid values passed to initialization', async () => {
635
+ const storage = await createTestStorage();
636
+ expect(() => {
637
+ storage.todos.put({
638
+ content: { invalid: 'value' },
639
+ });
640
+ }).toThrowErrorMatchingInlineSnapshot(`[Error: Validation error: Expected string for field content, got [object Object]]`);
641
+ });
623
642
  });
@@ -1,27 +1,25 @@
1
1
  import {
2
- assert,
3
2
  debounce,
4
3
  DocumentBaseline,
5
4
  EventSubscriber,
6
5
  Migration,
7
6
  Operation,
8
- SchemaCollection,
9
7
  } from '@verdant-web/common';
10
8
  import { Context } from '../context.js';
11
9
  import { DocumentManager } from '../DocumentManager.js';
10
+ import { EntityStore } from '../entities/EntityStore.js';
12
11
  import { FileManager, FileManagerConfig } from '../files/FileManager.js';
12
+ import { ReturnedFileData } from '../files/FileStorage.js';
13
13
  import {
14
14
  closeDatabase,
15
15
  deleteAllDatabases,
16
16
  getSizeOfObjectStore,
17
17
  } from '../idb.js';
18
18
  import { ExportData, Metadata } from '../metadata/Metadata.js';
19
- import { openDocumentDatabase } from '../migration/openDatabase.js';
20
- import { EntityStore } from '../entities/EntityStore.js';
21
- import { NoSync, ServerSync, ServerSyncOptions, Sync } from '../sync/Sync.js';
19
+ import { openQueryDatabase } from '../migration/openQueryDatabase.js';
22
20
  import { CollectionQueries } from '../queries/CollectionQueries.js';
23
21
  import { QueryCache } from '../queries/QueryCache.js';
24
- import { ReturnedFileData } from '../files/FileStorage.js';
22
+ import { NoSync, ServerSync, ServerSyncOptions, Sync } from '../sync/Sync.js';
25
23
 
26
24
  interface ClientConfig<Presence = any> {
27
25
  syncConfig?: ServerSyncOptions<Presence>;
@@ -382,7 +380,7 @@ export class Client<Presence = any, Profile = any> extends EventSubscriber<{
382
380
  }
383
381
  // now open the document DB empty at the specified version
384
382
  // and initialize it from the meta DB
385
- this.context.documentDb = await openDocumentDatabase({
383
+ this.context.documentDb = await openQueryDatabase({
386
384
  meta: this.meta,
387
385
  migrations: this.config.migrations,
388
386
  context: this.context,
@@ -402,7 +400,7 @@ export class Client<Presence = any, Profile = any> extends EventSubscriber<{
402
400
  this.context.log('Migrating up to latest schema...');
403
401
  // put the schema back
404
402
  this.context.schema = currentSchema;
405
- this.context.documentDb = await openDocumentDatabase({
403
+ this.context.documentDb = await openQueryDatabase({
406
404
  meta: this.meta,
407
405
  migrations: this.config.migrations,
408
406
  context: this.context,
@@ -12,10 +12,7 @@ import {
12
12
  openMetadataDatabase,
13
13
  openWIPMetadataDatabase,
14
14
  } from '../metadata/openMetadataDatabase.js';
15
- import {
16
- openDocumentDatabase,
17
- openWIPDocumentDatabase,
18
- } from '../migration/openDatabase.js';
15
+ import { openWIPDatabase } from '../migration/openWIPDatabase.js';
19
16
  import { ServerSyncOptions } from '../sync/Sync.js';
20
17
  import { UndoHistory } from '../UndoHistory.js';
21
18
  import { Client } from './Client.js';
@@ -26,10 +23,12 @@ import {
26
23
  } from '../idb.js';
27
24
  import { FakeWeakRef } from '../FakeWeakRef.js';
28
25
  import { METADATA_VERSION_KEY } from './constants.js';
26
+ import { openQueryDatabase } from '../migration/openQueryDatabase.js';
29
27
 
30
28
  export interface ClientDescriptorOptions<Presence = any, Profile = any> {
31
29
  /** The schema used to create this client */
32
30
  schema: StorageSchema<any>;
31
+ oldSchemas?: StorageSchema<any>[];
33
32
  /** Migrations, in order, to upgrade to each successive version of the schema */
34
33
  migrations: Migration<any>[];
35
34
  /** Provide a sync config to turn on synchronization with a server */
@@ -177,6 +176,7 @@ export class ClientDescriptor<
177
176
  }
178
177
  },
179
178
  migrations: init.migrations,
179
+ oldSchemas: init.oldSchemas,
180
180
  };
181
181
  const meta = new Metadata({
182
182
  context,
@@ -191,7 +191,7 @@ export class ClientDescriptor<
191
191
  getNow: () => meta.now,
192
192
  });
193
193
 
194
- const documentDb = await openDocumentDatabase({
194
+ const documentDb = await openQueryDatabase({
195
195
  context: contextWithNow,
196
196
  version: init.schema.version,
197
197
  meta,
@@ -245,6 +245,7 @@ export class ClientDescriptor<
245
245
  }
246
246
  },
247
247
  migrations: init.migrations,
248
+ oldSchemas: init.oldSchemas,
248
249
  };
249
250
  const meta = new Metadata({
250
251
  context,
@@ -258,7 +259,7 @@ export class ClientDescriptor<
258
259
  // verify schema integrity
259
260
  await meta.updateSchema(init.schema, init.overrideSchemaConflict);
260
261
 
261
- const documentDb = await openWIPDocumentDatabase({
262
+ const documentDb = await openWIPDatabase({
262
263
  context: contextWithNow,
263
264
  version: init.schema.version,
264
265
  meta,
package/src/context.ts CHANGED
@@ -17,6 +17,7 @@ export interface Context {
17
17
  documentDb: IDBDatabase;
18
18
  undoHistory: UndoHistory;
19
19
  schema: StorageSchema;
20
+ oldSchemas?: StorageSchema[];
20
21
  log: (...args: any[]) => void;
21
22
  entityEvents: EventSubscriber<{
22
23
  collectionsChanged: (names: string[]) => void;
@@ -42,12 +42,12 @@ export type EntityStoreEvents = {
42
42
  resetAll: WeakEvent<EntityStore, void>;
43
43
  };
44
44
 
45
- type IncomingData = {
45
+ export interface IncomingData {
46
46
  operations?: Operation[];
47
47
  baselines?: DocumentBaseline[];
48
48
  reset?: boolean;
49
49
  isLocal?: boolean;
50
- };
50
+ }
51
51
 
52
52
  export class EntityStore extends Disposable {
53
53
  private ctx;
@@ -137,6 +137,12 @@ export class EntityStore extends Disposable {
137
137
  await this.processData(data);
138
138
  };
139
139
 
140
+ empty = async () => {
141
+ await this.queryableStorage.reset();
142
+ this.events.resetAll.invoke(this);
143
+ this.cache.clear();
144
+ };
145
+
140
146
  private resetData = async () => {
141
147
  if (this.disposed) {
142
148
  this.ctx.log('warn', 'EntityStore is disposed, not resetting local data');
package/src/idb.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { roughSizeOfObject } from '@verdant-web/common';
2
2
 
3
+ export const globalIDB =
4
+ typeof window !== 'undefined' ? window.indexedDB : (undefined as any);
5
+
3
6
  export function isAbortError(err: unknown) {
4
7
  return err instanceof Error && err.name === 'AbortError';
5
8
  }
@@ -109,7 +112,7 @@ export async function closeDatabase(db: IDBDatabase) {
109
112
 
110
113
  export async function deleteAllDatabases(
111
114
  namespace: string,
112
- indexedDB: IDBFactory = window.indexedDB,
115
+ indexedDB: IDBFactory = globalIDB,
113
116
  ) {
114
117
  const req1 = indexedDB.deleteDatabase([namespace, 'meta'].join('_'));
115
118
  const req2 = indexedDB.deleteDatabase([namespace, 'collections'].join('_'));
@@ -163,3 +166,19 @@ export function createAbortableTransaction(
163
166
  }
164
167
  return tx;
165
168
  }
169
+
170
+ /**
171
+ * Empties all data in a database without changing
172
+ * its structure.
173
+ */
174
+ export function emptyDatabase(db: IDBDatabase) {
175
+ const storeNames = Array.from(db.objectStoreNames);
176
+ const tx = db.transaction(storeNames, 'readwrite');
177
+ for (const storeName of storeNames) {
178
+ tx.objectStore(storeName).clear();
179
+ }
180
+ return new Promise<void>((resolve, reject) => {
181
+ tx.oncomplete = () => resolve();
182
+ tx.onerror = () => reject(tx.error);
183
+ });
184
+ }
@@ -1,3 +1,6 @@
1
+ import { closeDatabase, globalIDB, storeRequestPromise } from '../idb.js';
2
+ import { OpenDocumentDbContext } from './types.js';
3
+
1
4
  export async function getDatabaseVersion(
2
5
  indexedDB: IDBFactory,
3
6
  namespace: string,
@@ -42,12 +45,6 @@ export async function getDatabaseVersion(
42
45
  return currentVersion;
43
46
  }
44
47
 
45
- export async function closeDatabase(db: IDBDatabase) {
46
- db.close();
47
- // FIXME: this isn't right!!!!
48
- await new Promise<void>((resolve) => resolve());
49
- }
50
-
51
48
  /**
52
49
  * Upgrades the database to the given version, using the given upgrader function.
53
50
  */
@@ -61,8 +58,11 @@ export async function upgradeDatabase(
61
58
  event: IDBVersionChangeEvent,
62
59
  ) => void,
63
60
  log?: (...args: any[]) => void,
64
- ): Promise<void> {
65
- function openAndUpgrade(resolve: () => void, reject: (err: Error) => void) {
61
+ ): Promise<IDBDatabase> {
62
+ function openAndUpgrade(
63
+ resolve: (db: IDBDatabase) => void,
64
+ reject: (err: Error) => void,
65
+ ) {
66
66
  const request = indexedDb.open(
67
67
  [namespace, 'collections'].join('_'),
68
68
  version,
@@ -74,9 +74,8 @@ export async function upgradeDatabase(
74
74
  wasUpgraded = true;
75
75
  };
76
76
  request.onsuccess = (event) => {
77
- request.result.close();
78
77
  if (wasUpgraded) {
79
- resolve();
78
+ resolve(request.result);
80
79
  } else {
81
80
  reject(
82
81
  new Error(
@@ -95,7 +94,7 @@ export async function upgradeDatabase(
95
94
  // }, 200);
96
95
  };
97
96
  }
98
- return new Promise(openAndUpgrade);
97
+ return new Promise<IDBDatabase>(openAndUpgrade);
99
98
  }
100
99
 
101
100
  export async function acquireLock(
@@ -110,15 +109,20 @@ export async function acquireLock(
110
109
  }
111
110
  }
112
111
 
113
- export async function openDatabase(
114
- indexedDb: IDBFactory,
115
- namespace: string,
116
- version: number,
117
- log?: (...args: any[]) => void,
118
- ): Promise<IDBDatabase> {
119
- log?.('debug', 'Opening database', namespace, 'at version', version);
112
+ export async function openDatabase({
113
+ indexedDB = globalIDB,
114
+ namespace,
115
+ version,
116
+ context,
117
+ }: {
118
+ indexedDB?: IDBFactory;
119
+ namespace: string;
120
+ version: number;
121
+ context: OpenDocumentDbContext;
122
+ }): Promise<IDBDatabase> {
123
+ context.log('debug', 'Opening database', namespace, 'at version', version);
120
124
  const db = await new Promise<IDBDatabase>((resolve, reject) => {
121
- const request = indexedDb.open(
125
+ const request = indexedDB.open(
122
126
  [namespace, 'collections'].join('_'),
123
127
  version,
124
128
  );
@@ -126,7 +130,7 @@ export async function openDatabase(
126
130
  const transaction = request.transaction!;
127
131
  transaction.abort();
128
132
 
129
- log?.(
133
+ context.log(
130
134
  'error',
131
135
  'Database upgrade needed, but not expected',
132
136
  'Expected',
@@ -158,3 +162,41 @@ export async function openDatabase(
158
162
 
159
163
  return db;
160
164
  }
165
+
166
+ export async function copyAll(
167
+ sourceDatabase: IDBDatabase,
168
+ targetDatabase: IDBDatabase,
169
+ ) {
170
+ // DOMStringList... doesn't have iterable... why
171
+ const sourceStoreNames = new Array<string>();
172
+ for (let i = 0; i < sourceDatabase.objectStoreNames.length; i++) {
173
+ sourceStoreNames.push(sourceDatabase.objectStoreNames[i]);
174
+ }
175
+
176
+ const copyFromTransaction = sourceDatabase.transaction(
177
+ sourceStoreNames,
178
+ 'readonly',
179
+ );
180
+ const copyFromStores = sourceStoreNames.map((name) =>
181
+ copyFromTransaction.objectStore(name),
182
+ );
183
+ const allObjects = await Promise.all(
184
+ copyFromStores.map((store) => storeRequestPromise(store.getAll())),
185
+ );
186
+
187
+ const copyToTransaction = targetDatabase.transaction(
188
+ sourceStoreNames,
189
+ 'readwrite',
190
+ );
191
+ const copyToStores = sourceStoreNames.map((name) =>
192
+ copyToTransaction.objectStore(name),
193
+ );
194
+
195
+ for (let i = 0; i < copyToStores.length; i++) {
196
+ await Promise.all(
197
+ allObjects[i].map((obj) => {
198
+ return storeRequestPromise(copyToStores[i].put(obj));
199
+ }),
200
+ );
201
+ }
202
+ }