@evolu/common 3.1.8 → 4.0.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/src/Config.d.ts +6 -0
- package/dist/src/Config.d.ts.map +1 -1
- package/dist/src/Config.js +1 -0
- package/dist/src/Crdt.d.ts +2 -2
- package/dist/src/Crdt.d.ts.map +1 -1
- package/dist/src/Crdt.js +2 -2
- package/dist/src/Crypto.d.ts +5 -4
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +2 -2
- package/dist/src/Db.d.ts +2 -2
- package/dist/src/Db.d.ts.map +1 -1
- package/dist/src/Db.js +1 -3
- package/dist/src/DbWorker.d.ts +8 -8
- package/dist/src/DbWorker.d.ts.map +1 -1
- package/dist/src/DbWorker.js +44 -28
- package/dist/src/Evolu.d.ts +3 -4
- package/dist/src/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu.js +4 -9
- package/dist/src/OnCompletes.d.ts +3 -3
- package/dist/src/OnCompletes.d.ts.map +1 -1
- package/dist/src/OnCompletes.js +3 -3
- package/dist/src/Platform.d.ts +3 -1
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +1 -0
- package/dist/src/Sql.d.ts.map +1 -1
- package/dist/src/Sql.js +4 -3
- package/dist/src/Sqlite.d.ts +2 -2
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/SyncWorker.d.ts +3 -4
- package/dist/src/SyncWorker.d.ts.map +1 -1
- package/dist/src/SyncWorker.js +1 -1
- package/dist/src/Types.d.ts +13 -0
- package/dist/src/Types.d.ts.map +1 -0
- package/dist/src/Types.js +1 -0
- package/package.json +5 -5
- package/src/Config.ts +8 -0
- package/src/Crdt.ts +2 -2
- package/src/Crypto.ts +11 -7
- package/src/Db.ts +3 -5
- package/src/DbWorker.ts +54 -44
- package/src/Evolu.ts +10 -12
- package/src/OnCompletes.ts +4 -4
- package/src/Platform.ts +6 -5
- package/src/Sql.ts +4 -3
- package/src/Sqlite.ts +2 -2
- package/src/SyncWorker.ts +4 -6
- package/src/Types.ts +11 -0
package/dist/src/Platform.js
CHANGED
|
@@ -5,6 +5,7 @@ export const PlatformName = Context.GenericTag("@services/PlatformName");
|
|
|
5
5
|
export const FlushSync = Context.GenericTag("@services/FlushSync");
|
|
6
6
|
export const FlushSyncDefaultLive = Layer.succeed(FlushSync, (callback) => callback());
|
|
7
7
|
export const SyncLock = Context.GenericTag("@services/SyncLock");
|
|
8
|
+
export const DbWorkerLock = Context.GenericTag("@services/DbWorkerLock");
|
|
8
9
|
export const Fetch = Context.GenericTag("@services/Fetch");
|
|
9
10
|
export const FetchLive = Layer.succeed(Fetch, Fetch.of((url, body) => Effect.tryPromise({
|
|
10
11
|
try: () => fetch(url, {
|
package/dist/src/Sql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sql.d.ts","sourceRoot":"","sources":["../../src/Sql.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,yFAOvB,CAAC;AAEF,eAAO,MAAM,kBAAkB,yKAS9B,CAAC;AAEF,eAAO,MAAM,uBAAuB,yHAInC,CAAC;AAEF,eAAO,MAAM,gBAAgB,yKAS5B,CAAC;AAEF,eAAO,MAAM,WAAW,0KAWvB,CAAC;AAEF,eAAO,MAAM,iCAAiC,4EAM7C,CAAC;AAEF,eAAO,MAAM,oCAAoC,wKAahD,CAAC;AAEF,eAAO,MAAM,6BAA6B,UACjC,MAAM,UACL,MAAM,KACb,
|
|
1
|
+
{"version":3,"file":"Sql.d.ts","sourceRoot":"","sources":["../../src/Sql.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,yFAOvB,CAAC;AAEF,eAAO,MAAM,kBAAkB,yKAS9B,CAAC;AAEF,eAAO,MAAM,uBAAuB,yHAInC,CAAC;AAEF,eAAO,MAAM,gBAAgB,yKAS5B,CAAC;AAEF,eAAO,MAAM,WAAW,0KAWvB,CAAC;AAEF,eAAO,MAAM,iCAAiC,4EAM7C,CAAC;AAEF,eAAO,MAAM,oCAAoC,wKAahD,CAAC;AAEF,eAAO,MAAM,6BAA6B,UACjC,MAAM,UACL,MAAM,KACb,MAQF,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,MAAM,KAAG,MAI9C,CAAC;AAEF,eAAO,MAAM,uBAAuB,uJAMnC,CAAC;AAEF,eAAO,MAAM,iCAAiC,gFAK7C,CAAC;AAEF,eAAO,MAAM,oBAAoB,uGAShC,CAAC"}
|
package/dist/src/Sql.js
CHANGED
|
@@ -69,11 +69,12 @@ LIMIT
|
|
|
69
69
|
`;
|
|
70
70
|
export const upsertValueIntoTableRowColumn = (table, column) => `
|
|
71
71
|
INSERT INTO
|
|
72
|
-
"${table}" ("id", "${column}")
|
|
72
|
+
"${table}" ("id", "${column}", "createdAt", "updatedAt")
|
|
73
73
|
VALUES
|
|
74
|
-
(?, ?)
|
|
74
|
+
(?, ?, ?, ?)
|
|
75
75
|
ON CONFLICT DO UPDATE SET
|
|
76
|
-
"${column}" =
|
|
76
|
+
"${column}" = ?,
|
|
77
|
+
"updatedAt" = ?
|
|
77
78
|
`;
|
|
78
79
|
export const deleteTableRow = (table) => `
|
|
79
80
|
DELETE FROM "${table}"
|
package/dist/src/Sqlite.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as Context from "effect/Context";
|
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Predicate from "effect/Predicate";
|
|
4
4
|
export interface Sqlite {
|
|
5
|
-
readonly exec: (arg: string | SqliteQuery) => Effect.Effect<
|
|
5
|
+
readonly exec: (arg: string | SqliteQuery) => Effect.Effect<SqliteExecResult>;
|
|
6
6
|
}
|
|
7
7
|
export declare const Sqlite: Context.Tag<Sqlite, Sqlite>;
|
|
8
8
|
export interface SqliteQuery {
|
|
@@ -18,7 +18,7 @@ type JsonObject = {
|
|
|
18
18
|
type JsonArray = ReadonlyArray<Json>;
|
|
19
19
|
type JsonPrimitive = string | number | boolean | null;
|
|
20
20
|
type Json = JsonPrimitive | JsonObject | JsonArray;
|
|
21
|
-
interface
|
|
21
|
+
export interface SqliteExecResult {
|
|
22
22
|
readonly rows: SqliteRow[];
|
|
23
23
|
readonly changes: number;
|
|
24
24
|
}
|
package/dist/src/Sqlite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,SAAS,MAAM,kBAAkB,CAAC;AAE9C,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,SAAS,MAAM,kBAAkB,CAAC;AAE9C,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;CAC/E;AAED,eAAO,MAAM,MAAM,6BAAiD,CAAC;AAErE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC;CAC9B;AAED,MAAM,MAAM,KAAK,GAAG,WAAW,GAAG,iBAAiB,CAAC;AACpD,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,SAAS,CAAC;AACvD,KAAK,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC1C,KAAK,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;AACrC,KAAK,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AACtD,KAAK,IAAI,GAAG,aAAa,GAAG,UAAU,GAAG,SAAS,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEpD,eAAO,MAAM,mBAAmB,EAAE,SAAS,CAAC,UAAU,CACpD,KAAK,EACL,iBAAiB,CAE4D,CAAC;AAEhF,eAAO,MAAM,oBAAoB,WACvB,cAAc,KAAK,CAAC,KAC3B,WAAW,EAGX,CAAC;AAEJ,eAAO,MAAM,iBAAiB,QAAS,MAAM,GAAG,WAAW,KAAG,WAG7D,CAAC;AAEF,eAAO,MAAM,cAAc,SAAU,SAAS,EAAE,KAAG,SAAS,EAC1C,CAAC;AA0BnB,eAAO,MAAM,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,CACpB,CAAC"}
|
package/dist/src/SyncWorker.d.ts
CHANGED
|
@@ -8,9 +8,8 @@ import { Id } from "./Model.js";
|
|
|
8
8
|
import { Owner } from "./Owner.js";
|
|
9
9
|
import { Fetch, SyncLock } from "./Platform.js";
|
|
10
10
|
import { Value } from "./Sqlite.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
onMessage: (output: SyncWorkerOutput) => void;
|
|
11
|
+
import { Messaging } from "./Types.js";
|
|
12
|
+
export interface SyncWorker extends Messaging<SyncWorkerInput, SyncWorkerOutput> {
|
|
14
13
|
}
|
|
15
14
|
export declare const SyncWorker: Context.Tag<SyncWorker, SyncWorker>;
|
|
16
15
|
export type SyncWorkerPostMessage = SyncWorker["postMessage"];
|
|
@@ -76,6 +75,6 @@ export interface SyncStateServerError {
|
|
|
76
75
|
export interface SyncStatePaymentRequiredError {
|
|
77
76
|
readonly _tag: "PaymentRequiredError";
|
|
78
77
|
}
|
|
79
|
-
export declare const
|
|
78
|
+
export declare const SyncWorkerCommonLive: Layer.Layer<SyncWorker, never, SecretBox | SyncLock | Fetch>;
|
|
80
79
|
export {};
|
|
81
80
|
//# sourceMappingURL=SyncWorker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyncWorker.d.ts","sourceRoot":"","sources":["../../src/SyncWorker.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAE1C,OAAO,KAAK,WAAW,MAAM,oBAAoB,CAAC;AAGlD,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAKtC,OAAO,EACL,UAAU,EACV,MAAM,EACN,SAAS,EACT,eAAe,EAGhB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,eAAe,EAAuB,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAOhD,OAAO,EAAqB,KAAK,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"SyncWorker.d.ts","sourceRoot":"","sources":["../../src/SyncWorker.ts"],"names":[],"mappings":"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"}
|
package/dist/src/SyncWorker.js
CHANGED
|
@@ -131,7 +131,7 @@ const sync = (input) => Effect.gen(function* (_) {
|
|
|
131
131
|
syncLoopCount: input.syncLoopCount,
|
|
132
132
|
})))), Effect.tapError(() => syncLock.release), Effect.merge, Effect.map(syncWorkerOnMessage));
|
|
133
133
|
});
|
|
134
|
-
export const
|
|
134
|
+
export const SyncWorkerCommonLive = Layer.effect(SyncWorker, Effect.gen(function* (_) {
|
|
135
135
|
const syncLock = yield* _(SyncLock);
|
|
136
136
|
const onError = (error) => Effect.sync(() => {
|
|
137
137
|
syncWorker.onMessage(error);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Add types for WebWorker and BroadcastChannel. Messages must have a `_tag`
|
|
3
|
+
* property.
|
|
4
|
+
*/
|
|
5
|
+
export interface Messaging<Input extends {
|
|
6
|
+
_tag: string;
|
|
7
|
+
}, Output extends {
|
|
8
|
+
_tag: string;
|
|
9
|
+
}> {
|
|
10
|
+
readonly postMessage: (input: Input) => void;
|
|
11
|
+
onMessage: (output: Output) => void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=Types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Types.d.ts","sourceRoot":"","sources":["../../src/Types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,SAAS,CACxB,KAAK,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAC9B,MAAM,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;IAE/B,QAAQ,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evolu/common",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Local-first platform designed for privacy, ease of use, and no vendor lock-in to sync and backup people's lifetime data",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"evolu",
|
|
@@ -52,11 +52,11 @@
|
|
|
52
52
|
"nanoid": "^5.0.6"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@effect/schema": "^0.63.
|
|
55
|
+
"@effect/schema": "^0.63.2",
|
|
56
56
|
"@protobuf-ts/plugin": "^2.9.3",
|
|
57
57
|
"@protobuf-ts/protoc": "^2.9.3",
|
|
58
58
|
"array-shuffle": "^3.0.0",
|
|
59
|
-
"effect": "2.4.
|
|
59
|
+
"effect": "2.4.1",
|
|
60
60
|
"eslint": "^8.57.0",
|
|
61
61
|
"typescript": "^5.3.3",
|
|
62
62
|
"vitest": "^1.3.1",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"eslint-config-evolu": "1.0.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@effect/schema": "^0.63.
|
|
68
|
-
"effect": "2.4.
|
|
67
|
+
"@effect/schema": "^0.63.2",
|
|
68
|
+
"effect": "2.4.1"
|
|
69
69
|
},
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
package/src/Config.ts
CHANGED
|
@@ -16,6 +16,13 @@ export interface Config {
|
|
|
16
16
|
* 1000 (5 minutes).
|
|
17
17
|
*/
|
|
18
18
|
readonly maxDrift: number;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Evolu application name. For now, this is only useful for localhost
|
|
22
|
+
* development, where we want each application to have its own database. The
|
|
23
|
+
* default value is: "Evolu".
|
|
24
|
+
*/
|
|
25
|
+
readonly name: string;
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
export const Config = Context.GenericTag<Config>("@services/Config");
|
|
@@ -27,6 +34,7 @@ export const ConfigLive = (config?: Partial<Config>): Layer.Layer<Config> =>
|
|
|
27
34
|
syncUrl: "https://evolu.world",
|
|
28
35
|
maxDrift: 5 * 60 * 1000,
|
|
29
36
|
reloadUrl: "/",
|
|
37
|
+
name: "Evolu",
|
|
30
38
|
...config,
|
|
31
39
|
}),
|
|
32
40
|
);
|
package/src/Crdt.ts
CHANGED
|
@@ -10,7 +10,7 @@ import * as Option from "effect/Option";
|
|
|
10
10
|
import * as ReadonlyArray from "effect/ReadonlyArray";
|
|
11
11
|
import * as String from "effect/String";
|
|
12
12
|
import { Config } from "./Config.js";
|
|
13
|
-
import {
|
|
13
|
+
import { NanoIdGenerator, NodeId } from "./Crypto.js";
|
|
14
14
|
import { murmurhash } from "./Murmurhash.js";
|
|
15
15
|
|
|
16
16
|
// https://muratbuffalo.blogspot.com/2014/07/hybrid-logical-clocks.html
|
|
@@ -86,7 +86,7 @@ export const makeSyncTimestamp = (
|
|
|
86
86
|
node: syncNodeId,
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
export const makeInitialTimestamp =
|
|
89
|
+
export const makeInitialTimestamp = NanoIdGenerator.pipe(
|
|
90
90
|
Effect.flatMap(({ nanoidAsNodeId }) => nanoidAsNodeId),
|
|
91
91
|
Effect.map(
|
|
92
92
|
(node): Timestamp => ({
|
package/src/Crypto.ts
CHANGED
|
@@ -36,12 +36,16 @@ export interface InvalidMnemonicError {
|
|
|
36
36
|
*/
|
|
37
37
|
export type Mnemonic = string & Brand.Brand<"Mnemonic">;
|
|
38
38
|
|
|
39
|
-
export interface
|
|
40
|
-
readonly nanoid: Effect.Effect<
|
|
39
|
+
export interface NanoIdGenerator {
|
|
40
|
+
readonly nanoid: Effect.Effect<NanoId>;
|
|
41
41
|
readonly nanoidAsNodeId: Effect.Effect<NodeId>;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export const
|
|
44
|
+
export const NanoIdGenerator = Context.GenericTag<NanoIdGenerator>(
|
|
45
|
+
"@services/NanoIdGenerator",
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
export type NanoId = string & Brand.Brand<"NanoId">;
|
|
45
49
|
|
|
46
50
|
export const NodeId = S.string.pipe(
|
|
47
51
|
S.pattern(/^[\w-]{16}$/),
|
|
@@ -51,10 +55,10 @@ export type NodeId = S.Schema.To<typeof NodeId>;
|
|
|
51
55
|
|
|
52
56
|
const nanoidForNodeId = customAlphabet("0123456789abcdef", 16);
|
|
53
57
|
|
|
54
|
-
export const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
nanoid: Effect.sync(() => nanoid()),
|
|
58
|
+
export const NanoIdGeneratorLive = Layer.succeed(
|
|
59
|
+
NanoIdGenerator,
|
|
60
|
+
NanoIdGenerator.of({
|
|
61
|
+
nanoid: Effect.sync(() => nanoid() as NanoId),
|
|
58
62
|
nanoidAsNodeId: Effect.sync(() => nanoidForNodeId() as NodeId),
|
|
59
63
|
}),
|
|
60
64
|
);
|
package/src/Db.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as AST from "@effect/schema/AST";
|
|
2
2
|
import * as S from "@effect/schema/Schema";
|
|
3
3
|
import { make } from "@effect/schema/Schema";
|
|
4
|
-
import { bytesToHex } from "@noble/ciphers/utils";
|
|
5
4
|
import * as Brand from "effect/Brand";
|
|
6
5
|
import * as Context from "effect/Context";
|
|
7
6
|
import * as Effect from "effect/Effect";
|
|
@@ -21,7 +20,7 @@ import {
|
|
|
21
20
|
merkleTreeToString,
|
|
22
21
|
timestampToString,
|
|
23
22
|
} from "./Crdt.js";
|
|
24
|
-
import { Bip39, Mnemonic,
|
|
23
|
+
import { Bip39, Mnemonic, NanoIdGenerator } from "./Crypto.js";
|
|
25
24
|
import { EvoluTypeError } from "./ErrorStore.js";
|
|
26
25
|
import { Id, SqliteBoolean, SqliteDate } from "./Model.js";
|
|
27
26
|
import { Owner, makeOwner } from "./Owner.js";
|
|
@@ -323,7 +322,7 @@ export const someDefectToNoSuchTableOrColumnError = Effect.catchSomeDefect(
|
|
|
323
322
|
|
|
324
323
|
export const lazyInit = (
|
|
325
324
|
mnemonic?: Mnemonic,
|
|
326
|
-
): Effect.Effect<Owner, never, Sqlite | Bip39 |
|
|
325
|
+
): Effect.Effect<Owner, never, Sqlite | Bip39 | NanoIdGenerator> =>
|
|
327
326
|
Effect.gen(function* (_) {
|
|
328
327
|
const [owner, sqlite, initialTimestampString] = yield* _(
|
|
329
328
|
Effect.all([makeOwner(mnemonic), Sqlite, makeInitialTimestamp], {
|
|
@@ -341,8 +340,7 @@ export const lazyInit = (
|
|
|
341
340
|
parameters: [
|
|
342
341
|
owner.id,
|
|
343
342
|
owner.mnemonic,
|
|
344
|
-
|
|
345
|
-
bytesToHex(owner.encryptionKey),
|
|
343
|
+
owner.encryptionKey,
|
|
346
344
|
timestampToString(initialTimestampString),
|
|
347
345
|
merkleTreeToString(initialMerkleTree),
|
|
348
346
|
],
|
package/src/DbWorker.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { hexToBytes } from "@noble/ciphers/utils";
|
|
2
1
|
import * as Context from "effect/Context";
|
|
3
2
|
import * as Effect from "effect/Effect";
|
|
4
3
|
import * as Function from "effect/Function";
|
|
@@ -11,6 +10,7 @@ import * as ReadonlyRecord from "effect/ReadonlyRecord";
|
|
|
11
10
|
import { Config, ConfigLive } from "./Config.js";
|
|
12
11
|
import {
|
|
13
12
|
MerkleTree,
|
|
13
|
+
Millis,
|
|
14
14
|
Time,
|
|
15
15
|
TimeLive,
|
|
16
16
|
Timestamp,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
timestampToString,
|
|
29
29
|
unsafeTimestampFromString,
|
|
30
30
|
} from "./Crdt.js";
|
|
31
|
-
import { Bip39, Mnemonic,
|
|
31
|
+
import { Bip39, Mnemonic, NanoIdGenerator } from "./Crypto.js";
|
|
32
32
|
import {
|
|
33
33
|
Queries,
|
|
34
34
|
Query,
|
|
@@ -44,9 +44,10 @@ import {
|
|
|
44
44
|
} from "./Db.js";
|
|
45
45
|
import { QueryPatches, makePatches } from "./Diff.js";
|
|
46
46
|
import { EvoluError, makeUnexpectedError } from "./ErrorStore.js";
|
|
47
|
-
import { Id,
|
|
47
|
+
import { Id, cast } from "./Model.js";
|
|
48
48
|
import { OnCompleteId } from "./OnCompletes.js";
|
|
49
49
|
import { Owner, OwnerId } from "./Owner.js";
|
|
50
|
+
import { DbWorkerLock } from "./Platform.js";
|
|
50
51
|
import * as Sql from "./Sql.js";
|
|
51
52
|
import { Sqlite, Value } from "./Sqlite.js";
|
|
52
53
|
import {
|
|
@@ -58,12 +59,9 @@ import {
|
|
|
58
59
|
SyncWorkerOutputSyncResponse,
|
|
59
60
|
SyncWorkerPostMessage,
|
|
60
61
|
} from "./SyncWorker.js";
|
|
62
|
+
import { Messaging } from "./Types.js";
|
|
61
63
|
|
|
62
|
-
export interface DbWorker {
|
|
63
|
-
readonly postMessage: (input: DbWorkerInput) => void;
|
|
64
|
-
onMessage: (output: DbWorkerOutput) => void;
|
|
65
|
-
}
|
|
66
|
-
|
|
64
|
+
export interface DbWorker extends Messaging<DbWorkerInput, DbWorkerOutput> {}
|
|
67
65
|
export const DbWorker = Context.GenericTag<DbWorker>("@services/DbWorker");
|
|
68
66
|
|
|
69
67
|
export type DbWorkerInput =
|
|
@@ -157,7 +155,6 @@ export interface Mutation {
|
|
|
157
155
|
Value | Date | boolean | undefined
|
|
158
156
|
>;
|
|
159
157
|
readonly isInsert: boolean;
|
|
160
|
-
readonly now: SqliteDate;
|
|
161
158
|
readonly onCompleteId: OnCompleteId | null;
|
|
162
159
|
}
|
|
163
160
|
|
|
@@ -170,8 +167,7 @@ const init = Effect.gen(function* (_) {
|
|
|
170
167
|
({ rows: [row] }): Owner => ({
|
|
171
168
|
id: row.id as OwnerId,
|
|
172
169
|
mnemonic: row.mnemonic as Mnemonic,
|
|
173
|
-
|
|
174
|
-
encryptionKey: hexToBytes(row.encryptionKey as string),
|
|
170
|
+
encryptionKey: row.encryptionKey as Uint8Array,
|
|
175
171
|
}),
|
|
176
172
|
),
|
|
177
173
|
someDefectToNoSuchTableOrColumnError,
|
|
@@ -222,9 +218,8 @@ const readTimestampAndMerkleTree = Sqlite.pipe(
|
|
|
222
218
|
Effect.flatMap((sqlite) =>
|
|
223
219
|
sqlite.exec(Sql.selectOwnerTimestampAndMerkleTree),
|
|
224
220
|
),
|
|
225
|
-
Effect.map((result) => result.rows),
|
|
226
221
|
Effect.map(
|
|
227
|
-
([{ timestamp, merkleTree }]): TimestampAndMerkleTree => ({
|
|
222
|
+
({ rows: [{ timestamp, merkleTree }] }): TimestampAndMerkleTree => ({
|
|
228
223
|
timestamp: unsafeTimestampFromString(timestamp as TimestampString),
|
|
229
224
|
merkleTree: merkleTree as MerkleTree,
|
|
230
225
|
}),
|
|
@@ -236,9 +231,10 @@ export const mutationsToNewMessages = (
|
|
|
236
231
|
): ReadonlyArray<NewMessage> =>
|
|
237
232
|
pipe(
|
|
238
233
|
mutations,
|
|
239
|
-
ReadonlyArray.map(({ id, isInsert,
|
|
234
|
+
ReadonlyArray.map(({ id, isInsert, table, values }) =>
|
|
240
235
|
pipe(
|
|
241
236
|
Object.entries(values),
|
|
237
|
+
// Filter values.
|
|
242
238
|
ReadonlyArray.filterMap(([key, value]) =>
|
|
243
239
|
// The value can be undefined if exactOptionalPropertyTypes isn't true.
|
|
244
240
|
// Don't insert nulls because null is the default value.
|
|
@@ -246,6 +242,7 @@ export const mutationsToNewMessages = (
|
|
|
246
242
|
? Option.none()
|
|
247
243
|
: Option.some([key, value] as const),
|
|
248
244
|
),
|
|
245
|
+
// Cast values.
|
|
249
246
|
ReadonlyArray.map(
|
|
250
247
|
([key, value]) =>
|
|
251
248
|
[
|
|
@@ -257,7 +254,6 @@ export const mutationsToNewMessages = (
|
|
|
257
254
|
: value,
|
|
258
255
|
] as const,
|
|
259
256
|
),
|
|
260
|
-
ReadonlyArray.append([isInsert ? "createdAt" : "updatedAt", now]),
|
|
261
257
|
ReadonlyArray.map(
|
|
262
258
|
([key, value]): NewMessage => ({
|
|
263
259
|
table,
|
|
@@ -282,7 +278,7 @@ const ensureSchemaByNewMessages = (
|
|
|
282
278
|
if (table == null) {
|
|
283
279
|
tablesMap.set(message.table, {
|
|
284
280
|
name: message.table,
|
|
285
|
-
columns: [message.column],
|
|
281
|
+
columns: [message.column, "createdAt", "updatedAt"],
|
|
286
282
|
});
|
|
287
283
|
return;
|
|
288
284
|
}
|
|
@@ -298,13 +294,21 @@ const ensureSchemaByNewMessages = (
|
|
|
298
294
|
export const upsertValueIntoTableRowColumn = (
|
|
299
295
|
message: NewMessage,
|
|
300
296
|
messages: ReadonlyArray<NewMessage>,
|
|
297
|
+
millis: Millis,
|
|
301
298
|
): Effect.Effect<void, never, Sqlite> =>
|
|
302
299
|
Effect.gen(function* (_) {
|
|
303
300
|
const sqlite = yield* _(Sqlite);
|
|
304
|
-
|
|
301
|
+
const createdAtOrUpdatedAt = cast(new Date(millis));
|
|
305
302
|
const insert = sqlite.exec({
|
|
306
303
|
sql: Sql.upsertValueIntoTableRowColumn(message.table, message.column),
|
|
307
|
-
parameters: [
|
|
304
|
+
parameters: [
|
|
305
|
+
message.row,
|
|
306
|
+
message.value,
|
|
307
|
+
createdAtOrUpdatedAt,
|
|
308
|
+
createdAtOrUpdatedAt,
|
|
309
|
+
message.value,
|
|
310
|
+
createdAtOrUpdatedAt,
|
|
311
|
+
],
|
|
308
312
|
});
|
|
309
313
|
|
|
310
314
|
yield* _(
|
|
@@ -340,7 +344,8 @@ const applyMessages = ({
|
|
|
340
344
|
);
|
|
341
345
|
|
|
342
346
|
if (timestamp == null || timestamp < message.timestamp) {
|
|
343
|
-
|
|
347
|
+
const { millis } = unsafeTimestampFromString(message.timestamp);
|
|
348
|
+
yield* _(upsertValueIntoTableRowColumn(message, messages, millis));
|
|
344
349
|
}
|
|
345
350
|
|
|
346
351
|
if (timestamp == null || timestamp !== message.timestamp) {
|
|
@@ -406,11 +411,11 @@ const mutate = ({
|
|
|
406
411
|
),
|
|
407
412
|
).map(mutationsToNewMessages);
|
|
408
413
|
|
|
409
|
-
yield* _(
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
+
const time = yield* _(Time);
|
|
415
|
+
for (const messageToUpsert of toUpsert) {
|
|
416
|
+
const now = yield* _(time.now);
|
|
417
|
+
yield* _(upsertValueIntoTableRowColumn(messageToUpsert, toUpsert, now));
|
|
418
|
+
}
|
|
414
419
|
|
|
415
420
|
const { exec } = yield* _(Sqlite);
|
|
416
421
|
yield* _(
|
|
@@ -537,8 +542,8 @@ const sync = ({
|
|
|
537
542
|
> =>
|
|
538
543
|
Effect.gen(function* (_) {
|
|
539
544
|
if (queries.length > 0) yield* _(query({ queries }));
|
|
540
|
-
|
|
541
|
-
(
|
|
545
|
+
const syncWorkerPostMessage = yield* _(SyncWorkerPostMessage);
|
|
546
|
+
syncWorkerPostMessage({
|
|
542
547
|
_tag: "sync",
|
|
543
548
|
...(yield* _(readTimestampAndMerkleTree)),
|
|
544
549
|
syncUrl: (yield* _(Config)).syncUrl,
|
|
@@ -550,7 +555,11 @@ const sync = ({
|
|
|
550
555
|
|
|
551
556
|
const reset = (
|
|
552
557
|
input: DbWorkerInputReset,
|
|
553
|
-
): Effect.Effect<
|
|
558
|
+
): Effect.Effect<
|
|
559
|
+
void,
|
|
560
|
+
never,
|
|
561
|
+
Sqlite | Bip39 | NanoIdGenerator | DbWorkerOnMessage
|
|
562
|
+
> =>
|
|
554
563
|
Effect.gen(function* (_) {
|
|
555
564
|
const sqlite = yield* _(Sqlite);
|
|
556
565
|
|
|
@@ -575,7 +584,7 @@ const reset = (
|
|
|
575
584
|
onMessage({ _tag: "onResetOrRestore" });
|
|
576
585
|
});
|
|
577
586
|
|
|
578
|
-
export const
|
|
587
|
+
export const DbWorkerCommonLive = Layer.effect(
|
|
579
588
|
DbWorker,
|
|
580
589
|
Effect.gen(function* (_) {
|
|
581
590
|
const syncWorker = yield* _(SyncWorker);
|
|
@@ -591,7 +600,7 @@ export const DbWorkerLive = Layer.effect(
|
|
|
591
600
|
onError(output).pipe(Effect.runSync);
|
|
592
601
|
break;
|
|
593
602
|
case "SyncWorkerOutputSyncResponse":
|
|
594
|
-
postMessage(output);
|
|
603
|
+
dbWorker.postMessage(output);
|
|
595
604
|
break;
|
|
596
605
|
default:
|
|
597
606
|
dbWorker.onMessage({ _tag: "onSyncState", state: output });
|
|
@@ -601,7 +610,7 @@ export const DbWorkerLive = Layer.effect(
|
|
|
601
610
|
const runContext = Context.empty().pipe(
|
|
602
611
|
Context.add(Sqlite, yield* _(Sqlite)),
|
|
603
612
|
Context.add(Bip39, yield* _(Bip39)),
|
|
604
|
-
Context.add(
|
|
613
|
+
Context.add(NanoIdGenerator, yield* _(NanoIdGenerator)),
|
|
605
614
|
Context.add(DbWorkerOnMessage, (output) => {
|
|
606
615
|
dbWorker.onMessage(output);
|
|
607
616
|
}),
|
|
@@ -611,7 +620,7 @@ export const DbWorkerLive = Layer.effect(
|
|
|
611
620
|
effect: Effect.Effect<
|
|
612
621
|
void,
|
|
613
622
|
EvoluError,
|
|
614
|
-
Sqlite | Bip39 |
|
|
623
|
+
Sqlite | Bip39 | NanoIdGenerator | DbWorkerOnMessage
|
|
615
624
|
>,
|
|
616
625
|
): Promise<void> =>
|
|
617
626
|
effect.pipe(
|
|
@@ -622,15 +631,18 @@ export const DbWorkerLive = Layer.effect(
|
|
|
622
631
|
Effect.runPromise,
|
|
623
632
|
);
|
|
624
633
|
|
|
625
|
-
type
|
|
634
|
+
type HandleInput = (input: DbWorkerInput) => Promise<void>;
|
|
626
635
|
|
|
627
|
-
|
|
628
|
-
const
|
|
636
|
+
/** If init fails, we have to allow reset at least. */
|
|
637
|
+
const handleInputForInitFail: HandleInput = (input): Promise<void> => {
|
|
629
638
|
if (input._tag !== "reset") return Promise.resolve(undefined);
|
|
630
639
|
return reset(input).pipe(run);
|
|
631
640
|
};
|
|
632
641
|
|
|
633
|
-
const
|
|
642
|
+
const makeHandleInputForInitSuccess = (
|
|
643
|
+
config: Config,
|
|
644
|
+
owner: Owner,
|
|
645
|
+
): HandleInput => {
|
|
634
646
|
let skipAllBecauseOfReset = false;
|
|
635
647
|
|
|
636
648
|
const layer = Layer.mergeAll(
|
|
@@ -663,27 +675,25 @@ export const DbWorkerLive = Layer.effect(
|
|
|
663
675
|
};
|
|
664
676
|
};
|
|
665
677
|
|
|
666
|
-
let
|
|
678
|
+
let handleInput: HandleInput = (input) => {
|
|
667
679
|
if (input._tag !== "init")
|
|
668
680
|
return run(makeUnexpectedError(new Error("init must be called first")));
|
|
669
|
-
|
|
681
|
+
handleInput = handleInputForInitFail;
|
|
670
682
|
return init.pipe(
|
|
671
683
|
Effect.map((owner) => {
|
|
672
684
|
dbWorker.onMessage({ _tag: "onOwner", owner });
|
|
673
|
-
|
|
685
|
+
handleInput = makeHandleInputForInitSuccess(input.config, owner);
|
|
674
686
|
}),
|
|
675
687
|
run,
|
|
676
688
|
);
|
|
677
689
|
};
|
|
678
690
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
const postMessage: DbWorker["postMessage"] = (input) => {
|
|
682
|
-
messageQueue = messageQueue.then(() => write(input));
|
|
683
|
-
};
|
|
691
|
+
const dbWorkerLock = yield* _(DbWorkerLock);
|
|
684
692
|
|
|
685
693
|
const dbWorker: DbWorker = {
|
|
686
|
-
postMessage
|
|
694
|
+
postMessage: (input) => {
|
|
695
|
+
dbWorkerLock(() => handleInput(input));
|
|
696
|
+
},
|
|
687
697
|
onMessage: Function.constVoid,
|
|
688
698
|
};
|
|
689
699
|
|
package/src/Evolu.ts
CHANGED
|
@@ -10,8 +10,7 @@ import * as Number from "effect/Number";
|
|
|
10
10
|
import * as ReadonlyArray from "effect/ReadonlyArray";
|
|
11
11
|
import * as Kysely from "kysely";
|
|
12
12
|
import { Config, ConfigLive } from "./Config.js";
|
|
13
|
-
import {
|
|
14
|
-
import { Mnemonic, NanoId, NanoIdLive } from "./Crypto.js";
|
|
13
|
+
import { Mnemonic, NanoIdGenerator, NanoIdGeneratorLive } from "./Crypto.js";
|
|
15
14
|
import {
|
|
16
15
|
DatabaseSchema,
|
|
17
16
|
Queries,
|
|
@@ -29,7 +28,7 @@ import {
|
|
|
29
28
|
import { DbWorker, DbWorkerOutputOnQuery, Mutation } from "./DbWorker.js";
|
|
30
29
|
import { applyPatches } from "./Diff.js";
|
|
31
30
|
import { EvoluError, makeErrorStore } from "./ErrorStore.js";
|
|
32
|
-
import { SqliteBoolean, SqliteDate
|
|
31
|
+
import { SqliteBoolean, SqliteDate } from "./Model.js";
|
|
33
32
|
import { OnCompletes, OnCompletesLive } from "./OnCompletes.js";
|
|
34
33
|
import { Owner } from "./Owner.js";
|
|
35
34
|
import { AppState, FlushSync, PlatformName } from "./Platform.js";
|
|
@@ -323,13 +322,15 @@ type QueryCallback<S extends DatabaseSchema, R extends Row> = (
|
|
|
323
322
|
) => Kysely.SelectQueryBuilder<any, any, R>;
|
|
324
323
|
|
|
325
324
|
type QuerySchema<S extends DatabaseSchema> = {
|
|
326
|
-
readonly [Table in keyof S]:
|
|
325
|
+
readonly [Table in keyof S]: NullableExceptForIdAndAutomaticColumns<{
|
|
327
326
|
readonly [Column in keyof S[Table]]: S[Table][Column];
|
|
328
327
|
}>;
|
|
329
328
|
};
|
|
330
329
|
|
|
331
|
-
type
|
|
332
|
-
readonly [K in keyof T]: K extends "id"
|
|
330
|
+
type NullableExceptForIdAndAutomaticColumns<T> = {
|
|
331
|
+
readonly [K in keyof T]: K extends "id" | "createdAt" | "updatedAt"
|
|
332
|
+
? T[K]
|
|
333
|
+
: T[K] | null;
|
|
333
334
|
};
|
|
334
335
|
|
|
335
336
|
const kysely = new Kysely.Kysely<QuerySchema<DatabaseSchema>>({
|
|
@@ -643,9 +644,8 @@ type Castable<T> = {
|
|
|
643
644
|
const MutateLive = Layer.effect(
|
|
644
645
|
Mutate,
|
|
645
646
|
Effect.gen(function* (_) {
|
|
646
|
-
const nanoid = yield* _(
|
|
647
|
+
const { nanoid } = yield* _(NanoIdGenerator);
|
|
647
648
|
const onCompletes = yield* _(OnCompletes);
|
|
648
|
-
const time = yield* _(Time);
|
|
649
649
|
const subscribedQueries = yield* _(SubscribedQueries);
|
|
650
650
|
const loadingPromises = yield* _(LoadingPromises);
|
|
651
651
|
const dbWorker = yield* _(DbWorker);
|
|
@@ -653,7 +653,7 @@ const MutateLive = Layer.effect(
|
|
|
653
653
|
|
|
654
654
|
return Mutate.of((table, { id, ...values }, onComplete) => {
|
|
655
655
|
const isInsert = id == null;
|
|
656
|
-
if (isInsert) id = Effect.runSync(nanoid
|
|
656
|
+
if (isInsert) id = Effect.runSync(nanoid) as never;
|
|
657
657
|
|
|
658
658
|
const onCompleteId = onComplete
|
|
659
659
|
? onCompletes.add(onComplete).pipe(Effect.runSync)
|
|
@@ -666,7 +666,6 @@ const MutateLive = Layer.effect(
|
|
|
666
666
|
id,
|
|
667
667
|
values,
|
|
668
668
|
isInsert,
|
|
669
|
-
now: cast(new Date(Effect.runSync(time.now))),
|
|
670
669
|
onCompleteId,
|
|
671
670
|
},
|
|
672
671
|
];
|
|
@@ -785,9 +784,8 @@ const EvoluCommon = Layer.effect(
|
|
|
785
784
|
Layer.provide(Layer.merge(RowsStoreLive, OnCompletesLive)),
|
|
786
785
|
);
|
|
787
786
|
|
|
788
|
-
/** EvoluCommonLive has only platform independent side-effects. */
|
|
789
787
|
export const EvoluCommonLive = EvoluCommon.pipe(
|
|
790
|
-
Layer.provide(
|
|
788
|
+
Layer.provide(NanoIdGeneratorLive),
|
|
791
789
|
);
|
|
792
790
|
|
|
793
791
|
/**
|
package/src/OnCompletes.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as Effect from "effect/Effect";
|
|
|
4
4
|
import * as Layer from "effect/Layer";
|
|
5
5
|
import * as Option from "effect/Option";
|
|
6
6
|
import * as ReadonlyArray from "effect/ReadonlyArray";
|
|
7
|
-
import { NanoId } from "./Crypto.js";
|
|
7
|
+
import { NanoId, NanoIdGenerator } from "./Crypto.js";
|
|
8
8
|
|
|
9
9
|
export interface OnCompletes {
|
|
10
10
|
readonly add: (onComplete: OnComplete) => Effect.Effect<OnCompleteId>;
|
|
@@ -16,7 +16,7 @@ export interface OnCompletes {
|
|
|
16
16
|
|
|
17
17
|
export type OnComplete = () => void;
|
|
18
18
|
|
|
19
|
-
export type OnCompleteId =
|
|
19
|
+
export type OnCompleteId = NanoId & Brand.Brand<"OnCompleteId">;
|
|
20
20
|
|
|
21
21
|
export const OnCompletes = Context.GenericTag<OnCompletes>(
|
|
22
22
|
"@services/OnCompletes",
|
|
@@ -25,12 +25,12 @@ export const OnCompletes = Context.GenericTag<OnCompletes>(
|
|
|
25
25
|
export const OnCompletesLive = Layer.effect(
|
|
26
26
|
OnCompletes,
|
|
27
27
|
Effect.gen(function* (_) {
|
|
28
|
-
const nanoid = yield* _(
|
|
28
|
+
const { nanoid } = yield* _(NanoIdGenerator);
|
|
29
29
|
const map = new Map<OnCompleteId, OnComplete>();
|
|
30
30
|
|
|
31
31
|
return OnCompletes.of({
|
|
32
32
|
add: (onComplete) =>
|
|
33
|
-
nanoid.
|
|
33
|
+
nanoid.pipe(
|
|
34
34
|
Effect.map((nanoid) => {
|
|
35
35
|
const id = nanoid as OnCompleteId;
|
|
36
36
|
map.set(id, onComplete);
|