@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.
@@ -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;
@@ -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;AAEnC,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,UAUF,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,eAAO,MAAM,mBAAmB,GAAI,MAAM,YAAY,KAAG,aACS,CAAC;AAEnE,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;AAEH,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"}
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"}
@@ -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 { Mnemonic, SimpleName } from "../Type.js";
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
- * Use this option to create Evolu with the specified mnemonic. If omitted,
63
- * the mnemonic will be autogenerated. That should be the default behavior
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 mnemonic?: Mnemonic;
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
- * the process ends, making them forensically safe for sensitive data.
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,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,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;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAE7B;;;;;;;;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"}
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"}
@@ -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, OwnerRow } from "./Owner.js";
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 owner: AppOwner;
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":"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"}
1
+ {"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EAGpB,2BAA2B,EAE5B,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAM,MAAM,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAEL,qBAAqB,EAErB,OAAO,EAEP,SAAS,EACT,WAAW,EAEX,SAAS,EAEV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAS,EAAE,EAAE,QAAQ,EAAU,UAAU,EAAU,MAAM,YAAY,CAAC;AAC7E,OAAO,EAEL,MAAM,EAEP,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAe,YAAY,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAqC,MAAM,YAAY,CAAC;AACzE,OAAO,EAKL,aAAa,EAEb,WAAW,EAGX,QAAQ,EAKR,aAAa,EAEb,OAAO,EAER,MAAM,eAAe,CAAC;AACvB,OAAO,EAIL,KAAK,EAEN,MAAM,YAAY,CAAC;AACpB,OAAO,EAGL,iBAAiB,EAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,aAAa,EAAuB,MAAM,WAAW,CAAC;AAC/D,OAAO,EASL,cAAc,EAMf,MAAM,gBAAgB,CAAC;AAExB,eAAO,MAAM,OAAO;;;EAGlB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAE1C,eAAO,MAAM,OAAO;;;EAAwC,CAAC;AAC7D,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAE1C,eAAO,MAAM,QAAQ;;;;;;;;;EAGnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAE5C,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;AAE7D,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,QAAQ,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;CACzC;AAED,MAAM,MAAM,aAAa,GACrB;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;IACnB,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAClD,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAClD,QAAQ,CAAC,iBAAiB,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;CAClD,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;IACnB,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC;CAChD,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE;QACjB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;KAC7B,CAAC;CACH,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;CACnC,CAAC;AAEN,MAAM,MAAM,cAAc,GACtB;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EACV,WAAW,GACX,iBAAiB,GACjB,cAAc,GACd,aAAa,GACb,2BAA2B,CAAC;CACjC,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;IACnB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAC9C,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;CACnD,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;CACrB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B,CAAC;AAEN,MAAM,MAAM,oBAAoB,GAAG,qBAAqB,GACtD,aAAa,GACb,UAAU,GACV,OAAO,GACP,SAAS,GACT,YAAY,GACZ,iBAAiB,GACjB,oBAAoB,CAAC;AA0DvB,eAAO,MAAM,yBAAyB,GACpC,cAAc,oBAAoB,KACjC,QA+VF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GACrB,MAAM,SAAS,MACf,iBAAwB;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,KAAG,MAAM,CAC7D,QAAQ,EACR,WAAW,CA4DZ,CAAC;AAKJ,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;KAChC,CAAC,CAAC;CACJ;AAGD,eAAO,MAAM,aAAa,GAAI,MAAM,SAAS,KAAG,UAmB/C,CAAC;AAiEF,eAAO,MAAM,cAAc,GACzB,WAAW,MAAM,EACjB,SAAS,aAAa,CAAC,MAAM,CAAC,KAC7B,OAcW,CAAC;AA0Mf,eAAO,MAAM,uCAAuC,GACjD,MAAM,SAAS,GAAG,gBAAgB,MAClC,SAAS,aAAa,EAAE,SAAS,WAAW,KAAG,MAAM,CAAC,IAAI,EAAE,WAAW,CA0BvE,CAAC;AA4FJ,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;CACjC;AAED,MAAM,WAAW,aAAc,SAAQ,iBAAiB,EAAE,OAAO;CAAG"}
@@ -1,20 +1,19 @@
1
- import { isNonEmptyArray, isNonEmptyReadonlyArray, } from "../Array.js";
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, createOwnerRow, } from "./Owner.js";
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 ownerExists = currentDbSchema.value.tables.some((table) => table.name === "evolu_owner");
54
- const appOwnerAndOwnerRow = ownerExists
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
- ownerRowRef: createRef(ownerRow),
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
- if (!ownerExists && isNonEmptyReadonlyArray(initMessage.initialData)) {
81
- const result = applyChanges(depsWithoutSync)(initMessage.initialData);
82
- if (!result.ok)
83
- return result;
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
- const owner = deps.ownerRowRef.get();
171
- // TODO: Check owner whether it's allowed to write, return an
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 initializeDbResult = initializeDb(deps)(message.restore.mnemonic);
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 selectAppOwner = (deps) => {
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
- "key" text not null primary key,
418
- "value" any not null
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 ("key", "value")
424
- values ('protocolVersion', ${protocolVersion});
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
- const appOwner = createAppOwner(deps)(mnemonic);
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 lastTimestamp = timestampStringToTimestamp(deps.ownerRowRef.get().timestamp);
532
+ let clockTimestamp = deps.clock.get();
505
533
  const messages = [];
506
534
  for (const change of changes) {
507
- const nextTimestamp = sendTimestamp(deps)(lastTimestamp);
535
+ const nextTimestamp = sendTimestamp(deps)(clockTimestamp);
508
536
  if (!nextTimestamp.ok)
509
537
  return nextTimestamp;
510
- lastTimestamp = nextTimestamp.value;
511
- messages.push({ timestamp: lastTimestamp, change });
538
+ clockTimestamp = nextTimestamp.value;
539
+ messages.push({ timestamp: clockTimestamp, change });
512
540
  }
513
- const apply = applyMessages(deps)(messages, lastTimestamp);
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, lastTimestamp) => {
522
- const ownerId = ownerIdToBinaryOwnerId(deps.ownerRowRef.get().id);
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
- const timestamp = timestampToTimestampString(lastTimestamp);
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 ownerId = deps.ownerRowRef.get().id;
645
- const message = createProtocolMessageForSync(deps)(ownerId);
646
- if (message) {
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: (_ownerId) => writeKey,
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: (_ownerId, messages) => {
675
- // TODO: Get owner by _ownerId when we support more.
676
- const owner = deps.ownerRowRef.get();
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 timestamp = timestampStringToTimestamp(owner.timestamp);
713
+ let clockTimestamp = deps.clock.get();
693
714
  for (const message of messages) {
694
- const receive = receiveTimestamp(deps)(timestamp, message.timestamp);
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
- timestamp = receive.value;
720
+ clockTimestamp = receive.value;
700
721
  }
701
- const applyMessagesResult = applyMessages({ ...deps, storage })(decodedAndDecryptedMessages, timestamp);
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
- const { encryptionKey } = deps.ownerRowRef.get();
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 EvoluConfigWithInitialData<S extends EvoluSchema = EvoluSchema> extends Config {
376
+ export interface EvoluConfigWithFunctions extends Config {
377
377
  /**
378
- * Use this option to create initial data (fixtures).
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
- * initialData: (evolu) => {
385
- * const todoCategory = evolu.insert("todoCategory", {
386
- * name: "Not Urgent",
387
- * });
388
- *
389
- * // This is a developer error, which should be fixed immediately.
390
- * assert(todoCategory.ok, "invalid initial data");
391
- *
392
- * evolu.insert("todo", {
393
- * title: "Try React Suspense",
394
- * categoryId: todoCategory.value.id,
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
- initialData?: (evolu: EvoluForInitialData<S>) => void;
401
- }
402
- export interface EvoluForInitialData<S extends EvoluSchema = EvoluSchema> {
403
- insert: Mutation<S, "insert">;
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<EvoluConfigWithInitialData<S>>) => Evolu<S>;
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