@evolu/common 6.0.1-preview.15 → 6.0.1-preview.17
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/src/Crypto.d.ts +0 -1
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +2 -1
- package/dist/src/Evolu/Config.d.ts +7 -7
- package/dist/src/Evolu/Config.d.ts.map +1 -1
- package/dist/src/Evolu/Db.d.ts +5 -9
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +139 -117
- package/dist/src/Evolu/Evolu.d.ts +21 -19
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +9 -31
- package/dist/src/Evolu/Owner.d.ts +84 -105
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +79 -89
- package/dist/src/Evolu/Protocol.d.ts +2 -2
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +2 -1
- package/dist/src/Evolu/Public.d.ts +1 -1
- package/dist/src/Evolu/Public.d.ts.map +1 -1
- package/dist/src/Evolu/Schema.d.ts +0 -7
- package/dist/src/Evolu/Schema.d.ts.map +1 -1
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +1 -0
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +1 -0
- package/package.json +1 -1
- package/src/Crypto.ts +6 -4
- package/src/Evolu/Config.ts +7 -7
- package/src/Evolu/Db.ts +206 -169
- package/src/Evolu/Evolu.ts +30 -56
- package/src/Evolu/Owner.ts +129 -203
- package/src/Evolu/Protocol.ts +3 -8
- package/src/Evolu/Public.ts +1 -6
- package/src/Evolu/Schema.ts +1 -9
- package/src/Result.ts +1 -0
- package/src/Type.ts +1 -0
package/dist/src/Crypto.d.ts
CHANGED
|
@@ -43,7 +43,6 @@ export declare const createSlip21Id: (seed: MnemonicSeed, path: ReadonlyArray<st
|
|
|
43
43
|
/** The encryption key for {@link SymmetricCrypto}. */
|
|
44
44
|
export declare const EncryptionKey: import("./Type.js").BrandType<import("./Type.js").BrandType<import("./Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("./Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("./Type.js").Uint8ArrayError>, "Length32", import("./Type.js").LengthError<32>, import("./Type.js").Uint8ArrayError>, "EncryptionKey", import("./Type.js").BrandWithoutRefineError<"EncryptionKey", import("./Type.js").Uint8ArrayError | import("./Type.js").LengthError<32>>, never>;
|
|
45
45
|
export type EncryptionKey = typeof EncryptionKey.Type;
|
|
46
|
-
export declare const createEncryptionKey: (seed: MnemonicSeed) => EncryptionKey;
|
|
47
46
|
/** Symmetric cryptography. */
|
|
48
47
|
export interface SymmetricCrypto {
|
|
49
48
|
readonly nonceLength: NonNegativeInt;
|
package/dist/src/Crypto.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Crypto.d.ts","sourceRoot":"","sources":["../../src/Crypto.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EAAc,MAAM,EAAW,MAAM,aAAa,CAAC;AAC1D,OAAO,EAEL,EAAE,EAEF,QAAQ,EACR,cAAc,EAEf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"Crypto.d.ts","sourceRoot":"","sources":["../../src/Crypto.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EAAc,MAAM,EAAW,MAAM,aAAa,CAAC;AAC1D,OAAO,EAEL,EAAE,EAEF,QAAQ,EACR,cAAc,EAEf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,yDAAyD;AACzD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG,CAAC,WAAW,CAAC,EAAE,MAAM,KAAK,WAAW,CAAC;AAEtE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;CAC/C;AAED,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,EAAE,iBACS,CAAC;AAE1C,MAAM,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;CACzC;AAED,eAAO,MAAM,qBAAqB,EAAE,cACe,CAAC;AAEpD,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;AAE9D,eAAO,MAAM,sBAAsB,GAAI,UAAU,QAAQ,KAAG,YACR,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,YAAY,EAClB,MAAM,aAAa,CAAC,MAAM,CAAC,KAC1B,UAeF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,GACzB,MAAM,YAAY,EAClB,MAAM,aAAa,CAAC,MAAM,CAAC,KAC1B,EAUF,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,aAAa,8fAAiD,CAAC;AAC5E,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,IAAI,CAAC;AAEtD,8BAA8B;AAC9B,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IAErC,QAAQ,CAAC,OAAO,EAAE,CAChB,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,aAAa,KACzB;QACH,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;QAC3B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;KACjC,CAAC;IAEF,QAAQ,CAAC,OAAO,EAAE,CAChB,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,aAAa,EAC5B,KAAK,EAAE,UAAU,KACd,MAAM,CAAC,UAAU,EAAE,2BAA2B,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC3C;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAChC,MAAM,oBAAoB,KACzB,eAyBF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,cAAc,KAAG,cAO1D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,cAAc,KAAG,cAE3D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC;AAExE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC3C"}
|
package/dist/src/Crypto.js
CHANGED
|
@@ -12,6 +12,7 @@ import { wordlist } from "@scure/bip39/wordlists/english";
|
|
|
12
12
|
import { urlAlphabet } from "nanoid";
|
|
13
13
|
import { getOrThrow, trySync } from "./Result.js";
|
|
14
14
|
import { brand, length, NonNegativeInt, Uint8Array, } from "./Type.js";
|
|
15
|
+
import { assert } from "./Assert.js";
|
|
15
16
|
/** Cryptographically secure PRNG. Uses internal OS-level crypto.getRandomValues. */
|
|
16
17
|
export const createRandomBytes = (bytesLength = 32) => randomBytes(bytesLength);
|
|
17
18
|
export const createEnglishMnemonic = () => bip39.generateMnemonic(wordlist, 128);
|
|
@@ -22,6 +23,7 @@ export const mnemonicToMnemonicSeed = (mnemonic) => bip39.mnemonicToSeedSync(mne
|
|
|
22
23
|
* https://github.com/satoshilabs/slips/blob/master/slip-0021.md
|
|
23
24
|
*/
|
|
24
25
|
export const createSlip21 = (seed, path) => {
|
|
26
|
+
assert(seed.length >= 16 && seed.length <= 64, `Unusual SLIP-0021 seed length: ${seed.length} bytes`);
|
|
25
27
|
let m = hmac(sha512, "Symmetric key seed", seed);
|
|
26
28
|
for (const component of path) {
|
|
27
29
|
const p = new TextEncoder().encode(component);
|
|
@@ -55,7 +57,6 @@ export const createSlip21Id = (seed, path) => {
|
|
|
55
57
|
};
|
|
56
58
|
/** The encryption key for {@link SymmetricCrypto}. */
|
|
57
59
|
export const EncryptionKey = brand("EncryptionKey", length(32)(Uint8Array));
|
|
58
|
-
export const createEncryptionKey = (seed) => createSlip21(seed, ["Evolu", "Encryption Key"]);
|
|
59
60
|
/**
|
|
60
61
|
* XChaCha20-Poly1305 encryption
|
|
61
62
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ConsoleConfig } from "../Console.js";
|
|
2
|
-
import {
|
|
2
|
+
import { SimpleName } from "../Type.js";
|
|
3
3
|
import type { DbIndexesBuilder } from "./Kysely.js";
|
|
4
|
+
import type { AppOwner } from "./Owner.js";
|
|
4
5
|
export interface Config extends ConsoleConfig {
|
|
5
6
|
/**
|
|
6
7
|
* The name of the Evolu instance. Evolu is multitenant - it can run multiple
|
|
@@ -59,17 +60,16 @@ export interface Config extends ConsoleConfig {
|
|
|
59
60
|
*/
|
|
60
61
|
readonly indexes?: DbIndexesBuilder;
|
|
61
62
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* until special UX requirements are needed (e.g., multitenancy).
|
|
63
|
+
* Initial AppOwner to use when creating Evolu instance. If omitted, a new
|
|
64
|
+
* AppOwner will be generated automatically.
|
|
65
65
|
*/
|
|
66
|
-
readonly
|
|
66
|
+
readonly initialAppOwner?: AppOwner;
|
|
67
67
|
/**
|
|
68
68
|
* Use in-memory SQLite database instead of persistent storage. Useful for
|
|
69
69
|
* testing or temporary data that doesn't need persistence.
|
|
70
70
|
*
|
|
71
|
-
* In-memory databases exist only in RAM and are completely destroyed when
|
|
72
|
-
*
|
|
71
|
+
* In-memory databases exist only in RAM and are completely destroyed when the
|
|
72
|
+
* process ends, making them forensically safe for sensitive data.
|
|
73
73
|
*
|
|
74
74
|
* The default value is: `false`.
|
|
75
75
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,MAAO,SAAQ,aAAa;IAC3C;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAE1B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC;IAEpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,aAAa,EAAE,MAM3B,CAAC"}
|
package/dist/src/Evolu/Db.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { CreateMnemonicDep, CreateRandomBytesDep, SymmetricCryptoDecryptError }
|
|
|
5
5
|
import { TransferableError } from "../Error.js";
|
|
6
6
|
import { NanoIdLibDep } from "../NanoId.js";
|
|
7
7
|
import { RandomDep } from "../Random.js";
|
|
8
|
-
import { Ref } from "../Ref.js";
|
|
9
8
|
import { Result } from "../Result.js";
|
|
10
9
|
import { CreateSqliteDriverDep, SafeSql, SqliteDep, SqliteError, SqliteRow } from "../Sqlite.js";
|
|
11
10
|
import { TimeDep } from "../Time.js";
|
|
@@ -13,7 +12,7 @@ import { Id, Mnemonic, SimpleName } from "../Type.js";
|
|
|
13
12
|
import { Worker } from "../Worker.js";
|
|
14
13
|
import { Config } from "./Config.js";
|
|
15
14
|
import { QueryPatches } from "./Diff.js";
|
|
16
|
-
import { AppOwner
|
|
15
|
+
import { AppOwner } from "./Owner.js";
|
|
17
16
|
import { BinaryOwnerId, CrdtMessage, DbChange, ProtocolError, Storage } from "./Protocol.js";
|
|
18
17
|
import { Query } from "./Query.js";
|
|
19
18
|
import { SqliteStorageBase } from "./Storage.js";
|
|
@@ -49,7 +48,6 @@ export type DbWorkerInput = {
|
|
|
49
48
|
readonly type: "init";
|
|
50
49
|
readonly config: Config;
|
|
51
50
|
readonly dbSchema: DbSchema;
|
|
52
|
-
readonly initialData: ReadonlyArray<DbChange>;
|
|
53
51
|
} | {
|
|
54
52
|
readonly type: "mutate";
|
|
55
53
|
readonly tabId: Id;
|
|
@@ -77,7 +75,8 @@ export type DbWorkerInput = {
|
|
|
77
75
|
};
|
|
78
76
|
export type DbWorkerOutput = {
|
|
79
77
|
readonly type: "onInit";
|
|
80
|
-
readonly
|
|
78
|
+
readonly appOwner: AppOwner;
|
|
79
|
+
readonly isFirst: boolean;
|
|
81
80
|
} | {
|
|
82
81
|
readonly type: "onError";
|
|
83
82
|
readonly error: SqliteError | TransferableError | TimestampError | ProtocolError | SymmetricCryptoDecryptError;
|
|
@@ -99,9 +98,6 @@ export type DbWorkerOutput = {
|
|
|
99
98
|
readonly file: Uint8Array;
|
|
100
99
|
};
|
|
101
100
|
export type DbWorkerPlatformDeps = CreateSqliteDriverDep & CreateSyncDep & ConsoleDep & TimeDep & RandomDep & NanoIdLibDep & CreateMnemonicDep & CreateRandomBytesDep;
|
|
102
|
-
export interface OwnerRowRefDep {
|
|
103
|
-
readonly ownerRowRef: Ref<OwnerRow>;
|
|
104
|
-
}
|
|
105
101
|
export declare const createDbWorkerForPlatform: (platformDeps: DbWorkerPlatformDeps) => DbWorker;
|
|
106
102
|
/**
|
|
107
103
|
* Get the current database schema by reading SQLite metadata.
|
|
@@ -121,9 +117,9 @@ export interface DbSnapshot {
|
|
|
121
117
|
export declare const getDbSnapshot: (deps: SqliteDep) => DbSnapshot;
|
|
122
118
|
export declare const createAppTable: (tableName: string, columns: ReadonlyArray<string>) => SafeSql;
|
|
123
119
|
export declare const applyMessageToTimestampAndHistoryTables: (deps: SqliteDep & ClientStorageDep) => (ownerId: BinaryOwnerId, message: CrdtMessage) => Result<void, SqliteError>;
|
|
124
|
-
export interface ClientStorage extends SqliteStorageBase, Storage {
|
|
125
|
-
}
|
|
126
120
|
export interface ClientStorageDep {
|
|
127
121
|
readonly storage: ClientStorage;
|
|
128
122
|
}
|
|
123
|
+
export interface ClientStorage extends SqliteStorageBase, Storage {
|
|
124
|
+
}
|
|
129
125
|
//# sourceMappingURL=Db.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Db.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Db.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Evolu/Db.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import { isNonEmptyArray
|
|
1
|
+
import { isNonEmptyArray } from "../Array.js";
|
|
2
2
|
import { assert, assertNonEmptyReadonlyArray } from "../Assert.js";
|
|
3
3
|
import { createSymmetricCrypto, } from "../Crypto.js";
|
|
4
4
|
import { eqArrayNumber } from "../Eq.js";
|
|
5
5
|
import { constFalse, exhaustiveCheck } from "../Function.js";
|
|
6
6
|
import { objectToEntries } from "../Object.js";
|
|
7
|
-
import { createRef } from "../Ref.js";
|
|
8
7
|
import { ok } from "../Result.js";
|
|
9
8
|
import { createSqlite, explainSqliteQueryPlan, sql, } from "../Sqlite.js";
|
|
10
9
|
import { array, object, String } from "../Type.js";
|
|
11
10
|
import { createInitializedWorker, } from "../Worker.js";
|
|
12
11
|
import { makePatches } from "./Diff.js";
|
|
13
|
-
import { createAppOwner
|
|
14
|
-
import { applyProtocolMessageAsClient, Base64Url256, binaryIdToId, createProtocolMessageForSync, createProtocolMessageFromCrdtMessages, decryptAndDecodeDbChange, encodeAndEncryptDbChange, idToBinaryId, ownerIdToBinaryOwnerId, protocolVersion, } from "./Protocol.js";
|
|
12
|
+
import { createAppOwner } from "./Owner.js";
|
|
13
|
+
import { applyProtocolMessageAsClient, Base64Url256, binaryIdToId, binaryOwnerIdToOwnerId, createProtocolMessageForSync, createProtocolMessageFromCrdtMessages, decryptAndDecodeDbChange, encodeAndEncryptDbChange, idToBinaryId, ownerIdToBinaryOwnerId, protocolVersion, } from "./Protocol.js";
|
|
15
14
|
import { createQueryRowsCache, deserializeQuery, emptyRows, } from "./Query.js";
|
|
16
15
|
import { createSqliteStorageBase, } from "./Storage.js";
|
|
17
|
-
import { binaryTimestampToTimestamp, receiveTimestamp, sendTimestamp, timestampStringToTimestamp, timestampToBinaryTimestamp, timestampToTimestampString, } from "./Timestamp.js";
|
|
16
|
+
import { binaryTimestampToTimestamp, createInitialTimestamp, receiveTimestamp, sendTimestamp, timestampStringToTimestamp, timestampToBinaryTimestamp, timestampToTimestampString, } from "./Timestamp.js";
|
|
18
17
|
export const DbTable = object({
|
|
19
18
|
name: Base64Url256,
|
|
20
19
|
columns: array(Base64Url256),
|
|
@@ -24,6 +23,22 @@ export const DbSchema = object({
|
|
|
24
23
|
tables: array(DbTable),
|
|
25
24
|
indexes: array(DbIndex),
|
|
26
25
|
});
|
|
26
|
+
const createClock = (deps) => (initialTimestamp = createInitialTimestamp(deps)) => {
|
|
27
|
+
let currentTimestamp = initialTimestamp;
|
|
28
|
+
return {
|
|
29
|
+
get: () => currentTimestamp,
|
|
30
|
+
save: (timestamp) => {
|
|
31
|
+
currentTimestamp = timestamp;
|
|
32
|
+
const timestampString = timestampToTimestampString(timestamp);
|
|
33
|
+
const saveTimestamp = deps.sqlite.exec(sql.prepared `
|
|
34
|
+
update evolu_config set "clock" = ${timestampString};
|
|
35
|
+
`);
|
|
36
|
+
if (!saveTimestamp.ok)
|
|
37
|
+
return saveTimestamp;
|
|
38
|
+
return ok();
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
};
|
|
27
42
|
export const createDbWorkerForPlatform = (platformDeps) => {
|
|
28
43
|
const tabQueryRowsCacheMap = new Map();
|
|
29
44
|
const getQueryRowsCache = (tabId) => {
|
|
@@ -43,20 +58,63 @@ export const createDbWorkerForPlatform = (platformDeps) => {
|
|
|
43
58
|
return null;
|
|
44
59
|
}
|
|
45
60
|
const sqlite = sqliteResult.value;
|
|
61
|
+
const platformDepsWithSqlite = { ...platformDeps, sqlite };
|
|
46
62
|
const deps = sqlite.transaction(() => {
|
|
47
63
|
const currentDbSchema = getDbSchema({ sqlite })();
|
|
48
64
|
if (!currentDbSchema.ok)
|
|
49
65
|
return currentDbSchema;
|
|
66
|
+
let appOwner;
|
|
67
|
+
let clock;
|
|
68
|
+
const dbIsInitialized = currentDbSchema.value.tables.some((table) => table.name === "evolu_version");
|
|
69
|
+
if (dbIsInitialized) {
|
|
70
|
+
const versionResult = sqlite.exec(sql `select protocolVersion from evolu_version limit 1;`);
|
|
71
|
+
if (!versionResult.ok)
|
|
72
|
+
return versionResult;
|
|
73
|
+
// TODO: Handle version migrations here if needed
|
|
74
|
+
// const [{ protocolVersion }] = protocolVersionResult.value.rows;
|
|
75
|
+
// if (protocolVersion < currentProtocolVersion) {
|
|
76
|
+
// const migrateResult = migrateDatabase({ sqlite })(
|
|
77
|
+
// protocolVersion,
|
|
78
|
+
// currentProtocolVersion
|
|
79
|
+
// );
|
|
80
|
+
// if (!migrateResult.ok) return migrateResult;
|
|
81
|
+
// }
|
|
82
|
+
const configResult = sqlite.exec(sql `
|
|
83
|
+
select
|
|
84
|
+
clock,
|
|
85
|
+
appOwnerId,
|
|
86
|
+
appOwnerEncryptionKey,
|
|
87
|
+
appOwnerWriteKey,
|
|
88
|
+
appOwnerMnemonic
|
|
89
|
+
from evolu_config
|
|
90
|
+
limit 1;
|
|
91
|
+
`);
|
|
92
|
+
if (!configResult.ok)
|
|
93
|
+
return configResult;
|
|
94
|
+
const [config] = configResult.value.rows;
|
|
95
|
+
appOwner = {
|
|
96
|
+
type: "AppOwner",
|
|
97
|
+
id: config.appOwnerId,
|
|
98
|
+
encryptionKey: config.appOwnerEncryptionKey,
|
|
99
|
+
writeKey: config.appOwnerWriteKey,
|
|
100
|
+
mnemonic: config.appOwnerMnemonic,
|
|
101
|
+
};
|
|
102
|
+
clock = createClock(platformDepsWithSqlite)(timestampStringToTimestamp(config.clock));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
appOwner =
|
|
106
|
+
initMessage.config.initialAppOwner ??
|
|
107
|
+
createAppOwner(platformDeps.createMnemonic());
|
|
108
|
+
clock = createClock(platformDepsWithSqlite)();
|
|
109
|
+
const initializeDbResult = initializeDb(platformDepsWithSqlite)(appOwner, clock);
|
|
110
|
+
if (!initializeDbResult.ok)
|
|
111
|
+
return initializeDbResult;
|
|
112
|
+
}
|
|
50
113
|
const ensureDbSchemaResult = ensureDbSchema({ sqlite })(initMessage.dbSchema, currentDbSchema.value);
|
|
51
114
|
if (!ensureDbSchemaResult.ok)
|
|
52
115
|
return ensureDbSchemaResult;
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
? selectAppOwner({ sqlite })
|
|
56
|
-
: initializeDb({ ...platformDeps, sqlite })(initMessage.config.mnemonic);
|
|
57
|
-
if (!appOwnerAndOwnerRow.ok)
|
|
58
|
-
return appOwnerAndOwnerRow;
|
|
59
|
-
const [appOwner, ownerRow] = appOwnerAndOwnerRow.value;
|
|
116
|
+
const owners = new Map();
|
|
117
|
+
owners.set(appOwner.id, appOwner);
|
|
60
118
|
const depsWithoutSyncAndStorage = {
|
|
61
119
|
...platformDeps,
|
|
62
120
|
postMessage,
|
|
@@ -64,7 +122,8 @@ export const createDbWorkerForPlatform = (platformDeps) => {
|
|
|
64
122
|
timestampConfig: initMessage.config,
|
|
65
123
|
symmetricCrypto: createSymmetricCrypto(platformDeps),
|
|
66
124
|
getQueryRowsCache,
|
|
67
|
-
|
|
125
|
+
clock,
|
|
126
|
+
owners,
|
|
68
127
|
};
|
|
69
128
|
const storage = createClientStorage(depsWithoutSyncAndStorage)({
|
|
70
129
|
onStorageError: (error) => {
|
|
@@ -77,12 +136,11 @@ export const createDbWorkerForPlatform = (platformDeps) => {
|
|
|
77
136
|
...depsWithoutSyncAndStorage,
|
|
78
137
|
storage: storage.value,
|
|
79
138
|
};
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
postMessage({ type: "onInit", owner: appOwner });
|
|
139
|
+
postMessage({
|
|
140
|
+
type: "onInit",
|
|
141
|
+
appOwner,
|
|
142
|
+
isFirst: !dbIsInitialized,
|
|
143
|
+
});
|
|
86
144
|
const sync = platformDeps.createSync(platformDeps)({
|
|
87
145
|
...initMessage.config,
|
|
88
146
|
onOpen: safeHandler(handleSyncOpen(depsWithoutSync)),
|
|
@@ -167,12 +225,8 @@ export const createDbWorkerForPlatform = (platformDeps) => {
|
|
|
167
225
|
const messages = applyChanges(deps)(toSyncChanges, onChange);
|
|
168
226
|
if (!messages.ok)
|
|
169
227
|
return messages;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
// error if not.
|
|
173
|
-
if (owner.writeKey == null) {
|
|
174
|
-
return ok();
|
|
175
|
-
}
|
|
228
|
+
// TODO: Use owner from db change or AppOwner
|
|
229
|
+
const owner = Array.from(deps.owners.values())[0];
|
|
176
230
|
const protocolMessage = createProtocolMessageFromCrdtMessages(deps)(owner, messages.value);
|
|
177
231
|
deps.console.log("[db]", "send data message", messages.value, protocolMessage);
|
|
178
232
|
deps.sync.send(protocolMessage);
|
|
@@ -210,7 +264,9 @@ export const createDbWorkerForPlatform = (platformDeps) => {
|
|
|
210
264
|
const ensureDbSchemaResult = ensureDbSchema(deps)(message.restore.dbSchema, dbSchema.value);
|
|
211
265
|
if (!ensureDbSchemaResult.ok)
|
|
212
266
|
return ensureDbSchemaResult;
|
|
213
|
-
const
|
|
267
|
+
const appOwner = createAppOwner(message.restore.mnemonic);
|
|
268
|
+
const clock = createClock(deps)();
|
|
269
|
+
const initializeDbResult = initializeDb(deps)(appOwner, clock);
|
|
214
270
|
if (!initializeDbResult.ok)
|
|
215
271
|
return initializeDbResult;
|
|
216
272
|
}
|
|
@@ -389,39 +445,46 @@ export const createAppTable = (tableName, columns) => `
|
|
|
389
445
|
.join(", ")}
|
|
390
446
|
);
|
|
391
447
|
`;
|
|
392
|
-
const
|
|
393
|
-
const result = deps.sqlite.exec(sql `
|
|
394
|
-
select mnemonic, id, createdAt, encryptionKey, writeKey, timestamp
|
|
395
|
-
from evolu_owner
|
|
396
|
-
order by createdAt asc
|
|
397
|
-
limit 1;
|
|
398
|
-
`);
|
|
399
|
-
if (!result.ok)
|
|
400
|
-
return result;
|
|
401
|
-
const { rows: [ownerRow], } = result.value;
|
|
402
|
-
assert(ownerRow.writeKey != null, "The writeKey is null");
|
|
403
|
-
const appOwner = {
|
|
404
|
-
type: "AppOwner",
|
|
405
|
-
mnemonic: ownerRow.mnemonic,
|
|
406
|
-
createdAt: ownerRow.createdAt,
|
|
407
|
-
id: ownerRow.id,
|
|
408
|
-
encryptionKey: ownerRow.encryptionKey,
|
|
409
|
-
writeKey: ownerRow.writeKey,
|
|
410
|
-
};
|
|
411
|
-
return ok([appOwner, ownerRow]);
|
|
412
|
-
};
|
|
413
|
-
const initializeDb = (deps) => (mnemonic) => {
|
|
448
|
+
const initializeDb = (deps) => (initialAppOwner, initialClock) => {
|
|
414
449
|
for (const query of [
|
|
450
|
+
// Never change structure to ensure all versions can read it.
|
|
451
|
+
sql `
|
|
452
|
+
create table evolu_version (
|
|
453
|
+
"protocolVersion" integer not null
|
|
454
|
+
)
|
|
455
|
+
strict;
|
|
456
|
+
`,
|
|
457
|
+
sql `
|
|
458
|
+
insert into evolu_version ("protocolVersion")
|
|
459
|
+
values (${protocolVersion});
|
|
460
|
+
`,
|
|
415
461
|
sql `
|
|
416
462
|
create table evolu_config (
|
|
417
|
-
"
|
|
418
|
-
"
|
|
463
|
+
"clock" text not null,
|
|
464
|
+
"appOwnerId" text not null,
|
|
465
|
+
"appOwnerEncryptionKey" blob not null,
|
|
466
|
+
"appOwnerWriteKey" blob not null,
|
|
467
|
+
"appOwnerMnemonic" text
|
|
419
468
|
)
|
|
420
469
|
strict;
|
|
421
470
|
`,
|
|
422
471
|
sql `
|
|
423
|
-
insert into evolu_config
|
|
424
|
-
|
|
472
|
+
insert into evolu_config
|
|
473
|
+
(
|
|
474
|
+
"clock",
|
|
475
|
+
"appOwnerId",
|
|
476
|
+
"appOwnerEncryptionKey",
|
|
477
|
+
"appOwnerWriteKey",
|
|
478
|
+
"appOwnerMnemonic"
|
|
479
|
+
)
|
|
480
|
+
values
|
|
481
|
+
(
|
|
482
|
+
${timestampToTimestampString(initialClock.get())},
|
|
483
|
+
${initialAppOwner.id},
|
|
484
|
+
${initialAppOwner.encryptionKey},
|
|
485
|
+
${initialAppOwner.writeKey},
|
|
486
|
+
${initialAppOwner.mnemonic ?? null}
|
|
487
|
+
);
|
|
425
488
|
`,
|
|
426
489
|
/**
|
|
427
490
|
* The History table stores all values per ownerId, timestamp, table, id,
|
|
@@ -458,59 +521,24 @@ const initializeDb = (deps) => (mnemonic) => {
|
|
|
458
521
|
"timestamp" desc
|
|
459
522
|
);
|
|
460
523
|
`,
|
|
461
|
-
sql `
|
|
462
|
-
create table evolu_owner (
|
|
463
|
-
"mnemonic" text not null primary key,
|
|
464
|
-
"id" text not null,
|
|
465
|
-
"encryptionKey" blob not null,
|
|
466
|
-
"createdAt" text not null,
|
|
467
|
-
"writeKey" blob,
|
|
468
|
-
"timestamp" text not null
|
|
469
|
-
)
|
|
470
|
-
strict;
|
|
471
|
-
`,
|
|
472
524
|
]) {
|
|
473
525
|
const result = deps.sqlite.exec(query);
|
|
474
526
|
if (!result.ok)
|
|
475
527
|
return result;
|
|
476
528
|
}
|
|
477
|
-
|
|
478
|
-
const ownerRow = createOwnerRow(deps)(appOwner);
|
|
479
|
-
const result = deps.sqlite.exec(sql `
|
|
480
|
-
insert into evolu_owner
|
|
481
|
-
(
|
|
482
|
-
"mnemonic",
|
|
483
|
-
"id",
|
|
484
|
-
"encryptionKey",
|
|
485
|
-
"createdAt",
|
|
486
|
-
"writeKey",
|
|
487
|
-
"timestamp"
|
|
488
|
-
)
|
|
489
|
-
values
|
|
490
|
-
(
|
|
491
|
-
${ownerRow.mnemonic},
|
|
492
|
-
${ownerRow.id},
|
|
493
|
-
${ownerRow.encryptionKey},
|
|
494
|
-
${ownerRow.createdAt},
|
|
495
|
-
${ownerRow.writeKey},
|
|
496
|
-
${ownerRow.timestamp}
|
|
497
|
-
);
|
|
498
|
-
`);
|
|
499
|
-
if (!result.ok)
|
|
500
|
-
return result;
|
|
501
|
-
return ok([appOwner, ownerRow]);
|
|
529
|
+
return ok();
|
|
502
530
|
};
|
|
503
531
|
const applyChanges = (deps) => (changes, onChange) => {
|
|
504
|
-
let
|
|
532
|
+
let clockTimestamp = deps.clock.get();
|
|
505
533
|
const messages = [];
|
|
506
534
|
for (const change of changes) {
|
|
507
|
-
const nextTimestamp = sendTimestamp(deps)(
|
|
535
|
+
const nextTimestamp = sendTimestamp(deps)(clockTimestamp);
|
|
508
536
|
if (!nextTimestamp.ok)
|
|
509
537
|
return nextTimestamp;
|
|
510
|
-
|
|
511
|
-
messages.push({ timestamp:
|
|
538
|
+
clockTimestamp = nextTimestamp.value;
|
|
539
|
+
messages.push({ timestamp: clockTimestamp, change });
|
|
512
540
|
}
|
|
513
|
-
const apply = applyMessages(deps)(messages,
|
|
541
|
+
const apply = applyMessages(deps)(messages, clockTimestamp);
|
|
514
542
|
if (!apply.ok)
|
|
515
543
|
return apply;
|
|
516
544
|
if (onChange)
|
|
@@ -518,8 +546,8 @@ const applyChanges = (deps) => (changes, onChange) => {
|
|
|
518
546
|
assertNonEmptyReadonlyArray(messages);
|
|
519
547
|
return ok(messages);
|
|
520
548
|
};
|
|
521
|
-
const applyMessages = (deps) => (messages,
|
|
522
|
-
const ownerId = ownerIdToBinaryOwnerId(deps.
|
|
549
|
+
const applyMessages = (deps) => (messages, clockTimestamp) => {
|
|
550
|
+
const ownerId = ownerIdToBinaryOwnerId(Array.from(deps.owners.values())[0].id);
|
|
523
551
|
for (const message of messages) {
|
|
524
552
|
const result1 = applyMessageToAppTable(deps)(ownerId, message);
|
|
525
553
|
if (!result1.ok)
|
|
@@ -528,14 +556,7 @@ const applyMessages = (deps) => (messages, lastTimestamp) => {
|
|
|
528
556
|
if (!result2.ok)
|
|
529
557
|
return result2;
|
|
530
558
|
}
|
|
531
|
-
|
|
532
|
-
deps.ownerRowRef.modify((owner) => ({ ...owner, timestamp }));
|
|
533
|
-
const saveTimestamp = deps.sqlite.exec(sql.prepared `
|
|
534
|
-
update evolu_owner set "timestamp" = ${timestamp};
|
|
535
|
-
`);
|
|
536
|
-
if (!saveTimestamp.ok)
|
|
537
|
-
return saveTimestamp;
|
|
538
|
-
return ok();
|
|
559
|
+
return deps.clock.save(clockTimestamp);
|
|
539
560
|
};
|
|
540
561
|
const applyMessageToAppTable = (deps) => (ownerId, message) => {
|
|
541
562
|
const timestamp = timestampToBinaryTimestamp(message.timestamp);
|
|
@@ -641,18 +662,18 @@ const dropAllTables = (deps) => {
|
|
|
641
662
|
return ok();
|
|
642
663
|
};
|
|
643
664
|
const handleSyncOpen = (deps) => (send) => {
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
665
|
+
for (const [id] of deps.owners) {
|
|
666
|
+
const message = createProtocolMessageForSync(deps)(id);
|
|
667
|
+
if (!message)
|
|
668
|
+
return;
|
|
647
669
|
deps.console.log("[db]", "send initial sync message", message);
|
|
648
670
|
send(message);
|
|
649
671
|
}
|
|
650
672
|
};
|
|
651
673
|
const createHandleSyncMessage = (deps) => (input, send) => {
|
|
652
674
|
deps.console.log("[db]", "receive sync message", input);
|
|
653
|
-
const { writeKey } = deps.ownerRowRef.get();
|
|
654
675
|
const output = deps.sqlite.transaction(() => applyProtocolMessageAsClient(deps)(input, {
|
|
655
|
-
getWriteKey: (
|
|
676
|
+
getWriteKey: (ownerId) => deps.owners.get(ownerId)?.writeKey ?? null,
|
|
656
677
|
}));
|
|
657
678
|
if (!output.ok) {
|
|
658
679
|
deps.postMessage({ type: "onError", error: output.error });
|
|
@@ -671,9 +692,9 @@ const createClientStorage = (deps) => (options) => {
|
|
|
671
692
|
...sqliteStorageBase.value,
|
|
672
693
|
validateWriteKey: constFalse,
|
|
673
694
|
setWriteKey: constFalse,
|
|
674
|
-
writeMessages: (
|
|
675
|
-
|
|
676
|
-
|
|
695
|
+
writeMessages: (ownerId, messages) => {
|
|
696
|
+
const owner = deps.owners.get(binaryOwnerIdToOwnerId(ownerId));
|
|
697
|
+
assert(owner, "Missing owner");
|
|
677
698
|
const decodedAndDecryptedMessages = [];
|
|
678
699
|
for (const message of messages) {
|
|
679
700
|
const dbChange = decryptAndDecodeDbChange(deps)(message, owner.encryptionKey);
|
|
@@ -689,16 +710,16 @@ const createClientStorage = (deps) => (options) => {
|
|
|
689
710
|
change: dbChange.value,
|
|
690
711
|
});
|
|
691
712
|
}
|
|
692
|
-
let
|
|
713
|
+
let clockTimestamp = deps.clock.get();
|
|
693
714
|
for (const message of messages) {
|
|
694
|
-
const receive = receiveTimestamp(deps)(
|
|
715
|
+
const receive = receiveTimestamp(deps)(clockTimestamp, message.timestamp);
|
|
695
716
|
if (!receive.ok) {
|
|
696
717
|
deps.postMessage({ type: "onError", error: receive.error });
|
|
697
718
|
return false;
|
|
698
719
|
}
|
|
699
|
-
|
|
720
|
+
clockTimestamp = receive.value;
|
|
700
721
|
}
|
|
701
|
-
const applyMessagesResult = applyMessages({ ...deps, storage })(decodedAndDecryptedMessages,
|
|
722
|
+
const applyMessagesResult = applyMessages({ ...deps, storage })(decodedAndDecryptedMessages, clockTimestamp);
|
|
702
723
|
if (!applyMessagesResult.ok) {
|
|
703
724
|
deps.postMessage({
|
|
704
725
|
type: "onError",
|
|
@@ -710,6 +731,8 @@ const createClientStorage = (deps) => (options) => {
|
|
|
710
731
|
return true;
|
|
711
732
|
},
|
|
712
733
|
readDbChange: (ownerId, timestamp) => {
|
|
734
|
+
const owner = deps.owners.get(binaryOwnerIdToOwnerId(ownerId));
|
|
735
|
+
assert(owner, "Missing owner");
|
|
713
736
|
const result = deps.sqlite.exec(sql `
|
|
714
737
|
select "table", "id", "column", "value"
|
|
715
738
|
from evolu_history
|
|
@@ -736,8 +759,7 @@ const createClientStorage = (deps) => (options) => {
|
|
|
736
759
|
values,
|
|
737
760
|
},
|
|
738
761
|
};
|
|
739
|
-
|
|
740
|
-
return encodeAndEncryptDbChange(deps)(message, encryptionKey);
|
|
762
|
+
return encodeAndEncryptDbChange(deps)(message, owner.encryptionKey);
|
|
741
763
|
},
|
|
742
764
|
};
|
|
743
765
|
return ok(storage);
|
|
@@ -373,34 +373,36 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> {
|
|
|
373
373
|
/** Represent errors that can occur in Evolu. */
|
|
374
374
|
export type EvoluError = TimestampError | ProtocolError | TransferableError | SymmetricCryptoDecryptError | ProtocolUnsupportedVersionError | SqliteError;
|
|
375
375
|
export type EvoluDeps = CreateDbWorkerDep & TimeDep & NanoIdLibDep & Partial<FlushSyncDep> & ConsoleDep & CreateAppStateDep;
|
|
376
|
-
export interface
|
|
376
|
+
export interface EvoluConfigWithFunctions extends Config {
|
|
377
377
|
/**
|
|
378
|
-
*
|
|
378
|
+
* Callback invoked when the database is initialized. Use `isFirst` to perform
|
|
379
|
+
* one-time setup like initial data seeding.
|
|
379
380
|
*
|
|
380
381
|
* ### Example
|
|
381
382
|
*
|
|
382
383
|
* ```ts
|
|
383
384
|
* const evolu = createEvolu(evoluReactWebDeps)(Schema, {
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
385
|
+
* onInit: ({ appOwner, isFirst }) => {
|
|
386
|
+
* if (isFirst) {
|
|
387
|
+
* const todoCategoryId = getOrThrow(
|
|
388
|
+
* evolu.insert("todoCategory", {
|
|
389
|
+
* name: "Not Urgent",
|
|
390
|
+
* }),
|
|
391
|
+
* );
|
|
392
|
+
*
|
|
393
|
+
* evolu.insert("todo", {
|
|
394
|
+
* title: "Try React Suspense",
|
|
395
|
+
* categoryId: todoCategoryId.id,
|
|
396
|
+
* });
|
|
397
|
+
* }
|
|
396
398
|
* },
|
|
397
399
|
* });
|
|
398
400
|
* ```
|
|
399
401
|
*/
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
402
|
+
readonly onInit?: (params: {
|
|
403
|
+
readonly appOwner: AppOwner;
|
|
404
|
+
readonly isFirst: boolean;
|
|
405
|
+
}) => void;
|
|
404
406
|
}
|
|
405
407
|
/**
|
|
406
408
|
* Creates an {@link Evolu} instance configured with the specified
|
|
@@ -449,6 +451,6 @@ export interface EvoluForInitialData<S extends EvoluSchema = EvoluSchema> {
|
|
|
449
451
|
* const evolu = createEvolu(evoluReactDeps)(Schema);
|
|
450
452
|
* ```
|
|
451
453
|
*/
|
|
452
|
-
export declare const createEvolu: (deps: EvoluDeps) => <S extends EvoluSchema>(schema: ValidateSchema<S> extends never ? S : ValidateSchema<S>, partialConfig?: Partial<
|
|
454
|
+
export declare const createEvolu: (deps: EvoluDeps) => <S extends EvoluSchema>(schema: ValidateSchema<S> extends never ? S : ValidateSchema<S>, partialConfig?: Partial<EvoluConfigWithFunctions>) => Evolu<S>;
|
|
453
455
|
export declare const createNamespaceName: (config: Config) => (name: string) => string;
|
|
454
456
|
//# sourceMappingURL=Evolu.d.ts.map
|