@evolu/common 5.4.8 → 6.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 +30 -34
- package/dist/src/Array.d.ts +17 -0
- package/dist/src/Array.d.ts.map +1 -0
- package/dist/src/Array.js +12 -0
- package/dist/src/Assert.d.ts +68 -0
- package/dist/src/Assert.d.ts.map +1 -0
- package/dist/src/Assert.js +77 -0
- package/dist/src/BigInt.d.ts +20 -0
- package/dist/src/BigInt.d.ts.map +1 -0
- package/dist/src/BigInt.js +18 -0
- package/dist/src/Buffer.d.ts +92 -0
- package/dist/src/Buffer.d.ts.map +1 -0
- package/dist/src/Buffer.js +62 -0
- package/dist/src/Callbacks.d.ts +20 -0
- package/dist/src/Callbacks.d.ts.map +1 -0
- package/dist/src/Callbacks.js +18 -0
- package/dist/src/Console.d.ts +78 -0
- package/dist/src/Console.d.ts.map +1 -0
- package/dist/src/Console.js +103 -0
- package/dist/src/Crypto.d.ts +72 -39
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +89 -54
- package/dist/src/Eq.d.ts +97 -0
- package/dist/src/Eq.d.ts.map +1 -0
- package/dist/src/Eq.js +167 -0
- package/dist/src/Error.d.ts +14 -10
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +43 -11
- package/dist/src/Evolu/Config.d.ts +69 -0
- package/dist/src/Evolu/Config.d.ts.map +1 -0
- package/dist/src/Evolu/Config.js +9 -0
- package/dist/src/Evolu/Db.d.ts +126 -0
- package/dist/src/Evolu/Db.d.ts.map +1 -0
- package/dist/src/Evolu/Db.js +774 -0
- package/dist/src/Evolu/Diff.d.ts +43 -0
- package/dist/src/Evolu/Diff.d.ts.map +1 -0
- package/dist/src/Evolu/Diff.js +95 -0
- package/dist/src/Evolu/Evolu.d.ts +334 -0
- package/dist/src/Evolu/Evolu.d.ts.map +1 -0
- package/dist/src/Evolu/Evolu.js +434 -0
- package/dist/src/Evolu/Internal.d.ts +26 -0
- package/dist/src/Evolu/Internal.d.ts.map +1 -0
- package/dist/src/Evolu/Internal.js +25 -0
- package/dist/src/Evolu/Kysely.d.ts +6 -0
- package/dist/src/Evolu/Kysely.d.ts.map +1 -0
- package/dist/src/Evolu/Kysely.js +21 -0
- package/dist/src/Evolu/Owner.d.ts +155 -0
- package/dist/src/Evolu/Owner.d.ts.map +1 -0
- package/dist/src/Evolu/Owner.js +126 -0
- package/dist/src/Evolu/Platform.d.ts +23 -0
- package/dist/src/Evolu/Platform.d.ts.map +1 -0
- package/dist/src/Evolu/Platform.js +1 -0
- package/dist/src/Evolu/Protocol.d.ts +401 -0
- package/dist/src/Evolu/Protocol.d.ts.map +1 -0
- package/dist/src/Evolu/Protocol.js +1151 -0
- package/dist/src/Evolu/Public.d.ts +18 -0
- package/dist/src/Evolu/Public.d.ts.map +1 -0
- package/dist/src/Evolu/Public.js +11 -0
- package/dist/src/Evolu/PublicKysely.d.ts +148 -0
- package/dist/src/Evolu/PublicKysely.d.ts.map +1 -0
- package/dist/src/Evolu/PublicKysely.js +185 -0
- package/dist/src/Evolu/Query.d.ts +63 -0
- package/dist/src/Evolu/Query.d.ts.map +1 -0
- package/dist/src/Evolu/Query.js +61 -0
- package/dist/src/Evolu/Relay.d.ts +13 -0
- package/dist/src/Evolu/Relay.d.ts.map +1 -0
- package/dist/src/Evolu/Relay.js +109 -0
- package/dist/src/Evolu/Schema.d.ts +201 -0
- package/dist/src/Evolu/Schema.d.ts.map +1 -0
- package/dist/src/Evolu/Schema.js +150 -0
- package/dist/src/Evolu/Storage.d.ts +49 -0
- package/dist/src/Evolu/Storage.d.ts.map +1 -0
- package/dist/src/Evolu/Storage.js +1111 -0
- package/dist/src/Evolu/Sync.d.ts +59 -0
- package/dist/src/Evolu/Sync.d.ts.map +1 -0
- package/dist/src/Evolu/Sync.js +29 -0
- package/dist/src/Evolu/Timestamp.d.ts +106 -0
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -0
- package/dist/src/Evolu/Timestamp.js +179 -0
- package/dist/src/Function.d.ts +54 -0
- package/dist/src/Function.d.ts.map +1 -0
- package/dist/src/Function.js +38 -0
- package/dist/src/ManyToManyMap.d.ts +26 -0
- package/dist/src/ManyToManyMap.d.ts.map +1 -0
- package/dist/src/ManyToManyMap.js +92 -0
- package/dist/src/NanoId.d.ts +27 -0
- package/dist/src/NanoId.d.ts.map +1 -0
- package/dist/src/NanoId.js +6 -0
- package/dist/src/Number.d.ts +42 -0
- package/dist/src/Number.d.ts.map +1 -0
- package/dist/src/Number.js +55 -0
- package/dist/src/Object.d.ts +35 -0
- package/dist/src/Object.d.ts.map +1 -0
- package/dist/src/Object.js +36 -0
- package/dist/src/Order.d.ts +90 -0
- package/dist/src/Order.d.ts.map +1 -0
- package/dist/src/Order.js +85 -0
- package/dist/src/Promise.d.ts +180 -0
- package/dist/src/Promise.d.ts.map +1 -0
- package/dist/src/Promise.js +176 -0
- package/dist/src/Random.d.ts +52 -0
- package/dist/src/Random.d.ts.map +1 -0
- package/dist/src/Random.js +29 -0
- package/dist/src/Ref.d.ts +40 -0
- package/dist/src/Ref.d.ts.map +1 -0
- package/dist/src/Ref.js +13 -0
- package/dist/src/Result.d.ts +421 -0
- package/dist/src/Result.d.ts.map +1 -0
- package/dist/src/Result.js +357 -0
- package/dist/src/Skiplist.d.ts +23 -0
- package/dist/src/Skiplist.d.ts.map +1 -0
- package/dist/src/Skiplist.js +58 -0
- package/dist/src/Sqlite.d.ts +116 -52
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +183 -67
- package/dist/src/Store.d.ts +45 -8
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +33 -17
- package/dist/src/String.d.ts +2 -0
- package/dist/src/String.d.ts.map +1 -0
- package/dist/src/String.js +14 -0
- package/dist/src/Time.d.ts +20 -0
- package/dist/src/Time.d.ts.map +1 -0
- package/dist/src/Time.js +25 -0
- package/dist/src/Type.d.ts +1937 -0
- package/dist/src/Type.d.ts.map +1 -0
- package/dist/src/Type.js +2002 -0
- package/dist/src/Types.d.ts +188 -0
- package/dist/src/Types.d.ts.map +1 -0
- package/dist/src/Types.js +6 -0
- package/dist/src/WebSocket.d.ts +112 -0
- package/dist/src/WebSocket.d.ts.map +1 -0
- package/dist/src/WebSocket.js +139 -0
- package/dist/src/Worker.d.ts +44 -0
- package/dist/src/Worker.d.ts.map +1 -0
- package/dist/src/Worker.js +66 -0
- package/dist/src/index.d.ts +24 -11
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +24 -11
- package/package.json +29 -38
- package/src/Array.ts +39 -0
- package/src/Assert.ts +116 -0
- package/src/BigInt.ts +29 -0
- package/src/Buffer.ts +175 -0
- package/src/Callbacks.ts +43 -0
- package/src/Console.ts +159 -0
- package/src/Crypto.ts +169 -115
- package/src/Eq.ts +204 -0
- package/src/Error.ts +57 -20
- package/src/Evolu/Config.ts +83 -0
- package/src/Evolu/Db.ts +1275 -0
- package/src/Evolu/Diff.ts +142 -0
- package/src/Evolu/Evolu.ts +947 -0
- package/src/Evolu/Internal.ts +26 -0
- package/src/Evolu/Kysely.ts +38 -0
- package/src/Evolu/Owner.ts +296 -0
- package/src/Evolu/Platform.ts +27 -0
- package/src/Evolu/Protocol.ts +1857 -0
- package/src/Evolu/Public.ts +43 -0
- package/src/Evolu/PublicKysely.ts +240 -0
- package/src/Evolu/Query.ts +167 -0
- package/src/Evolu/Relay.ts +142 -0
- package/src/Evolu/Schema.ts +417 -0
- package/src/Evolu/Storage.ts +1281 -0
- package/src/Evolu/Sync.ts +105 -0
- package/src/Evolu/Timestamp.ts +311 -0
- package/src/Function.ts +58 -0
- package/src/ManyToManyMap.ts +140 -0
- package/src/NanoId.ts +39 -0
- package/src/Number.ts +90 -0
- package/src/Object.ts +64 -0
- package/src/Order.ts +113 -0
- package/src/Promise.ts +295 -0
- package/src/Random.ts +68 -0
- package/src/Ref.ts +63 -0
- package/src/Result.ts +453 -0
- package/src/Skiplist.ts +102 -0
- package/src/Sqlite.ts +366 -153
- package/src/Store.ts +79 -36
- package/src/String.ts +10 -0
- package/src/Time.ts +36 -0
- package/src/Type.ts +3978 -0
- package/src/Types.ts +209 -0
- package/src/WebSocket.ts +273 -0
- package/src/Worker.ts +129 -0
- package/src/index.ts +24 -11
- package/dist/src/Config.d.ts +0 -56
- package/dist/src/Config.d.ts.map +0 -1
- package/dist/src/Config.js +0 -39
- package/dist/src/Crdt.d.ts +0 -89
- package/dist/src/Crdt.d.ts.map +0 -1
- package/dist/src/Crdt.js +0 -181
- package/dist/src/Db.d.ts +0 -107
- package/dist/src/Db.d.ts.map +0 -1
- package/dist/src/Db.js +0 -443
- package/dist/src/Diff.d.ts +0 -27
- package/dist/src/Diff.d.ts.map +0 -1
- package/dist/src/Diff.js +0 -84
- package/dist/src/Evolu.d.ts +0 -426
- package/dist/src/Evolu.d.ts.map +0 -1
- package/dist/src/Evolu.js +0 -333
- package/dist/src/Model.d.ts +0 -141
- package/dist/src/Model.d.ts.map +0 -1
- package/dist/src/Model.js +0 -125
- package/dist/src/Murmurhash.d.ts +0 -2
- package/dist/src/Murmurhash.d.ts.map +0 -1
- package/dist/src/Murmurhash.js +0 -60
- package/dist/src/Owner.d.ts +0 -33
- package/dist/src/Owner.d.ts.map +0 -1
- package/dist/src/Owner.js +0 -26
- package/dist/src/Platform.d.ts +0 -37
- package/dist/src/Platform.d.ts.map +0 -1
- package/dist/src/Platform.js +0 -11
- package/dist/src/Protobuf.d.ts +0 -81
- package/dist/src/Protobuf.d.ts.map +0 -1
- package/dist/src/Protobuf.js +0 -92
- package/dist/src/Public.d.ts +0 -13
- package/dist/src/Public.d.ts.map +0 -1
- package/dist/src/Public.js +0 -6
- package/dist/src/Socket.d.ts +0 -8
- package/dist/src/Socket.d.ts.map +0 -1
- package/dist/src/Socket.js +0 -51
- package/dist/src/Sql.d.ts +0 -12
- package/dist/src/Sql.d.ts.map +0 -1
- package/dist/src/Sql.js +0 -30
- package/dist/src/Sync.d.ts +0 -70
- package/dist/src/Sync.d.ts.map +0 -1
- package/dist/src/Sync.js +0 -127
- package/src/Config.ts +0 -119
- package/src/Crdt.ts +0 -361
- package/src/Db.ts +0 -955
- package/src/Diff.ts +0 -114
- package/src/Evolu.ts +0 -1016
- package/src/Model.ts +0 -233
- package/src/Murmurhash.ts +0 -70
- package/src/Owner.ts +0 -69
- package/src/Platform.ts +0 -47
- package/src/Protobuf.ts +0 -155
- package/src/Public.ts +0 -12
- package/src/Socket.ts +0 -83
- package/src/Sql.ts +0 -41
- package/src/Sync.ts +0 -315
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
import { isNonEmptyArray, isNonEmptyReadonlyArray } from "../Array.js";
|
|
2
|
+
import { assertNonEmptyArray } from "../Assert.js";
|
|
3
|
+
import { createCallbacks } from "../Callbacks.js";
|
|
4
|
+
import { exhaustiveCheck } from "../Function.js";
|
|
5
|
+
import { err, ok } from "../Result.js";
|
|
6
|
+
import { isSqlMutation } from "../Sqlite.js";
|
|
7
|
+
import { createStore } from "../Store.js";
|
|
8
|
+
import { createId, } from "../Type.js";
|
|
9
|
+
import { defaultConfig } from "./Config.js";
|
|
10
|
+
import { applyPatches } from "./Diff.js";
|
|
11
|
+
import { kysely } from "./Kysely.js";
|
|
12
|
+
import { createSubscribedQueries, emptyRows, serializeQuery, } from "./Query.js";
|
|
13
|
+
import { assertValidEvoluSchema, insertable, updateable, upsertable, validEvoluSchemaToDbSchema, } from "./Schema.js";
|
|
14
|
+
import { initialSyncState } from "./Sync.js";
|
|
15
|
+
// For hot reloading and Evolu multitenancy.
|
|
16
|
+
const evoluInstances = new Map();
|
|
17
|
+
let tabId = null;
|
|
18
|
+
/**
|
|
19
|
+
* Creates an {@link Evolu} instance configured with the specified
|
|
20
|
+
* {@link EvoluSchema} and optional configuration.
|
|
21
|
+
*
|
|
22
|
+
* This function returns a configured Evolu instance, providing a typed
|
|
23
|
+
* interface for querying, mutating, and syncing your application's data. The
|
|
24
|
+
* returned instance includes:
|
|
25
|
+
*
|
|
26
|
+
* - Subscription methods for receiving updates on queries, the owner, errors, and
|
|
27
|
+
* sync state.
|
|
28
|
+
* - Methods for creating, updating, or deleting rows in a type-safe manner.
|
|
29
|
+
* - Methods for querying data using Evolu's typed SQL queries, leveraging Kysely
|
|
30
|
+
* under the hood.
|
|
31
|
+
* - Built-in support for local-first and offline-first data with automatic sync
|
|
32
|
+
* and merging.
|
|
33
|
+
* - Automatic schema evolution that updates the underlying database with new
|
|
34
|
+
* columns or tables.
|
|
35
|
+
* - Managing owner data with resetAppOwner and restoreAppOwner.
|
|
36
|
+
*
|
|
37
|
+
* ### Example
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* const TodoId = id("Todo");
|
|
41
|
+
* type TodoId = InferType<typeof TodoId>;
|
|
42
|
+
*
|
|
43
|
+
* const TodoCategoryId = id("TodoCategory");
|
|
44
|
+
* type TodoCategoryId = InferType<typeof TodoCategoryId>;
|
|
45
|
+
*
|
|
46
|
+
* const NonEmptyString50 = maxLength(50, NonEmptyString);
|
|
47
|
+
* type NonEmptyString50 = InferType<typeof NonEmptyString50>;
|
|
48
|
+
*
|
|
49
|
+
* const Schema = {
|
|
50
|
+
* todo: {
|
|
51
|
+
* id: TodoId,
|
|
52
|
+
* title: NonEmptyString1000,
|
|
53
|
+
* isCompleted: nullOr(SqliteBoolean),
|
|
54
|
+
* categoryId: nullOr(TodoCategoryId),
|
|
55
|
+
* },
|
|
56
|
+
* todoCategory: {
|
|
57
|
+
* id: TodoCategoryId,
|
|
58
|
+
* name: NonEmptyString50,
|
|
59
|
+
* },
|
|
60
|
+
* };
|
|
61
|
+
*
|
|
62
|
+
* const evolu = createEvolu(evoluReactDeps)(Schema);
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export const createEvolu = (deps) => (
|
|
66
|
+
// TODO: Validate missing Id, unsupported types, used default types via TS types
|
|
67
|
+
// with type errors messages as we had it in the old Evolu.
|
|
68
|
+
schema, partialConfig = {}) => {
|
|
69
|
+
const config = { ...defaultConfig, ...partialConfig };
|
|
70
|
+
let evolu = evoluInstances.get(config.name);
|
|
71
|
+
if (evolu == null) {
|
|
72
|
+
evolu = createEvoluInstance(deps)(schema, config);
|
|
73
|
+
evoluInstances.set(config.name, evolu);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// Hot reloading. Note that indexes are intentionally omitted.
|
|
77
|
+
evolu.ensureSchema(schema);
|
|
78
|
+
}
|
|
79
|
+
return evolu;
|
|
80
|
+
};
|
|
81
|
+
const createEvoluInstance = (deps) => (schema, evoluConfig) => {
|
|
82
|
+
deps.console.enabled = evoluConfig.enableLogging ?? false;
|
|
83
|
+
deps.console.log("[evolu]", "createEvoluInstance");
|
|
84
|
+
const { initialData, indexes, ...config } = evoluConfig;
|
|
85
|
+
const errorStore = createStore(null);
|
|
86
|
+
const rowsStore = createStore(new Map());
|
|
87
|
+
const ownerStore = createStore(null);
|
|
88
|
+
const syncStore = createStore(initialSyncState);
|
|
89
|
+
const subscribedQueries = createSubscribedQueries(rowsStore);
|
|
90
|
+
const loadingPromises = createLoadingPromises(subscribedQueries);
|
|
91
|
+
const callbacks = createCallbacks(deps);
|
|
92
|
+
const appState = deps.createAppState(config);
|
|
93
|
+
const dbWorker = deps.createDbWorker(config.name);
|
|
94
|
+
const getTabId = () => {
|
|
95
|
+
tabId ??= createId(deps);
|
|
96
|
+
return tabId;
|
|
97
|
+
};
|
|
98
|
+
dbWorker.onMessage((message) => {
|
|
99
|
+
switch (message.type) {
|
|
100
|
+
case "onInit": {
|
|
101
|
+
ownerStore.set(message.owner);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case "onError": {
|
|
105
|
+
errorStore.set(message.error);
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case "onChange": {
|
|
109
|
+
if (message.tabId !== getTabId())
|
|
110
|
+
return;
|
|
111
|
+
const state = rowsStore.get();
|
|
112
|
+
const nextState = new Map([
|
|
113
|
+
...state,
|
|
114
|
+
...message.patches.map(({ query, patches }) => [
|
|
115
|
+
query,
|
|
116
|
+
applyPatches(patches, state.get(query) ?? emptyRows),
|
|
117
|
+
]),
|
|
118
|
+
]);
|
|
119
|
+
for (const { query } of message.patches) {
|
|
120
|
+
loadingPromises.resolve(query, nextState.get(query) ?? emptyRows);
|
|
121
|
+
}
|
|
122
|
+
if (deps.flushSync && message.onCompleteIds.length > 0) {
|
|
123
|
+
deps.flushSync(() => {
|
|
124
|
+
rowsStore.set(nextState);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
rowsStore.set(nextState);
|
|
129
|
+
}
|
|
130
|
+
for (const id of message.onCompleteIds) {
|
|
131
|
+
callbacks.execute(id);
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case "onReceive": {
|
|
136
|
+
if (message.tabId && message.tabId === getTabId())
|
|
137
|
+
return;
|
|
138
|
+
loadingPromises.releaseUnsubscribed();
|
|
139
|
+
const queries = subscribedQueries.get();
|
|
140
|
+
if (isNonEmptyReadonlyArray(queries)) {
|
|
141
|
+
dbWorker.postMessage({ type: "query", tabId: getTabId(), queries });
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case "onReset": {
|
|
146
|
+
if (message.reload) {
|
|
147
|
+
appState.reset();
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
callbacks.execute(message.onCompleteId);
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case "onExport": {
|
|
155
|
+
callbacks.execute(message.onCompleteId, message.file);
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
default:
|
|
159
|
+
exhaustiveCheck(message);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
const dbSchema = validEvoluSchemaToDbSchema(assertValidEvoluSchema(schema), indexes);
|
|
163
|
+
const mutationTypesCache = new Map();
|
|
164
|
+
// Lazy create mutation Types like this: `insertable(Schema.todo)`
|
|
165
|
+
const getMutationType = (table, kind) => {
|
|
166
|
+
let types = mutationTypesCache.get(kind);
|
|
167
|
+
if (!types) {
|
|
168
|
+
types = new Map();
|
|
169
|
+
mutationTypesCache.set(kind, types);
|
|
170
|
+
}
|
|
171
|
+
let type = types.get(table);
|
|
172
|
+
if (!type) {
|
|
173
|
+
type = { insert: insertable, update: updateable, upsert: upsertable }[kind](schema[table]);
|
|
174
|
+
types.set(table, type);
|
|
175
|
+
}
|
|
176
|
+
return type;
|
|
177
|
+
};
|
|
178
|
+
const initialDataDbChanges = [];
|
|
179
|
+
/**
|
|
180
|
+
* Note that the initial data function is called even if it is unnecessary
|
|
181
|
+
* (initial data are already in the DB) because we don't want to wait for
|
|
182
|
+
* SQLite's response. Initial data should be small (because they are inlined
|
|
183
|
+
* in the code), so it's ok.
|
|
184
|
+
*/
|
|
185
|
+
if (initialData)
|
|
186
|
+
initialData({
|
|
187
|
+
insert: (table, props) => {
|
|
188
|
+
const Type = getMutationType(table, "insert");
|
|
189
|
+
const id = createId(deps);
|
|
190
|
+
const result = Type.fromUnknown(props);
|
|
191
|
+
if (result.ok) {
|
|
192
|
+
initialDataDbChanges.push({
|
|
193
|
+
id,
|
|
194
|
+
table,
|
|
195
|
+
values: result.value,
|
|
196
|
+
});
|
|
197
|
+
return ok({ id });
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
dbWorker.postMessage({
|
|
203
|
+
type: "init",
|
|
204
|
+
config,
|
|
205
|
+
dbSchema,
|
|
206
|
+
initialData: initialDataDbChanges,
|
|
207
|
+
});
|
|
208
|
+
const loadQueryMicrotaskQueue = [];
|
|
209
|
+
const mutateMicrotaskQueue = [];
|
|
210
|
+
const createMutation = (kind) => (table, props, options) => {
|
|
211
|
+
const Type = getMutationType(table, kind);
|
|
212
|
+
const result = Type.fromUnknown(props);
|
|
213
|
+
const id = kind === "insert"
|
|
214
|
+
? createId(deps)
|
|
215
|
+
: props.id;
|
|
216
|
+
if (options?.onlyValidate !== true) {
|
|
217
|
+
if (!result.ok) {
|
|
218
|
+
// One error must invalidate the whole queue.
|
|
219
|
+
// We insert `undefined` to detect such a situation.
|
|
220
|
+
mutateMicrotaskQueue.push([undefined, undefined]);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// Remove `id` from values.
|
|
224
|
+
const { id: _id, ...values } = result.value;
|
|
225
|
+
// EvoluSchema Types ensure valid types.
|
|
226
|
+
const change = { table, id, values };
|
|
227
|
+
mutateMicrotaskQueue.push([change, options?.onComplete]);
|
|
228
|
+
}
|
|
229
|
+
if (mutateMicrotaskQueue.length === 1)
|
|
230
|
+
queueMicrotask(() => {
|
|
231
|
+
const changes = [];
|
|
232
|
+
const onCompletes = [];
|
|
233
|
+
for (const [change, onComplete] of mutateMicrotaskQueue) {
|
|
234
|
+
if (change)
|
|
235
|
+
changes.push(change);
|
|
236
|
+
if (onComplete)
|
|
237
|
+
onCompletes.push(onComplete);
|
|
238
|
+
}
|
|
239
|
+
const mutateMicrotaskQueueLength = mutateMicrotaskQueue.length;
|
|
240
|
+
mutateMicrotaskQueue.length = 0;
|
|
241
|
+
// Don't mutate anything if there was a validation error.
|
|
242
|
+
// All mutations within a queue are considered to be a transaction.
|
|
243
|
+
if (changes.length !== mutateMicrotaskQueueLength) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const onCompleteIds = onCompletes.map((onComplete) => callbacks.register(onComplete));
|
|
247
|
+
loadingPromises.releaseUnsubscribed();
|
|
248
|
+
if (isNonEmptyArray(changes))
|
|
249
|
+
dbWorker.postMessage({
|
|
250
|
+
type: "mutate",
|
|
251
|
+
tabId: getTabId(),
|
|
252
|
+
changes,
|
|
253
|
+
onCompleteIds,
|
|
254
|
+
subscribedQueries: subscribedQueries.get(),
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (result.ok)
|
|
259
|
+
return ok({ id });
|
|
260
|
+
return err(result.error);
|
|
261
|
+
};
|
|
262
|
+
const evolu = {
|
|
263
|
+
subscribeError: errorStore.subscribe,
|
|
264
|
+
getError: errorStore.get,
|
|
265
|
+
createQuery: (queryCallback, options) => {
|
|
266
|
+
const compiledQuery = queryCallback(kysely).compile();
|
|
267
|
+
if (isSqlMutation(compiledQuery.sql))
|
|
268
|
+
throw new Error("SQL mutation (INSERT, UPDATE, DELETE, etc.) isn't allowed in the Evolu `createQuery` function. Kysely suggests it because there is no read-only Kysely yet, and removing such an API is not possible. For mutations, use Evolu Mutation API.");
|
|
269
|
+
return serializeQuery({
|
|
270
|
+
sql: compiledQuery.sql,
|
|
271
|
+
parameters: compiledQuery.parameters,
|
|
272
|
+
...(options && { options }),
|
|
273
|
+
});
|
|
274
|
+
},
|
|
275
|
+
loadQuery: (query) => {
|
|
276
|
+
const { promise, isNew } = loadingPromises.get(query);
|
|
277
|
+
if (isNew) {
|
|
278
|
+
loadQueryMicrotaskQueue.push(query);
|
|
279
|
+
if (loadQueryMicrotaskQueue.length === 1) {
|
|
280
|
+
queueMicrotask(() => {
|
|
281
|
+
// Dedupe
|
|
282
|
+
const queries = [...new Set(loadQueryMicrotaskQueue)];
|
|
283
|
+
loadQueryMicrotaskQueue.length = 0;
|
|
284
|
+
assertNonEmptyArray(queries);
|
|
285
|
+
dbWorker.postMessage({
|
|
286
|
+
type: "query",
|
|
287
|
+
tabId: getTabId(),
|
|
288
|
+
queries,
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return promise;
|
|
294
|
+
},
|
|
295
|
+
loadQueries: (queries) => queries.map(evolu.loadQuery),
|
|
296
|
+
subscribeQuery: (query) => (listener) => {
|
|
297
|
+
// Call the listener only if the result has been changed.
|
|
298
|
+
let previousResult = null;
|
|
299
|
+
const unsubscribe = subscribedQueries.subscribe(query)(() => {
|
|
300
|
+
const result = evolu.getQueryRows(query);
|
|
301
|
+
if (previousResult === result)
|
|
302
|
+
return;
|
|
303
|
+
previousResult = result;
|
|
304
|
+
listener();
|
|
305
|
+
});
|
|
306
|
+
return () => {
|
|
307
|
+
previousResult = null;
|
|
308
|
+
unsubscribe();
|
|
309
|
+
};
|
|
310
|
+
},
|
|
311
|
+
getQueryRows: (query) => (rowsStore.get().get(query) ?? emptyRows),
|
|
312
|
+
subscribeAppOwner: ownerStore.subscribe,
|
|
313
|
+
getAppOwner: ownerStore.get,
|
|
314
|
+
subscribeSyncState: syncStore.subscribe,
|
|
315
|
+
getSyncState: syncStore.get,
|
|
316
|
+
insert: createMutation("insert"),
|
|
317
|
+
update: createMutation("update"),
|
|
318
|
+
upsert: createMutation("upsert"),
|
|
319
|
+
resetAppOwner: (options) => {
|
|
320
|
+
// Eslint bug, Promise<void> is correct by docs.
|
|
321
|
+
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
322
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
323
|
+
const onCompleteId = callbacks.register(() => {
|
|
324
|
+
resolve();
|
|
325
|
+
});
|
|
326
|
+
dbWorker.postMessage({
|
|
327
|
+
type: "reset",
|
|
328
|
+
onCompleteId,
|
|
329
|
+
reload: options?.reload ?? true,
|
|
330
|
+
});
|
|
331
|
+
return promise;
|
|
332
|
+
},
|
|
333
|
+
restoreAppOwner: (mnemonic, options) => {
|
|
334
|
+
// Eslint bug, Promise<void> is correct by docs.
|
|
335
|
+
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
336
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
337
|
+
const onCompleteId = callbacks.register(() => {
|
|
338
|
+
resolve();
|
|
339
|
+
});
|
|
340
|
+
dbWorker.postMessage({
|
|
341
|
+
type: "reset",
|
|
342
|
+
onCompleteId,
|
|
343
|
+
reload: options?.reload ?? true,
|
|
344
|
+
restore: { mnemonic, dbSchema },
|
|
345
|
+
});
|
|
346
|
+
return promise;
|
|
347
|
+
},
|
|
348
|
+
reloadApp: () => {
|
|
349
|
+
appState.reset();
|
|
350
|
+
},
|
|
351
|
+
ensureSchema: (schema) => {
|
|
352
|
+
mutationTypesCache.clear();
|
|
353
|
+
const validSchema = assertValidEvoluSchema(schema);
|
|
354
|
+
dbWorker.postMessage({
|
|
355
|
+
type: "ensureDbSchema",
|
|
356
|
+
dbSchema: validEvoluSchemaToDbSchema(validSchema),
|
|
357
|
+
});
|
|
358
|
+
},
|
|
359
|
+
exportDatabase: () => {
|
|
360
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
361
|
+
const onCompleteId = callbacks.register((arg) => {
|
|
362
|
+
if (arg instanceof Uint8Array)
|
|
363
|
+
resolve(arg);
|
|
364
|
+
});
|
|
365
|
+
dbWorker.postMessage({ type: "export", onCompleteId });
|
|
366
|
+
return promise;
|
|
367
|
+
},
|
|
368
|
+
};
|
|
369
|
+
return evolu;
|
|
370
|
+
};
|
|
371
|
+
export const createNamespaceName = (config) => (name) => `evolu:${config.name}:${name}`;
|
|
372
|
+
const createLoadingPromises = (subscribedQueries) => {
|
|
373
|
+
const loadingPromiseMap = new Map();
|
|
374
|
+
const loadingPromises = {
|
|
375
|
+
get: (query) => {
|
|
376
|
+
let loadingPromise = loadingPromiseMap.get(query);
|
|
377
|
+
const isNew = !loadingPromise;
|
|
378
|
+
if (!loadingPromise) {
|
|
379
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
380
|
+
loadingPromise = { resolve, promise, releaseOnResolve: false };
|
|
381
|
+
loadingPromiseMap.set(query, loadingPromise);
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
promise: loadingPromise.promise,
|
|
385
|
+
isNew,
|
|
386
|
+
};
|
|
387
|
+
},
|
|
388
|
+
resolve: (query, rows) => {
|
|
389
|
+
const loadingPromise = loadingPromiseMap.get(query);
|
|
390
|
+
if (!loadingPromise)
|
|
391
|
+
return;
|
|
392
|
+
if (loadingPromise.promise.status !== "fulfilled") {
|
|
393
|
+
loadingPromise.resolve(rows);
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
// A promise can't be fulfilled 2x, so we need a new one.
|
|
397
|
+
loadingPromise.promise = Promise.resolve(rows);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* "For example, a data framework can set the status and value fields on a
|
|
401
|
+
* promise preemptively, before passing to React, so that React can unwrap
|
|
402
|
+
* it without waiting a microtask."
|
|
403
|
+
* https://github.com/acdlite/rfcs/blob/first-class-promises/text/0000-first-class-support-for-promises.md
|
|
404
|
+
*/
|
|
405
|
+
void Object.assign(loadingPromise.promise, {
|
|
406
|
+
status: "fulfilled",
|
|
407
|
+
value: rows,
|
|
408
|
+
});
|
|
409
|
+
if (loadingPromise.releaseOnResolve) {
|
|
410
|
+
loadingPromiseMap.delete(query);
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
/**
|
|
414
|
+
* We can't delete loading promises in `resolveLoadingPromises` because they
|
|
415
|
+
* must be cached, so repeated calls to `loadQuery` will always return the
|
|
416
|
+
* same promise until the data changes, and we also can't cache them forever
|
|
417
|
+
* because only subscribed queries are automatically updated (reactivity is
|
|
418
|
+
* expensive) hence this function must be called manually on any mutation.
|
|
419
|
+
*/
|
|
420
|
+
releaseUnsubscribed: () => {
|
|
421
|
+
[...loadingPromiseMap.entries()]
|
|
422
|
+
.filter(([query]) => !subscribedQueries.has(query))
|
|
423
|
+
.forEach(([query, loadingPromise]) => {
|
|
424
|
+
if (loadingPromise.promise.status === "fulfilled") {
|
|
425
|
+
loadingPromiseMap.delete(query);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
loadingPromise.releaseOnResolve = true;
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
return loadingPromises;
|
|
434
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🛠️
|
|
3
|
+
*
|
|
4
|
+
* ### Example
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { Evolu } from "@evolu/common/evolu";
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
export * from "./Config.js";
|
|
13
|
+
export * from "./Db.js";
|
|
14
|
+
export * from "./Diff.js";
|
|
15
|
+
export * from "./Evolu.js";
|
|
16
|
+
export * from "./Kysely.js";
|
|
17
|
+
export * from "./Owner.js";
|
|
18
|
+
export * from "./Platform.js";
|
|
19
|
+
export * from "./Protocol.js";
|
|
20
|
+
export * from "./Query.js";
|
|
21
|
+
export * from "./Relay.js";
|
|
22
|
+
export * from "./Schema.js";
|
|
23
|
+
export * from "./Storage.js";
|
|
24
|
+
export * from "./Sync.js";
|
|
25
|
+
export * from "./Timestamp.js";
|
|
26
|
+
//# sourceMappingURL=Internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Internal.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🛠️
|
|
3
|
+
*
|
|
4
|
+
* ### Example
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { Evolu } from "@evolu/common/evolu";
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
export * from "./Config.js";
|
|
13
|
+
export * from "./Db.js";
|
|
14
|
+
export * from "./Diff.js";
|
|
15
|
+
export * from "./Evolu.js";
|
|
16
|
+
export * from "./Kysely.js";
|
|
17
|
+
export * from "./Owner.js";
|
|
18
|
+
export * from "./Platform.js";
|
|
19
|
+
export * from "./Protocol.js";
|
|
20
|
+
export * from "./Query.js";
|
|
21
|
+
export * from "./Relay.js";
|
|
22
|
+
export * from "./Schema.js";
|
|
23
|
+
export * from "./Storage.js";
|
|
24
|
+
export * from "./Sync.js";
|
|
25
|
+
export * from "./Timestamp.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CreateIndexBuilder, Kysely } from "kysely";
|
|
2
|
+
import { DbIndex } from "./Db.js";
|
|
3
|
+
export declare const kysely: Kysely<unknown>;
|
|
4
|
+
export type DbIndexesBuilder = (create: (indexName: string) => CreateIndexBuilder) => ReadonlyArray<CreateIndexBuilder<any>>;
|
|
5
|
+
export declare const createIndexes: (indexes?: DbIndexesBuilder) => ReadonlyArray<DbIndex>;
|
|
6
|
+
//# sourceMappingURL=Kysely.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Kysely.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Kysely.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAElB,MAAM,EAGP,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,eAAO,MAAM,MAAM,iBASjB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,kBAAkB,KAC9C,aAAa,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC;AAI5C,eAAO,MAAM,aAAa,GACxB,UAAU,gBAAgB,KACzB,aAAa,CAAC,OAAO,CAQvB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DummyDriver, Kysely, SqliteAdapter, SqliteQueryCompiler, } from "kysely";
|
|
2
|
+
// https://kysely.dev/docs/recipes/splitting-query-building-and-execution
|
|
3
|
+
export const kysely = new Kysely({
|
|
4
|
+
dialect: {
|
|
5
|
+
createAdapter: () => new SqliteAdapter(),
|
|
6
|
+
createDriver: () => new DummyDriver(),
|
|
7
|
+
createIntrospector() {
|
|
8
|
+
throw new Error("Not implemeneted");
|
|
9
|
+
},
|
|
10
|
+
createQueryCompiler: () => new SqliteQueryCompiler(),
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
const createIndex = kysely.schema.createIndex.bind(kysely.schema);
|
|
14
|
+
export const createIndexes = (indexes) => {
|
|
15
|
+
if (!indexes)
|
|
16
|
+
return [];
|
|
17
|
+
return indexes(createIndex).map((index) => ({
|
|
18
|
+
name: index.toOperationNode().name.name,
|
|
19
|
+
sql: index.compile().sql,
|
|
20
|
+
}));
|
|
21
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { CreateMnemonicDep, CreateRandomBytesDep, EncryptionKey, MnemonicSeed } from "../Crypto.js";
|
|
2
|
+
import { NanoIdLibDep } from "../NanoId.js";
|
|
3
|
+
import { TimeDep } from "../Time.js";
|
|
4
|
+
import { DateIsoString, Mnemonic, NonNegativeInt } from "../Type.js";
|
|
5
|
+
import { TimestampString } from "./Timestamp.js";
|
|
6
|
+
/**
|
|
7
|
+
* `Owner` is an entity in Evolu that owns data, meaning it is locally stored on
|
|
8
|
+
* a device under the user’s control. Data can be personal private, peer-to-peer
|
|
9
|
+
* shared, or aggregated from multiple owners.
|
|
10
|
+
*
|
|
11
|
+
* An owner has a {@link Mnemonic} from which {@link OwnerId} and
|
|
12
|
+
* {@link EncryptionKey} are deterministically derived using SLIP-21, and an
|
|
13
|
+
* optional {@link WriteKey} that, when present, enables writing to the Evolu
|
|
14
|
+
* Relay or peers. The {@link WriteKey} can be rotated.
|
|
15
|
+
*
|
|
16
|
+
* Variants include {@link AppOwner}, {@link ShardOwner}, {@link SharedOwner}, and
|
|
17
|
+
* {@link SharedReadonlyOwner}, each with specific roles and properties detailed
|
|
18
|
+
* in their respective definitions.
|
|
19
|
+
*
|
|
20
|
+
* Public-key cryptography isn’t included here as it belongs to data and varies
|
|
21
|
+
* by use case. An Evolu app without collaboration doesn’t need it, while a
|
|
22
|
+
* Nostr-like app can leverage Nostr NIPs, or a super-safe app can use
|
|
23
|
+
* post-quantum cryptography.
|
|
24
|
+
*/
|
|
25
|
+
export interface Owner {
|
|
26
|
+
readonly mnemonic: Mnemonic;
|
|
27
|
+
readonly createdAt: DateIsoString;
|
|
28
|
+
readonly id: OwnerId;
|
|
29
|
+
readonly encryptionKey: EncryptionKey;
|
|
30
|
+
readonly writeKey: WriteKey;
|
|
31
|
+
}
|
|
32
|
+
export interface OwnerWithWriteAccess {
|
|
33
|
+
readonly id: OwnerId;
|
|
34
|
+
readonly encryptionKey: EncryptionKey;
|
|
35
|
+
readonly writeKey: WriteKey;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The unique identifier of {@link Owner} derived from the {@link Mnemonic}.
|
|
39
|
+
*
|
|
40
|
+
* This branded {@link Id} type, generated by {@link createSlip21Id}, is a
|
|
41
|
+
* 21-character {@link Base64Url} string (126 bits of entropy), providing a
|
|
42
|
+
* compact, shareable, and secure identifier for UI use, tied to the owner's
|
|
43
|
+
* mnemonic and derivation path.
|
|
44
|
+
*/
|
|
45
|
+
export declare const OwnerId: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "Id", import("../Type.js").RegexError<"Id">, import("../Type.js").StringError>, "OwnerId", import("../Type.js").BrandWithoutRefineError<"OwnerId", import("../Type.js").StringError | import("../Type.js").RegexError<"Id">>, never>;
|
|
46
|
+
export type OwnerId = typeof OwnerId.Type;
|
|
47
|
+
export declare const writeKeyLength: NonNegativeInt;
|
|
48
|
+
/**
|
|
49
|
+
* A secure token proving the initiator can write changes. Derived from a
|
|
50
|
+
* mnemonic or randomly generated. It's rotatable.
|
|
51
|
+
*/
|
|
52
|
+
export declare const WriteKey: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>, `Length${number & import("../Types.js").Brand<"Int"> & import("../Types.js").Brand<"NonNegative">}`, import("../Type.js").LengthError<number & import("../Types.js").Brand<"Int"> & import("../Types.js").Brand<"NonNegative">>, import("../Type.js").Uint8ArrayError>, "WriteKey", import("../Type.js").BrandWithoutRefineError<"WriteKey", import("../Type.js").Uint8ArrayError | import("../Type.js").LengthError<number & import("../Types.js").Brand<"Int"> & import("../Types.js").Brand<"NonNegative">>>, never>;
|
|
53
|
+
export type WriteKey = typeof WriteKey.Type;
|
|
54
|
+
/**
|
|
55
|
+
* The root owner of an Evolu app, created from a mnemonic safely generated on a
|
|
56
|
+
* device when the app is initialized or restored on another device using an
|
|
57
|
+
* existing mnemonic. It manages the app's core data, including the storage of
|
|
58
|
+
* other owners' mnemonics in an encrypted app table. Its `writeKey` is
|
|
59
|
+
* deterministic and rotatable. Never share the AppOwner mnemonic with anyone.
|
|
60
|
+
*/
|
|
61
|
+
export interface AppOwner extends Owner {
|
|
62
|
+
readonly type: "AppOwner";
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Used to shard data within an app for partial or deferred sync. Created in the
|
|
66
|
+
* Evolu `initialData` function or dynamically as needed. Its mnemonic is stored
|
|
67
|
+
* in an app table (encrypted by `AppOwner`) and synced between devices. Its
|
|
68
|
+
* `writeKey` is deterministic and rotatable, enabling selective syncing of data
|
|
69
|
+
* subsets. Not intended for sharing outside the app.
|
|
70
|
+
*
|
|
71
|
+
* This type omits `id`, `encryptionKey`, and `createdAt` as they are derived by
|
|
72
|
+
* Evolu from the `mnemonic`, reducing storage overhead.
|
|
73
|
+
*/
|
|
74
|
+
export interface ShardOwner {
|
|
75
|
+
readonly type: "ShardOwner";
|
|
76
|
+
readonly mnemonic: Mnemonic;
|
|
77
|
+
readonly writeKey: WriteKey;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Used to share data among one or more users, enabling collaboration or
|
|
81
|
+
* controlled access. Its `writeKey` is random (not derived from the mnemonic,
|
|
82
|
+
* stored alongside it in the app table) and rotatable, ensuring it cannot be
|
|
83
|
+
* regenerated by others if shared. Share the `mnemonic` alone for read-only
|
|
84
|
+
* access (as `SharedReadonlyOwner`) or share SharedOwner itself for write
|
|
85
|
+
* access.
|
|
86
|
+
*
|
|
87
|
+
* This type omits `id`, `encryptionKey`, and `createdAt` as they are derived by
|
|
88
|
+
* Evolu from the `mnemonic`, reducing storage overhead.
|
|
89
|
+
*/
|
|
90
|
+
export interface SharedOwner {
|
|
91
|
+
readonly type: "SharedOwner";
|
|
92
|
+
readonly mnemonic: Mnemonic;
|
|
93
|
+
readonly writeKey: WriteKey;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Used for sharing data that can only be read, such as with followers or peers
|
|
97
|
+
* in a read-only sync scenario. It lacks a `writeKey`, containing only the
|
|
98
|
+
* `mnemonic` from which `id` and `encryptionKey` are derived by Evolu.
|
|
99
|
+
* Typically derived from a `SharedOwner` by sharing its `mnemonic` without the
|
|
100
|
+
* `writeKey`.
|
|
101
|
+
*/
|
|
102
|
+
export interface SharedReadonlyOwner {
|
|
103
|
+
readonly type: "SharedReadonlyOwner";
|
|
104
|
+
readonly mnemonic: Mnemonic;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Creates an {@link AppOwner}, optionally from an existing mnemonic to restore
|
|
108
|
+
* it on another device; otherwise, generates a new mnemonic.
|
|
109
|
+
*/
|
|
110
|
+
export declare const createAppOwner: (deps: TimeDep & CreateRandomBytesDep & CreateMnemonicDep) => (mnemonic?: string & import("../Types.js").Brand<"Trimmed"> & import("../Types.js").Brand<"MinLength1"> & import("../Types.js").Brand<"Mnemonic">) => AppOwner;
|
|
111
|
+
/**
|
|
112
|
+
* Creates a {@link ShardOwner} for sharding app data with a freshly generated
|
|
113
|
+
* mnemonic. Unlike {@link createAppOwner}, it doesn’t accept an existing
|
|
114
|
+
* mnemonic because ShardOwner mnemonics are always generated and restored
|
|
115
|
+
* automatically via database sync.
|
|
116
|
+
*/
|
|
117
|
+
export declare const createShardOwner: (deps: TimeDep & CreateRandomBytesDep & CreateMnemonicDep) => ShardOwner;
|
|
118
|
+
/**
|
|
119
|
+
* Creates a fresh {@link SharedOwner} for sharing data with write access. Takes
|
|
120
|
+
* no arguments as both `mnemonic` and rotatable `writeKey` are newly generated;
|
|
121
|
+
* when shared, recipients use the provided `mnemonic` and `writeKey` directly
|
|
122
|
+
* as a {@link SharedOwner} without needing to recreate it.
|
|
123
|
+
*/
|
|
124
|
+
export declare const createSharedOwner: (deps: CreateRandomBytesDep & CreateMnemonicDep) => SharedOwner;
|
|
125
|
+
/**
|
|
126
|
+
* Creates a {@link SharedReadonlyOwner} from a {@link SharedOwner} for read-only
|
|
127
|
+
* data sharing. Extracts the `mnemonic` from the provided {@link SharedOwner},
|
|
128
|
+
* omitting its `writeKey` to ensure read-only access.
|
|
129
|
+
*/
|
|
130
|
+
export declare const createSharedReadonlyOwner: (sharedOwner: SharedOwner) => SharedReadonlyOwner;
|
|
131
|
+
/** Creates an {@link Owner} with optional `mnemonic` and `writeKey`. */
|
|
132
|
+
export declare const createOwner: (deps: TimeDep & CreateRandomBytesDep & CreateMnemonicDep) => (mnemonic?: string & import("../Types.js").Brand<"Trimmed"> & import("../Types.js").Brand<"MinLength1"> & import("../Types.js").Brand<"Mnemonic">, writeKey?: WriteKey) => Owner;
|
|
133
|
+
export declare const createWriteKey: (deps: CreateRandomBytesDep) => (seed?: MnemonicSeed) => WriteKey;
|
|
134
|
+
/**
|
|
135
|
+
* An `OwnerRow` represents a row in the `evolu_owner` table, based on an
|
|
136
|
+
* {@link Owner} with an added `timestamp` ({@link TimestampString}) for CRDT
|
|
137
|
+
* sync. It supports all {@link Owner} variants with an optional `writeKey`; use
|
|
138
|
+
* {@link createOwnerRow} to align it with a specific {@link Owner}.
|
|
139
|
+
*/
|
|
140
|
+
export type OwnerRow = Omit<Owner, "writeKey"> & {
|
|
141
|
+
readonly writeKey: WriteKey | null;
|
|
142
|
+
readonly timestamp: TimestampString;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Creates an {@link OwnerRow} from any {@link Owner} variant for the
|
|
146
|
+
* `evolu_owner` table, adding a `timestamp` ({@link TimestampString}) for CRDT
|
|
147
|
+
* sync.
|
|
148
|
+
*/
|
|
149
|
+
export declare const createOwnerRow: (deps: TimeDep & CreateRandomBytesDep & CreateMnemonicDep & NanoIdLibDep) => (owner: AppOwner | ShardOwner | SharedOwner | SharedReadonlyOwner) => OwnerRow;
|
|
150
|
+
/**
|
|
151
|
+
* Rotates the {@link WriteKey} for an {@link AppOwner}, {@link ShardOwner}, or
|
|
152
|
+
* {@link SharedOwner}, returning a new instance with the updated key.
|
|
153
|
+
*/
|
|
154
|
+
export declare const rotateWriteKey: <T extends AppOwner | ShardOwner | SharedOwner>(owner: T, newWriteKey: WriteKey) => T;
|
|
155
|
+
//# sourceMappingURL=Owner.d.ts.map
|