@evolu/common 1.0.16 → 2.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/README.md +7 -7
- package/dist/src/Config.d.ts +4 -6
- package/dist/src/Config.d.ts.map +1 -1
- package/dist/src/Config.js +1 -1
- package/dist/src/Crdt.d.ts +15 -9
- package/dist/src/Crdt.d.ts.map +1 -1
- package/dist/src/Crdt.js +15 -14
- package/dist/src/Crypto.d.ts +7 -13
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +7 -9
- package/dist/src/Db.d.ts +36 -70
- package/dist/src/Db.d.ts.map +1 -1
- package/dist/src/Db.js +45 -51
- package/dist/src/DbWorker.d.ts +13 -14
- package/dist/src/DbWorker.d.ts.map +1 -1
- package/dist/src/DbWorker.js +56 -57
- package/dist/src/Diff.d.ts +3 -1
- package/dist/src/Diff.d.ts.map +1 -1
- package/dist/src/Diff.js +3 -7
- package/dist/src/{Errors.d.ts → ErrorStore.d.ts} +14 -7
- package/dist/src/ErrorStore.d.ts.map +1 -0
- package/dist/src/{Errors.js → ErrorStore.js} +2 -0
- package/dist/src/Evolu.d.ts +316 -58
- package/dist/src/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu.js +199 -185
- package/dist/src/Model.d.ts +47 -57
- package/dist/src/Model.d.ts.map +1 -1
- package/dist/src/Model.js +30 -35
- package/dist/src/OnCompletes.d.ts +11 -0
- package/dist/src/OnCompletes.d.ts.map +1 -0
- package/dist/src/OnCompletes.js +21 -0
- package/dist/src/Owner.d.ts +31 -0
- package/dist/src/Owner.d.ts.map +1 -0
- package/dist/src/Owner.js +20 -0
- package/dist/src/Platform.d.ts +15 -8
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +5 -5
- package/dist/src/Protobuf.d.ts +25 -73
- package/dist/src/Protobuf.d.ts.map +1 -1
- package/dist/src/Protobuf.js +4 -12
- package/dist/src/Public.d.ts +5 -3
- package/dist/src/Public.d.ts.map +1 -1
- package/dist/src/Public.js +1 -0
- package/dist/src/Sqlite.d.ts +8 -11
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +7 -7
- package/dist/src/Store.d.ts +6 -5
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +21 -16
- package/dist/src/SyncWorker.d.ts +8 -2
- package/dist/src/SyncWorker.d.ts.map +1 -1
- package/dist/src/SyncWorker.js +12 -19
- package/dist/src/index.d.ts +6 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -2
- package/package.json +23 -13
- package/src/Config.ts +7 -7
- package/src/Crdt.ts +29 -26
- package/src/Crypto.ts +14 -19
- package/src/Db.ts +113 -166
- package/src/DbWorker.ts +110 -140
- package/src/Diff.ts +5 -7
- package/src/{Errors.ts → ErrorStore.ts} +17 -8
- package/src/Evolu.ts +682 -442
- package/src/Model.ts +60 -85
- package/src/OnCompletes.ts +46 -0
- package/src/Owner.ts +65 -0
- package/src/Platform.ts +24 -16
- package/src/Protobuf.ts +25 -73
- package/src/Public.ts +5 -3
- package/src/Sqlite.ts +13 -24
- package/src/Store.ts +36 -24
- package/src/SyncWorker.ts +30 -38
- package/src/index.ts +6 -2
- package/dist/src/Errors.d.ts.map +0 -1
package/src/Model.ts
CHANGED
|
@@ -1,89 +1,70 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as S from "@effect/schema/Schema";
|
|
2
2
|
import { Brand } from "effect";
|
|
3
3
|
import { maybeJson } from "./Sqlite.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Branded Id Schema for any table Id.
|
|
7
|
-
*
|
|
6
|
+
* Branded Id Schema for any table Id. To create Id Schema for a specific table,
|
|
7
|
+
* use {@link id}.
|
|
8
8
|
*/
|
|
9
|
-
export const Id =
|
|
10
|
-
|
|
11
|
-
Schema.brand("Id"),
|
|
12
|
-
);
|
|
13
|
-
export type Id = Schema.Schema.To<typeof Id>;
|
|
9
|
+
export const Id = S.string.pipe(S.pattern(/^[\w-]{21}$/), S.brand("Id"));
|
|
10
|
+
export type Id = S.Schema.To<typeof Id>;
|
|
14
11
|
|
|
15
12
|
/**
|
|
16
13
|
* A factory function to create {@link Id} Schema for a specific table.
|
|
17
14
|
*
|
|
18
15
|
* ### Example
|
|
19
16
|
*
|
|
20
|
-
* ```
|
|
21
|
-
* import * as
|
|
17
|
+
* ```ts
|
|
18
|
+
* import * as S from "@effect/schema/Schema";
|
|
22
19
|
* import * as Evolu from "@evolu/react";
|
|
23
20
|
*
|
|
24
21
|
* const TodoId = Evolu.id("Todo");
|
|
25
|
-
* type TodoId =
|
|
26
|
-
*
|
|
27
|
-
* if (!Schema.is(TodoId)(value)) return;
|
|
22
|
+
* type TodoId = S.Schema.To<typeof TodoId>;
|
|
28
23
|
* ```
|
|
29
24
|
*/
|
|
30
25
|
export const id = <T extends string>(
|
|
31
26
|
table: T,
|
|
32
|
-
):
|
|
33
|
-
Id.pipe(
|
|
27
|
+
): S.BrandSchema<string, string & Brand.Brand<"Id"> & Brand.Brand<T>> =>
|
|
28
|
+
Id.pipe(S.brand(table));
|
|
34
29
|
|
|
35
30
|
/**
|
|
36
|
-
* SQLite doesn't support the Date type, so Evolu uses SqliteDate instead.
|
|
37
|
-
*
|
|
31
|
+
* SQLite doesn't support the Date type, so Evolu uses SqliteDate instead. Use
|
|
32
|
+
* the {@link cast} helper to cast SqliteDate from Date and back.
|
|
38
33
|
* https://www.sqlite.org/quirks.html#no_separate_datetime_datatype
|
|
39
34
|
*/
|
|
40
|
-
export const SqliteDate =
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
export const SqliteDate = S.string.pipe(
|
|
36
|
+
S.filter((s) => !isNaN(Date.parse(s))),
|
|
37
|
+
S.brand("SqliteDate"),
|
|
43
38
|
);
|
|
44
|
-
export type SqliteDate =
|
|
39
|
+
export type SqliteDate = S.Schema.To<typeof SqliteDate>;
|
|
45
40
|
|
|
46
41
|
/**
|
|
47
42
|
* SQLite doesn't support the boolean type, so Evolu uses SqliteBoolean instead.
|
|
48
43
|
* Use the {@link cast} helper to cast SqliteBoolean from boolean and back.
|
|
49
44
|
* https://www.sqlite.org/quirks.html#no_separate_boolean_datatype
|
|
50
45
|
*/
|
|
51
|
-
export const SqliteBoolean =
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
export const SqliteBoolean = S.number.pipe(
|
|
47
|
+
S.int(),
|
|
48
|
+
S.filter((s) => s === 0 || s === 1),
|
|
49
|
+
S.brand("SqliteBoolean"),
|
|
55
50
|
);
|
|
56
|
-
export type SqliteBoolean =
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* SQLite doesn't support Date nor Boolean types, so Evolu emulates them
|
|
60
|
-
* with {@link SqliteBoolean} and {@link SqliteDate}.
|
|
61
|
-
*
|
|
62
|
-
* For {@link SqliteBoolean}, you can use JavaScript boolean.
|
|
63
|
-
* For {@link SqliteDate}, you can use JavaScript Date.
|
|
64
|
-
*/
|
|
65
|
-
export type CastableForMutate<T> = {
|
|
66
|
-
readonly [K in keyof T]: T[K] extends SqliteBoolean
|
|
67
|
-
? boolean | SqliteBoolean
|
|
68
|
-
: T[K] extends null | SqliteBoolean
|
|
69
|
-
? null | boolean | SqliteBoolean
|
|
70
|
-
: T[K] extends SqliteDate
|
|
71
|
-
? Date | SqliteDate
|
|
72
|
-
: T[K] extends null | SqliteDate
|
|
73
|
-
? null | Date | SqliteDate
|
|
74
|
-
: T[K];
|
|
75
|
-
};
|
|
51
|
+
export type SqliteBoolean = S.Schema.To<typeof SqliteBoolean>;
|
|
76
52
|
|
|
77
53
|
/**
|
|
78
|
-
* A helper for casting types not supported by SQLite.
|
|
79
|
-
*
|
|
80
|
-
*
|
|
54
|
+
* A helper for casting types not supported by SQLite. SQLite doesn't support
|
|
55
|
+
* Date nor Boolean types, so Evolu emulates them with {@link SqliteBoolean} and
|
|
56
|
+
* {@link SqliteDate}.
|
|
81
57
|
*
|
|
82
58
|
* ### Example
|
|
83
59
|
*
|
|
84
|
-
* ```
|
|
85
|
-
*
|
|
86
|
-
*
|
|
60
|
+
* ```ts
|
|
61
|
+
* const allTodosNotDeleted = evolu.createQuery((db) =>
|
|
62
|
+
* db
|
|
63
|
+
* .selectFrom("todo")
|
|
64
|
+
* .selectAll()
|
|
65
|
+
* // isDeleted is SqliteBoolean
|
|
66
|
+
* .where("isDeleted", "is not", Evolu.cast(true)),
|
|
67
|
+
* );
|
|
87
68
|
* ```
|
|
88
69
|
*/
|
|
89
70
|
export function cast(value: boolean): SqliteBoolean;
|
|
@@ -101,13 +82,13 @@ export function cast(
|
|
|
101
82
|
}
|
|
102
83
|
|
|
103
84
|
/**
|
|
104
|
-
* String schema represents a string that is not stringified JSON. Using
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
85
|
+
* String schema represents a string that is not stringified JSON. Using String
|
|
86
|
+
* schema for strings stored in SQLite is crucial to ensure a stored string is
|
|
87
|
+
* not automatically parsed to a JSON object or array when retrieved. Use String
|
|
88
|
+
* schema for all string-based schemas.
|
|
108
89
|
*/
|
|
109
|
-
export const String =
|
|
110
|
-
|
|
90
|
+
export const String = S.string.pipe(
|
|
91
|
+
S.filter(
|
|
111
92
|
(s) => {
|
|
112
93
|
if (!maybeJson(s)) return true;
|
|
113
94
|
try {
|
|
@@ -119,65 +100,59 @@ export const String = Schema.string.pipe(
|
|
|
119
100
|
},
|
|
120
101
|
{ message: () => "a string that is not stringified JSON" },
|
|
121
102
|
),
|
|
122
|
-
|
|
103
|
+
S.brand("String"),
|
|
123
104
|
);
|
|
124
|
-
export type String =
|
|
105
|
+
export type String = S.Schema.To<typeof String>;
|
|
125
106
|
|
|
126
107
|
/**
|
|
127
108
|
* A string with a maximum length of 1000 characters.
|
|
128
109
|
*
|
|
129
110
|
* ### Example
|
|
130
111
|
*
|
|
131
|
-
* ```
|
|
132
|
-
* import * as
|
|
112
|
+
* ```ts
|
|
113
|
+
* import * as S from "@effect/schema/Schema";
|
|
133
114
|
* import * as Evolu from "@evolu/react";
|
|
134
115
|
*
|
|
135
|
-
*
|
|
136
|
-
* function foo(value: Evolu.String1000) {}
|
|
116
|
+
* S.parse(Evolu.String1000)(value);
|
|
137
117
|
* ```
|
|
138
118
|
*/
|
|
139
|
-
export const String1000 = String.pipe(
|
|
140
|
-
|
|
141
|
-
Schema.brand("String1000"),
|
|
142
|
-
);
|
|
143
|
-
export type String1000 = Schema.Schema.To<typeof String1000>;
|
|
119
|
+
export const String1000 = String.pipe(S.maxLength(1000), S.brand("String1000"));
|
|
120
|
+
export type String1000 = S.Schema.To<typeof String1000>;
|
|
144
121
|
|
|
145
122
|
/**
|
|
146
123
|
* A nonempty string with a maximum length of 1000 characters.
|
|
147
124
|
*
|
|
148
125
|
* ### Example
|
|
149
126
|
*
|
|
150
|
-
* ```
|
|
151
|
-
* import * as
|
|
127
|
+
* ```ts
|
|
128
|
+
* import * as S from "@effect/schema/Schema";
|
|
152
129
|
* import * as Evolu from "@evolu/react";
|
|
153
130
|
*
|
|
154
|
-
*
|
|
155
|
-
* function foo(value: Evolu.NonEmptyString1000) {}
|
|
131
|
+
* S.parse(Evolu.NonEmptyString1000)(value);
|
|
156
132
|
* ```
|
|
157
133
|
*/
|
|
158
134
|
export const NonEmptyString1000 = String.pipe(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
135
|
+
S.minLength(1),
|
|
136
|
+
S.maxLength(1000),
|
|
137
|
+
S.brand("NonEmptyString1000"),
|
|
162
138
|
);
|
|
163
|
-
export type NonEmptyString1000 =
|
|
139
|
+
export type NonEmptyString1000 = S.Schema.To<typeof NonEmptyString1000>;
|
|
164
140
|
|
|
165
141
|
/**
|
|
166
142
|
* A positive integer.
|
|
167
143
|
*
|
|
168
144
|
* ### Example
|
|
169
145
|
*
|
|
170
|
-
* ```
|
|
171
|
-
* import * as
|
|
146
|
+
* ```ts
|
|
147
|
+
* import * as S from "@effect/schema/Schema";
|
|
172
148
|
* import * as Evolu from "@evolu/react";
|
|
173
149
|
*
|
|
174
|
-
*
|
|
175
|
-
* function foo(value: Evolu.PositiveInt) {}
|
|
150
|
+
* S.parse(Evolu.PositiveInt)(value);
|
|
176
151
|
* ```
|
|
177
152
|
*/
|
|
178
|
-
export const PositiveInt =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
153
|
+
export const PositiveInt = S.number.pipe(
|
|
154
|
+
S.int(),
|
|
155
|
+
S.positive(),
|
|
156
|
+
S.brand("PositiveInt"),
|
|
182
157
|
);
|
|
183
|
-
export type PositiveInt =
|
|
158
|
+
export type PositiveInt = S.Schema.To<typeof PositiveInt>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Brand, Context, Effect, Layer, Option, ReadonlyArray } from "effect";
|
|
2
|
+
import { NanoId } from "./Crypto.js";
|
|
3
|
+
|
|
4
|
+
export interface OnCompletes {
|
|
5
|
+
readonly add: (
|
|
6
|
+
onComplete: OnComplete,
|
|
7
|
+
) => Effect.Effect<never, never, OnCompleteId>;
|
|
8
|
+
|
|
9
|
+
readonly complete: (
|
|
10
|
+
onCompleteIds: readonly OnCompleteId[],
|
|
11
|
+
) => Effect.Effect<never, never, void>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type OnComplete = () => void;
|
|
15
|
+
|
|
16
|
+
export type OnCompleteId = string & Brand.Brand<"OnCompleteId">;
|
|
17
|
+
|
|
18
|
+
export const OnCompletes = Context.Tag<OnCompletes>();
|
|
19
|
+
|
|
20
|
+
export const OnCompletesLive = Layer.effect(
|
|
21
|
+
OnCompletes,
|
|
22
|
+
Effect.gen(function* (_) {
|
|
23
|
+
const nanoid = yield* _(NanoId);
|
|
24
|
+
const map = new Map<OnCompleteId, OnComplete>();
|
|
25
|
+
|
|
26
|
+
return OnCompletes.of({
|
|
27
|
+
add: (onComplete) =>
|
|
28
|
+
nanoid.nanoid.pipe(
|
|
29
|
+
Effect.map((nanoid) => {
|
|
30
|
+
const id = nanoid as OnCompleteId;
|
|
31
|
+
map.set(id, onComplete);
|
|
32
|
+
return id;
|
|
33
|
+
}),
|
|
34
|
+
),
|
|
35
|
+
|
|
36
|
+
complete: (onCompleteIds) =>
|
|
37
|
+
Effect.sync(() => {
|
|
38
|
+
ReadonlyArray.filterMap(onCompleteIds, (id) => {
|
|
39
|
+
const onComplete = map.get(id);
|
|
40
|
+
map.delete(id);
|
|
41
|
+
return Option.fromNullable(onComplete);
|
|
42
|
+
}).forEach((onComplete) => onComplete());
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
}),
|
|
46
|
+
);
|
package/src/Owner.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Brand, Context, Effect } from "effect";
|
|
2
|
+
import { urlAlphabet } from "nanoid";
|
|
3
|
+
import { Bip39, Mnemonic, slip21Derive } from "./Crypto.js";
|
|
4
|
+
import { Id } from "./Model.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The Owner represents the Evolu database owner, a user. Instead of traditional
|
|
8
|
+
* email with a password, the Owner uses a mnemonic, also known as a "seed
|
|
9
|
+
* phrase," which is a set of 12 words in a specific order chosen from a
|
|
10
|
+
* predefined list.
|
|
11
|
+
*
|
|
12
|
+
* The purpose of the BIP39 mnemonic is to provide a human-readable way of
|
|
13
|
+
* storing a private key.
|
|
14
|
+
*
|
|
15
|
+
* Mnemonic is generated safely in the user's device and must not be shared with
|
|
16
|
+
* anyone.
|
|
17
|
+
*/
|
|
18
|
+
export interface Owner {
|
|
19
|
+
/** The {@link Mnemonic} associated with {@link Owner}. */
|
|
20
|
+
readonly mnemonic: Mnemonic;
|
|
21
|
+
|
|
22
|
+
/** The unique identifier safely derived from {@link Mnemonic}. */
|
|
23
|
+
readonly id: OwnerId;
|
|
24
|
+
|
|
25
|
+
/** The encryption key safely derived from {@link Mnemonic}. */
|
|
26
|
+
readonly encryptionKey: Uint8Array;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const Owner = Context.Tag<Owner>();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The unique identifier of {@link Owner} safely derived from its
|
|
33
|
+
* {@link Mnemonic}.
|
|
34
|
+
*/
|
|
35
|
+
export type OwnerId = Id & Brand.Brand<"Owner">;
|
|
36
|
+
|
|
37
|
+
export const makeOwner = (
|
|
38
|
+
mnemonic?: Mnemonic,
|
|
39
|
+
): Effect.Effect<Bip39, never, Owner> =>
|
|
40
|
+
Effect.gen(function* (_) {
|
|
41
|
+
const bip39 = yield* _(Bip39);
|
|
42
|
+
|
|
43
|
+
if (mnemonic == null) mnemonic = yield* _(bip39.make);
|
|
44
|
+
|
|
45
|
+
const seed = yield* _(bip39.toSeed(mnemonic));
|
|
46
|
+
|
|
47
|
+
const id = yield* _(
|
|
48
|
+
slip21Derive(seed, ["Evolu", "Owner Id"]).pipe(
|
|
49
|
+
Effect.map((key) => {
|
|
50
|
+
// convert key to nanoid
|
|
51
|
+
let id = "";
|
|
52
|
+
for (let i = 0; i < 21; i++) {
|
|
53
|
+
id += urlAlphabet[key[i] & 63];
|
|
54
|
+
}
|
|
55
|
+
return id as OwnerId;
|
|
56
|
+
}),
|
|
57
|
+
),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const encryptionKey = yield* _(
|
|
61
|
+
slip21Derive(seed, ["Evolu", "Encryption Key"]),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return { mnemonic, id, encryptionKey };
|
|
65
|
+
});
|
package/src/Platform.ts
CHANGED
|
@@ -1,36 +1,40 @@
|
|
|
1
1
|
import { Context, Effect, Layer } from "effect";
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
| "react-native";
|
|
9
|
-
}
|
|
3
|
+
export type PlatformName =
|
|
4
|
+
| "server"
|
|
5
|
+
| "web-with-opfs"
|
|
6
|
+
| "web-without-opfs"
|
|
7
|
+
| "react-native";
|
|
10
8
|
|
|
11
|
-
export const
|
|
9
|
+
export const PlatformName = Context.Tag<PlatformName>();
|
|
12
10
|
|
|
13
11
|
export type FlushSync = (callback: () => void) => void;
|
|
14
12
|
|
|
15
|
-
export const FlushSync = Context.Tag<FlushSync>(
|
|
13
|
+
export const FlushSync = Context.Tag<FlushSync>();
|
|
16
14
|
|
|
17
15
|
export interface SyncLock {
|
|
16
|
+
/**
|
|
17
|
+
* Try to acquire a sync lock. The caller must not call sync if a sync lock
|
|
18
|
+
* can't be acquired.
|
|
19
|
+
*/
|
|
18
20
|
readonly acquire: Effect.Effect<never, never, boolean>;
|
|
21
|
+
|
|
22
|
+
/** Release a sync lock. */
|
|
19
23
|
readonly release: Effect.Effect<never, never, void>;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
export const SyncLock = Context.Tag<SyncLock>(
|
|
26
|
+
export const SyncLock = Context.Tag<SyncLock>();
|
|
23
27
|
|
|
24
28
|
export type Fetch = (
|
|
25
29
|
url: string,
|
|
26
30
|
body: Uint8Array,
|
|
27
31
|
) => Effect.Effect<never, FetchError, Response>;
|
|
28
32
|
|
|
29
|
-
export const Fetch = Context.Tag<Fetch>(
|
|
33
|
+
export const Fetch = Context.Tag<Fetch>();
|
|
30
34
|
|
|
31
35
|
/**
|
|
32
|
-
* This error occurs when there is a problem with the network connection,
|
|
33
|
-
*
|
|
36
|
+
* This error occurs when there is a problem with the network connection, or the
|
|
37
|
+
* server cannot be reached.
|
|
34
38
|
*/
|
|
35
39
|
export interface FetchError {
|
|
36
40
|
readonly _tag: "FetchError";
|
|
@@ -54,13 +58,17 @@ export const FetchLive = Layer.succeed(
|
|
|
54
58
|
),
|
|
55
59
|
);
|
|
56
60
|
|
|
61
|
+
interface AppStateConfig {
|
|
62
|
+
readonly onFocus: () => void;
|
|
63
|
+
readonly onReconnect: () => void;
|
|
64
|
+
}
|
|
65
|
+
|
|
57
66
|
export interface AppState {
|
|
58
|
-
readonly
|
|
59
|
-
readonly onReconnect: (callback: () => void) => void;
|
|
67
|
+
readonly init: (config: AppStateConfig) => void;
|
|
60
68
|
readonly reset: Effect.Effect<never, never, void>;
|
|
61
69
|
}
|
|
62
70
|
|
|
63
|
-
export const AppState = Context.Tag<AppState>(
|
|
71
|
+
export const AppState = Context.Tag<AppState>();
|
|
64
72
|
|
|
65
73
|
/**
|
|
66
74
|
* To detect whether DOM can be used.
|
package/src/Protobuf.ts
CHANGED
|
@@ -5,101 +5,61 @@
|
|
|
5
5
|
import { MessageType } from "@protobuf-ts/runtime";
|
|
6
6
|
import { MerkleTreeString, TimestampString } from "./Crdt.js";
|
|
7
7
|
import { NodeId } from "./Crypto.js";
|
|
8
|
-
import { OwnerId } from "./
|
|
8
|
+
import { OwnerId } from "./Owner.js";
|
|
9
9
|
import { Id } from "./Model.js";
|
|
10
|
-
/**
|
|
11
|
-
* @generated from protobuf message SyncRequest
|
|
12
|
-
*/
|
|
10
|
+
/** @generated from protobuf message SyncRequest */
|
|
13
11
|
export interface SyncRequest {
|
|
14
|
-
/**
|
|
15
|
-
* @generated from protobuf field: repeated EncryptedMessage messages = 1;
|
|
16
|
-
*/
|
|
12
|
+
/** @generated from protobuf field: repeated EncryptedMessage messages = 1; */
|
|
17
13
|
messages: ReadonlyArray<EncryptedMessage>;
|
|
18
|
-
/**
|
|
19
|
-
* @generated from protobuf field: string userId = 2;
|
|
20
|
-
*/
|
|
14
|
+
/** @generated from protobuf field: string userId = 2; */
|
|
21
15
|
userId: OwnerId;
|
|
22
|
-
/**
|
|
23
|
-
* @generated from protobuf field: string nodeId = 3;
|
|
24
|
-
*/
|
|
16
|
+
/** @generated from protobuf field: string nodeId = 3; */
|
|
25
17
|
nodeId: NodeId;
|
|
26
|
-
/**
|
|
27
|
-
* @generated from protobuf field: string merkleTree = 4;
|
|
28
|
-
*/
|
|
18
|
+
/** @generated from protobuf field: string merkleTree = 4; */
|
|
29
19
|
merkleTree: MerkleTreeString;
|
|
30
20
|
}
|
|
31
|
-
/**
|
|
32
|
-
* @generated from protobuf message SyncResponse
|
|
33
|
-
*/
|
|
21
|
+
/** @generated from protobuf message SyncResponse */
|
|
34
22
|
export interface SyncResponse {
|
|
35
|
-
/**
|
|
36
|
-
* @generated from protobuf field: repeated EncryptedMessage messages = 1;
|
|
37
|
-
*/
|
|
23
|
+
/** @generated from protobuf field: repeated EncryptedMessage messages = 1; */
|
|
38
24
|
messages: ReadonlyArray<EncryptedMessage>;
|
|
39
|
-
/**
|
|
40
|
-
* @generated from protobuf field: string merkleTree = 2;
|
|
41
|
-
*/
|
|
25
|
+
/** @generated from protobuf field: string merkleTree = 2; */
|
|
42
26
|
merkleTree: MerkleTreeString;
|
|
43
27
|
}
|
|
44
|
-
/**
|
|
45
|
-
* @generated from protobuf message EncryptedMessage
|
|
46
|
-
*/
|
|
28
|
+
/** @generated from protobuf message EncryptedMessage */
|
|
47
29
|
export interface EncryptedMessage {
|
|
48
|
-
/**
|
|
49
|
-
* @generated from protobuf field: string timestamp = 1;
|
|
50
|
-
*/
|
|
30
|
+
/** @generated from protobuf field: string timestamp = 1; */
|
|
51
31
|
timestamp: TimestampString;
|
|
52
|
-
/**
|
|
53
|
-
* @generated from protobuf field: bytes content = 2;
|
|
54
|
-
*/
|
|
32
|
+
/** @generated from protobuf field: bytes content = 2; */
|
|
55
33
|
content: Uint8Array;
|
|
56
34
|
}
|
|
57
|
-
/**
|
|
58
|
-
* @generated from protobuf message MessageContent
|
|
59
|
-
*/
|
|
35
|
+
/** @generated from protobuf message MessageContent */
|
|
60
36
|
export interface MessageContent {
|
|
61
|
-
/**
|
|
62
|
-
* @generated from protobuf field: string table = 1;
|
|
63
|
-
*/
|
|
37
|
+
/** @generated from protobuf field: string table = 1; */
|
|
64
38
|
table: string;
|
|
65
|
-
/**
|
|
66
|
-
* @generated from protobuf field: string row = 2;
|
|
67
|
-
*/
|
|
39
|
+
/** @generated from protobuf field: string row = 2; */
|
|
68
40
|
row: Id;
|
|
69
|
-
/**
|
|
70
|
-
* @generated from protobuf field: string column = 3;
|
|
71
|
-
*/
|
|
41
|
+
/** @generated from protobuf field: string column = 3; */
|
|
72
42
|
column: string;
|
|
73
|
-
/**
|
|
74
|
-
* @generated from protobuf oneof: value
|
|
75
|
-
*/
|
|
43
|
+
/** @generated from protobuf oneof: value */
|
|
76
44
|
value:
|
|
77
45
|
| {
|
|
78
46
|
oneofKind: "stringValue";
|
|
79
|
-
/**
|
|
80
|
-
* @generated from protobuf field: string stringValue = 4;
|
|
81
|
-
*/
|
|
47
|
+
/** @generated from protobuf field: string stringValue = 4; */
|
|
82
48
|
stringValue: string;
|
|
83
49
|
}
|
|
84
50
|
| {
|
|
85
51
|
oneofKind: "numberValue";
|
|
86
|
-
/**
|
|
87
|
-
* @generated from protobuf field: int32 numberValue = 5;
|
|
88
|
-
*/
|
|
52
|
+
/** @generated from protobuf field: int32 numberValue = 5; */
|
|
89
53
|
numberValue: number;
|
|
90
54
|
}
|
|
91
55
|
| {
|
|
92
56
|
oneofKind: "bytesValue";
|
|
93
|
-
/**
|
|
94
|
-
* @generated from protobuf field: bytes bytesValue = 6;
|
|
95
|
-
*/
|
|
57
|
+
/** @generated from protobuf field: bytes bytesValue = 6; */
|
|
96
58
|
bytesValue: Uint8Array;
|
|
97
59
|
}
|
|
98
60
|
| {
|
|
99
61
|
oneofKind: "jsonValue";
|
|
100
|
-
/**
|
|
101
|
-
* @generated from protobuf field: string jsonValue = 7;
|
|
102
|
-
*/
|
|
62
|
+
/** @generated from protobuf field: string jsonValue = 7; */
|
|
103
63
|
jsonValue: string;
|
|
104
64
|
}
|
|
105
65
|
| {
|
|
@@ -123,9 +83,7 @@ class SyncRequest$Type extends MessageType<SyncRequest> {
|
|
|
123
83
|
]);
|
|
124
84
|
}
|
|
125
85
|
}
|
|
126
|
-
/**
|
|
127
|
-
* @generated MessageType for protobuf message SyncRequest
|
|
128
|
-
*/
|
|
86
|
+
/** @generated MessageType for protobuf message SyncRequest */
|
|
129
87
|
export const SyncRequest = new SyncRequest$Type();
|
|
130
88
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
131
89
|
class SyncResponse$Type extends MessageType<SyncResponse> {
|
|
@@ -142,9 +100,7 @@ class SyncResponse$Type extends MessageType<SyncResponse> {
|
|
|
142
100
|
]);
|
|
143
101
|
}
|
|
144
102
|
}
|
|
145
|
-
/**
|
|
146
|
-
* @generated MessageType for protobuf message SyncResponse
|
|
147
|
-
*/
|
|
103
|
+
/** @generated MessageType for protobuf message SyncResponse */
|
|
148
104
|
export const SyncResponse = new SyncResponse$Type();
|
|
149
105
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
150
106
|
class EncryptedMessage$Type extends MessageType<EncryptedMessage> {
|
|
@@ -155,9 +111,7 @@ class EncryptedMessage$Type extends MessageType<EncryptedMessage> {
|
|
|
155
111
|
]);
|
|
156
112
|
}
|
|
157
113
|
}
|
|
158
|
-
/**
|
|
159
|
-
* @generated MessageType for protobuf message EncryptedMessage
|
|
160
|
-
*/
|
|
114
|
+
/** @generated MessageType for protobuf message EncryptedMessage */
|
|
161
115
|
export const EncryptedMessage = new EncryptedMessage$Type();
|
|
162
116
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
163
117
|
class MessageContent$Type extends MessageType<MessageContent> {
|
|
@@ -197,7 +151,5 @@ class MessageContent$Type extends MessageType<MessageContent> {
|
|
|
197
151
|
]);
|
|
198
152
|
}
|
|
199
153
|
}
|
|
200
|
-
/**
|
|
201
|
-
* @generated MessageType for protobuf message MessageContent
|
|
202
|
-
*/
|
|
154
|
+
/** @generated MessageType for protobuf message MessageContent */
|
|
203
155
|
export const MessageContent = new MessageContent$Type();
|
package/src/Public.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
|
|
2
|
-
export type {
|
|
3
|
-
export type {
|
|
4
|
-
export type { EvoluError } from "./
|
|
2
|
+
export type { Timestamp, TimestampError } from "./Crdt.js";
|
|
3
|
+
export type { Mnemonic, InvalidMnemonicError } from "./Crypto.js";
|
|
4
|
+
export type { EvoluError, UnexpectedError } from "./ErrorStore.js";
|
|
5
5
|
export * from "./Model.js";
|
|
6
|
+
export type { Owner, OwnerId } from "./Owner.js";
|
|
7
|
+
export { canUseDom } from "./Platform.js";
|
|
6
8
|
export type { SyncState } from "./SyncWorker.js";
|
package/src/Sqlite.ts
CHANGED
|
@@ -1,45 +1,37 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Context, Effect, Predicate, ReadonlyRecord } from "effect";
|
|
2
2
|
|
|
3
3
|
export interface Sqlite {
|
|
4
4
|
readonly exec: (
|
|
5
|
-
arg: string |
|
|
5
|
+
arg: string | SqliteQuery,
|
|
6
6
|
) => Effect.Effect<never, never, ExecResult>;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export const Sqlite = Context.Tag<Sqlite>(
|
|
9
|
+
export const Sqlite = Context.Tag<Sqlite>();
|
|
10
10
|
|
|
11
|
-
export interface
|
|
11
|
+
export interface SqliteQuery {
|
|
12
12
|
readonly sql: string;
|
|
13
|
-
readonly parameters:
|
|
13
|
+
readonly parameters: Value[];
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export type Value = SqliteValue | JsonObjectOrArray;
|
|
17
|
-
|
|
18
17
|
export type SqliteValue = null | string | number | Uint8Array;
|
|
19
|
-
export type SqliteRow = Record<string, SqliteValue>;
|
|
20
|
-
|
|
21
18
|
export type JsonObjectOrArray = JsonObject | JsonArray;
|
|
22
|
-
|
|
23
19
|
type JsonObject = ReadonlyRecord.ReadonlyRecord<Json>;
|
|
24
20
|
type JsonArray = ReadonlyArray<Json>;
|
|
25
21
|
type Json = string | number | boolean | null | JsonObject | JsonArray;
|
|
26
22
|
|
|
27
23
|
interface ExecResult {
|
|
28
|
-
readonly rows:
|
|
24
|
+
readonly rows: SqliteRow[];
|
|
29
25
|
readonly changes: number;
|
|
30
26
|
}
|
|
31
27
|
|
|
32
|
-
export type
|
|
33
|
-
Value | Row | ReadonlyArray<Row>
|
|
34
|
-
>;
|
|
35
|
-
|
|
36
|
-
export type Query = string & Brand.Brand<"Query">;
|
|
28
|
+
export type SqliteRow = Record<string, SqliteValue>;
|
|
37
29
|
|
|
38
30
|
export const isJsonObjectOrArray: Predicate.Refinement<
|
|
39
31
|
Value,
|
|
40
32
|
JsonObjectOrArray
|
|
41
33
|
> = (value): value is JsonObjectOrArray =>
|
|
42
|
-
value !== null && typeof value === "object" && !(value
|
|
34
|
+
value !== null && typeof value === "object" && !Predicate.isUint8Array(value);
|
|
43
35
|
|
|
44
36
|
export const valuesToSqliteValues = (
|
|
45
37
|
values: ReadonlyArray<Value>,
|
|
@@ -48,15 +40,13 @@ export const valuesToSqliteValues = (
|
|
|
48
40
|
isJsonObjectOrArray(value) ? JSON.stringify(value) : value,
|
|
49
41
|
);
|
|
50
42
|
|
|
51
|
-
export const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
JSON.parse(s) as QueryObject;
|
|
43
|
+
export const ensureSqliteQuery = (arg: string | SqliteQuery): SqliteQuery => {
|
|
44
|
+
if (typeof arg !== "string") return arg;
|
|
45
|
+
return { sql: arg, parameters: [] };
|
|
46
|
+
};
|
|
56
47
|
|
|
57
|
-
export const
|
|
48
|
+
export const maybeParseJson = (rows: SqliteRow[]): SqliteRow[] =>
|
|
58
49
|
parseArray(rows);
|
|
59
|
-
};
|
|
60
50
|
|
|
61
51
|
const parseArray = <T>(a: T[]): T[] => {
|
|
62
52
|
for (let i = 0; i < a.length; ++i) a[i] = parse(a[i]) as T;
|
|
@@ -67,7 +57,6 @@ const parse = (o: unknown): unknown => {
|
|
|
67
57
|
if (Predicate.isString(o)) return parseString(o);
|
|
68
58
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
69
59
|
if (Array.isArray(o)) return parseArray(o);
|
|
70
|
-
// Predicate.isReadonlyRecord
|
|
71
60
|
if (typeof o === "object" && o !== null && !Predicate.isUint8Array(o))
|
|
72
61
|
return parseObject(o as Record<string, unknown>);
|
|
73
62
|
return o;
|