@evolu/common 6.0.1-preview.28 → 6.0.1-preview.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/Array.d.ts +58 -5
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +53 -5
- package/dist/src/Evolu/Evolu.d.ts +3 -3
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +3 -3
- package/dist/src/Evolu/Owner.d.ts +48 -19
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +11 -2
- package/dist/src/Evolu/Protocol.d.ts +31 -31
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +51 -28
- package/dist/src/Evolu/Relay.d.ts +40 -25
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +106 -49
- package/dist/src/Evolu/Storage.d.ts +59 -12
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +77 -50
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +14 -5
- package/dist/src/Evolu/Timestamp.d.ts +25 -0
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +25 -0
- package/dist/src/Instances.d.ts +34 -0
- package/dist/src/Instances.d.ts.map +1 -0
- package/dist/src/{Multiton.js → Instances.js} +20 -9
- package/dist/src/Sqlite.d.ts +6 -0
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +6 -0
- package/dist/src/Task.d.ts +75 -0
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +29 -6
- package/dist/src/Time.d.ts +7 -1
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +13 -2
- package/dist/src/Type.d.ts +56 -9
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +40 -8
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/package.json +1 -1
- package/src/Array.ts +76 -11
- package/src/Evolu/Evolu.ts +4 -5
- package/src/Evolu/Owner.ts +75 -26
- package/src/Evolu/Protocol.ts +90 -61
- package/src/Evolu/Relay.ts +182 -77
- package/src/Evolu/Storage.ts +157 -67
- package/src/Evolu/Sync.ts +18 -6
- package/src/Evolu/Timestamp.ts +25 -0
- package/src/Instances.ts +90 -0
- package/src/Sqlite.ts +6 -0
- package/src/Task.ts +88 -7
- package/src/Time.ts +13 -2
- package/src/Type.ts +56 -9
- package/src/index.ts +1 -1
- package/dist/src/Multiton.d.ts +0 -50
- package/dist/src/Multiton.d.ts.map +0 -1
- package/src/Multiton.ts +0 -98
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
2
|
import { assert } from "../Assert.js";
|
|
3
|
+
import { concatBytes } from "../Buffer.js";
|
|
3
4
|
import { decrement } from "../Number.js";
|
|
4
5
|
import { ok } from "../Result.js";
|
|
5
6
|
import { sql, SqliteValue } from "../Sqlite.js";
|
|
@@ -24,46 +25,14 @@ export const DbChange = object({
|
|
|
24
25
|
id: Id,
|
|
25
26
|
values: record(String, SqliteValue),
|
|
26
27
|
});
|
|
27
|
-
export const createBaseSqliteStorage = (deps) => (
|
|
28
|
-
// TODO: Use
|
|
28
|
+
export const createBaseSqliteStorage = (deps) => (config) => {
|
|
29
|
+
// TODO: Use evolu_usage table.
|
|
29
30
|
const ownerStats = new Map();
|
|
30
31
|
return {
|
|
31
|
-
insertTimestamp: (ownerId, timestamp) => {
|
|
32
|
-
const ownerIdString = ownerIdBytesToOwnerId(ownerId);
|
|
33
|
-
const level = randomSkiplistLevel(deps);
|
|
34
|
-
let stats = ownerStats.get(ownerIdString);
|
|
35
|
-
if (!stats) {
|
|
36
|
-
const result = deps.sqlite.exec(sql.prepared `
|
|
37
|
-
select min(t) as minT, max(t) as maxT
|
|
38
|
-
from evolu_timestamp
|
|
39
|
-
where ownerId = ${ownerId};
|
|
40
|
-
`);
|
|
41
|
-
if (!result.ok)
|
|
42
|
-
return result;
|
|
43
|
-
stats = {
|
|
44
|
-
minT: result.value.rows[0].minT ?? timestamp,
|
|
45
|
-
maxT: result.value.rows[0].maxT ?? timestamp,
|
|
46
|
-
};
|
|
47
|
-
ownerStats.set(ownerIdString, stats);
|
|
48
|
-
}
|
|
49
|
-
let strategy;
|
|
50
|
-
if (orderTimestampBytes(timestamp, stats.maxT) === 1) {
|
|
51
|
-
strategy = "append";
|
|
52
|
-
stats.maxT = timestamp;
|
|
53
|
-
}
|
|
54
|
-
else if (orderTimestampBytes(timestamp, stats.minT) === -1) {
|
|
55
|
-
strategy = "prepend";
|
|
56
|
-
stats.minT = timestamp;
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
strategy = "insert";
|
|
60
|
-
}
|
|
61
|
-
return insertTimestamp(deps)(ownerId, timestamp, level, strategy);
|
|
62
|
-
},
|
|
63
32
|
getSize: (ownerId) => {
|
|
64
33
|
const size = getSize(deps)(ownerId);
|
|
65
34
|
if (!size.ok) {
|
|
66
|
-
|
|
35
|
+
config.onStorageError(size.error);
|
|
67
36
|
return null;
|
|
68
37
|
}
|
|
69
38
|
return size.value;
|
|
@@ -72,7 +41,7 @@ export const createBaseSqliteStorage = (deps) => (options) => {
|
|
|
72
41
|
assertBeginEnd(begin, end);
|
|
73
42
|
const result = fingerprint(deps)(ownerId, begin, end);
|
|
74
43
|
if (!result.ok) {
|
|
75
|
-
|
|
44
|
+
config.onStorageError(result.error);
|
|
76
45
|
return null;
|
|
77
46
|
}
|
|
78
47
|
return result.value;
|
|
@@ -80,7 +49,7 @@ export const createBaseSqliteStorage = (deps) => (options) => {
|
|
|
80
49
|
fingerprintRanges: (ownerId, buckets, upperBound) => {
|
|
81
50
|
const ranges = fingerprintRanges(deps)(ownerId, buckets, upperBound);
|
|
82
51
|
if (!ranges.ok) {
|
|
83
|
-
|
|
52
|
+
config.onStorageError(ranges.error);
|
|
84
53
|
return null;
|
|
85
54
|
}
|
|
86
55
|
return ranges.value;
|
|
@@ -88,7 +57,7 @@ export const createBaseSqliteStorage = (deps) => (options) => {
|
|
|
88
57
|
findLowerBound: (ownerId, begin, end, upperBound) => {
|
|
89
58
|
const lowerBound = findLowerBound(deps)(ownerId, begin, end, upperBound);
|
|
90
59
|
if (!lowerBound.ok) {
|
|
91
|
-
|
|
60
|
+
config.onStorageError(lowerBound.error);
|
|
92
61
|
return null;
|
|
93
62
|
}
|
|
94
63
|
return lowerBound.value;
|
|
@@ -101,7 +70,7 @@ export const createBaseSqliteStorage = (deps) => (options) => {
|
|
|
101
70
|
// This is much faster than SQL limit with offset.
|
|
102
71
|
const first = getTimestampByIndex(deps)(ownerId, begin);
|
|
103
72
|
if (!first.ok) {
|
|
104
|
-
|
|
73
|
+
config.onStorageError(first.error);
|
|
105
74
|
return;
|
|
106
75
|
}
|
|
107
76
|
if (!callback(first.value, begin))
|
|
@@ -126,7 +95,7 @@ export const createBaseSqliteStorage = (deps) => (options) => {
|
|
|
126
95
|
limit ${length - 1};
|
|
127
96
|
`);
|
|
128
97
|
if (!result.ok) {
|
|
129
|
-
|
|
98
|
+
config.onStorageError(result.error);
|
|
130
99
|
return;
|
|
131
100
|
}
|
|
132
101
|
for (let i = 0; i < result.value.rows.length; i++) {
|
|
@@ -140,11 +109,68 @@ export const createBaseSqliteStorage = (deps) => (options) => {
|
|
|
140
109
|
delete from evolu_timestamp where ownerId = ${ownerId};
|
|
141
110
|
`);
|
|
142
111
|
if (!result.ok) {
|
|
143
|
-
|
|
112
|
+
config.onStorageError(result.error);
|
|
144
113
|
return false;
|
|
145
114
|
}
|
|
146
115
|
return true;
|
|
147
116
|
},
|
|
117
|
+
insertTimestamp: (ownerId, timestamp) => {
|
|
118
|
+
const ownerIdString = ownerIdBytesToOwnerId(ownerId);
|
|
119
|
+
const level = randomSkiplistLevel(deps);
|
|
120
|
+
let stats = ownerStats.get(ownerIdString);
|
|
121
|
+
if (!stats) {
|
|
122
|
+
const result = deps.sqlite.exec(sql.prepared `
|
|
123
|
+
select min(t) as minT, max(t) as maxT
|
|
124
|
+
from evolu_timestamp
|
|
125
|
+
where ownerId = ${ownerId};
|
|
126
|
+
`);
|
|
127
|
+
if (!result.ok)
|
|
128
|
+
return result;
|
|
129
|
+
stats = {
|
|
130
|
+
minT: result.value.rows[0].minT ?? timestamp,
|
|
131
|
+
maxT: result.value.rows[0].maxT ?? timestamp,
|
|
132
|
+
};
|
|
133
|
+
ownerStats.set(ownerIdString, stats);
|
|
134
|
+
}
|
|
135
|
+
let strategy;
|
|
136
|
+
if (orderTimestampBytes(timestamp, stats.maxT) === 1) {
|
|
137
|
+
strategy = "append";
|
|
138
|
+
stats.maxT = timestamp;
|
|
139
|
+
}
|
|
140
|
+
else if (orderTimestampBytes(timestamp, stats.minT) === -1) {
|
|
141
|
+
strategy = "prepend";
|
|
142
|
+
stats.minT = timestamp;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
strategy = "insert";
|
|
146
|
+
}
|
|
147
|
+
return insertTimestamp(deps)(ownerId, timestamp, level, strategy);
|
|
148
|
+
},
|
|
149
|
+
getExistingTimestamps: (ownerIdBytes, timestampsBytes) => {
|
|
150
|
+
const concatenatedTimestamps = concatBytes(...timestampsBytes);
|
|
151
|
+
const result = deps.sqlite.exec(sql `
|
|
152
|
+
with recursive
|
|
153
|
+
split_timestamps(timestampBytes, pos) as (
|
|
154
|
+
select
|
|
155
|
+
substr(${concatenatedTimestamps}, 1, 16),
|
|
156
|
+
17 as pos
|
|
157
|
+
union all
|
|
158
|
+
select
|
|
159
|
+
substr(${concatenatedTimestamps}, pos, 16),
|
|
160
|
+
pos + 16
|
|
161
|
+
from split_timestamps
|
|
162
|
+
where pos <= length(${concatenatedTimestamps})
|
|
163
|
+
)
|
|
164
|
+
select s.timestampBytes
|
|
165
|
+
from
|
|
166
|
+
split_timestamps s
|
|
167
|
+
join evolu_timestamp t
|
|
168
|
+
on t.ownerId = ${ownerIdBytes} and s.timestampBytes = t.t;
|
|
169
|
+
`);
|
|
170
|
+
if (!result.ok)
|
|
171
|
+
return result;
|
|
172
|
+
return ok(result.value.rows.map((row) => row.timestampBytes));
|
|
173
|
+
},
|
|
148
174
|
};
|
|
149
175
|
};
|
|
150
176
|
const assertBeginEnd = (begin, end) => {
|
|
@@ -203,19 +229,20 @@ export const createBaseSqliteStorageTables = (deps) => {
|
|
|
203
229
|
*
|
|
204
230
|
* - `ownerId` – OwnerIdBytes (primary key)
|
|
205
231
|
* - `storedBytes` – total bytes stored in database
|
|
206
|
-
* - `receivedBytes` –
|
|
207
|
-
* - `sentBytes` –
|
|
208
|
-
* - `firstTimestamp` –
|
|
209
|
-
* - `lastTimestamp` –
|
|
232
|
+
* - `receivedBytes` – TODO: Decide how to use
|
|
233
|
+
* - `sentBytes` – TODO: Decide how to use
|
|
234
|
+
* - `firstTimestamp` – TODO: Decide how to use (nullable)
|
|
235
|
+
* - `lastTimestamp` – TODO: Decide how to use (nullable)
|
|
210
236
|
*/
|
|
211
237
|
sql `
|
|
212
238
|
create table evolu_usage (
|
|
213
239
|
"ownerId" blob primary key,
|
|
214
|
-
"storedBytes" integer not null
|
|
215
|
-
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
"
|
|
240
|
+
"storedBytes" integer not null
|
|
241
|
+
-- TODO: Decide how to use receivedBytes, sentBytes, firstTimestamp, lastTimestamp
|
|
242
|
+
-- "receivedBytes" integer not null,
|
|
243
|
+
-- "sentBytes" integer not null,
|
|
244
|
+
-- "firstTimestamp" blob,
|
|
245
|
+
-- "lastTimestamp" blob
|
|
219
246
|
)
|
|
220
247
|
strict;
|
|
221
248
|
`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sync.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGnE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EACL,cAAc,EACd,2BAA2B,EAC3B,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAA2B,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGzE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,
|
|
1
|
+
{"version":3,"file":"Sync.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Sync.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Evolu/Sync.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createTransferableError } from "../Error.js";
|
|
|
4
4
|
import { constFalse } from "../Function.js";
|
|
5
5
|
import { objectToEntries } from "../Object.js";
|
|
6
6
|
import { createRefCountedResourceManager } from "../RefCountedResourceManager.js";
|
|
7
|
-
import { ok } from "../Result.js";
|
|
7
|
+
import { err, ok } from "../Result.js";
|
|
8
8
|
import { sql } from "../Sqlite.js";
|
|
9
9
|
import { createMutex } from "../Task.js";
|
|
10
10
|
import { idBytesToId, idToIdBytes } from "../Type.js";
|
|
@@ -222,18 +222,27 @@ const createClientStorage = (deps) => (config) => {
|
|
|
222
222
|
const sqliteStorageBase = createBaseSqliteStorage(deps)({
|
|
223
223
|
onStorageError: config.onError,
|
|
224
224
|
});
|
|
225
|
+
// TODO: Mutex per OwnerId
|
|
225
226
|
const mutex = createMutex();
|
|
226
227
|
const storage = {
|
|
227
228
|
...sqliteStorageBase,
|
|
229
|
+
// Not implemented yet.
|
|
228
230
|
validateWriteKey: constFalse,
|
|
229
231
|
setWriteKey: constFalse,
|
|
230
232
|
writeMessages: async (ownerIdBytes, encryptedMessages) => {
|
|
233
|
+
const ownerId = ownerIdBytesToOwnerId(ownerIdBytes);
|
|
234
|
+
// Everything is sync now, but we will need async crypto in the future.
|
|
231
235
|
const writeResult = await mutex.withLock(async () => {
|
|
232
|
-
const ownerId = ownerIdBytesToOwnerId(ownerIdBytes);
|
|
233
236
|
const owner = deps.getSyncOwner(ownerId);
|
|
234
237
|
// Owner can be removed during syncing.
|
|
238
|
+
// `ok(true)` means success, we just skipped the write.
|
|
235
239
|
if (!owner)
|
|
236
|
-
return ok(
|
|
240
|
+
return ok(true);
|
|
241
|
+
// TODO: Add quota checking for collaborative scenarios.
|
|
242
|
+
// When receiving messages from other owners via relay broadcast,
|
|
243
|
+
// check if this owner is within quota before accepting the data.
|
|
244
|
+
// This prevents an owner from exceeding storage limits when receiving
|
|
245
|
+
// data shared by other collaborators.
|
|
237
246
|
const messages = [];
|
|
238
247
|
for (const message of encryptedMessages) {
|
|
239
248
|
const change = decryptAndDecodeDbChange(deps)(message, owner.encryptionKey);
|
|
@@ -270,10 +279,10 @@ const createClientStorage = (deps) => (config) => {
|
|
|
270
279
|
if (writeResult.error.type !== "AbortError") {
|
|
271
280
|
config.onError(writeResult.error);
|
|
272
281
|
}
|
|
273
|
-
return
|
|
282
|
+
return err({ type: "StorageWriteError", ownerId });
|
|
274
283
|
}
|
|
275
284
|
config.onReceive();
|
|
276
|
-
return
|
|
285
|
+
return ok();
|
|
277
286
|
},
|
|
278
287
|
readDbChange: (ownerId, timestamp) => {
|
|
279
288
|
const owner = deps.getSyncOwner(ownerIdBytesToOwnerId(ownerId));
|
|
@@ -82,6 +82,31 @@ export declare const maxNodeId: NodeId;
|
|
|
82
82
|
* Timestamps serve as globally unique, causally ordered identifiers for CRDT
|
|
83
83
|
* messages in Evolu's sync protocol.
|
|
84
84
|
*
|
|
85
|
+
* ### Why Hybrid Logical Clocks
|
|
86
|
+
*
|
|
87
|
+
* Evolu uses Hybrid Logical Clocks (HLC), which combine physical time (millis)
|
|
88
|
+
* with a logical counter. This hybrid approach preserves causality like logical
|
|
89
|
+
* clocks while staying close to physical time for better human
|
|
90
|
+
* interpretability.
|
|
91
|
+
*
|
|
92
|
+
* The counter component ensures causality is maintained even when physical
|
|
93
|
+
* clocks are imperfect. When clocks drift or operations occur concurrently, the
|
|
94
|
+
* counter increments to establish a total order. This means Evolu achieves
|
|
95
|
+
* well-defined, eventually-consistent behavior regardless of physical clock
|
|
96
|
+
* accuracy.
|
|
97
|
+
*
|
|
98
|
+
* Vector clocks can accurately track causality and detect concurrent
|
|
99
|
+
* operations, but they require unbounded space in peer-to-peer systems and
|
|
100
|
+
* crucially, still don't solve our fundamental problem: when they detect
|
|
101
|
+
* operations as concurrent, we still need a deterministic way to choose a
|
|
102
|
+
* winner. Additionally, any deterministic conflict resolution can be gamed by
|
|
103
|
+
* malicious actors.
|
|
104
|
+
*
|
|
105
|
+
* HLC timestamps work well in practice because modern device clocks accurately
|
|
106
|
+
* reflect the order of sequential edits in the common case. Evolu's `maxDrift`
|
|
107
|
+
* configuration protects against buggy clocks and prevents problematic
|
|
108
|
+
* future-dated entries from propagating through the network.
|
|
109
|
+
*
|
|
85
110
|
* ### References
|
|
86
111
|
*
|
|
87
112
|
* - https://muratbuffalo.blogspot.com/2014/07/hybrid-logical-clocks.html
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Timestamp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,EAAE,KAAK,EAAmB,MAAM,aAAa,CAAC;AACrD,OAAO,EAAW,MAAM,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAEL,SAAS,EAOV,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC3C;AAED,MAAM,MAAM,cAAc,GACtB,mBAAmB,GACnB,6BAA6B,GAC7B,4BAA4B,CAAC;AAEjC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,IAAI,EAAE,+BAA+B,CAAC;CAChD;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,IAAI,EAAE,8BAA8B,CAAC;CAC/C;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,MAAM,gsBAGlB,CAAC;AACF,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAC;AAExC,eAAO,MAAM,SAAS,EAAQ,MAAM,CAAC;AACrC,eAAO,MAAM,SAAS,EAA4B,MAAM,CAAC;AAEzD,eAAO,MAAM,OAAO,4rBAGnB,CAAC;AACF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAE1C,eAAO,MAAM,UAAU,EAAQ,OAAO,CAAC;AACvC,eAAO,MAAM,UAAU,EAAY,OAAO,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,MAAM,wPAA4C,CAAC;AAChE,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAC;AAExC,eAAO,MAAM,SAAS,EAAyB,MAAM,CAAC;AACtD,eAAO,MAAM,SAAS,EAAyB,MAAM,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Timestamp.ts"],"names":[],"mappings":"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"}
|
|
@@ -57,6 +57,31 @@ export const maxNodeId = "ffffffffffffffff";
|
|
|
57
57
|
* Timestamps serve as globally unique, causally ordered identifiers for CRDT
|
|
58
58
|
* messages in Evolu's sync protocol.
|
|
59
59
|
*
|
|
60
|
+
* ### Why Hybrid Logical Clocks
|
|
61
|
+
*
|
|
62
|
+
* Evolu uses Hybrid Logical Clocks (HLC), which combine physical time (millis)
|
|
63
|
+
* with a logical counter. This hybrid approach preserves causality like logical
|
|
64
|
+
* clocks while staying close to physical time for better human
|
|
65
|
+
* interpretability.
|
|
66
|
+
*
|
|
67
|
+
* The counter component ensures causality is maintained even when physical
|
|
68
|
+
* clocks are imperfect. When clocks drift or operations occur concurrently, the
|
|
69
|
+
* counter increments to establish a total order. This means Evolu achieves
|
|
70
|
+
* well-defined, eventually-consistent behavior regardless of physical clock
|
|
71
|
+
* accuracy.
|
|
72
|
+
*
|
|
73
|
+
* Vector clocks can accurately track causality and detect concurrent
|
|
74
|
+
* operations, but they require unbounded space in peer-to-peer systems and
|
|
75
|
+
* crucially, still don't solve our fundamental problem: when they detect
|
|
76
|
+
* operations as concurrent, we still need a deterministic way to choose a
|
|
77
|
+
* winner. Additionally, any deterministic conflict resolution can be gamed by
|
|
78
|
+
* malicious actors.
|
|
79
|
+
*
|
|
80
|
+
* HLC timestamps work well in practice because modern device clocks accurately
|
|
81
|
+
* reflect the order of sequential edits in the common case. Evolu's `maxDrift`
|
|
82
|
+
* configuration protects against buggy clocks and prevents problematic
|
|
83
|
+
* future-dated entries from propagating through the network.
|
|
84
|
+
*
|
|
60
85
|
* ### References
|
|
61
86
|
*
|
|
62
87
|
* - https://muratbuffalo.blogspot.com/2014/07/hybrid-logical-clocks.html
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages disposable instances by key, ensuring exactly one instance per key.
|
|
3
|
+
*
|
|
4
|
+
* Use cases:
|
|
5
|
+
*
|
|
6
|
+
* - One mutex per key to prevent concurrent writes
|
|
7
|
+
* - Preserving state during hot module reloading
|
|
8
|
+
*
|
|
9
|
+
* **Important:** Do not use this as global shared state. Use it locally or pass
|
|
10
|
+
* it as a dependency instead. The only exception is for hot reloading support,
|
|
11
|
+
* where Evolu uses it to ensure only one instance exists across module reloads
|
|
12
|
+
* (having two Evolu instances with the same name would mean two SQLite
|
|
13
|
+
* connections to the same file, which could corrupt data).
|
|
14
|
+
*/
|
|
15
|
+
export interface Instances<K extends string, T extends Disposable> extends Disposable {
|
|
16
|
+
/**
|
|
17
|
+
* Ensures an instance exists for the given key, creating it if necessary. If
|
|
18
|
+
* the instance already exists, the optional `onCacheHit` callback is invoked
|
|
19
|
+
* to update the existing instance.
|
|
20
|
+
*/
|
|
21
|
+
readonly ensure: (key: K, create: () => T, onCacheHit?: (instance: T) => void) => T;
|
|
22
|
+
/** Gets an instance by key, or returns `null` if it doesn't exist. */
|
|
23
|
+
readonly get: (key: K) => T | null;
|
|
24
|
+
/** Checks if an instance exists for the given key. */
|
|
25
|
+
readonly has: (key: K) => boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Deletes and disposes an instance by key. Returns `true` if the instance
|
|
28
|
+
* existed and was deleted, `false` otherwise.
|
|
29
|
+
*/
|
|
30
|
+
readonly delete: (key: K) => boolean;
|
|
31
|
+
}
|
|
32
|
+
/** Creates an {@link Instances} manager. */
|
|
33
|
+
export declare const createInstances: <K extends string, T extends Disposable>() => Instances<K, T>;
|
|
34
|
+
//# sourceMappingURL=Instances.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Instances.d.ts","sourceRoot":"","sources":["../../src/Instances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,UAAU,CAC/D,SAAQ,UAAU;IAClB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,CACf,GAAG,EAAE,CAAC,EACN,MAAM,EAAE,MAAM,CAAC,EACf,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,KAC/B,CAAC,CAAC;IAEP,sEAAsE;IACtE,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IAEnC,sDAAsD;IACtD,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IAElC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;CACtC;AAED,4CAA4C;AAC5C,eAAO,MAAM,eAAe,GAC1B,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,UAAU,OACjB,SAAS,CAAC,CAAC,EAAE,CAAC,CA6ClB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** Creates
|
|
2
|
-
export const
|
|
1
|
+
/** Creates an {@link Instances} manager. */
|
|
2
|
+
export const createInstances = () => {
|
|
3
3
|
const instances = new Map();
|
|
4
4
|
return {
|
|
5
5
|
ensure: (key, create, onCacheHit) => {
|
|
@@ -15,19 +15,30 @@ export const createMultiton = () => {
|
|
|
15
15
|
},
|
|
16
16
|
get: (key) => instances.get(key) ?? null,
|
|
17
17
|
has: (key) => instances.has(key),
|
|
18
|
-
|
|
18
|
+
delete: (key) => {
|
|
19
19
|
const instance = instances.get(key);
|
|
20
|
-
if (instance)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return
|
|
20
|
+
if (instance == null)
|
|
21
|
+
return false;
|
|
22
|
+
instances.delete(key);
|
|
23
|
+
instance[Symbol.dispose]();
|
|
24
|
+
return true;
|
|
25
25
|
},
|
|
26
26
|
[Symbol.dispose]: () => {
|
|
27
|
+
const errors = [];
|
|
27
28
|
for (const instance of instances.values()) {
|
|
28
|
-
|
|
29
|
+
try {
|
|
30
|
+
instance[Symbol.dispose]();
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
errors.push(error);
|
|
34
|
+
}
|
|
29
35
|
}
|
|
30
36
|
instances.clear();
|
|
37
|
+
if (errors.length === 1)
|
|
38
|
+
throw errors[0];
|
|
39
|
+
if (errors.length > 1) {
|
|
40
|
+
throw new AggregateError(errors, "Multiple disposal errors occurred");
|
|
41
|
+
}
|
|
31
42
|
},
|
|
32
43
|
};
|
|
33
44
|
};
|
package/dist/src/Sqlite.d.ts
CHANGED
|
@@ -142,6 +142,12 @@ export type SqlTemplateParam = SqliteValue | SqlIdentifier | RawSql;
|
|
|
142
142
|
* const orderBy = "created_at desc";
|
|
143
143
|
* sqlite.exec(sql`select * from users order by ${sql.raw(orderBy)};`);
|
|
144
144
|
* ```
|
|
145
|
+
*
|
|
146
|
+
* ### TIP
|
|
147
|
+
*
|
|
148
|
+
* Use `prettier-plugin-sql-cst` for SQL formatting. Like Prettier for
|
|
149
|
+
* JavaScript, this plugin formats SQL expressions differently depending on
|
|
150
|
+
* their length.
|
|
145
151
|
*/
|
|
146
152
|
export declare const sql: {
|
|
147
153
|
(strings: TemplateStringsArray, ...parameters: Array<SqlTemplateParam>): SqliteQuery;
|
package/dist/src/Sqlite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Sqlite.js
CHANGED
|
@@ -153,6 +153,12 @@ export const createPreparedStatementsCache = (factory, disposeFn) => {
|
|
|
153
153
|
* const orderBy = "created_at desc";
|
|
154
154
|
* sqlite.exec(sql`select * from users order by ${sql.raw(orderBy)};`);
|
|
155
155
|
* ```
|
|
156
|
+
*
|
|
157
|
+
* ### TIP
|
|
158
|
+
*
|
|
159
|
+
* Use `prettier-plugin-sql-cst` for SQL formatting. Like Prettier for
|
|
160
|
+
* JavaScript, this plugin formats SQL expressions differently depending on
|
|
161
|
+
* their length.
|
|
156
162
|
*/
|
|
157
163
|
export const sql = (strings, ...parameters) => {
|
|
158
164
|
let sql = "";
|
package/dist/src/Task.d.ts
CHANGED
|
@@ -508,4 +508,79 @@ export declare const createMutex: () => Mutex;
|
|
|
508
508
|
* ```
|
|
509
509
|
*/
|
|
510
510
|
export declare const requestIdleTask: <T, E>(task: Task<T, E>) => Task<T, E>;
|
|
511
|
+
/**
|
|
512
|
+
* Represents a value that can be either synchronous or asynchronous.
|
|
513
|
+
*
|
|
514
|
+
* This type is useful for functions that may complete synchronously or
|
|
515
|
+
* asynchronously depending on runtime conditions (e.g., cache hit vs network
|
|
516
|
+
* fetch).
|
|
517
|
+
*
|
|
518
|
+
* ### Why MaybeAsync?
|
|
519
|
+
*
|
|
520
|
+
* When a function can be sync or async, the typical approaches are:
|
|
521
|
+
*
|
|
522
|
+
* 1. **Always return Promise** - Simple but forces microtask overhead even for
|
|
523
|
+
* sync values (see "await always adds microtask" test in Task.test.ts)
|
|
524
|
+
* 2. **Use callbacks** - Can avoid microtask, but calling code must still `await`
|
|
525
|
+
* for sane composition, which adds microtask anyway
|
|
526
|
+
* 3. **Return `T | PromiseLike<T>`** - Calling code can check the value and only
|
|
527
|
+
* `await` when needed, avoiding microtask overhead for sync cases
|
|
528
|
+
*
|
|
529
|
+
* The third approach (MaybeAsync) provides:
|
|
530
|
+
*
|
|
531
|
+
* - **Performance**: No microtask overhead for synchronous operations
|
|
532
|
+
* - **Reliability**: No interleaving via microtask queue when operations are
|
|
533
|
+
* _synchronous_, reducing need for mutexes to protect shared state
|
|
534
|
+
*
|
|
535
|
+
* ### Example
|
|
536
|
+
*
|
|
537
|
+
* ```ts
|
|
538
|
+
* // Function that may be sync or async
|
|
539
|
+
* const getData = (id: string): MaybeAsync<Data> => {
|
|
540
|
+
* const cached = cache.get(id);
|
|
541
|
+
* if (cached) return cached; // Sync path
|
|
542
|
+
* return fetchData(id); // Async path
|
|
543
|
+
* };
|
|
544
|
+
*
|
|
545
|
+
* // Caller can optimize based on actual behavior
|
|
546
|
+
* const result = getData(id);
|
|
547
|
+
* const data = isAsync(result) ? await result : result;
|
|
548
|
+
* ```
|
|
549
|
+
*
|
|
550
|
+
* ### Alternative Approaches
|
|
551
|
+
*
|
|
552
|
+
* It's possible to eliminate the sync/async distinction using complex
|
|
553
|
+
* frameworks with custom schedulers. However, such frameworks require depending
|
|
554
|
+
* on other people's code that controls how your code executes, resulting in
|
|
555
|
+
* more complex stack traces and debugging experiences. With MaybeAsync, we
|
|
556
|
+
* don't need that machinery - it works directly with JavaScript's native
|
|
557
|
+
* primitives and TypeScript's type system.
|
|
558
|
+
*
|
|
559
|
+
* ### TODO: Consider
|
|
560
|
+
*
|
|
561
|
+
* Use MaybeAsync in Task and Task helpers to preserve synchronous execution
|
|
562
|
+
* when possible (e.g., mutex with available permit, retry on first success).
|
|
563
|
+
*/
|
|
564
|
+
export type MaybeAsync<T> = T | PromiseLike<T>;
|
|
565
|
+
/**
|
|
566
|
+
* Type guard to check if a {@link MaybeAsync} value is async (a promise).
|
|
567
|
+
*
|
|
568
|
+
* This function narrows the type of a {@link MaybeAsync} value, allowing you to
|
|
569
|
+
* conditionally `await` only when necessary.
|
|
570
|
+
*
|
|
571
|
+
* ### Example
|
|
572
|
+
*
|
|
573
|
+
* ```ts
|
|
574
|
+
* const getData = (id: string): MaybeAsync<Data> => {
|
|
575
|
+
* const cached = cache.get(id);
|
|
576
|
+
* if (cached) return cached; // Sync path
|
|
577
|
+
* return fetchData(id); // Async path
|
|
578
|
+
* };
|
|
579
|
+
*
|
|
580
|
+
* const result = getData(id);
|
|
581
|
+
* const data = isAsync(result) ? await result : result;
|
|
582
|
+
* // No microtask overhead when cached!
|
|
583
|
+
* ```
|
|
584
|
+
*/
|
|
585
|
+
export declare const isAsync: <T>(value: MaybeAsync<T>) => value is T extends PromiseLike<unknown> ? never : PromiseLike<T>;
|
|
511
586
|
//# sourceMappingURL=Task.d.ts.map
|
package/dist/src/Task.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../src/Task.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../src/Task.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Task.js
CHANGED
|
@@ -411,12 +411,6 @@ export const createMutex = () => {
|
|
|
411
411
|
[Symbol.dispose]: mutex[Symbol.dispose],
|
|
412
412
|
};
|
|
413
413
|
};
|
|
414
|
-
// TODO: Add tracing support
|
|
415
|
-
// - Extend TaskContext with optional tracing field
|
|
416
|
-
// - Add traced(name, task) helper that wraps Task execution
|
|
417
|
-
// - Collect span data (name, timing, parent-child relationships, status)
|
|
418
|
-
// - Support OpenTelemetry export format with proper traceId/spanId generation
|
|
419
|
-
// - Automatic parent-child span relationships through context propagation
|
|
420
414
|
/**
|
|
421
415
|
* Schedule a task to run after all interactions (animations, gestures,
|
|
422
416
|
* navigation) have completed.
|
|
@@ -444,3 +438,32 @@ export const requestIdleTask = (task) => toTask(async (context) => new Promise((
|
|
|
444
438
|
const idleCallback = typeof globalThis.requestIdleCallback === "function"
|
|
445
439
|
? globalThis.requestIdleCallback
|
|
446
440
|
: (callback) => setTimeout(callback, 0);
|
|
441
|
+
/**
|
|
442
|
+
* Type guard to check if a {@link MaybeAsync} value is async (a promise).
|
|
443
|
+
*
|
|
444
|
+
* This function narrows the type of a {@link MaybeAsync} value, allowing you to
|
|
445
|
+
* conditionally `await` only when necessary.
|
|
446
|
+
*
|
|
447
|
+
* ### Example
|
|
448
|
+
*
|
|
449
|
+
* ```ts
|
|
450
|
+
* const getData = (id: string): MaybeAsync<Data> => {
|
|
451
|
+
* const cached = cache.get(id);
|
|
452
|
+
* if (cached) return cached; // Sync path
|
|
453
|
+
* return fetchData(id); // Async path
|
|
454
|
+
* };
|
|
455
|
+
*
|
|
456
|
+
* const result = getData(id);
|
|
457
|
+
* const data = isAsync(result) ? await result : result;
|
|
458
|
+
* // No microtask overhead when cached!
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
export const isAsync = (value) =>
|
|
462
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
463
|
+
typeof value?.then === "function";
|
|
464
|
+
// TODO: Add tracing support
|
|
465
|
+
// - Extend TaskContext with optional tracing field
|
|
466
|
+
// - Add traced(name, task) helper that wraps Task execution
|
|
467
|
+
// - Collect span data (name, timing, parent-child relationships, status)
|
|
468
|
+
// - Support OpenTelemetry export format with proper traceId/spanId generation
|
|
469
|
+
// - Automatic parent-child span relationships through context propagation
|
package/dist/src/Time.d.ts
CHANGED
|
@@ -12,7 +12,13 @@ export interface Time {
|
|
|
12
12
|
export interface TimeDep {
|
|
13
13
|
readonly time: Time;
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Creates a {@link Time} using Date.now().
|
|
17
|
+
*
|
|
18
|
+
* If the system clock is misconfigured (out of allowed range), the application
|
|
19
|
+
* will fail with an assertion error. This is intentional - there's no
|
|
20
|
+
* reasonable fallback when the system clock is fundamentally wrong.
|
|
21
|
+
*/
|
|
16
22
|
export declare const createTime: () => Time;
|
|
17
23
|
/**
|
|
18
24
|
* Creates a {@link Time} that returns a monotonically increasing number based on
|