@verdant-web/store 3.4.0-next.0 → 3.4.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/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__/fixtures/testStorage.d.ts +76 -0
- 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 +148 -0
- 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 +2 -2
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { DocumentBaseline, ObjectIdentifier, Operation } from '@verdant-web/common';
|
|
2
|
+
import { Context } from '../context.js';
|
|
3
|
+
import { EntityChange } from './types.js';
|
|
4
|
+
export type EntityMetadataView = {
|
|
5
|
+
view: any;
|
|
6
|
+
fromOlderVersion: boolean;
|
|
7
|
+
deleted: boolean;
|
|
8
|
+
empty: boolean;
|
|
9
|
+
updatedAt: number;
|
|
10
|
+
};
|
|
11
|
+
export declare class EntityMetadata {
|
|
12
|
+
private ctx;
|
|
13
|
+
private baseline;
|
|
14
|
+
private confirmedOperations;
|
|
15
|
+
private pendingOperations;
|
|
16
|
+
readonly oid: string;
|
|
17
|
+
constructor({ oid, ctx, confirmedOperations, pendingOperations, baseline, }: {
|
|
18
|
+
oid: ObjectIdentifier;
|
|
19
|
+
ctx: Context;
|
|
20
|
+
confirmedOperations?: Operation[];
|
|
21
|
+
pendingOperations?: Operation[];
|
|
22
|
+
baseline?: DocumentBaseline;
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Compute the current view of the entity.
|
|
26
|
+
*/
|
|
27
|
+
computeView: (omitPending?: boolean) => EntityMetadataView;
|
|
28
|
+
addBaseline: (baseline: DocumentBaseline) => void;
|
|
29
|
+
/**
|
|
30
|
+
* @returns total number of new operations added
|
|
31
|
+
*/
|
|
32
|
+
addConfirmedOperations: (operations: Operation[]) => number;
|
|
33
|
+
addPendingOperation: (operation: Operation) => void;
|
|
34
|
+
private applyOperations;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Represents the metadata for a group of entities underneath a Document.
|
|
38
|
+
* Metadata is separated out this way so that these classes can be
|
|
39
|
+
* garbage collected when the root Document goes out of scope.
|
|
40
|
+
*/
|
|
41
|
+
export declare class EntityFamilyMetadata {
|
|
42
|
+
private ctx;
|
|
43
|
+
private entities;
|
|
44
|
+
private onPendingOperations;
|
|
45
|
+
private rootOid;
|
|
46
|
+
constructor({ ctx, onPendingOperations, rootOid, }: {
|
|
47
|
+
ctx: Context;
|
|
48
|
+
onPendingOperations: (ops: Operation[]) => void;
|
|
49
|
+
rootOid: ObjectIdentifier;
|
|
50
|
+
});
|
|
51
|
+
get: (oid: ObjectIdentifier) => EntityMetadata;
|
|
52
|
+
getAllOids: () => string[];
|
|
53
|
+
addConfirmedData: ({ baselines, operations, isLocal, }: {
|
|
54
|
+
baselines?: DocumentBaseline[] | undefined;
|
|
55
|
+
operations?: Record<string, Operation[]> | undefined;
|
|
56
|
+
isLocal?: boolean | undefined;
|
|
57
|
+
}) => EntityChange[];
|
|
58
|
+
/**
|
|
59
|
+
* Adds local, unconfirmed operations to the system.
|
|
60
|
+
* The API is different here to streamline for the way
|
|
61
|
+
* local changes are usually handled, as a list.
|
|
62
|
+
*/
|
|
63
|
+
addPendingData: (operations: Operation[]) => EntityChange[];
|
|
64
|
+
replaceAllData: ({ operations, baselines, }: {
|
|
65
|
+
operations?: Record<string, Operation[]> | undefined;
|
|
66
|
+
baselines?: DocumentBaseline[] | undefined;
|
|
67
|
+
}) => EntityChange[];
|
|
68
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import { DocumentBaseline, ObjectIdentifier, Operation } from '@verdant-web/common';
|
|
3
|
+
import { Context } from '../context.js';
|
|
4
|
+
import { Metadata } from '../metadata/Metadata.js';
|
|
5
|
+
import { Entity } from './Entity.js';
|
|
6
|
+
import { Disposable } from '../utils/Disposable.js';
|
|
7
|
+
import { FileManager } from '../files/FileManager.js';
|
|
8
|
+
import { WeakEvent } from 'weak-event';
|
|
9
|
+
import { abort } from 'process';
|
|
10
|
+
export type EntityStoreEventData = {
|
|
11
|
+
oid: ObjectIdentifier;
|
|
12
|
+
operations?: Record<string, Operation[]>;
|
|
13
|
+
baselines?: DocumentBaseline[];
|
|
14
|
+
isLocal: boolean;
|
|
15
|
+
};
|
|
16
|
+
export type EntityStoreEvents = {
|
|
17
|
+
add: WeakEvent<EntityStore, EntityStoreEventData>;
|
|
18
|
+
replace: WeakEvent<EntityStore, EntityStoreEventData>;
|
|
19
|
+
resetAll: WeakEvent<EntityStore, void>;
|
|
20
|
+
};
|
|
21
|
+
type IncomingData = {
|
|
22
|
+
operations?: Operation[];
|
|
23
|
+
baselines?: DocumentBaseline[];
|
|
24
|
+
reset?: boolean;
|
|
25
|
+
isLocal?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare class EntityStore extends Disposable {
|
|
28
|
+
private ctx;
|
|
29
|
+
private meta;
|
|
30
|
+
private files;
|
|
31
|
+
private batcher;
|
|
32
|
+
private queryableStorage;
|
|
33
|
+
private events;
|
|
34
|
+
private cache;
|
|
35
|
+
private pendingEntityPromises;
|
|
36
|
+
private abortDataQueueController;
|
|
37
|
+
private ongoingResetPromise;
|
|
38
|
+
private entityFinalizationRegistry;
|
|
39
|
+
constructor({ ctx, meta, files, }: {
|
|
40
|
+
ctx: Context;
|
|
41
|
+
meta: Metadata;
|
|
42
|
+
files: FileManager;
|
|
43
|
+
});
|
|
44
|
+
get batch(): ({ undoable, batchName, max, timeout, }?: {
|
|
45
|
+
undoable?: boolean | undefined;
|
|
46
|
+
batchName?: string | undefined;
|
|
47
|
+
max?: number | null | undefined;
|
|
48
|
+
timeout?: number | null | undefined;
|
|
49
|
+
}) => import("./OperationBatcher.js").OperationBatch;
|
|
50
|
+
get flushAllBatches(): () => Promise<any[]>;
|
|
51
|
+
addData: (data: IncomingData) => Promise<void>;
|
|
52
|
+
private resetData;
|
|
53
|
+
private processData;
|
|
54
|
+
hydrate: (oid: string, opts?: {
|
|
55
|
+
abort: AbortSignal;
|
|
56
|
+
}) => Promise<Entity | null>;
|
|
57
|
+
destroy: () => Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Creates a new Entity with the given initial data.
|
|
60
|
+
*/
|
|
61
|
+
create: (initial: any, oid: ObjectIdentifier, { undoable }?: {
|
|
62
|
+
undoable?: boolean | undefined;
|
|
63
|
+
}) => Promise<Entity<any, any, any>>;
|
|
64
|
+
deleteAll: (oids: ObjectIdentifier[], options?: {
|
|
65
|
+
undoable?: boolean;
|
|
66
|
+
}) => Promise<void>;
|
|
67
|
+
delete: (oid: ObjectIdentifier, options?: {
|
|
68
|
+
undoable?: boolean;
|
|
69
|
+
}) => Promise<void>;
|
|
70
|
+
private getCollectionSchema;
|
|
71
|
+
/**
|
|
72
|
+
* Constructs an entity from an OID, but does not load it.
|
|
73
|
+
*/
|
|
74
|
+
private constructEntity;
|
|
75
|
+
private onPendingOperations;
|
|
76
|
+
/**
|
|
77
|
+
* Loads initial Entity data from storage
|
|
78
|
+
*/
|
|
79
|
+
private loadEntity;
|
|
80
|
+
}
|
|
81
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Operation } from '@verdant-web/common';
|
|
2
|
+
import { Metadata } from '../metadata/Metadata.js';
|
|
3
|
+
import { Context } from '../context.js';
|
|
4
|
+
import type { EntityStore } from './EntityStore.js';
|
|
5
|
+
import { Entity } from './Entity.js';
|
|
6
|
+
export interface OperationBatch {
|
|
7
|
+
run: (fn: () => void) => this;
|
|
8
|
+
/** @deprecated - use commit() */
|
|
9
|
+
flush: () => Promise<void>;
|
|
10
|
+
commit: () => Promise<void>;
|
|
11
|
+
discard: () => void;
|
|
12
|
+
}
|
|
13
|
+
export declare class OperationBatcher {
|
|
14
|
+
private batcher;
|
|
15
|
+
private currentBatchKey;
|
|
16
|
+
private defaultBatchTimeout;
|
|
17
|
+
private meta;
|
|
18
|
+
private ctx;
|
|
19
|
+
private entities;
|
|
20
|
+
constructor({ batchTimeout, meta, ctx, entities, }: {
|
|
21
|
+
batchTimeout?: number;
|
|
22
|
+
meta: Metadata;
|
|
23
|
+
ctx: Context;
|
|
24
|
+
entities: EntityStore;
|
|
25
|
+
});
|
|
26
|
+
get isDefaultBatch(): boolean;
|
|
27
|
+
private flushOperations;
|
|
28
|
+
/**
|
|
29
|
+
* Immediately flushes operations to storage / sync.
|
|
30
|
+
* Providing source to second arg skips hydrating related
|
|
31
|
+
* Entity from storage, which is useful when that Entity
|
|
32
|
+
* isn't in storage (i.e. still creating) or just to speed
|
|
33
|
+
* up the commit.
|
|
34
|
+
*/
|
|
35
|
+
commitOperations: (operations: Operation[], meta: {
|
|
36
|
+
undoable?: boolean;
|
|
37
|
+
source?: Entity;
|
|
38
|
+
}) => Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Adds operations to the active batch.
|
|
41
|
+
*/
|
|
42
|
+
addOperations: (operations: Operation[]) => void;
|
|
43
|
+
batch: ({ undoable, batchName, max, timeout, }?: {
|
|
44
|
+
undoable?: boolean | undefined;
|
|
45
|
+
batchName?: string | undefined;
|
|
46
|
+
max?: number | null | undefined;
|
|
47
|
+
timeout?: number | null | undefined;
|
|
48
|
+
}) => OperationBatch;
|
|
49
|
+
flushAll: () => Promise<any[]>;
|
|
50
|
+
private createUndo;
|
|
51
|
+
private getInverseOperations;
|
|
52
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { ObjectIdentifier } from '@verdant-web/common';
|
|
2
|
+
import type { Entity } from './Entity.js';
|
|
3
|
+
export type AccessibleEntityProperty<T> = T extends Array<any> ? number : T extends object ? keyof T : never;
|
|
4
|
+
export type DataFromInit<Init> = Init extends {
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
} ? {
|
|
7
|
+
[Key in keyof Init]: Init[Key];
|
|
8
|
+
} : Init extends Array<any> ? Init : any;
|
|
9
|
+
export type DeletableKeys<T> = keyof {
|
|
10
|
+
[Key in keyof T as IfNullableThen<T[Key], Key>]: Key;
|
|
11
|
+
};
|
|
12
|
+
type IfNullableThen<T, Out> = undefined extends T ? Out : null extends T ? Out : never;
|
|
13
|
+
export type EntityShape<E extends Entity<any, any>> = E extends Entity<infer Value, any> ? Value : never;
|
|
14
|
+
export type BaseEntityValue = {
|
|
15
|
+
[Key: string]: any;
|
|
16
|
+
} | any[];
|
|
17
|
+
export interface EntityChange {
|
|
18
|
+
oid: ObjectIdentifier;
|
|
19
|
+
isLocal: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface EntityChangeInfo {
|
|
22
|
+
isLocal?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export type EntityEvents = {
|
|
25
|
+
change: (info: EntityChangeInfo) => void;
|
|
26
|
+
changeDeep: (target: BaseEntity<any, any, any>, info: EntityChangeInfo) => void;
|
|
27
|
+
delete: (info: EntityChangeInfo) => void;
|
|
28
|
+
restore: (info: EntityChangeInfo) => void;
|
|
29
|
+
};
|
|
30
|
+
export interface BaseEntity<Init, Value extends BaseEntityValue, Snapshot = DataFromInit<Init>> {
|
|
31
|
+
dispose: () => void;
|
|
32
|
+
subscribe<EventName extends keyof EntityEvents>(event: EventName, callback: EntityEvents[EventName]): () => void;
|
|
33
|
+
get<Key extends keyof Value>(key: Key): Value[Key];
|
|
34
|
+
getAll(): Value;
|
|
35
|
+
getSnapshot(): Snapshot;
|
|
36
|
+
readonly deleted: boolean;
|
|
37
|
+
readonly updatedAt: number;
|
|
38
|
+
readonly uid: string;
|
|
39
|
+
}
|
|
40
|
+
export type DeepPartial<T> = T extends object ? {
|
|
41
|
+
[P in keyof T]?: DeepPartial<T[P]>;
|
|
42
|
+
} : T;
|
|
43
|
+
export interface ObjectEntity<Init, Value extends BaseEntityValue, Snapshot = DataFromInit<Init>> extends BaseEntity<Init, Value, Snapshot> {
|
|
44
|
+
keys(): string[];
|
|
45
|
+
entries(): [string, Exclude<Value[keyof Value], undefined>][];
|
|
46
|
+
values(): Exclude<Value[keyof Value], undefined>[];
|
|
47
|
+
set<Key extends keyof Init>(key: Key, value: Init[Key]): void;
|
|
48
|
+
delete(key: DeletableKeys<Value>): void;
|
|
49
|
+
update(value: DeepPartial<Init>, options?: {
|
|
50
|
+
/**
|
|
51
|
+
* Forces the replacement of sub-objects in the update payload - rather than
|
|
52
|
+
* Verdant keeping their identities intact and merging changes, your update
|
|
53
|
+
* will replace these objects entirely, overwriting any other changes from other
|
|
54
|
+
* sources.
|
|
55
|
+
*
|
|
56
|
+
* Useful when the update you're making is logically replacing sub-objects, rather
|
|
57
|
+
* than simply modifying them.
|
|
58
|
+
*
|
|
59
|
+
* Default: false
|
|
60
|
+
*/
|
|
61
|
+
replaceSubObjects?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* If set to false, this will drop any keys in the object which were
|
|
64
|
+
* not provided in your update payload, while also merging the ones that
|
|
65
|
+
* were. This option only works for `map` and `any` type fields; you cannot
|
|
66
|
+
* use it with defined `object` type fields.
|
|
67
|
+
*
|
|
68
|
+
* Default: true
|
|
69
|
+
*/
|
|
70
|
+
merge?: boolean;
|
|
71
|
+
}): void;
|
|
72
|
+
readonly isList: false;
|
|
73
|
+
}
|
|
74
|
+
export interface ListEntity<Init, Value extends BaseEntityValue, Snapshot = DataFromInit<Init>> extends Iterable<ListItemValue<Value>>, BaseEntity<Init, Value, Snapshot> {
|
|
75
|
+
readonly isList: true;
|
|
76
|
+
readonly length: number;
|
|
77
|
+
push(value: ListItemInit<Init>): void;
|
|
78
|
+
insert(index: number, value: ListItemInit<Init>): void;
|
|
79
|
+
move(from: number, to: number): void;
|
|
80
|
+
moveItem(item: ListItemValue<Value>, to: number): void;
|
|
81
|
+
/**
|
|
82
|
+
* A Set operation which adds a value if an equivalent value is not already present.
|
|
83
|
+
* Object values are never the same.
|
|
84
|
+
*/
|
|
85
|
+
add(value: ListItemValue<Value>): void;
|
|
86
|
+
removeAll(item: ListItemValue<Value>): void;
|
|
87
|
+
removeFirst(item: ListItemValue<Value>): void;
|
|
88
|
+
removeLast(item: ListItemValue<Value>): void;
|
|
89
|
+
map<U>(callback: (value: ListItemValue<Value>, index: number) => U): U[];
|
|
90
|
+
filter(callback: (value: ListItemValue<Value>, index: number) => boolean): ListItemValue<Value>[];
|
|
91
|
+
delete(index: number): void;
|
|
92
|
+
has(value: ListItemValue<Value>): boolean;
|
|
93
|
+
forEach(callback: (value: ListItemValue<Value>, index: number) => void): void;
|
|
94
|
+
some(predicate: (value: ListItemValue<Value>) => boolean): boolean;
|
|
95
|
+
every(predicate: (value: ListItemValue<Value>) => boolean): boolean;
|
|
96
|
+
find(predicate: (value: ListItemValue<Value>) => boolean): ListItemValue<Value> | undefined;
|
|
97
|
+
includes(value: ListItemValue<Value>): boolean;
|
|
98
|
+
}
|
|
99
|
+
export type AnyEntity<Init, KeyValue extends BaseEntityValue, Snapshot extends any> = ListEntity<Init, KeyValue, Snapshot> | ObjectEntity<Init, KeyValue, Snapshot>;
|
|
100
|
+
export type ListItemValue<KeyValue> = KeyValue extends Array<infer T> ? T : never;
|
|
101
|
+
export type ListItemInit<Init> = Init extends Array<infer T> ? T : never;
|
|
102
|
+
export type EntityDestructured<T extends AnyEntity<any, any, any> | null> = (T extends ListEntity<any, infer KeyValue, any> ? KeyValue : T extends ObjectEntity<any, infer KeyValue, any> ? KeyValue : never) | (T extends null ? null : never);
|
|
103
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { EventSubscriber, FileData } from '@verdant-web/common';
|
|
2
|
+
export type EntityFileEvents = {
|
|
3
|
+
change: () => void;
|
|
4
|
+
};
|
|
5
|
+
export declare const UPDATE: unique symbol;
|
|
6
|
+
export declare const MARK_FAILED: unique symbol;
|
|
7
|
+
export type EntityFileSnapshot = {
|
|
8
|
+
id: string;
|
|
9
|
+
url?: string | null;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Provides a consistent interface for files used in an app via
|
|
13
|
+
* Entity access.
|
|
14
|
+
*/
|
|
15
|
+
export declare class EntityFile extends EventSubscriber<EntityFileEvents> {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
private _objectUrl;
|
|
18
|
+
private _fileData;
|
|
19
|
+
private _loading;
|
|
20
|
+
private _failed;
|
|
21
|
+
private _downloadRemote;
|
|
22
|
+
constructor(id: string, { downloadRemote, }?: {
|
|
23
|
+
downloadRemote?: boolean;
|
|
24
|
+
});
|
|
25
|
+
get downloadRemote(): boolean;
|
|
26
|
+
[UPDATE]: (fileData: FileData) => void;
|
|
27
|
+
[MARK_FAILED]: () => void;
|
|
28
|
+
get url(): string | null;
|
|
29
|
+
get name(): string | null;
|
|
30
|
+
get type(): string | null;
|
|
31
|
+
get loading(): boolean;
|
|
32
|
+
get failed(): boolean;
|
|
33
|
+
destroy: () => void;
|
|
34
|
+
getSnapshot(): EntityFileSnapshot;
|
|
35
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { FileData } from '@verdant-web/common';
|
|
2
|
+
import { Context } from '../context.js';
|
|
3
|
+
import { Metadata } from '../metadata/Metadata.js';
|
|
4
|
+
import { Sync } from '../sync/Sync.js';
|
|
5
|
+
import { EntityFile } from './EntityFile.js';
|
|
6
|
+
import { ReturnedFileData } from './FileStorage.js';
|
|
7
|
+
export interface FileManagerConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Override the heuristic for deciding when a deleted file can be cleaned up.
|
|
10
|
+
* By default this waits 3 days since deletion, then deletes the file data.
|
|
11
|
+
* If the file has been synchronized to a server, it could still be restored
|
|
12
|
+
* if the server has not yet deleted it.
|
|
13
|
+
*/
|
|
14
|
+
canCleanupDeletedFile?: (file: ReturnedFileData) => boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare class FileManager {
|
|
17
|
+
private storage;
|
|
18
|
+
private sync;
|
|
19
|
+
private context;
|
|
20
|
+
private files;
|
|
21
|
+
private config;
|
|
22
|
+
private meta;
|
|
23
|
+
constructor({ db, sync, context, meta, config, }: {
|
|
24
|
+
db: IDBDatabase;
|
|
25
|
+
sync: Sync;
|
|
26
|
+
context: Context;
|
|
27
|
+
config?: FileManagerConfig;
|
|
28
|
+
meta: Metadata;
|
|
29
|
+
});
|
|
30
|
+
add: (fileInput: Omit<FileData, 'remote'>) => Promise<void>;
|
|
31
|
+
private uploadFile;
|
|
32
|
+
/**
|
|
33
|
+
* Immediately returns an EntityFile to use, then either loads
|
|
34
|
+
* the file from cache, local database, or the server.
|
|
35
|
+
*/
|
|
36
|
+
get: (id: string, options?: {
|
|
37
|
+
downloadRemote?: boolean;
|
|
38
|
+
}) => EntityFile;
|
|
39
|
+
private load;
|
|
40
|
+
listUnsynced: () => Promise<ReturnedFileData[]>;
|
|
41
|
+
exportAll: (downloadRemote?: boolean) => Promise<ReturnedFileData[]>;
|
|
42
|
+
importAll: (files: ReturnedFileData[]) => Promise<void>;
|
|
43
|
+
private onOnlineChange;
|
|
44
|
+
private tryCleanupDeletedFiles;
|
|
45
|
+
private handleFileRefsDeleted;
|
|
46
|
+
close: () => void;
|
|
47
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FileData } from '@verdant-web/common';
|
|
2
|
+
import { IDBService } from '../IDBService.js';
|
|
3
|
+
/**
|
|
4
|
+
* When stored in IDB, replace the file blob with an array buffer
|
|
5
|
+
* since it's more compatible, and replace remote boolean with
|
|
6
|
+
* a string since IDB doesn't support boolean indexes.
|
|
7
|
+
*/
|
|
8
|
+
export interface StoredFileData extends Omit<FileData, 'remote' | 'file'> {
|
|
9
|
+
remote: 'true' | 'false';
|
|
10
|
+
buffer?: ArrayBuffer;
|
|
11
|
+
deletedAt: number | null;
|
|
12
|
+
}
|
|
13
|
+
export interface ReturnedFileData extends FileData {
|
|
14
|
+
deletedAt: number | null;
|
|
15
|
+
}
|
|
16
|
+
export declare class FileStorage extends IDBService {
|
|
17
|
+
addFile: (file: FileData, { transaction, downloadRemote, }?: {
|
|
18
|
+
transaction?: IDBTransaction | undefined;
|
|
19
|
+
downloadRemote?: boolean | undefined;
|
|
20
|
+
}) => Promise<IDBValidKey>;
|
|
21
|
+
private hydrateFileData;
|
|
22
|
+
markUploaded: (id: string, { transaction }?: {
|
|
23
|
+
transaction?: IDBTransaction | undefined;
|
|
24
|
+
}) => Promise<IDBValidKey>;
|
|
25
|
+
private getFileRaw;
|
|
26
|
+
getFile: (id: string, { transaction }?: {
|
|
27
|
+
transaction?: IDBTransaction | undefined;
|
|
28
|
+
}) => Promise<ReturnedFileData | undefined>;
|
|
29
|
+
deleteFile(id: string, { transaction }?: {
|
|
30
|
+
transaction?: IDBTransaction;
|
|
31
|
+
}): Promise<undefined>;
|
|
32
|
+
markPendingDelete: (id: string, { transaction }?: {
|
|
33
|
+
transaction?: IDBTransaction | undefined;
|
|
34
|
+
}) => Promise<IDBValidKey>;
|
|
35
|
+
listUnsynced: () => Promise<ReturnedFileData[]>;
|
|
36
|
+
iterateOverPendingDelete: (iterator: (file: ReturnedFileData, store: IDBObjectStore) => void, transaction?: IDBTransaction) => Promise<void>;
|
|
37
|
+
getAll: () => Promise<ReturnedFileData[]>;
|
|
38
|
+
}
|
|
39
|
+
export declare function arrayBufferToBlob(buffer: ArrayBuffer, type: string): Blob;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FileData } from '@verdant-web/common';
|
|
2
|
+
export declare function createFileData(file: File): FileData;
|
|
3
|
+
export declare function isFile(value: any): value is File;
|
|
4
|
+
/**
|
|
5
|
+
* MUTATES the value.
|
|
6
|
+
* Replaces File values with refs and returns the normalized value.
|
|
7
|
+
* The list of files passed to the second argument will be populated with the files found in the value.
|
|
8
|
+
*/
|
|
9
|
+
export declare function processValueFiles(value: any, onFileIdentified: (fileData: FileData) => void): any;
|
|
10
|
+
export declare function fileToArrayBuffer(file: File | Blob): Promise<ArrayBuffer>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function isAbortError(err: unknown): boolean;
|
|
2
|
+
export declare function storeRequestPromise<T>(request: IDBRequest<T>): Promise<T>;
|
|
3
|
+
export declare function cursorIterator<T>(request: IDBRequest<IDBCursorWithValue | null>, callback: (value: T | null) => boolean): Promise<void>;
|
|
4
|
+
export declare function getSizeOfObjectStore(database: IDBDatabase, storeName: string): Promise<{
|
|
5
|
+
count: number;
|
|
6
|
+
size: number;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function getAllFromObjectStores(db: IDBDatabase, stores: string[]): Promise<any[][]>;
|
|
9
|
+
export declare function closeDatabase(db: IDBDatabase): Promise<void>;
|
|
10
|
+
export declare function deleteAllDatabases(namespace: string, indexedDB?: IDBFactory): Promise<void>;
|
|
11
|
+
export declare function deleteDatabase(name: string, indexedDB?: IDBFactory): Promise<IDBDatabase>;
|
|
12
|
+
export declare function getAllDatabaseNamesAndVersions(indexedDB?: IDBFactory): Promise<IDBDatabaseInfo[]>;
|
|
13
|
+
export declare function createAbortableTransaction(db: IDBDatabase, storeNames: string[], mode: 'readonly' | 'readwrite', abortSignal?: AbortSignal, log?: (...args: any[]) => void): IDBTransaction;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ClientDescriptor, ClientDescriptorOptions } from './client/ClientDescriptor.js';
|
|
2
|
+
import { Client } from './client/Client.js';
|
|
3
|
+
export type { ClientWithCollections } from './client/Client.js';
|
|
4
|
+
export { ClientDescriptor };
|
|
5
|
+
export { Client };
|
|
6
|
+
export { ClientDescriptor as StorageDescriptor };
|
|
7
|
+
export { Client as Storage };
|
|
8
|
+
export type { ClientDescriptorOptions };
|
|
9
|
+
export type { ClientDescriptorOptions as StorageInitOptions };
|
|
10
|
+
export { Entity } from './entities/Entity.js';
|
|
11
|
+
export type { ObjectEntity, ListEntity, EntityShape, AccessibleEntityProperty, AnyEntity, EntityDestructured, } from './entities/types.js';
|
|
12
|
+
export { ServerSync } from './sync/Sync.js';
|
|
13
|
+
export type { SyncTransportMode } from './sync/Sync.js';
|
|
14
|
+
export { EntityFile, type EntityFileSnapshot } from './files/EntityFile.js';
|
|
15
|
+
export {
|
|
16
|
+
/** @deprecated - use schema.collection */
|
|
17
|
+
collection, schema, createDefaultMigration, migrate, createMigration, } from '@verdant-web/common';
|
|
18
|
+
export type { StorageDocument, StorageSchema, StorageCollectionSchema, StorageAnyFieldSchema, StorageArrayFieldSchema, StorageObjectFieldSchema, StorageBooleanFieldSchema, StorageFieldSchema, StorageFileFieldSchema, StorageMapFieldSchema, StorageNumberFieldSchema, StorageStringFieldSchema, StorageFieldsSchema, IndexValueTag, Migration, } from '@verdant-web/common';
|
|
19
|
+
export type { UserInfo } from '@verdant-web/common';
|
|
20
|
+
export type { Query } from './queries/types.js';
|
|
21
|
+
export type { QueryStatus } from './queries/BaseQuery.js';
|
|
22
|
+
export type { CollectionQueries } from './queries/CollectionQueries.js';
|
|
23
|
+
export { MigrationPathError } from './migration/errors.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IDBService } from '../IDBService.js';
|
|
2
|
+
type AckInfo = {
|
|
3
|
+
type: 'ack';
|
|
4
|
+
globalAckTimestamp: string | null;
|
|
5
|
+
};
|
|
6
|
+
export declare class AckInfoStore extends IDBService {
|
|
7
|
+
getAckInfo: () => Promise<AckInfo>;
|
|
8
|
+
setGlobalAck: (ack: string) => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DocumentBaseline, ObjectIdentifier } from '@verdant-web/common';
|
|
2
|
+
import { IDBService } from '../IDBService.js';
|
|
3
|
+
import { Context } from '../context.js';
|
|
4
|
+
export declare class BaselinesStore extends IDBService {
|
|
5
|
+
constructor(db: IDBDatabase, opts: {
|
|
6
|
+
log?: Context['log'];
|
|
7
|
+
});
|
|
8
|
+
getAllForDocument: (oid: ObjectIdentifier, { mode, transaction, }?: {
|
|
9
|
+
mode?: "readonly" | "readwrite" | undefined;
|
|
10
|
+
transaction?: IDBTransaction | undefined;
|
|
11
|
+
}) => Promise<DocumentBaseline[]>;
|
|
12
|
+
iterateOverAllForDocument: (oid: ObjectIdentifier, iterator: (baseline: DocumentBaseline, store: IDBObjectStore) => void, { mode, transaction, }?: {
|
|
13
|
+
mode?: "readonly" | "readwrite" | undefined;
|
|
14
|
+
transaction?: IDBTransaction | undefined;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
iterateOverAllForCollection: (collection: string, iterator: (baseline: DocumentBaseline, store: IDBObjectStore) => void, { mode, transaction, }?: {
|
|
17
|
+
mode?: "readonly" | "readwrite" | undefined;
|
|
18
|
+
transaction?: IDBTransaction | undefined;
|
|
19
|
+
}) => Promise<void>;
|
|
20
|
+
getAllForMultipleDocuments: (docOids: string[], { mode }?: {
|
|
21
|
+
mode?: "readonly" | "readwrite" | undefined;
|
|
22
|
+
}) => Promise<DocumentBaseline[]>;
|
|
23
|
+
getAllSince: (timestamp: string | null, { mode }?: {
|
|
24
|
+
mode?: "readonly" | "readwrite" | undefined;
|
|
25
|
+
}) => Promise<DocumentBaseline[]>;
|
|
26
|
+
get: (oid: ObjectIdentifier, { transaction, mode, }?: {
|
|
27
|
+
transaction?: IDBTransaction | undefined;
|
|
28
|
+
mode?: "readonly" | "readwrite" | undefined;
|
|
29
|
+
}) => Promise<DocumentBaseline>;
|
|
30
|
+
set: <T>(baseline: DocumentBaseline<T>, { transaction }?: {
|
|
31
|
+
transaction?: IDBTransaction | undefined;
|
|
32
|
+
}) => Promise<void>;
|
|
33
|
+
setAll: <T>(baselines: DocumentBaseline<T>[], { transaction }?: {
|
|
34
|
+
transaction?: IDBTransaction | undefined;
|
|
35
|
+
}) => Promise<void>;
|
|
36
|
+
reset: () => Promise<undefined>;
|
|
37
|
+
delete: (oid: ObjectIdentifier, { transaction }: {
|
|
38
|
+
transaction?: IDBTransaction | undefined;
|
|
39
|
+
}) => Promise<void>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IDBService } from '../IDBService.js';
|
|
2
|
+
export type LocalReplicaInfo = {
|
|
3
|
+
type: 'localReplicaInfo';
|
|
4
|
+
id: string;
|
|
5
|
+
ackedLogicalTime: string | null;
|
|
6
|
+
lastSyncedLogicalTime: string | null;
|
|
7
|
+
};
|
|
8
|
+
export declare class LocalReplicaStore extends IDBService {
|
|
9
|
+
private _creating;
|
|
10
|
+
private cached;
|
|
11
|
+
get: ({ transaction, }?: {
|
|
12
|
+
transaction?: IDBTransaction | undefined;
|
|
13
|
+
}) => Promise<LocalReplicaInfo>;
|
|
14
|
+
update: (data: Partial<LocalReplicaInfo>, { transaction }?: {
|
|
15
|
+
transaction?: IDBTransaction | undefined;
|
|
16
|
+
}) => Promise<void>;
|
|
17
|
+
reset: () => Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AckMessage, HeartbeatMessage, OperationMessage, PresenceUpdateMessage, SyncMessage } from '@verdant-web/common';
|
|
2
|
+
import { Metadata } from './Metadata.js';
|
|
3
|
+
export declare class MessageCreator {
|
|
4
|
+
private meta;
|
|
5
|
+
constructor(meta: Metadata);
|
|
6
|
+
createOperation: (init: Pick<OperationMessage, 'operations'> & {
|
|
7
|
+
timestamp?: string;
|
|
8
|
+
}) => Promise<OperationMessage>;
|
|
9
|
+
createMigrationOperation: ({ targetVersion, ...init }: Pick<OperationMessage, "operations"> & {
|
|
10
|
+
targetVersion: number;
|
|
11
|
+
}) => Promise<OperationMessage>;
|
|
12
|
+
/**
|
|
13
|
+
* @param since - override local understanding of last sync time
|
|
14
|
+
*/
|
|
15
|
+
createSyncStep1: (since?: string | null) => Promise<SyncMessage>;
|
|
16
|
+
createPresenceUpdate: (presence: any) => Promise<PresenceUpdateMessage>;
|
|
17
|
+
createHeartbeat: () => Promise<HeartbeatMessage>;
|
|
18
|
+
createAck: (nonce: string) => Promise<AckMessage>;
|
|
19
|
+
}
|