@verdant-web/store 3.4.0-next.0 → 3.5.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/bundle/index.js +6 -6
- package/dist/bundle/index.js.map +3 -3
- package/dist/esm/BackoffScheduler.d.ts +19 -0
- package/dist/esm/DocumentManager.d.ts +28 -0
- package/dist/esm/FakeWeakRef.d.ts +11 -0
- package/dist/esm/IDBService.d.ts +30 -0
- package/dist/esm/UndoHistory.d.ts +16 -0
- package/dist/esm/__tests__/batching.test.d.ts +1 -0
- package/dist/esm/__tests__/documents.test.d.ts +1 -0
- package/dist/esm/__tests__/documents.test.js +26 -0
- package/dist/esm/__tests__/documents.test.js.map +1 -1
- package/dist/esm/__tests__/fixtures/testStorage.d.ts +80 -0
- package/dist/esm/__tests__/fixtures/testStorage.js +5 -0
- package/dist/esm/__tests__/fixtures/testStorage.js.map +1 -1
- package/dist/esm/__tests__/legacyOids.test.d.ts +1 -0
- package/dist/esm/__tests__/mutations.test.d.ts +1 -0
- package/dist/esm/__tests__/queries.test.d.ts +1 -0
- package/dist/esm/__tests__/setup/indexedDB.d.ts +1 -0
- package/dist/esm/__tests__/undo.test.d.ts +1 -0
- package/dist/esm/backup.d.ts +10 -0
- package/dist/esm/client/Client.d.ts +98 -0
- package/dist/esm/client/ClientDescriptor.d.ts +76 -0
- package/dist/esm/client/constants.d.ts +1 -0
- package/dist/esm/constants.d.ts +1 -0
- package/dist/esm/context.d.ts +38 -0
- package/dist/esm/entities/Entity.d.ts +162 -0
- package/dist/esm/entities/Entity.js +35 -9
- package/dist/esm/entities/Entity.js.map +1 -1
- package/dist/esm/entities/Entity.test.d.ts +1 -0
- package/dist/esm/entities/EntityCache.d.ts +15 -0
- package/dist/esm/entities/EntityMetadata.d.ts +68 -0
- package/dist/esm/entities/EntityStore.d.ts +81 -0
- package/dist/esm/entities/OperationBatcher.d.ts +52 -0
- package/dist/esm/entities/types.d.ts +103 -0
- package/dist/esm/files/EntityFile.d.ts +35 -0
- package/dist/esm/files/FileManager.d.ts +47 -0
- package/dist/esm/files/FileStorage.d.ts +39 -0
- package/dist/esm/files/utils.d.ts +10 -0
- package/dist/esm/files/utils.test.d.ts +1 -0
- package/dist/esm/idb.d.ts +13 -0
- package/dist/esm/index.d.ts +23 -0
- package/dist/esm/metadata/AckInfoStore.d.ts +10 -0
- package/dist/esm/metadata/BaselinesStore.d.ts +40 -0
- package/dist/esm/metadata/LocalReplicaStore.d.ts +18 -0
- package/dist/esm/metadata/MessageCreator.d.ts +19 -0
- package/dist/esm/metadata/Metadata.d.ts +135 -0
- package/dist/esm/metadata/OperationsStore.d.ts +62 -0
- package/dist/esm/metadata/SchemaStore.d.ts +9 -0
- package/dist/esm/metadata/openMetadataDatabase.d.ts +19 -0
- package/dist/esm/migration/db.d.ts +8 -0
- package/dist/esm/migration/errors.d.ts +5 -0
- package/dist/esm/migration/openDatabase.d.ts +20 -0
- package/dist/esm/migration/paths.d.ts +6 -0
- package/dist/esm/migration/paths.test.d.ts +1 -0
- package/dist/esm/queries/BaseQuery.d.ts +53 -0
- package/dist/esm/queries/CollectionQueries.d.ts +55 -0
- package/dist/esm/queries/FindAllQuery.d.ts +12 -0
- package/dist/esm/queries/FindInfiniteQuery.d.ts +19 -0
- package/dist/esm/queries/FindOneQuery.d.ts +12 -0
- package/dist/esm/queries/FindPageQuery.d.ts +24 -0
- package/dist/esm/queries/GetQuery.d.ts +10 -0
- package/dist/esm/queries/QueryCache.d.ts +17 -0
- package/dist/esm/queries/QueryableStorage.d.ts +20 -0
- package/dist/esm/queries/dbQueries.d.ts +22 -0
- package/dist/esm/queries/keys.d.ts +10 -0
- package/dist/esm/queries/ranges.d.ts +2 -0
- package/dist/esm/queries/types.d.ts +6 -0
- package/dist/esm/queries/utils.d.ts +3 -0
- package/dist/esm/sync/FileSync.d.ts +24 -0
- package/dist/esm/sync/Heartbeat.d.ts +25 -0
- package/dist/esm/sync/PresenceManager.d.ts +55 -0
- package/dist/esm/sync/PushPullSync.d.ts +39 -0
- package/dist/esm/sync/ServerSyncEndpointProvider.d.ts +34 -0
- package/dist/esm/sync/Sync.d.ts +160 -0
- package/dist/esm/sync/WebSocketSync.d.ts +44 -0
- package/dist/esm/types.d.ts +12 -0
- package/dist/esm/utils/Disposable.d.ts +6 -0
- package/dist/esm/utils/Resolvable.d.ts +8 -0
- package/dist/esm/vanilla.d.ts +1 -0
- package/package.json +3 -3
- package/src/__tests__/documents.test.ts +35 -2
- package/src/__tests__/fixtures/testStorage.ts +5 -0
- package/src/entities/Entity.ts +40 -9
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Operation } from '@verdant-web/common';
|
|
2
|
+
export type LogFunction = (...args: any[]) => void;
|
|
3
|
+
/**
|
|
4
|
+
* Operations moving through the client system are
|
|
5
|
+
* tagged with whether or not they are stored in
|
|
6
|
+
* the database (confirmed) or only in memory,
|
|
7
|
+
* which might mean they are lost if the client
|
|
8
|
+
* crashes.
|
|
9
|
+
*/
|
|
10
|
+
export interface TaggedOperation extends Operation {
|
|
11
|
+
confirmed?: boolean;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdant-web/store",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
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.0
|
|
30
|
+
"@verdant-web/common": "2.3.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "20.10.5",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"open-cli": "^7.2.0",
|
|
38
38
|
"puppeteer": "^21.5.1",
|
|
39
39
|
"typescript": "^5.4.2",
|
|
40
|
-
"vitest": "^1.
|
|
40
|
+
"vitest": "^1.4.0"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"test": "vitest",
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { assert } from '@verdant-web/common';
|
|
2
|
-
import cuid from 'cuid';
|
|
3
2
|
import { describe, it, expect, vi, MockedFunction, vitest } from 'vitest';
|
|
4
3
|
import { createTestStorage } from './fixtures/testStorage.js';
|
|
5
4
|
import { EntityFile } from '../index.js';
|
|
@@ -505,7 +504,9 @@ describe('storage documents', () => {
|
|
|
505
504
|
|
|
506
505
|
expect(() => {
|
|
507
506
|
item1.set('id', 'foo');
|
|
508
|
-
}).toThrowErrorMatchingInlineSnapshot(
|
|
507
|
+
}).toThrowErrorMatchingInlineSnapshot(
|
|
508
|
+
`[Error: Cannot set readonly key id]`,
|
|
509
|
+
);
|
|
509
510
|
});
|
|
510
511
|
|
|
511
512
|
it('should properly handle pushing to a list of files', async () => {
|
|
@@ -559,4 +560,36 @@ describe('storage documents', () => {
|
|
|
559
560
|
expect(fileList.get(1)).toBe(file3Ref);
|
|
560
561
|
expect(fileList.get(2)).toBe(file1Ref);
|
|
561
562
|
});
|
|
563
|
+
|
|
564
|
+
it('should return nullish for missing map items', async () => {
|
|
565
|
+
const storage = await createTestStorage();
|
|
566
|
+
const weird = await storage.weirds.put({});
|
|
567
|
+
|
|
568
|
+
const map = weird.get('map');
|
|
569
|
+
expect(map.get('foo')).toBeUndefined();
|
|
570
|
+
const objectMap = weird.get('objectMap');
|
|
571
|
+
expect(objectMap.get('foo')).toBeUndefined();
|
|
572
|
+
const arrayMap = weird.get('arrayMap');
|
|
573
|
+
expect(arrayMap.get('foo')).toBeUndefined();
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
it('should allow getOrSet for nullable fields', async () => {
|
|
577
|
+
const storage = await createTestStorage();
|
|
578
|
+
const weird = await storage.weirds.put({});
|
|
579
|
+
|
|
580
|
+
const map = weird.get('map');
|
|
581
|
+
const foo = map.getOrSet('foo', 'bar');
|
|
582
|
+
expect(foo).toBe('bar');
|
|
583
|
+
expect(map.get('foo')).toBe('bar');
|
|
584
|
+
|
|
585
|
+
const objectMap = weird.get('objectMap');
|
|
586
|
+
const fooObject = objectMap.getOrSet('foo', { content: 'bar' });
|
|
587
|
+
expect(fooObject.get('content')).toBe('bar');
|
|
588
|
+
expect(objectMap.get('foo').get('content')).toBe('bar');
|
|
589
|
+
|
|
590
|
+
const arrayMap = weird.get('arrayMap');
|
|
591
|
+
const fooArray = arrayMap.getOrSet('foo', ['bar']);
|
|
592
|
+
expect(fooArray.get(0)).toEqual('bar');
|
|
593
|
+
expect(arrayMap.get('foo').get(0)).toEqual('bar');
|
|
594
|
+
});
|
|
562
595
|
});
|
package/src/entities/Entity.ts
CHANGED
|
@@ -549,21 +549,23 @@ export class Entity<
|
|
|
549
549
|
);
|
|
550
550
|
}
|
|
551
551
|
const child = view[key as any];
|
|
552
|
-
const
|
|
553
|
-
if (!
|
|
552
|
+
const fieldSchema = getChildFieldSchema(this.schema, key);
|
|
553
|
+
if (!fieldSchema) {
|
|
554
554
|
throw new Error(
|
|
555
555
|
`No schema for key ${String(key)} in ${JSON.stringify(this.schema)}`,
|
|
556
556
|
);
|
|
557
557
|
}
|
|
558
558
|
if (isRef(child)) {
|
|
559
559
|
if (isFileRef(child)) {
|
|
560
|
-
if (
|
|
560
|
+
if (fieldSchema.type !== 'file') {
|
|
561
561
|
throw new Error(
|
|
562
|
-
`Expected file schema for key ${String(key)}, got ${
|
|
562
|
+
`Expected file schema for key ${String(key)}, got ${
|
|
563
|
+
fieldSchema.type
|
|
564
|
+
}`,
|
|
563
565
|
);
|
|
564
566
|
}
|
|
565
567
|
const file = this.files.get(child.id, {
|
|
566
|
-
downloadRemote: !!
|
|
568
|
+
downloadRemote: !!fieldSchema.downloadRemote,
|
|
567
569
|
});
|
|
568
570
|
|
|
569
571
|
// FIXME: this seems bad and inconsistent
|
|
@@ -576,20 +578,25 @@ export class Entity<
|
|
|
576
578
|
return this.getChild(key, child.id) as KeyValue[Key];
|
|
577
579
|
}
|
|
578
580
|
} else {
|
|
581
|
+
// if this is a Map type, a missing child is
|
|
582
|
+
// just an empty spot
|
|
583
|
+
if (this.schema.type === 'map' && child === undefined) {
|
|
584
|
+
return undefined as KeyValue[Key];
|
|
585
|
+
}
|
|
579
586
|
// prune invalid primitive fields
|
|
580
587
|
if (
|
|
581
588
|
validateEntityField({
|
|
582
|
-
field:
|
|
589
|
+
field: fieldSchema,
|
|
583
590
|
value: child,
|
|
584
591
|
fieldPath: [...this.fieldPath, key],
|
|
585
592
|
depth: 1,
|
|
586
593
|
requireDefaults: true,
|
|
587
594
|
})
|
|
588
595
|
) {
|
|
589
|
-
if (hasDefault(
|
|
590
|
-
return getDefault(
|
|
596
|
+
if (hasDefault(fieldSchema)) {
|
|
597
|
+
return getDefault(fieldSchema);
|
|
591
598
|
}
|
|
592
|
-
if (isNullable(
|
|
599
|
+
if (isNullable(fieldSchema)) {
|
|
593
600
|
return null as any;
|
|
594
601
|
}
|
|
595
602
|
return undefined as any;
|
|
@@ -598,6 +605,30 @@ export class Entity<
|
|
|
598
605
|
}
|
|
599
606
|
};
|
|
600
607
|
|
|
608
|
+
/**
|
|
609
|
+
* Gets a value on this entity. If the value is not
|
|
610
|
+
* present, it will be set to the provided default
|
|
611
|
+
* and returned synchronously. This method only sets
|
|
612
|
+
* a new value once when a field is empty; subsequent
|
|
613
|
+
* calls will retrieve the created value until it is
|
|
614
|
+
* deleted.
|
|
615
|
+
*
|
|
616
|
+
* Note that this should only be called for nullable
|
|
617
|
+
* fields. If the field is not nullable, the existing
|
|
618
|
+
* value or the default value will always be returned,
|
|
619
|
+
* and the default will not be set.
|
|
620
|
+
*/
|
|
621
|
+
getOrSet = <Key extends keyof Init & keyof KeyValue>(
|
|
622
|
+
key: Key,
|
|
623
|
+
init: Init[Key],
|
|
624
|
+
): KeyValue[Key] => {
|
|
625
|
+
assertNotSymbol(key);
|
|
626
|
+
const existing = this.get(key);
|
|
627
|
+
if (existing) return existing;
|
|
628
|
+
this.set(key as any, init);
|
|
629
|
+
return this.get(key);
|
|
630
|
+
};
|
|
631
|
+
|
|
601
632
|
private processInputValue = (value: any, key: any) => {
|
|
602
633
|
if (this.readonlyKeys.includes(key as string)) {
|
|
603
634
|
throw new Error(`Cannot set readonly key ${key.toString()}`);
|