@evolu/common 1.0.17 → 2.0.1
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 +16 -12
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +18 -12
- 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 +38 -25
- 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/dist/src/DbWorker.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Context, Effect, Layer, ReadonlyArray, ReadonlyRecord } from "effect";
|
|
2
2
|
import { Config } from "./Config.js";
|
|
3
3
|
import { Bip39, Mnemonic, NanoId } from "./Crypto.js";
|
|
4
|
-
import {
|
|
4
|
+
import { Queries, Query, Tables } from "./Db.js";
|
|
5
5
|
import { QueryPatches } from "./Diff.js";
|
|
6
|
-
import { EvoluError } from "./
|
|
6
|
+
import { EvoluError } from "./ErrorStore.js";
|
|
7
7
|
import { Id, SqliteDate } from "./Model.js";
|
|
8
|
-
import {
|
|
8
|
+
import { OnCompleteId } from "./OnCompletes.js";
|
|
9
|
+
import { Owner } from "./Owner.js";
|
|
10
|
+
import { Sqlite, Value } from "./Sqlite.js";
|
|
9
11
|
import { NewMessage, SyncState, SyncWorker, SyncWorkerOutputSyncResponse } from "./SyncWorker.js";
|
|
10
12
|
export interface DbWorker {
|
|
11
13
|
readonly postMessage: (input: DbWorkerInput) => void;
|
|
@@ -16,7 +18,6 @@ export type DbWorkerInput = DbWorkerInputInit | DbWorkerInputQuery | DbWorkerInp
|
|
|
16
18
|
interface DbWorkerInputInit {
|
|
17
19
|
readonly _tag: "init";
|
|
18
20
|
readonly config: Config;
|
|
19
|
-
readonly tables: Tables;
|
|
20
21
|
}
|
|
21
22
|
interface DbWorkerInputQuery {
|
|
22
23
|
readonly _tag: "query";
|
|
@@ -24,12 +25,12 @@ interface DbWorkerInputQuery {
|
|
|
24
25
|
}
|
|
25
26
|
interface DbWorkerInputMutate {
|
|
26
27
|
readonly _tag: "mutate";
|
|
27
|
-
readonly
|
|
28
|
-
readonly queries:
|
|
28
|
+
readonly mutations: ReadonlyArray.NonEmptyReadonlyArray<Mutation>;
|
|
29
|
+
readonly queries: Queries;
|
|
29
30
|
}
|
|
30
31
|
interface DbWorkerInputSync {
|
|
31
32
|
readonly _tag: "sync";
|
|
32
|
-
readonly queries:
|
|
33
|
+
readonly queries: Queries;
|
|
33
34
|
}
|
|
34
35
|
interface DbWorkerInputReset {
|
|
35
36
|
readonly _tag: "reset";
|
|
@@ -40,11 +41,11 @@ interface DbWorkerInputEnsureSchema {
|
|
|
40
41
|
readonly tables: Tables;
|
|
41
42
|
}
|
|
42
43
|
export type DbWorkerOutput = DbWorkerOutputOnError | DbWorkerOutputOnOwner | DbWorkerOutputOnQuery | DbWorkerOutputOnReceive | DbWorkerOutputOnResetOrRestore | DbWorkerOutputOnSyncState;
|
|
43
|
-
interface DbWorkerOutputOnError {
|
|
44
|
+
export interface DbWorkerOutputOnError {
|
|
44
45
|
readonly _tag: "onError";
|
|
45
46
|
readonly error: EvoluError;
|
|
46
47
|
}
|
|
47
|
-
interface DbWorkerOutputOnOwner {
|
|
48
|
+
export interface DbWorkerOutputOnOwner {
|
|
48
49
|
readonly _tag: "onOwner";
|
|
49
50
|
readonly owner: Owner;
|
|
50
51
|
}
|
|
@@ -53,7 +54,6 @@ export interface DbWorkerOutputOnQuery {
|
|
|
53
54
|
readonly queriesPatches: ReadonlyArray<QueryPatches>;
|
|
54
55
|
readonly onCompleteIds: ReadonlyArray<OnCompleteId>;
|
|
55
56
|
}
|
|
56
|
-
export type OnCompleteId = string & Brand.Brand<"Id"> & Brand.Brand<"OnComplete">;
|
|
57
57
|
interface DbWorkerOutputOnReceive {
|
|
58
58
|
readonly _tag: "onReceive";
|
|
59
59
|
}
|
|
@@ -64,7 +64,7 @@ interface DbWorkerOutputOnSyncState {
|
|
|
64
64
|
readonly _tag: "onSyncState";
|
|
65
65
|
readonly state: SyncState;
|
|
66
66
|
}
|
|
67
|
-
export interface
|
|
67
|
+
export interface Mutation {
|
|
68
68
|
readonly table: string;
|
|
69
69
|
readonly id: Id;
|
|
70
70
|
readonly values: ReadonlyRecord.ReadonlyRecord<Value | Date | boolean | undefined>;
|
|
@@ -72,8 +72,7 @@ export interface MutateItem {
|
|
|
72
72
|
readonly now: SqliteDate;
|
|
73
73
|
readonly onCompleteId: OnCompleteId | null;
|
|
74
74
|
}
|
|
75
|
-
export
|
|
76
|
-
export declare const mutateItemsToNewMessages: (items: ReadonlyArray<MutateItem>) => ReadonlyArray<NewMessage>;
|
|
75
|
+
export declare const mutationsToNewMessages: (mutations: ReadonlyArray<Mutation>) => ReadonlyArray<NewMessage>;
|
|
77
76
|
export declare const upsertValueIntoTableRowColumn: (message: NewMessage, messages: ReadonlyArray<NewMessage>) => Effect.Effect<Sqlite, never, void>;
|
|
78
77
|
export declare const DbWorkerLive: Layer.Layer<Bip39 | NanoId | Sqlite | SyncWorker, never, DbWorker>;
|
|
79
78
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DbWorker.d.ts","sourceRoot":"","sources":["../../src/DbWorker.ts"],"names":[],"mappings":"AACA,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"DbWorker.d.ts","sourceRoot":"","sources":["../../src/DbWorker.ts"],"names":[],"mappings":"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"}
|
package/dist/src/DbWorker.js
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
import { hexToBytes } from "@noble/ciphers/utils";
|
|
2
|
-
import { Context, Effect, Function, Layer, Option, ReadonlyArray,
|
|
2
|
+
import { Context, Effect, Function, Layer, Match, Option, ReadonlyArray, pipe, } from "effect";
|
|
3
3
|
import { Config, ConfigLive } from "./Config.js";
|
|
4
4
|
import { Time, TimeLive, diffMerkleTrees, insertIntoMerkleTree, makeSyncTimestamp, merkleTreeToString, receiveTimestamp, sendTimestamp, timestampToString, unsafeTimestampFromString, } from "./Crdt.js";
|
|
5
5
|
import { Bip39, NanoId } from "./Crypto.js";
|
|
6
|
-
import {
|
|
6
|
+
import { RowsStore, RowsStoreLive, deserializeQuery, ensureSchema, lazyInit, someDefectToNoSuchTableOrColumnError, transaction, } from "./Db.js";
|
|
7
7
|
import { makePatches } from "./Diff.js";
|
|
8
|
-
import { makeUnexpectedError } from "./
|
|
8
|
+
import { makeUnexpectedError } from "./ErrorStore.js";
|
|
9
9
|
import { cast } from "./Model.js";
|
|
10
|
+
import { Owner } from "./Owner.js";
|
|
10
11
|
import * as Sql from "./Sql.js";
|
|
11
|
-
import { Sqlite
|
|
12
|
+
import { Sqlite } from "./Sqlite.js";
|
|
12
13
|
import { NewMessageEquivalence, SyncWorker, SyncWorkerPostMessage, } from "./SyncWorker.js";
|
|
13
|
-
export const DbWorker = Context.Tag(
|
|
14
|
-
const DbWorkerOnMessage = Context.Tag(
|
|
15
|
-
const init =
|
|
14
|
+
export const DbWorker = Context.Tag();
|
|
15
|
+
const DbWorkerOnMessage = Context.Tag();
|
|
16
|
+
const init = Effect.gen(function* (_) {
|
|
16
17
|
const sqlite = yield* _(Sqlite);
|
|
17
18
|
return yield* _(sqlite.exec(Sql.selectOwner), Effect.map(({ rows: [row] }) => ({
|
|
18
19
|
id: row.id,
|
|
19
20
|
mnemonic: row.mnemonic,
|
|
20
21
|
// expo-sqlite 11.3.2 doesn't support Uint8Array
|
|
21
22
|
encryptionKey: hexToBytes(row.encryptionKey),
|
|
22
|
-
})), someDefectToNoSuchTableOrColumnError, Effect.catchTag("NoSuchTableOrColumnError", () => lazyInit())
|
|
23
|
+
})), someDefectToNoSuchTableOrColumnError, Effect.catchTag("NoSuchTableOrColumnError", () => lazyInit()));
|
|
23
24
|
});
|
|
24
|
-
const RowsCacheRef = Context.Tag("evolu/RowsCacheRef");
|
|
25
25
|
const query = ({ queries, onCompleteIds = [], }) => Effect.gen(function* (_) {
|
|
26
26
|
const sqlite = yield* _(Sqlite);
|
|
27
|
-
const
|
|
27
|
+
const rowsStore = yield* _(RowsStore);
|
|
28
28
|
const dbWorkerOnMessage = yield* _(DbWorkerOnMessage);
|
|
29
|
-
const queriesRows = yield* _(
|
|
30
|
-
.exec(
|
|
29
|
+
const queriesRows = yield* _(ReadonlyArray.dedupe(queries), Effect.forEach((query) => sqlite
|
|
30
|
+
.exec(deserializeQuery(query))
|
|
31
31
|
.pipe(Effect.map((result) => [query, result.rows]))));
|
|
32
|
-
const previous =
|
|
33
|
-
yield* _(
|
|
32
|
+
const previous = rowsStore.getState();
|
|
33
|
+
yield* _(rowsStore.setState(new Map([...previous, ...queriesRows])));
|
|
34
34
|
const queriesPatches = queriesRows.map(([query, rows]) => ({
|
|
35
35
|
query,
|
|
36
36
|
patches: makePatches(previous.get(query), rows),
|
|
@@ -41,7 +41,7 @@ const readTimestampAndMerkleTree = Sqlite.pipe(Effect.flatMap((sqlite) => sqlite
|
|
|
41
41
|
timestamp: unsafeTimestampFromString(timestamp),
|
|
42
42
|
merkleTree: merkleTree,
|
|
43
43
|
})));
|
|
44
|
-
export const
|
|
44
|
+
export const mutationsToNewMessages = (mutations) => pipe(mutations, ReadonlyArray.map(({ id, isInsert, now, table, values }) => pipe(Object.entries(values), ReadonlyArray.filterMap(([key, value]) =>
|
|
45
45
|
// The value can be undefined if exactOptionalPropertyTypes isn't true.
|
|
46
46
|
// Don't insert nulls because null is the default value.
|
|
47
47
|
value === undefined || (isInsert && value == null)
|
|
@@ -125,15 +125,15 @@ const writeTimestampAndMerkleTree = ({ timestamp, merkleTree, }) => Effect.flatM
|
|
|
125
125
|
merkleTreeToString(merkleTree),
|
|
126
126
|
],
|
|
127
127
|
}));
|
|
128
|
-
const mutate = ({
|
|
129
|
-
const [toSync,
|
|
130
|
-
const [toUpsert, toDelete] = ReadonlyArray.partition(
|
|
128
|
+
const mutate = ({ mutations, queries, }) => Effect.gen(function* (_) {
|
|
129
|
+
const [toSync, localOnly] = ReadonlyArray.partition(mutations, (item) => item.table.startsWith("_"));
|
|
130
|
+
const [toUpsert, toDelete] = ReadonlyArray.partition(localOnly, (item) => mutationsToNewMessages([item]).some((message) => message.column === "isDeleted" && message.value === 1)).map(mutationsToNewMessages);
|
|
131
131
|
yield* _(Effect.forEach(toUpsert, (message) => upsertValueIntoTableRowColumn(message, toUpsert)));
|
|
132
132
|
const { exec } = yield* _(Sqlite);
|
|
133
133
|
yield* _(Effect.forEach(toDelete, ({ table, row }) => exec({ sql: Sql.deleteTableRow(table), parameters: [row] })));
|
|
134
134
|
if (toSync.length > 0) {
|
|
135
135
|
let { timestamp, merkleTree } = yield* _(readTimestampAndMerkleTree);
|
|
136
|
-
const messages = yield* _(
|
|
136
|
+
const messages = yield* _(mutationsToNewMessages(toSync), Effect.forEach((message) => Effect.map(sendTimestamp(timestamp), (nextTimestamp) => {
|
|
137
137
|
timestamp = nextTimestamp;
|
|
138
138
|
return { ...message, timestamp: timestampToString(timestamp) };
|
|
139
139
|
})));
|
|
@@ -149,20 +149,20 @@ const mutate = ({ items, queries, }) => Effect.gen(function* (_) {
|
|
|
149
149
|
syncLoopCount: 0,
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
|
-
const onCompleteIds = ReadonlyArray.filterMap(
|
|
152
|
+
const onCompleteIds = ReadonlyArray.filterMap(mutations, (item) => Option.fromNullable(item.onCompleteId));
|
|
153
153
|
if (queries.length > 0 || onCompleteIds.length > 0)
|
|
154
154
|
yield* _(query({ queries, onCompleteIds }));
|
|
155
155
|
});
|
|
156
156
|
const handleSyncResponse = ({ messages, ...response }) => Effect.gen(function* (_) {
|
|
157
157
|
let { timestamp, merkleTree } = yield* _(readTimestampAndMerkleTree);
|
|
158
|
+
const dbWorkerOnMessage = yield* _(DbWorkerOnMessage);
|
|
158
159
|
if (messages.length > 0) {
|
|
159
160
|
for (const message of messages)
|
|
160
161
|
timestamp = yield* _(unsafeTimestampFromString(message.timestamp), (remote) => receiveTimestamp({ local: timestamp, remote }));
|
|
161
162
|
merkleTree = yield* _(applyMessages({ merkleTree, messages }));
|
|
162
163
|
yield* _(writeTimestampAndMerkleTree({ timestamp, merkleTree }));
|
|
164
|
+
dbWorkerOnMessage({ _tag: "onReceive" });
|
|
163
165
|
}
|
|
164
|
-
const dbWorkerOnMessage = yield* _(DbWorkerOnMessage);
|
|
165
|
-
dbWorkerOnMessage({ _tag: "onReceive" });
|
|
166
166
|
const diff = diffMerkleTrees(response.merkleTree, merkleTree);
|
|
167
167
|
const syncWorkerPostMessage = yield* _(SyncWorkerPostMessage);
|
|
168
168
|
if (Option.isNone(diff)) {
|
|
@@ -176,11 +176,19 @@ const handleSyncResponse = ({ messages, ...response }) => Effect.gen(function* (
|
|
|
176
176
|
});
|
|
177
177
|
return;
|
|
178
178
|
}
|
|
179
|
-
const
|
|
179
|
+
const sqlite = yield* _(Sqlite);
|
|
180
|
+
const config = yield* _(Config);
|
|
181
|
+
const owner = yield* _(Owner);
|
|
180
182
|
const messagesToSync = yield* _(sqlite.exec({
|
|
181
183
|
sql: Sql.selectMessagesToSync,
|
|
182
184
|
parameters: [timestampToString(makeSyncTimestamp(diff.value))],
|
|
183
185
|
}), Effect.map(({ rows }) => rows));
|
|
186
|
+
if (response.syncLoopCount > 100) {
|
|
187
|
+
// TODO: dbWorkerOnMessage({ _tag: "onError" });
|
|
188
|
+
// eslint-disable-next-line no-console
|
|
189
|
+
console.error("Evolu: syncLoopCount > 100");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
184
192
|
syncWorkerPostMessage({
|
|
185
193
|
_tag: "sync",
|
|
186
194
|
syncUrl: config.syncUrl,
|
|
@@ -194,12 +202,10 @@ const handleSyncResponse = ({ messages, ...response }) => Effect.gen(function* (
|
|
|
194
202
|
const sync = ({ queries, }) => Effect.gen(function* (_) {
|
|
195
203
|
if (queries.length > 0)
|
|
196
204
|
yield* _(query({ queries }));
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
readTimestampAndMerkleTree,
|
|
202
|
-
]));
|
|
205
|
+
const syncWorkerPostMessage = yield* _(SyncWorkerPostMessage);
|
|
206
|
+
const config = yield* _(Config);
|
|
207
|
+
const owner = yield* _(Owner);
|
|
208
|
+
const timestampAndMerkleTree = yield* _(readTimestampAndMerkleTree);
|
|
203
209
|
syncWorkerPostMessage({
|
|
204
210
|
...timestampAndMerkleTree,
|
|
205
211
|
_tag: "sync",
|
|
@@ -224,7 +230,6 @@ const reset = (input) => Effect.gen(function* (_) {
|
|
|
224
230
|
});
|
|
225
231
|
export const DbWorkerLive = Layer.effect(DbWorker, Effect.gen(function* (_) {
|
|
226
232
|
const syncWorker = yield* _(SyncWorker);
|
|
227
|
-
const rowsCacheRef = yield* _(Ref.make(new Map()));
|
|
228
233
|
const onError = (error) => Effect.sync(() => {
|
|
229
234
|
dbWorker.onMessage({ _tag: "onError", error });
|
|
230
235
|
});
|
|
@@ -240,49 +245,43 @@ export const DbWorkerLive = Layer.effect(DbWorker, Effect.gen(function* (_) {
|
|
|
240
245
|
dbWorker.onMessage({ _tag: "onSyncState", state: output });
|
|
241
246
|
}
|
|
242
247
|
};
|
|
243
|
-
const
|
|
244
|
-
|
|
248
|
+
const runContext = Context.empty().pipe(Context.add(Sqlite, yield* _(Sqlite)), Context.add(Bip39, yield* _(Bip39)), Context.add(NanoId, yield* _(NanoId)), Context.add(DbWorkerOnMessage, (output) => {
|
|
249
|
+
dbWorker.onMessage(output);
|
|
250
|
+
}));
|
|
251
|
+
const run = (effect) => effect.pipe(Effect.catchAllDefect(makeUnexpectedError), transaction, Effect.catchAll(onError), Effect.provide(runContext), Effect.runPromise);
|
|
245
252
|
// Write for reset only in case init fails.
|
|
246
253
|
const writeForInitFail = (input) => {
|
|
247
254
|
if (input._tag !== "reset")
|
|
248
255
|
return Promise.resolve(undefined);
|
|
249
|
-
return reset(input).pipe(
|
|
256
|
+
return reset(input).pipe(run);
|
|
250
257
|
};
|
|
251
|
-
const makeWriteForInitSuccess = (
|
|
258
|
+
const makeWriteForInitSuccess = (config, owner) => {
|
|
252
259
|
let skipAllBecauseOfReset = false;
|
|
253
|
-
const layer = Layer.mergeAll(ConfigLive(config), Layer.succeed(
|
|
254
|
-
const mapInputToEffect = (input) => {
|
|
255
|
-
switch (input._tag) {
|
|
256
|
-
case "init":
|
|
257
|
-
return makeUnexpectedError(new Error("init must be called once"));
|
|
258
|
-
case "query":
|
|
259
|
-
return query(input);
|
|
260
|
-
case "mutate":
|
|
261
|
-
return mutate(input);
|
|
262
|
-
case "sync":
|
|
263
|
-
return sync(input);
|
|
264
|
-
case "reset":
|
|
265
|
-
skipAllBecauseOfReset = true;
|
|
266
|
-
return reset(input);
|
|
267
|
-
case "ensureSchema":
|
|
268
|
-
return ensureSchema(input.tables);
|
|
269
|
-
case "SyncWorkerOutputSyncResponse":
|
|
270
|
-
return handleSyncResponse(input);
|
|
271
|
-
}
|
|
272
|
-
};
|
|
260
|
+
const layer = Layer.mergeAll(ConfigLive(config), Layer.succeed(Owner, owner), Layer.succeed(SyncWorkerPostMessage, syncWorker.postMessage), RowsStoreLive, TimeLive);
|
|
273
261
|
return (input) => {
|
|
274
262
|
if (skipAllBecauseOfReset)
|
|
275
263
|
return Promise.resolve(undefined);
|
|
276
|
-
return
|
|
264
|
+
return Match.value(input).pipe(Match.tagsExhaustive({
|
|
265
|
+
init: () => makeUnexpectedError(new Error("init must be called once")),
|
|
266
|
+
query,
|
|
267
|
+
mutate,
|
|
268
|
+
sync,
|
|
269
|
+
reset: (input) => {
|
|
270
|
+
skipAllBecauseOfReset = true;
|
|
271
|
+
return reset(input);
|
|
272
|
+
},
|
|
273
|
+
ensureSchema: ({ tables }) => ensureSchema(tables),
|
|
274
|
+
SyncWorkerOutputSyncResponse: handleSyncResponse,
|
|
275
|
+
}), Effect.provide(layer), run);
|
|
277
276
|
};
|
|
278
277
|
};
|
|
279
278
|
let write = (input) => {
|
|
280
279
|
if (input._tag !== "init")
|
|
281
280
|
return run(makeUnexpectedError(new Error("init must be called first")));
|
|
282
281
|
write = writeForInitFail;
|
|
283
|
-
return init
|
|
282
|
+
return init.pipe(Effect.map((owner) => {
|
|
284
283
|
dbWorker.onMessage({ _tag: "onOwner", owner });
|
|
285
|
-
write = makeWriteForInitSuccess(
|
|
284
|
+
write = makeWriteForInitSuccess(input.config, owner);
|
|
286
285
|
}), run);
|
|
287
286
|
};
|
|
288
287
|
let messageQueue = Promise.resolve(undefined);
|
package/dist/src/Diff.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReadonlyArray } from "effect";
|
|
2
|
+
import { Query, Row } from "./Db.js";
|
|
3
|
+
import { Value } from "./Sqlite.js";
|
|
2
4
|
export interface QueryPatches {
|
|
3
5
|
readonly query: Query;
|
|
4
6
|
readonly patches: ReadonlyArray<Patch>;
|
package/dist/src/Diff.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Diff.d.ts","sourceRoot":"","sources":["../../src/Diff.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Diff.d.ts","sourceRoot":"","sources":["../../src/Diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,aAAa,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,KAAK,GAAG,eAAe,GAAG,cAAc,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;CACrB;AAED,eAAO,MAAM,YAAY,YACb,cAAc,KAAK,CAAC,eACpB,cAAc,GAAG,CAAC,KAAG,cAAc,GAAG,CASnC,CAAC;AAQhB,eAAO,MAAM,WAAW,iBACR,cAAc,GAAG,CAAC,GAAG,SAAS,YAClC,cAAc,GAAG,CAAC,KAC3B,SAAS,KAAK,EA2BhB,CAAC;AAEF,eAAO,MAAM,QAAQ,MAChB,KAAK,GAAG,GAAG,GAAG,cAAc,GAAG,CAAC,KAChC,KAAK,GAAG,GAAG,GAAG,cAAc,GAAG,CAAC,KAClC,OAkCF,CAAC"}
|
package/dist/src/Diff.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import { Predicate } from "effect";
|
|
2
|
-
export const applyPatches = (patches) => (current) => patches.reduce((
|
|
1
|
+
import { Predicate, ReadonlyArray } from "effect";
|
|
2
|
+
export const applyPatches = (patches) => (current) => patches.reduce((next, patch) => {
|
|
3
3
|
switch (patch.op) {
|
|
4
4
|
case "replaceAll":
|
|
5
5
|
return patch.value;
|
|
6
6
|
case "replaceAt": {
|
|
7
|
-
|
|
8
|
-
return a;
|
|
9
|
-
const next = [...a];
|
|
10
|
-
next[patch.index] = patch.value;
|
|
11
|
-
return next;
|
|
7
|
+
return ReadonlyArray.replace(next, patch.index, patch.value);
|
|
12
8
|
}
|
|
13
9
|
}
|
|
14
10
|
}, current);
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { TimestampError } from "./Crdt.js";
|
|
3
|
+
export declare const makeErrorStore: Effect.Effect<never, never, import("./Store.js").Store<EvoluError | null>>;
|
|
4
|
+
/** The EvoluError type is used to represent errors that can occur in Evolu. */
|
|
3
5
|
export type EvoluError = UnexpectedError | TimestampError;
|
|
6
|
+
/**
|
|
7
|
+
* The UnexpectedError interface is designed to represent errors that can occur
|
|
8
|
+
* unexpectedly anywhere, even in third-party libraries, because Evolu uses
|
|
9
|
+
* Effect to track all errors.
|
|
10
|
+
*/
|
|
11
|
+
export interface UnexpectedError {
|
|
12
|
+
readonly _tag: "UnexpectedError";
|
|
13
|
+
readonly error: TransferableError;
|
|
14
|
+
}
|
|
15
|
+
export declare const makeUnexpectedError: (error: unknown) => Effect.Effect<never, UnexpectedError, never>;
|
|
4
16
|
/**
|
|
5
17
|
* We can't use the whole error because of WebWorker postMessage DataCloneError
|
|
6
|
-
* in Safari and Firefox.
|
|
18
|
+
* in Safari and Firefox. TODO:
|
|
7
19
|
* https://discord.com/channels/795981131316985866/795983589644304396/1096736473396564079
|
|
8
20
|
*/
|
|
9
21
|
interface TransferableError {
|
|
10
22
|
readonly message: string;
|
|
11
23
|
readonly stack: string | undefined;
|
|
12
24
|
}
|
|
13
|
-
export interface UnexpectedError {
|
|
14
|
-
readonly _tag: "UnexpectedError";
|
|
15
|
-
readonly error: TransferableError;
|
|
16
|
-
}
|
|
17
|
-
export declare const makeUnexpectedError: (error: unknown) => Effect.Effect<never, UnexpectedError, never>;
|
|
18
25
|
export {};
|
|
19
|
-
//# sourceMappingURL=
|
|
26
|
+
//# sourceMappingURL=ErrorStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorStore.d.ts","sourceRoot":"","sources":["../../src/ErrorStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C,eAAO,MAAM,cAAc,4EAAqC,CAAC;AAEjE,+EAA+E;AAC/E,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,cAAc,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;CACnC;AAED,eAAO,MAAM,mBAAmB,UACvB,OAAO,KACb,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,CAU7C,CAAC;AAEF;;;;GAIG;AACH,UAAU,iBAAiB;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC"}
|