@evolu/common 4.1.1 → 5.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 +1 -1
- package/dist/src/Config.d.ts +27 -30
- package/dist/src/Config.d.ts.map +1 -1
- package/dist/src/Config.js +32 -5
- package/dist/src/Crdt.d.ts +5 -4
- package/dist/src/Crdt.d.ts.map +1 -1
- package/dist/src/Crdt.js +27 -24
- package/dist/src/Crypto.d.ts +16 -10
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +24 -11
- package/dist/src/Db.d.ts +58 -78
- package/dist/src/Db.d.ts.map +1 -1
- package/dist/src/Db.js +368 -170
- package/dist/src/Diff.d.ts +9 -3
- package/dist/src/Diff.d.ts.map +1 -1
- package/dist/src/Diff.js +12 -11
- package/dist/src/Error.d.ts +15 -0
- package/dist/src/Error.d.ts.map +1 -0
- package/dist/src/Error.js +14 -0
- package/dist/src/Evolu.d.ts +139 -91
- package/dist/src/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu.js +267 -239
- package/dist/src/Model.d.ts +52 -0
- package/dist/src/Model.d.ts.map +1 -1
- package/dist/src/Model.js +47 -5
- package/dist/src/Owner.d.ts.map +1 -1
- package/dist/src/Owner.js +14 -8
- package/dist/src/Platform.d.ts +24 -34
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +9 -31
- package/dist/src/Public.d.ts +3 -5
- package/dist/src/Public.d.ts.map +1 -1
- package/dist/src/Public.js +2 -3
- package/dist/src/Sqlite.d.ts +25 -16
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +28 -20
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Sync.d.ts +70 -0
- package/dist/src/Sync.d.ts.map +1 -0
- package/dist/src/Sync.js +126 -0
- package/dist/src/index.d.ts +2 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -5
- package/package.json +12 -10
- package/src/Config.ts +77 -36
- package/src/Crdt.ts +61 -76
- package/src/Crypto.ts +83 -60
- package/src/Db.ts +782 -352
- package/src/Diff.ts +23 -21
- package/src/Error.ts +29 -0
- package/src/Evolu.ts +599 -499
- package/src/Model.ts +102 -6
- package/src/Owner.ts +24 -24
- package/src/Platform.ts +33 -81
- package/src/Public.ts +3 -5
- package/src/Sqlite.ts +81 -44
- package/src/Sync.ts +306 -0
- package/src/index.ts +2 -5
- package/dist/src/DbWorker.d.ts +0 -82
- package/dist/src/DbWorker.d.ts.map +0 -1
- package/dist/src/DbWorker.js +0 -335
- package/dist/src/ErrorStore.d.ts +0 -29
- package/dist/src/ErrorStore.d.ts.map +0 -1
- package/dist/src/ErrorStore.js +0 -13
- package/dist/src/OnCompletes.d.ts +0 -14
- package/dist/src/OnCompletes.d.ts.map +0 -1
- package/dist/src/OnCompletes.js +0 -25
- package/dist/src/SyncWorker.d.ts +0 -80
- package/dist/src/SyncWorker.d.ts.map +0 -1
- package/dist/src/SyncWorker.js +0 -150
- package/dist/src/Types.d.ts +0 -13
- package/dist/src/Types.d.ts.map +0 -1
- package/dist/src/Types.js +0 -1
- package/src/DbWorker.ts +0 -721
- package/src/ErrorStore.ts +0 -46
- package/src/OnCompletes.ts +0 -51
- package/src/SyncWorker.ts +0 -361
- package/src/Types.ts +0 -11
package/dist/src/Model.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as S from "@effect/schema/Schema";
|
|
2
2
|
import { maybeJson } from "./Sqlite.js";
|
|
3
3
|
/** Branded Id Schema. To create Id Schema for a specific table, use {@link id}. */
|
|
4
|
-
export const Id = S.
|
|
4
|
+
export const Id = S.String.pipe(S.pattern(/^[\w-]{21}$/), S.brand("Id"));
|
|
5
5
|
/**
|
|
6
6
|
* A factory function to create {@link Id} Schema for a specific table.
|
|
7
7
|
*
|
|
@@ -18,13 +18,13 @@ export const id = (table) => Id.pipe(S.brand(table));
|
|
|
18
18
|
* the {@link cast} helper to cast SqliteDate from Date and back.
|
|
19
19
|
* https://www.sqlite.org/quirks.html#no_separate_datetime_datatype
|
|
20
20
|
*/
|
|
21
|
-
export const SqliteDate = S.
|
|
21
|
+
export const SqliteDate = S.String.pipe(S.filter((s) => !isNaN(Date.parse(s))), S.brand("SqliteDate"));
|
|
22
22
|
/**
|
|
23
23
|
* SQLite doesn't support the boolean type, so Evolu uses SqliteBoolean instead.
|
|
24
24
|
* Use the {@link cast} helper to cast SqliteBoolean from boolean and back.
|
|
25
25
|
* https://www.sqlite.org/quirks.html#no_separate_boolean_datatype
|
|
26
26
|
*/
|
|
27
|
-
export const SqliteBoolean = S.
|
|
27
|
+
export const SqliteBoolean = S.Number.pipe(S.int(), S.filter((s) => s === 0 || s === 1), S.brand("SqliteBoolean"));
|
|
28
28
|
export function cast(value) {
|
|
29
29
|
if (typeof value === "boolean")
|
|
30
30
|
return (value === true ? 1 : 0);
|
|
@@ -34,13 +34,55 @@ export function cast(value) {
|
|
|
34
34
|
return value.toISOString();
|
|
35
35
|
return new Date(value);
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Create table schema.
|
|
39
|
+
*
|
|
40
|
+
* Supported types are null, string, number, Uint8Array, JSON Object, and JSON
|
|
41
|
+
* Array. Use SqliteDate for dates and SqliteBoolean for booleans.
|
|
42
|
+
*
|
|
43
|
+
* Reserved columns are createdAt, updatedAt, isDeleted. Those columns are added
|
|
44
|
+
* by default.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const TodoId = id("Todo");
|
|
48
|
+
* type TodoId = S.Schema.Type<typeof TodoId>;
|
|
49
|
+
*
|
|
50
|
+
* const TodoTable = table({
|
|
51
|
+
* id: TodoId,
|
|
52
|
+
* title: NonEmptyString1000,
|
|
53
|
+
* isCompleted: S.nullable(SqliteBoolean),
|
|
54
|
+
* });
|
|
55
|
+
* type TodoTable = S.Schema.Type<typeof TodoTable>;
|
|
56
|
+
*/
|
|
57
|
+
export const table = (fields) => S.Struct(fields).pipe(S.extend(ReservedColumns));
|
|
58
|
+
const ReservedColumns = S.Struct({
|
|
59
|
+
createdAt: SqliteDate,
|
|
60
|
+
updatedAt: SqliteDate,
|
|
61
|
+
isDeleted: SqliteBoolean,
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Create database schema.
|
|
65
|
+
*
|
|
66
|
+
* Tables with a name prefixed with _ are local-only, which means they are not
|
|
67
|
+
* synced. Local-only tables are useful for device-specific or temporal data.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* const Database = database({
|
|
71
|
+
* // A local-only table.
|
|
72
|
+
* _todo: TodoTable,
|
|
73
|
+
* todo: TodoTable,
|
|
74
|
+
* todoCategory: TodoCategoryTable,
|
|
75
|
+
* });
|
|
76
|
+
* type Database = S.Schema.Type<typeof Database>;
|
|
77
|
+
*/
|
|
78
|
+
export const database = S.Struct;
|
|
37
79
|
/**
|
|
38
80
|
* String schema represents a string that is not stringified JSON. Using String
|
|
39
81
|
* schema for strings stored in SQLite is crucial to ensure a stored string is
|
|
40
82
|
* not automatically parsed to a JSON object or array when retrieved. Use String
|
|
41
83
|
* schema for all string-based schemas.
|
|
42
84
|
*/
|
|
43
|
-
export const String = S.
|
|
85
|
+
export const String = S.String.pipe(S.filter((s) => {
|
|
44
86
|
if (!maybeJson(s))
|
|
45
87
|
return true;
|
|
46
88
|
try {
|
|
@@ -80,4 +122,4 @@ export const NonEmptyString1000 = String.pipe(S.minLength(1), S.maxLength(1000),
|
|
|
80
122
|
*
|
|
81
123
|
* S.decode(PositiveInt)(value);
|
|
82
124
|
*/
|
|
83
|
-
export const PositiveInt = S.
|
|
125
|
+
export const PositiveInt = S.Number.pipe(S.int(), S.positive(), S.brand("PositiveInt"));
|
package/dist/src/Owner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Owner.d.ts","sourceRoot":"","sources":["../../src/Owner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"Owner.d.ts","sourceRoot":"","sources":["../../src/Owner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAgB,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEhC;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,KAAK;IACpB,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAE5B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IAErB,+DAA+D;IAC/D,QAAQ,CAAC,aAAa,EAAE,UAAU,CAAC;CACpC;AAED,eAAO,MAAM,KAAK,2BAAqC,CAAC;AAExD;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAEhD,eAAO,MAAM,SAAS,cACT,QAAQ,KAClB,OAAO,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAqBhC,CAAC"}
|
package/dist/src/Owner.js
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import * as Context from "effect/Context";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
-
import { urlAlphabet } from "nanoid";
|
|
4
3
|
import { Bip39, slip21Derive } from "./Crypto.js";
|
|
5
|
-
export const Owner = Context.GenericTag("
|
|
4
|
+
export const Owner = Context.GenericTag("Owner");
|
|
6
5
|
export const makeOwner = (mnemonic) => Effect.gen(function* (_) {
|
|
7
|
-
const bip39 = yield*
|
|
6
|
+
const bip39 = yield* Bip39;
|
|
8
7
|
if (mnemonic == null)
|
|
9
|
-
mnemonic = yield*
|
|
10
|
-
const seed = yield*
|
|
11
|
-
const id = yield*
|
|
8
|
+
mnemonic = yield* bip39.make;
|
|
9
|
+
const seed = yield* bip39.toSeed(mnemonic);
|
|
10
|
+
const id = yield* Effect.map(slip21Derive(seed, ["Evolu", "Owner Id"]), (key) => {
|
|
12
11
|
// convert key to nanoid
|
|
13
12
|
let id = "";
|
|
14
13
|
for (let i = 0; i < 21; i++) {
|
|
15
14
|
id += urlAlphabet[key[i] & 63];
|
|
16
15
|
}
|
|
17
16
|
return id;
|
|
18
|
-
})
|
|
19
|
-
const encryptionKey = yield*
|
|
17
|
+
});
|
|
18
|
+
const encryptionKey = yield* slip21Derive(seed, [
|
|
19
|
+
"Evolu",
|
|
20
|
+
"Encryption Key",
|
|
21
|
+
]);
|
|
20
22
|
return { mnemonic, id, encryptionKey };
|
|
21
23
|
});
|
|
24
|
+
// From https://github.com/ai/nanoid/blob/main/url-alphabet/index.js
|
|
25
|
+
// It's copy-pasted for now because NanoId import breaks Metro bundler.
|
|
26
|
+
// https://github.com/ai/nanoid/issues/468
|
|
27
|
+
const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
package/dist/src/Platform.d.ts
CHANGED
|
@@ -1,47 +1,37 @@
|
|
|
1
1
|
import * as Context from "effect/Context";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as
|
|
3
|
+
import * as Scope from "effect/Scope";
|
|
4
|
+
import { Config } from "./Config.js";
|
|
4
5
|
/**
|
|
5
|
-
* FlushSync
|
|
6
|
-
*
|
|
6
|
+
* FlushSync is a service for libraries like React to synchronously flush
|
|
7
|
+
* updates inside the provided callback to ensure the DOM is updated
|
|
8
|
+
* immediately.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
* that, so it should be a no-op.
|
|
10
|
+
* https://react.dev/reference/react-dom/flushSync
|
|
10
11
|
*/
|
|
11
12
|
export type FlushSync = (callback: () => void) => void;
|
|
12
13
|
export declare const FlushSync: Context.Tag<FlushSync, FlushSync>;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
/** Release a sync lock. */
|
|
21
|
-
readonly release: Effect.Effect<void>;
|
|
14
|
+
declare const AppState_base: Context.TagClass<AppState, "AppState", {
|
|
15
|
+
readonly init: (options: {
|
|
16
|
+
readonly reloadUrl: string;
|
|
17
|
+
readonly onRequestSync: () => void;
|
|
18
|
+
}) => Effect.Effect<AppStateReset>;
|
|
19
|
+
}>;
|
|
20
|
+
export declare class AppState extends AppState_base {
|
|
22
21
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export declare const DbWorkerLock: Context.Tag<DbWorkerLock, DbWorkerLock>;
|
|
26
|
-
export type Fetch = (url: string, body: Uint8Array) => Effect.Effect<Response, FetchError>;
|
|
27
|
-
export declare const Fetch: Context.Tag<Fetch, Fetch>;
|
|
28
|
-
/**
|
|
29
|
-
* This error occurs when there is a problem with the network connection, or the
|
|
30
|
-
* server cannot be reached.
|
|
31
|
-
*/
|
|
32
|
-
export interface FetchError {
|
|
33
|
-
readonly _tag: "FetchError";
|
|
22
|
+
interface AppStateReset {
|
|
23
|
+
readonly reset: Effect.Effect<void>;
|
|
34
24
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
declare const SyncLock_base: Context.TagClass<SyncLock, "SyncLock", {
|
|
26
|
+
readonly tryAcquire: Effect.Effect<SyncLockRelease, SyncLockAlreadySyncingError, Config | Scope.Scope>;
|
|
27
|
+
}>;
|
|
28
|
+
export declare class SyncLock extends SyncLock_base {
|
|
38
29
|
}
|
|
39
|
-
export interface
|
|
40
|
-
readonly
|
|
41
|
-
|
|
30
|
+
export interface SyncLockRelease {
|
|
31
|
+
readonly release: Effect.Effect<void>;
|
|
32
|
+
}
|
|
33
|
+
export declare class SyncLockAlreadySyncingError {
|
|
34
|
+
readonly _tag = "SyncLockAlreadySyncingError";
|
|
42
35
|
}
|
|
43
|
-
export declare const AppState: Context.Tag<AppState, AppState>;
|
|
44
|
-
/** To detect whether DOM can be used. */
|
|
45
|
-
export declare const canUseDom: boolean;
|
|
46
36
|
export {};
|
|
47
37
|
//# sourceMappingURL=Platform.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Platform.d.ts","sourceRoot":"","sources":["../../src/Platform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"Platform.d.ts","sourceRoot":"","sources":["../../src/Platform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AACvD,eAAO,MAAM,SAAS,mCAA6C,CAAC;;mBAKjD,CAAC,OAAO,EAAE;QACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC;KACpC,KAAK,OAAO,MAAM,CAAC,aAAa,CAAC;;AANtC,qBAAa,QAAS,SAAQ,aAQ3B;CAAG;AAEN,UAAU,aAAa;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CACrC;;yBAKwB,OAAO,MAAM,CAChC,eAAe,EACf,2BAA2B,EAC3B,MAAM,GAAG,MAAM,KAAK,CACrB;;AAPL,qBAAa,QAAS,SAAQ,aAS3B;CAAG;AAEN,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,qBAAa,2BAA2B;IACtC,QAAQ,CAAC,IAAI,iCAAiC;CAC/C"}
|
package/dist/src/Platform.js
CHANGED
|
@@ -1,33 +1,11 @@
|
|
|
1
1
|
import * as Context from "effect/Context";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
try: () => fetch(url, {
|
|
11
|
-
method: "POST",
|
|
12
|
-
body,
|
|
13
|
-
headers: {
|
|
14
|
-
"Content-Type": "application/x-protobuf",
|
|
15
|
-
"Content-Length": body.length.toString(),
|
|
16
|
-
},
|
|
17
|
-
}),
|
|
18
|
-
catch: () => ({ _tag: "FetchError" }),
|
|
19
|
-
})));
|
|
20
|
-
export const AppState = Context.GenericTag("@services/AppState");
|
|
21
|
-
/** To detect whether DOM can be used. */
|
|
22
|
-
export const canUseDom = (() => {
|
|
23
|
-
// IDK why try-catch is necessary, but it is.
|
|
24
|
-
// "ReferenceError: window is not defined" should not happen, but it does.
|
|
25
|
-
try {
|
|
26
|
-
return !!(typeof window !== "undefined" &&
|
|
27
|
-
window.document &&
|
|
28
|
-
window.document.createElement);
|
|
2
|
+
export const FlushSync = Context.GenericTag("FlushSync");
|
|
3
|
+
export class AppState extends Context.Tag("AppState")() {
|
|
4
|
+
}
|
|
5
|
+
export class SyncLock extends Context.Tag("SyncLock")() {
|
|
6
|
+
}
|
|
7
|
+
export class SyncLockAlreadySyncingError {
|
|
8
|
+
constructor() {
|
|
9
|
+
this._tag = "SyncLockAlreadySyncingError";
|
|
29
10
|
}
|
|
30
|
-
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
})();
|
|
11
|
+
}
|
package/dist/src/Public.d.ts
CHANGED
|
@@ -3,12 +3,10 @@ export type { NotNull } from "kysely";
|
|
|
3
3
|
export { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
|
|
4
4
|
export type { Timestamp, TimestampError } from "./Crdt.js";
|
|
5
5
|
export type { InvalidMnemonicError, Mnemonic } from "./Crypto.js";
|
|
6
|
-
export { database, table } from "./Db.js";
|
|
7
6
|
export type { ExtractRow, QueryResult } from "./Db.js";
|
|
8
|
-
export
|
|
9
|
-
export {
|
|
7
|
+
export * from "./Error.js";
|
|
8
|
+
export { createIndexes } from "./Evolu.js";
|
|
10
9
|
export * from "./Model.js";
|
|
11
10
|
export type { Owner, OwnerId } from "./Owner.js";
|
|
12
|
-
export {
|
|
13
|
-
export type { SyncState } from "./SyncWorker.js";
|
|
11
|
+
export type { SyncState } from "./Sync.js";
|
|
14
12
|
//# sourceMappingURL=Public.d.ts.map
|
package/dist/src/Public.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Public.d.ts","sourceRoot":"","sources":["../../src/Public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC7B,YAAY,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACtE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3D,YAAY,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClE,
|
|
1
|
+
{"version":3,"file":"Public.d.ts","sourceRoot":"","sources":["../../src/Public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC7B,YAAY,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACtE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3D,YAAY,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACvD,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,cAAc,YAAY,CAAC;AAC3B,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/src/Public.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { sql } from "kysely";
|
|
2
2
|
export { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
|
|
3
|
-
export
|
|
4
|
-
export {
|
|
3
|
+
export * from "./Error.js";
|
|
4
|
+
export { createIndexes } from "./Evolu.js";
|
|
5
5
|
export * from "./Model.js";
|
|
6
|
-
export { canUseDom } from "./Platform.js";
|
package/dist/src/Sqlite.d.ts
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
import * as Context from "effect/Context";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
-
import
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
4
|
import * as Predicate from "effect/Predicate";
|
|
5
|
+
import { Config } from "./Config.js";
|
|
5
6
|
export interface Sqlite {
|
|
6
7
|
readonly exec: (query: SqliteQuery) => Effect.Effect<SqliteExecResult>;
|
|
8
|
+
readonly transaction: (
|
|
9
|
+
/**
|
|
10
|
+
* Use `exclusive` for mutations and `shared` for read-only queries. This
|
|
11
|
+
* shared/exclusive lock pattern allows multiple simultaneous readers but
|
|
12
|
+
* only one writer. In Evolu, this pattern also ensures that every write can
|
|
13
|
+
* be immediately read without waiting to complete. For example, we can add
|
|
14
|
+
* data on one page and then immediately redirect to another, and the data
|
|
15
|
+
* will be there.
|
|
16
|
+
*
|
|
17
|
+
* There is also a `last` mode that ensures no other transaction can run.
|
|
18
|
+
* It's for Db reset to ensure no data are accidentally saved after database
|
|
19
|
+
* wipe-out.
|
|
20
|
+
*/
|
|
21
|
+
mode: SqliteTransactionMode) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Sqlite | R>;
|
|
7
22
|
}
|
|
8
23
|
export declare const Sqlite: Context.Tag<Sqlite, Sqlite>;
|
|
24
|
+
export type SqliteTransactionMode = "exclusive" | "shared" | "last";
|
|
25
|
+
declare const SqliteFactory_base: Context.TagClass<SqliteFactory, "SqliteFactory", {
|
|
26
|
+
readonly createSqlite: Effect.Effect<Sqlite, never, Config>;
|
|
27
|
+
}>;
|
|
28
|
+
export declare class SqliteFactory extends SqliteFactory_base {
|
|
29
|
+
static Common: Layer.Layer<SqliteFactory, never, SqliteFactory>;
|
|
30
|
+
}
|
|
9
31
|
export interface SqliteQuery {
|
|
10
32
|
readonly sql: string;
|
|
11
33
|
readonly parameters?: Value[];
|
|
@@ -32,7 +54,8 @@ export interface SqliteExecResult {
|
|
|
32
54
|
export type SqliteRow = Record<string, SqliteValue>;
|
|
33
55
|
export declare const isJsonObjectOrArray: Predicate.Refinement<Value, JsonObjectOrArray>;
|
|
34
56
|
export declare const valuesToSqliteValues: (values: ReadonlyArray<Value>) => SqliteValue[];
|
|
35
|
-
|
|
57
|
+
/** This function mutates for better performance. */
|
|
58
|
+
export declare const maybeParseJson: (rows: SqliteRow[]) => void;
|
|
36
59
|
export declare const maybeJson: Predicate.Predicate<string>;
|
|
37
60
|
export declare const isSqlMutation: (sql: string) => boolean;
|
|
38
61
|
export declare const maybeLogSqliteQueryExecutionTime: (query: SqliteQuery) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
@@ -42,19 +65,5 @@ export type SqliteQueryPlanRow = {
|
|
|
42
65
|
detail: string;
|
|
43
66
|
};
|
|
44
67
|
export declare const drawSqliteQueryPlan: (rows: SqliteQueryPlanRow[]) => string;
|
|
45
|
-
export interface SqliteSchema {
|
|
46
|
-
readonly tables: ReadonlyArray<Table>;
|
|
47
|
-
readonly indexes: ReadonlyArray<Index>;
|
|
48
|
-
}
|
|
49
|
-
export interface Table {
|
|
50
|
-
readonly name: string;
|
|
51
|
-
readonly columns: ReadonlyArray<string>;
|
|
52
|
-
}
|
|
53
|
-
export interface Index {
|
|
54
|
-
readonly name: string;
|
|
55
|
-
readonly sql: string;
|
|
56
|
-
}
|
|
57
|
-
export declare const indexEquivalence: Equivalence<Index>;
|
|
58
|
-
export declare const maybeLogSql: (query: SqliteQuery, logSql: boolean) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
59
68
|
export {};
|
|
60
69
|
//# sourceMappingURL=Sqlite.d.ts.map
|
package/dist/src/Sqlite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Sqlite.js
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
|
+
import * as Console from "effect/Console";
|
|
1
2
|
import * as Context from "effect/Context";
|
|
2
3
|
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Exit from "effect/Exit";
|
|
5
|
+
import * as Layer from "effect/Layer";
|
|
3
6
|
import * as Predicate from "effect/Predicate";
|
|
4
|
-
export const Sqlite = Context.GenericTag("
|
|
7
|
+
export const Sqlite = Context.GenericTag("Sqlite");
|
|
8
|
+
export class SqliteFactory extends Context.Tag("SqliteFactory")() {
|
|
9
|
+
}
|
|
10
|
+
SqliteFactory.Common = Layer.effect(SqliteFactory, Effect.map(SqliteFactory, (platformSqliteFactory) => ({
|
|
11
|
+
createSqlite: Effect.logTrace("SqliteFactory createSqlite").pipe(Effect.zipRight(platformSqliteFactory.createSqlite), Effect.map((platformSqlite) => ({
|
|
12
|
+
exec: (query) => platformSqlite.exec(query).pipe(Effect.tap((result) => {
|
|
13
|
+
maybeParseJson(result.rows);
|
|
14
|
+
}), Effect.tap((result) => ["begin", "rollback", "commit"].includes(query.sql)
|
|
15
|
+
? Effect.logDebug(`SQLiteCommon ${query.sql} transaction`)
|
|
16
|
+
: Effect.logDebug(["SQLiteCommon exec", query, result]))),
|
|
17
|
+
transaction: (mode) => (effect) => {
|
|
18
|
+
// Shared is for readonly queries.
|
|
19
|
+
if (mode === "shared")
|
|
20
|
+
return platformSqlite.transaction(mode)(effect);
|
|
21
|
+
return Effect.flatMap(Sqlite, (sqlite) => Effect.acquireUseRelease(sqlite.exec({ sql: "begin" }), () => effect, (_, exit) => Exit.isFailure(exit)
|
|
22
|
+
? sqlite.exec({ sql: "rollback" })
|
|
23
|
+
: sqlite.exec({ sql: "commit" }))).pipe(platformSqlite.transaction(mode));
|
|
24
|
+
},
|
|
25
|
+
}))),
|
|
26
|
+
})));
|
|
5
27
|
export const isJsonObjectOrArray = (value) => value !== null && typeof value === "object" && !Predicate.isUint8Array(value);
|
|
6
28
|
export const valuesToSqliteValues = (values) => values.map((value) => isJsonObjectOrArray(value) ? JSON.stringify(value) : value);
|
|
7
|
-
|
|
29
|
+
/** This function mutates for better performance. */
|
|
30
|
+
export const maybeParseJson = (rows) => {
|
|
31
|
+
parseArray(rows);
|
|
32
|
+
};
|
|
8
33
|
const parseArray = (a) => {
|
|
9
34
|
for (let i = 0; i < a.length; ++i)
|
|
10
35
|
a[i] = parse(a[i]);
|
|
@@ -50,10 +75,7 @@ export const isSqlMutation = (sql) => isSqlMutationRegEx.test(sql);
|
|
|
50
75
|
export const maybeLogSqliteQueryExecutionTime = (query) => (effect) => {
|
|
51
76
|
if (!query.options?.logQueryExecutionTime)
|
|
52
77
|
return effect;
|
|
53
|
-
return
|
|
54
|
-
// Not using Effect.log because of formating
|
|
55
|
-
// eslint-disable-next-line no-console
|
|
56
|
-
Effect.tap(() => console.log(query.sql)), Effect.withLogSpan("duration"));
|
|
78
|
+
return Effect.Do.pipe(Effect.let("start", () => performance.now()), Effect.bind("result", () => effect), Effect.let("elapsed", ({ start }) => performance.now() - start), Effect.tap(({ elapsed }) => Console.log(`QueryExecutionTime: ${elapsed}ms`, query)), Effect.map(({ result }) => result));
|
|
57
79
|
};
|
|
58
80
|
export const drawSqliteQueryPlan = (rows) => rows
|
|
59
81
|
.map((row) => {
|
|
@@ -70,17 +92,3 @@ export const drawSqliteQueryPlan = (rows) => rows
|
|
|
70
92
|
return `${" ".repeat(indent)}${row.detail}`;
|
|
71
93
|
})
|
|
72
94
|
.join("\n");
|
|
73
|
-
export const indexEquivalence = (self, that) => self.name === that.name && self.sql === that.sql;
|
|
74
|
-
export const maybeLogSql = (query, logSql) => (effect) => {
|
|
75
|
-
if (!logSql)
|
|
76
|
-
return effect;
|
|
77
|
-
return effect.pipe(Effect.tap(() => Effect.log("SQL")),
|
|
78
|
-
// Not using Effect.log because of formating
|
|
79
|
-
Effect.tap(() => {
|
|
80
|
-
// eslint-disable-next-line no-console
|
|
81
|
-
console.log(query.sql);
|
|
82
|
-
if (query.parameters && query.parameters.length > 0)
|
|
83
|
-
// eslint-disable-next-line no-console
|
|
84
|
-
console.log(query.parameters);
|
|
85
|
-
}));
|
|
86
|
-
};
|
package/dist/src/Store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../../src/Store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC,MAAM,WAAW,KAAK,CAAC,CAAC;IAEtB,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,WAAW,CAAC;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAG3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CACtD;AAED,eAAO,MAAM,SAAS,oBAAqB,CAAC,KAAG,
|
|
1
|
+
{"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../../src/Store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC,MAAM,WAAW,KAAK,CAAC,CAAC;IAEtB,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,WAAW,CAAC;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAG3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CACtD;AAED,eAAO,MAAM,SAAS,oBAAqB,CAAC,KAAG,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CA0BjE,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as Context from "effect/Context";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import { Config } from "./Config.js";
|
|
4
|
+
import { MerkleTree, Millis, Timestamp, TimestampString } from "./Crdt.js";
|
|
5
|
+
import { SecretBox } from "./Crypto.js";
|
|
6
|
+
import { Id } from "./Model.js";
|
|
7
|
+
import { Owner } from "./Owner.js";
|
|
8
|
+
import { Value } from "./Sqlite.js";
|
|
9
|
+
export interface Sync {
|
|
10
|
+
readonly init: (owner: Owner) => Effect.Effect<void>;
|
|
11
|
+
readonly sync: (syncData: SyncData) => Effect.Effect<SyncResult, SyncStateIsNotSynced, Config>;
|
|
12
|
+
}
|
|
13
|
+
export declare const Sync: Context.Tag<Sync, Sync>;
|
|
14
|
+
export interface SyncData {
|
|
15
|
+
merkleTree: MerkleTree;
|
|
16
|
+
timestamp: Timestamp;
|
|
17
|
+
messages?: ReadonlyArray<Message>;
|
|
18
|
+
}
|
|
19
|
+
export interface Message extends NewMessage {
|
|
20
|
+
readonly timestamp: TimestampString;
|
|
21
|
+
}
|
|
22
|
+
export interface NewMessage {
|
|
23
|
+
readonly table: string;
|
|
24
|
+
readonly row: Id;
|
|
25
|
+
readonly column: string;
|
|
26
|
+
readonly value: Value;
|
|
27
|
+
}
|
|
28
|
+
export interface SyncResult {
|
|
29
|
+
readonly messages: ReadonlyArray<Message>;
|
|
30
|
+
readonly merkleTree: MerkleTree;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The SyncState type represents the various states that a synchronization
|
|
34
|
+
* process can be in.
|
|
35
|
+
*/
|
|
36
|
+
export type SyncState = SyncStateInitial | SyncStateIsSyncing | SyncStateIsSynced | SyncStateIsNotSynced;
|
|
37
|
+
/** On app start, we need to find out whether the state is synced. */
|
|
38
|
+
export interface SyncStateInitial {
|
|
39
|
+
readonly _tag: "SyncStateInitial";
|
|
40
|
+
}
|
|
41
|
+
export declare const initialSyncState: SyncStateInitial;
|
|
42
|
+
export interface SyncStateIsSyncing {
|
|
43
|
+
readonly _tag: "SyncStateIsSyncing";
|
|
44
|
+
}
|
|
45
|
+
export interface SyncStateIsSynced {
|
|
46
|
+
readonly _tag: "SyncStateIsSynced";
|
|
47
|
+
readonly time: Millis;
|
|
48
|
+
}
|
|
49
|
+
export interface SyncStateIsNotSynced {
|
|
50
|
+
readonly _tag: "SyncStateIsNotSynced";
|
|
51
|
+
readonly error: NetworkError | ServerError | PaymentRequiredError;
|
|
52
|
+
}
|
|
53
|
+
export interface NetworkError {
|
|
54
|
+
readonly _tag: "NetworkError";
|
|
55
|
+
}
|
|
56
|
+
export interface ServerError {
|
|
57
|
+
readonly _tag: "ServerError";
|
|
58
|
+
readonly status: number;
|
|
59
|
+
}
|
|
60
|
+
export interface PaymentRequiredError {
|
|
61
|
+
readonly _tag: "PaymentRequiredError";
|
|
62
|
+
}
|
|
63
|
+
declare const SyncFactory_base: Context.TagClass<SyncFactory, "SyncFactory", {
|
|
64
|
+
readonly createSync: Effect.Effect<Sync, never, never>;
|
|
65
|
+
}>;
|
|
66
|
+
export declare class SyncFactory extends SyncFactory_base {
|
|
67
|
+
}
|
|
68
|
+
export declare const createSync: Effect.Effect<Sync, never, SecretBox>;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=Sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sync.d.ts","sourceRoot":"","sources":["../../src/Sync.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAE1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,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,EAAE,MAAM,YAAY,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAqB,KAAK,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrD,QAAQ,CAAC,IAAI,EAAE,CACb,QAAQ,EAAE,QAAQ,KACf,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;CAC9D;AAED,eAAO,MAAM,IAAI,yBAAmC,CAAC;AAErD,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,OAAQ,SAAQ,UAAU;IACzC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;CACrC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GACjB,gBAAgB,GAChB,kBAAkB,GAClB,iBAAiB,GACjB,oBAAoB,CAAC;AAEzB,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;CACnC;AAGD,eAAO,MAAM,gBAAgB,EAAE,gBAA+C,CAAC;AAE/E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,GAAG,oBAAoB,CAAC;CACnE;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;CACvC;;yBAKwB,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC;;AAH1D,qBAAa,WAAY,SAAQ,gBAK9B;CAAG;AAEN,eAAO,MAAM,UAAU,uCAoHrB,CAAC"}
|