@evolu/common 8.6.2 → 8.8.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/dist/src/Array.d.ts +21 -21
- package/dist/src/Array.js +5 -5
- package/dist/src/Assert.d.ts +478 -141
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +644 -99
- package/dist/src/Binary.d.ts +254 -0
- package/dist/src/Binary.d.ts.map +1 -0
- package/dist/src/Binary.js +958 -0
- package/dist/src/Console.d.ts +2 -10
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +6 -12
- package/dist/src/Crypto.d.ts +5 -5
- package/dist/src/Crypto.js +1 -1
- package/dist/src/Eq.d.ts +35 -40
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +51 -87
- package/dist/src/Function.d.ts +9 -14
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +7 -9
- package/dist/src/Http.d.ts +6 -7
- package/dist/src/Http.d.ts.map +1 -1
- package/dist/src/LeakDetector.d.ts.map +1 -1
- package/dist/src/LeakDetector.js +1 -0
- package/dist/src/LockManager.d.ts +1 -1
- package/dist/src/LockManager.js +1 -1
- package/dist/src/Lookup.d.ts +3 -2
- package/dist/src/Lookup.d.ts.map +1 -1
- package/dist/src/Lookup.js +4 -3
- package/dist/src/Number.d.ts +1 -1
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +1 -1
- package/dist/src/Object.d.ts +4 -4
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +5 -4
- package/dist/src/Option.d.ts +1 -2
- package/dist/src/Option.d.ts.map +1 -1
- package/dist/src/Option.js +1 -2
- package/dist/src/Platform.js +2 -0
- package/dist/src/Polyfills.js +4 -1
- package/dist/src/Random.d.ts +1 -1
- package/dist/src/Result.d.ts +49 -54
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +17 -22
- package/dist/src/Set.d.ts +6 -6
- package/dist/src/Set.js +2 -2
- package/dist/src/Sqlite.js +1 -1
- package/dist/src/String.js +3 -2
- package/dist/src/Task.d.ts +32 -32
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +20 -22
- package/dist/src/Test.d.ts +31 -3
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +46 -3
- package/dist/src/Time.d.ts +3 -11
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +10 -18
- package/dist/src/Type.d.ts +87 -85
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +70 -63
- package/dist/src/Types.d.ts +12 -12
- package/dist/src/Types.js +1 -1
- package/dist/src/WebSocket.d.ts +4 -7
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/Worker.d.ts +1 -1
- package/dist/src/Worker.js +7 -7
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/intl/_en.d.ts.map +1 -1
- package/dist/src/intl/_en.js +1 -1
- package/dist/src/intl/ar.d.ts.map +1 -1
- package/dist/src/intl/ar.js +1 -1
- package/dist/src/intl/bn.d.ts.map +1 -1
- package/dist/src/intl/bn.js +1 -1
- package/dist/src/intl/ca.d.ts.map +1 -1
- package/dist/src/intl/ca.js +1 -1
- package/dist/src/intl/cs.d.ts.map +1 -1
- package/dist/src/intl/cs.js +1 -1
- package/dist/src/intl/da.d.ts.map +1 -1
- package/dist/src/intl/da.js +1 -1
- package/dist/src/intl/de.d.ts.map +1 -1
- package/dist/src/intl/de.js +1 -1
- package/dist/src/intl/el.d.ts.map +1 -1
- package/dist/src/intl/el.js +1 -1
- package/dist/src/intl/es.d.ts.map +1 -1
- package/dist/src/intl/es.js +1 -1
- package/dist/src/intl/fa.d.ts.map +1 -1
- package/dist/src/intl/fa.js +1 -1
- package/dist/src/intl/fi.d.ts.map +1 -1
- package/dist/src/intl/fi.js +1 -1
- package/dist/src/intl/fil.d.ts.map +1 -1
- package/dist/src/intl/fil.js +1 -1
- package/dist/src/intl/fr.d.ts.map +1 -1
- package/dist/src/intl/fr.js +1 -1
- package/dist/src/intl/he.d.ts.map +1 -1
- package/dist/src/intl/he.js +1 -1
- package/dist/src/intl/hi.d.ts.map +1 -1
- package/dist/src/intl/hi.js +1 -1
- package/dist/src/intl/hr.d.ts.map +1 -1
- package/dist/src/intl/hr.js +1 -1
- package/dist/src/intl/hu.d.ts.map +1 -1
- package/dist/src/intl/hu.js +1 -1
- package/dist/src/intl/id.d.ts.map +1 -1
- package/dist/src/intl/id.js +1 -1
- package/dist/src/intl/it.d.ts.map +1 -1
- package/dist/src/intl/it.js +1 -1
- package/dist/src/intl/ja.d.ts.map +1 -1
- package/dist/src/intl/ja.js +1 -1
- package/dist/src/intl/ko.d.ts.map +1 -1
- package/dist/src/intl/ko.js +1 -1
- package/dist/src/intl/ml.d.ts.map +1 -1
- package/dist/src/intl/ml.js +1 -1
- package/dist/src/intl/mr.d.ts.map +1 -1
- package/dist/src/intl/mr.js +1 -1
- package/dist/src/intl/ms.d.ts.map +1 -1
- package/dist/src/intl/ms.js +1 -1
- package/dist/src/intl/nb.d.ts.map +1 -1
- package/dist/src/intl/nb.js +1 -1
- package/dist/src/intl/nl.d.ts.map +1 -1
- package/dist/src/intl/nl.js +1 -1
- package/dist/src/intl/pa.d.ts.map +1 -1
- package/dist/src/intl/pa.js +1 -1
- package/dist/src/intl/pl.d.ts.map +1 -1
- package/dist/src/intl/pl.js +1 -1
- package/dist/src/intl/pt-BR.d.ts.map +1 -1
- package/dist/src/intl/pt-BR.js +1 -1
- package/dist/src/intl/pt.d.ts.map +1 -1
- package/dist/src/intl/pt.js +1 -1
- package/dist/src/intl/ro.d.ts.map +1 -1
- package/dist/src/intl/ro.js +1 -1
- package/dist/src/intl/sk.d.ts.map +1 -1
- package/dist/src/intl/sk.js +1 -1
- package/dist/src/intl/sl.d.ts.map +1 -1
- package/dist/src/intl/sl.js +1 -1
- package/dist/src/intl/sv.d.ts.map +1 -1
- package/dist/src/intl/sv.js +1 -1
- package/dist/src/intl/sw.d.ts.map +1 -1
- package/dist/src/intl/sw.js +1 -1
- package/dist/src/intl/ta.d.ts.map +1 -1
- package/dist/src/intl/ta.js +1 -1
- package/dist/src/intl/te.d.ts.map +1 -1
- package/dist/src/intl/te.js +1 -1
- package/dist/src/intl/th.d.ts.map +1 -1
- package/dist/src/intl/th.js +1 -1
- package/dist/src/intl/tr.d.ts.map +1 -1
- package/dist/src/intl/tr.js +1 -1
- package/dist/src/intl/uk.d.ts.map +1 -1
- package/dist/src/intl/uk.js +1 -1
- package/dist/src/intl/ur.d.ts.map +1 -1
- package/dist/src/intl/ur.js +1 -1
- package/dist/src/intl/vi.d.ts.map +1 -1
- package/dist/src/intl/vi.js +1 -1
- package/dist/src/intl/zh-CN.d.ts.map +1 -1
- package/dist/src/intl/zh-CN.js +1 -1
- package/dist/src/intl/zh-TW.d.ts.map +1 -1
- package/dist/src/intl/zh-TW.js +1 -1
- package/dist/src/local-first/Evolu.d.ts +12 -12
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +2 -2
- package/dist/src/local-first/Protocol.d.ts +28 -76
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +45 -229
- package/dist/src/local-first/Query.d.ts +11 -11
- package/dist/src/local-first/Query.js +6 -6
- package/dist/src/local-first/Relay.d.ts +2 -2
- package/dist/src/local-first/Schema.d.ts +3 -5
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +2 -4
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +5 -5
- package/dist/src/local-first/Storage.js +4 -4
- package/dist/src/local-first/Timestamp.d.ts +9 -0
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +13 -10
- package/package.json +7 -5
- package/src/Array.test.ts +809 -0
- package/src/Array.ts +21 -21
- package/src/Assert.test.ts +1181 -0
- package/src/Assert.ts +971 -227
- package/src/BigInt.test.ts +28 -0
- package/src/Binary.test.ts +1128 -0
- package/src/Binary.ts +1377 -0
- package/src/Brand.test.ts +90 -0
- package/src/Cache.test.ts +183 -0
- package/src/Callbacks.test.ts +66 -0
- package/src/Console.test.ts +809 -0
- package/src/Console.ts +9 -17
- package/src/Crypto.test.ts +138 -0
- package/src/Crypto.ts +5 -5
- package/src/Eq.test.ts +333 -0
- package/src/Eq.ts +110 -176
- package/src/Error.test.ts +118 -0
- package/src/Function.test.ts +204 -0
- package/src/Function.ts +10 -15
- package/src/Http.test.ts +816 -0
- package/src/Http.ts +6 -7
- package/src/LeakDetector.test.ts +210 -0
- package/src/LeakDetector.ts +1 -0
- package/src/LockManager.ts +2 -2
- package/src/Lookup.test.ts +418 -0
- package/src/Lookup.ts +4 -3
- package/src/Microtask.test.ts +140 -0
- package/src/Number.test.ts +218 -0
- package/src/Number.ts +2 -2
- package/src/Object.test.ts +293 -0
- package/src/Object.ts +5 -4
- package/src/Option.test.ts +104 -0
- package/src/Option.ts +1 -2
- package/src/Order.test.ts +56 -0
- package/src/Platform.ts +2 -0
- package/src/Polyfills.ts +3 -4
- package/src/Random.test.ts +89 -0
- package/src/Random.ts +1 -1
- package/src/Ref.test.ts +139 -0
- package/src/RefCount.test.ts +184 -0
- package/src/Relation.test.ts +505 -0
- package/src/Resource.test.ts +4623 -0
- package/src/Result.test.ts +1829 -0
- package/src/Result.ts +49 -54
- package/src/Schedule.test.ts +1554 -0
- package/src/Set.test.ts +279 -0
- package/src/Set.ts +6 -6
- package/src/Sqlite.ts +1 -1
- package/src/Store.test.ts +288 -0
- package/src/String.test.ts +54 -0
- package/src/String.ts +3 -3
- package/src/Task.test.ts +10820 -0
- package/src/Task.ts +38 -43
- package/src/Test.test.ts +88 -0
- package/src/Test.ts +49 -3
- package/src/Time.test.ts +926 -0
- package/src/Time.ts +13 -21
- package/src/Type.base64.test.ts +88 -0
- package/src/Type.test.ts +20465 -0
- package/src/Type.ts +114 -111
- package/src/Types.test.ts +324 -0
- package/src/Types.ts +13 -13
- package/src/WebSocket.ts +4 -7
- package/src/Worker.test.ts +755 -0
- package/src/Worker.ts +13 -18
- package/src/index.ts +1 -1
- package/src/intl/_en.ts +1 -1
- package/src/intl/ar.ts +1 -1
- package/src/intl/bn.ts +1 -1
- package/src/intl/ca.ts +1 -1
- package/src/intl/cs.ts +1 -1
- package/src/intl/da.ts +1 -1
- package/src/intl/de.ts +1 -1
- package/src/intl/el.ts +1 -1
- package/src/intl/es.ts +1 -1
- package/src/intl/fa.ts +1 -1
- package/src/intl/fi.ts +1 -1
- package/src/intl/fil.ts +1 -1
- package/src/intl/fr.ts +1 -1
- package/src/intl/he.ts +1 -1
- package/src/intl/hi.ts +1 -1
- package/src/intl/hr.ts +1 -1
- package/src/intl/hu.ts +1 -1
- package/src/intl/id.ts +1 -1
- package/src/intl/intl.test.ts +3106 -0
- package/src/intl/it.ts +1 -1
- package/src/intl/ja.ts +1 -1
- package/src/intl/ko.ts +1 -1
- package/src/intl/ml.ts +1 -1
- package/src/intl/mr.ts +1 -1
- package/src/intl/ms.ts +1 -1
- package/src/intl/nb.ts +1 -1
- package/src/intl/nl.ts +1 -1
- package/src/intl/pa.ts +1 -1
- package/src/intl/pl.ts +1 -1
- package/src/intl/pt-BR.ts +1 -1
- package/src/intl/pt.ts +1 -1
- package/src/intl/ro.ts +1 -1
- package/src/intl/sk.ts +1 -1
- package/src/intl/sl.ts +1 -1
- package/src/intl/sv.ts +1 -1
- package/src/intl/sw.ts +1 -1
- package/src/intl/ta.ts +1 -1
- package/src/intl/te.ts +1 -1
- package/src/intl/th.ts +1 -1
- package/src/intl/tr.ts +1 -1
- package/src/intl/uk.ts +1 -1
- package/src/intl/ur.ts +1 -1
- package/src/intl/vi.ts +1 -1
- package/src/intl/zh-CN.ts +1 -1
- package/src/intl/zh-TW.ts +1 -1
- package/src/local-first/Evolu.test.ts +1921 -0
- package/src/local-first/Evolu.ts +18 -14
- package/src/local-first/Owner.test.ts +83 -0
- package/src/local-first/Protocol.test.ts +1037 -0
- package/src/local-first/Protocol.ts +75 -290
- package/src/local-first/Query.test.ts +349 -0
- package/src/local-first/Query.ts +11 -11
- package/src/local-first/Relay.ts +2 -2
- package/src/local-first/Schema.ts +3 -5
- package/src/local-first/Shared.test.ts +1828 -0
- package/src/local-first/Shared.ts +9 -8
- package/src/local-first/Storage.ts +4 -4
- package/src/local-first/Timestamp.test.ts +374 -0
- package/src/local-first/Timestamp.ts +22 -10
- package/dist/src/Buffer.d.ts +0 -122
- package/dist/src/Buffer.d.ts.map +0 -1
- package/dist/src/Buffer.js +0 -69
- package/src/Buffer.ts +0 -206
|
@@ -170,29 +170,41 @@
|
|
|
170
170
|
* initiator/non-initiator terminology instead, and consolidate into a single
|
|
171
171
|
* `applyProtocolMessage` function with conditional arguments to reduce code
|
|
172
172
|
* duplication.
|
|
173
|
-
* - Replace try-catch with Result + new Error (to preserve stacktraces). Measure
|
|
174
|
-
* Result overhead, it should be super small.
|
|
175
173
|
* - Allow clients to broadcast messages that are not persisted by relays. This
|
|
176
174
|
* would enable real-time ephemeral data (like cursor positions, typing
|
|
177
175
|
* indicators) to be forwarded by relays without storage overhead.
|
|
178
176
|
*/
|
|
179
177
|
|
|
180
|
-
import { Packr } from "msgpackr";
|
|
181
178
|
import {
|
|
182
179
|
createMutableArray,
|
|
183
180
|
isNonEmptyArray,
|
|
184
181
|
type NonEmptyReadonlyArray,
|
|
185
182
|
} from "../Array.ts";
|
|
186
|
-
import {
|
|
183
|
+
import {
|
|
184
|
+
assert,
|
|
185
|
+
assertNonNullable,
|
|
186
|
+
assertNotUndefined,
|
|
187
|
+
assertSame,
|
|
188
|
+
} from "../Assert.ts";
|
|
187
189
|
import type { Brand } from "../Brand.ts";
|
|
188
190
|
import {
|
|
189
191
|
type Buffer,
|
|
190
|
-
bytesToHex,
|
|
191
|
-
bytesToUtf8,
|
|
192
192
|
createBuffer,
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
createRunLengthEncoder,
|
|
194
|
+
decodeFlags,
|
|
195
|
+
decodeJsonValue,
|
|
196
|
+
decodeLength,
|
|
197
|
+
decodeNonNegativeInt,
|
|
198
|
+
decodeNumber,
|
|
199
|
+
decodeRle,
|
|
200
|
+
decodeString,
|
|
201
|
+
encodeFlags,
|
|
202
|
+
encodeJsonValue,
|
|
203
|
+
encodeLength,
|
|
204
|
+
encodeNonNegativeInt,
|
|
205
|
+
encodeNumber,
|
|
206
|
+
encodeString,
|
|
207
|
+
} from "../Binary.ts";
|
|
196
208
|
import type { ConsoleDep } from "../Console.ts";
|
|
197
209
|
import {
|
|
198
210
|
createPadmePadding,
|
|
@@ -209,10 +221,11 @@ import { eqArrayNumber } from "../Eq.ts";
|
|
|
209
221
|
import { computeBalancedBuckets } from "../Number.ts";
|
|
210
222
|
import { createMutableRecord, objectToEntries } from "../Object.ts";
|
|
211
223
|
import { err, ok, type Result } from "../Result.ts";
|
|
212
|
-
import { SqliteValue } from "../Sqlite.ts";
|
|
224
|
+
import type { SqliteValue } from "../Sqlite.ts";
|
|
213
225
|
import { AbortError, type Task } from "../Task.ts";
|
|
214
226
|
import { Millis } from "../Time.ts";
|
|
215
227
|
import {
|
|
228
|
+
assertType,
|
|
216
229
|
Base64Url,
|
|
217
230
|
base64UrlToUint8Array,
|
|
218
231
|
between,
|
|
@@ -264,6 +277,10 @@ import {
|
|
|
264
277
|
Counter,
|
|
265
278
|
eqTimestamp,
|
|
266
279
|
NodeId,
|
|
280
|
+
type NodeIdBytes,
|
|
281
|
+
nodeIdBytesLength,
|
|
282
|
+
nodeIdBytesToNodeId,
|
|
283
|
+
nodeIdToNodeIdBytes,
|
|
267
284
|
Timestamp,
|
|
268
285
|
TimestampBytes,
|
|
269
286
|
timestampBytesLength,
|
|
@@ -271,14 +288,6 @@ import {
|
|
|
271
288
|
timestampToTimestampBytes,
|
|
272
289
|
} from "./Timestamp.ts";
|
|
273
290
|
|
|
274
|
-
/**
|
|
275
|
-
* Evolu uses MessagePack for numbers and JSONs.
|
|
276
|
-
*
|
|
277
|
-
* - `variableMapSize: true` - More compact maps, ~5-10% slower encoding
|
|
278
|
-
* - `useRecords: false` - Standard MessagePack without extensions
|
|
279
|
-
*/
|
|
280
|
-
const packr = new Packr({ variableMapSize: true, useRecords: false });
|
|
281
|
-
|
|
282
291
|
const minProtocolMessageMaxSize = 1_000_000;
|
|
283
292
|
const maxProtocolMessageMaxSize = 100_000_000;
|
|
284
293
|
|
|
@@ -434,7 +443,7 @@ export interface ProtocolVersionError
|
|
|
434
443
|
|
|
435
444
|
/** Error for invalid or corrupted protocol message data. */
|
|
436
445
|
export interface ProtocolInvalidDataError extends Typed<"ProtocolInvalidDataError"> {
|
|
437
|
-
readonly data:
|
|
446
|
+
readonly data: Uint8Array;
|
|
438
447
|
readonly error: unknown;
|
|
439
448
|
}
|
|
440
449
|
|
|
@@ -843,13 +852,13 @@ export const createTimestampsBuffer = (): TimestampsBuffer => {
|
|
|
843
852
|
encodeNonNegativeInt(buffer, value);
|
|
844
853
|
});
|
|
845
854
|
const nodeIdEncoder = createRunLengthEncoder<NodeId>((buffer, value) => {
|
|
846
|
-
|
|
855
|
+
buffer.extend(nodeIdToNodeIdBytes(value));
|
|
847
856
|
});
|
|
848
857
|
|
|
849
858
|
return {
|
|
850
859
|
add: (timestamp) => {
|
|
851
860
|
const delta = timestamp.millis - previousMillis;
|
|
852
|
-
|
|
861
|
+
assertType(NonNegativeInt, delta);
|
|
853
862
|
|
|
854
863
|
count++;
|
|
855
864
|
syncCount();
|
|
@@ -883,40 +892,6 @@ export const createTimestampsBuffer = (): TimestampsBuffer => {
|
|
|
883
892
|
};
|
|
884
893
|
};
|
|
885
894
|
|
|
886
|
-
interface RunLengthEncoder<T> {
|
|
887
|
-
add: (value: T) => void;
|
|
888
|
-
getLength: () => NonNegativeInt;
|
|
889
|
-
unwrap: () => Uint8Array;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
const createRunLengthEncoder = <T>(
|
|
893
|
-
encodeValue: (buffer: Buffer, value: T) => void,
|
|
894
|
-
): RunLengthEncoder<T> => {
|
|
895
|
-
const buffer = createBuffer();
|
|
896
|
-
let previousLength = zeroNonNegativeInt;
|
|
897
|
-
let previousValue = null as T | null;
|
|
898
|
-
let runLength = zeroNonNegativeInt;
|
|
899
|
-
|
|
900
|
-
return {
|
|
901
|
-
add: (value) => {
|
|
902
|
-
if (value === previousValue) {
|
|
903
|
-
runLength++;
|
|
904
|
-
buffer.truncate(previousLength);
|
|
905
|
-
} else {
|
|
906
|
-
previousValue = value;
|
|
907
|
-
runLength = NonNegativeInt.orThrow(1);
|
|
908
|
-
}
|
|
909
|
-
previousLength = buffer.getLength();
|
|
910
|
-
encodeValue(buffer, value);
|
|
911
|
-
encodeNonNegativeInt(buffer, runLength);
|
|
912
|
-
},
|
|
913
|
-
|
|
914
|
-
getLength: () => buffer.getLength(),
|
|
915
|
-
|
|
916
|
-
unwrap: () => buffer.unwrap(),
|
|
917
|
-
};
|
|
918
|
-
};
|
|
919
|
-
|
|
920
895
|
export interface ApplyProtocolMessageAsClientOptions {
|
|
921
896
|
writeKey?: OwnerWriteKey;
|
|
922
897
|
|
|
@@ -1130,7 +1105,7 @@ export const applyProtocolMessageAsRelay =
|
|
|
1130
1105
|
}
|
|
1131
1106
|
|
|
1132
1107
|
const messageType = input.shift() as MessageType;
|
|
1133
|
-
|
|
1108
|
+
assertSame(messageType, MessageType.Request);
|
|
1134
1109
|
|
|
1135
1110
|
const hasWriteKey = input.shift();
|
|
1136
1111
|
let writeKey: OwnerWriteKey | undefined;
|
|
@@ -1722,7 +1697,9 @@ const decodeTimestamps = (
|
|
|
1722
1697
|
return counter.value;
|
|
1723
1698
|
});
|
|
1724
1699
|
|
|
1725
|
-
const nodeIds = decodeRle(buffer, length, (): NodeId =>
|
|
1700
|
+
const nodeIds = decodeRle(buffer, length, (): NodeId =>
|
|
1701
|
+
nodeIdBytesToNodeId(buffer.shiftN(nodeIdBytesLength) as NodeIdBytes),
|
|
1702
|
+
);
|
|
1726
1703
|
|
|
1727
1704
|
const timestamps = createMutableArray<Timestamp>(length);
|
|
1728
1705
|
for (let i = 0; i < length; i++) {
|
|
@@ -1736,135 +1713,11 @@ const decodeTimestamps = (
|
|
|
1736
1713
|
return timestamps;
|
|
1737
1714
|
};
|
|
1738
1715
|
|
|
1739
|
-
export const decodeRle = <T>(
|
|
1740
|
-
buffer: Buffer,
|
|
1741
|
-
length: NonNegativeInt,
|
|
1742
|
-
decodeValue: () => T,
|
|
1743
|
-
): ReadonlyArray<T> => {
|
|
1744
|
-
const values = createMutableArray<T>(length);
|
|
1745
|
-
let index = 0;
|
|
1746
|
-
while (index < length) {
|
|
1747
|
-
const value = decodeValue();
|
|
1748
|
-
const runLength = decodeNonNegativeInt(buffer);
|
|
1749
|
-
|
|
1750
|
-
// Prevent infinite loop on malformed input.
|
|
1751
|
-
if (runLength === 0) {
|
|
1752
|
-
throw new ProtocolDecodeError(
|
|
1753
|
-
"Invalid RLE encoding: runLength must be positive",
|
|
1754
|
-
);
|
|
1755
|
-
}
|
|
1756
|
-
const remaining = length - index;
|
|
1757
|
-
|
|
1758
|
-
// Prevent CPU/memory amplification via oversized runLength.
|
|
1759
|
-
if (runLength > remaining) {
|
|
1760
|
-
throw new ProtocolDecodeError(
|
|
1761
|
-
`Invalid RLE encoding: runLength ${runLength} exceeds remaining ${remaining}`,
|
|
1762
|
-
);
|
|
1763
|
-
}
|
|
1764
|
-
for (let i = 0; i < runLength; i++) {
|
|
1765
|
-
values[index] = value;
|
|
1766
|
-
index++;
|
|
1767
|
-
}
|
|
1768
|
-
}
|
|
1769
|
-
return values;
|
|
1770
|
-
};
|
|
1771
|
-
|
|
1772
1716
|
const decodeId = (buffer: Buffer): Id => {
|
|
1773
1717
|
const bytes = buffer.shiftN(idBytesTypeValueLength);
|
|
1774
1718
|
return idBytesToId(bytes as IdBytes);
|
|
1775
1719
|
};
|
|
1776
1720
|
|
|
1777
|
-
/**
|
|
1778
|
-
* Evolu uses MessagePack to handle finite numbers except for NonNegativeInt.
|
|
1779
|
-
* For NonNegativeInt, Evolu provides more efficient encoding.
|
|
1780
|
-
*/
|
|
1781
|
-
export const encodeNumber = (buffer: Buffer, number: FiniteNumber): void => {
|
|
1782
|
-
buffer.extend(packr.pack(number));
|
|
1783
|
-
};
|
|
1784
|
-
|
|
1785
|
-
export const decodeNumber = (buffer: Buffer): FiniteNumber => {
|
|
1786
|
-
let number: unknown;
|
|
1787
|
-
let end: unknown;
|
|
1788
|
-
|
|
1789
|
-
packr.unpackMultiple(
|
|
1790
|
-
buffer.unwrap(),
|
|
1791
|
-
(n: unknown, _: unknown, e: unknown) => {
|
|
1792
|
-
number = n;
|
|
1793
|
-
end = e;
|
|
1794
|
-
return false;
|
|
1795
|
-
},
|
|
1796
|
-
);
|
|
1797
|
-
|
|
1798
|
-
const endResult = NonNegativeInt.fromUnknown(end);
|
|
1799
|
-
if (!endResult.ok) throw new ProtocolDecodeError(endResult.error.type);
|
|
1800
|
-
|
|
1801
|
-
const numberResult = FiniteNumber.fromUnknown(number);
|
|
1802
|
-
if (!numberResult.ok) throw new ProtocolDecodeError(numberResult.error.type);
|
|
1803
|
-
|
|
1804
|
-
buffer.shiftN(endResult.value);
|
|
1805
|
-
return numberResult.value;
|
|
1806
|
-
};
|
|
1807
|
-
|
|
1808
|
-
/**
|
|
1809
|
-
* Encodes an array of boolean flags into a single byte.
|
|
1810
|
-
*
|
|
1811
|
-
* Each element in the array corresponds to a bit (0-7). Array can have 0-8
|
|
1812
|
-
* elements.
|
|
1813
|
-
*
|
|
1814
|
-
* ### Example
|
|
1815
|
-
*
|
|
1816
|
-
* ```ts
|
|
1817
|
-
* import { assertEqual, createBuffer } from "@evolu/common";
|
|
1818
|
-
* import { encodeFlags } from "@evolu/common/local-first";
|
|
1819
|
-
*
|
|
1820
|
-
* const buffer = createBuffer();
|
|
1821
|
-
* encodeFlags(buffer, [true, false, true]);
|
|
1822
|
-
*
|
|
1823
|
-
* assertEqual(buffer.unwrap(), new Uint8Array([0b101]));
|
|
1824
|
-
* ```
|
|
1825
|
-
*/
|
|
1826
|
-
export const encodeFlags = (
|
|
1827
|
-
buffer: Buffer,
|
|
1828
|
-
flags: ReadonlyArray<boolean>,
|
|
1829
|
-
): void => {
|
|
1830
|
-
let byte = 0;
|
|
1831
|
-
for (let i = 0; i < flags.length && i < 8; i++) {
|
|
1832
|
-
if (flags[i]) {
|
|
1833
|
-
byte |= 1 << i;
|
|
1834
|
-
}
|
|
1835
|
-
}
|
|
1836
|
-
buffer.extend([byte]);
|
|
1837
|
-
};
|
|
1838
|
-
|
|
1839
|
-
/**
|
|
1840
|
-
* Decodes a byte into an array of boolean flags.
|
|
1841
|
-
*
|
|
1842
|
-
* ### Example
|
|
1843
|
-
*
|
|
1844
|
-
* ```ts
|
|
1845
|
-
* import { assertEqual, createBuffer, PositiveInt } from "@evolu/common";
|
|
1846
|
-
* import { decodeFlags } from "@evolu/common/local-first";
|
|
1847
|
-
*
|
|
1848
|
-
* const buffer = createBuffer([0b101]);
|
|
1849
|
-
* const flags = decodeFlags(buffer, PositiveInt.orThrow(3));
|
|
1850
|
-
*
|
|
1851
|
-
* assertEqual(flags, [true, false, true]);
|
|
1852
|
-
* assertEqual(buffer.getLength(), 0);
|
|
1853
|
-
* ```
|
|
1854
|
-
*/
|
|
1855
|
-
export const decodeFlags = (
|
|
1856
|
-
buffer: Buffer,
|
|
1857
|
-
count: PositiveInt,
|
|
1858
|
-
): ReadonlyArray<boolean> => {
|
|
1859
|
-
const byte = buffer.shift();
|
|
1860
|
-
const length = globalThis.Math.min(count, 8);
|
|
1861
|
-
const flags = createMutableArray<boolean>(length);
|
|
1862
|
-
for (let i = 0; i < length; i++) {
|
|
1863
|
-
flags[i] = (byte & (1 << i)) !== 0;
|
|
1864
|
-
}
|
|
1865
|
-
return flags;
|
|
1866
|
-
};
|
|
1867
|
-
|
|
1868
1721
|
/**
|
|
1869
1722
|
* Encodes and encrypts a {@link DbChange} using the provided owner's encryption
|
|
1870
1723
|
* key. Returns an encrypted binary representation as {@link EncryptedDbChange}.
|
|
@@ -1996,91 +1849,30 @@ export const decryptAndDecodeDbChange = (
|
|
|
1996
1849
|
};
|
|
1997
1850
|
|
|
1998
1851
|
/**
|
|
1999
|
-
*
|
|
2000
|
-
* more efficient than encoding via {@link encodeNumber}.
|
|
1852
|
+
* Decodes a ProtocolMessage into a readable JSON object for debugging.
|
|
2001
1853
|
*
|
|
2002
|
-
*
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
if (int === 0) {
|
|
2009
|
-
buffer.extend([0]);
|
|
2010
|
-
return;
|
|
2011
|
-
}
|
|
2012
|
-
|
|
2013
|
-
let remaining = BigInt(int);
|
|
2014
|
-
const bytes: Array<number> = [];
|
|
2015
|
-
|
|
2016
|
-
while (remaining !== 0n) {
|
|
2017
|
-
const byte = globalThis.Number(remaining & 127n);
|
|
2018
|
-
bytes.push(byte);
|
|
2019
|
-
remaining >>= 7n;
|
|
2020
|
-
}
|
|
2021
|
-
|
|
2022
|
-
for (let i = 0; i < bytes.length - 1; i++) {
|
|
2023
|
-
bytes[i] |= 128;
|
|
2024
|
-
}
|
|
2025
|
-
|
|
2026
|
-
buffer.extend(bytes);
|
|
2027
|
-
};
|
|
2028
|
-
|
|
2029
|
-
/**
|
|
2030
|
-
* Decodes a non-negative integer from a variable-length integer format.
|
|
1854
|
+
* Note: This is a stub for future implementation. It should use:
|
|
1855
|
+
*
|
|
1856
|
+
* - DecodeVersionAndOwner
|
|
1857
|
+
* - DecodeError or decodeWriteKeys (depending on context)
|
|
1858
|
+
* - DecodeMessages
|
|
1859
|
+
* - DecodeRanges
|
|
2031
1860
|
*
|
|
2032
|
-
*
|
|
1861
|
+
* If you want to help, please contribute to this function.
|
|
2033
1862
|
*/
|
|
2034
|
-
export const
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
//
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
shift += 7n;
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
const int = NonNegativeInt.fromUnknown(globalThis.Number(result));
|
|
2048
|
-
if (!int.ok) throw new ProtocolDecodeError(int.error.type);
|
|
2049
|
-
|
|
2050
|
-
return int.value;
|
|
2051
|
-
};
|
|
2052
|
-
|
|
2053
|
-
export const encodeLength = (buffer: Buffer, value: ArrayLike<any>): void => {
|
|
2054
|
-
encodeNonNegativeInt(buffer, NonNegativeInt.orThrow(value.length));
|
|
2055
|
-
};
|
|
2056
|
-
|
|
2057
|
-
export const decodeLength = decodeNonNegativeInt;
|
|
2058
|
-
|
|
2059
|
-
export const encodeString = (buffer: Buffer, value: string): void => {
|
|
2060
|
-
const bytes = utf8ToBytes(value);
|
|
2061
|
-
encodeLength(buffer, bytes);
|
|
2062
|
-
buffer.extend(bytes);
|
|
2063
|
-
};
|
|
2064
|
-
|
|
2065
|
-
export const decodeString = (buffer: Buffer): string => {
|
|
2066
|
-
const length = decodeLength(buffer);
|
|
2067
|
-
const bytes = buffer.shiftN(length);
|
|
2068
|
-
return bytesToUtf8(bytes);
|
|
2069
|
-
};
|
|
2070
|
-
|
|
2071
|
-
export const encodeNodeId = (buffer: Buffer, nodeId: NodeId): void => {
|
|
2072
|
-
buffer.extend(hexToBytes(nodeId));
|
|
2073
|
-
};
|
|
2074
|
-
|
|
2075
|
-
export const decodeNodeId = (buffer: Buffer): NodeId => {
|
|
2076
|
-
const bytes = buffer.shiftN(NonNegativeInt.orThrow(8));
|
|
2077
|
-
return bytesToHex(bytes) as NodeId;
|
|
1863
|
+
export const decodeProtocolMessageToJson = (
|
|
1864
|
+
_protocolMessage: ProtocolMessage,
|
|
1865
|
+
_isInitiator: boolean,
|
|
1866
|
+
): unknown => {
|
|
1867
|
+
// TODO: Implement using
|
|
1868
|
+
// - decodeVersionAndOwner
|
|
1869
|
+
// -- decodeError or decodeWriteKeys (should be refactored out),
|
|
1870
|
+
// -- decodeMessages, and decodeRanges.
|
|
1871
|
+
// This is a stub for PRs and community contributions.
|
|
1872
|
+
throw new Error("decodeProtocolMessageToJson is not implemented yet.");
|
|
2078
1873
|
};
|
|
2079
1874
|
|
|
2080
1875
|
// Small ints are encoded into ProtocolValueType, saving one byte per int.
|
|
2081
|
-
const isSmallInt: Predicate<number> = (value: number) =>
|
|
2082
|
-
value >= 0 && value < 20;
|
|
2083
|
-
|
|
2084
1876
|
export const ProtocolValueType = {
|
|
2085
1877
|
// 0-19 small ints
|
|
2086
1878
|
|
|
@@ -2157,10 +1949,16 @@ export const encodeSqliteValue = (buffer: Buffer, value: SqliteValue): void => {
|
|
|
2157
1949
|
// Some valid JSON strings like "-0E0" get normalized to "0" during parsing,
|
|
2158
1950
|
// which would cause data corruption if we don't verify round-trip safety.
|
|
2159
1951
|
if (json.ok && JSON.stringify(jsonToJsonValue(json.value)) === value) {
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
1952
|
+
jsonBuffer.reset();
|
|
1953
|
+
try {
|
|
1954
|
+
encodeJsonValue(jsonBuffer, jsonToJsonValue(json.value));
|
|
1955
|
+
const jsonBytes = jsonBuffer.unwrap();
|
|
1956
|
+
encodeNonNegativeInt(buffer, ProtocolValueType.Json);
|
|
1957
|
+
encodeLength(buffer, jsonBytes);
|
|
1958
|
+
buffer.extend(jsonBytes);
|
|
1959
|
+
} finally {
|
|
1960
|
+
jsonBuffer.reset();
|
|
1961
|
+
}
|
|
2164
1962
|
return;
|
|
2165
1963
|
}
|
|
2166
1964
|
|
|
@@ -2179,7 +1977,9 @@ export const encodeSqliteValue = (buffer: Buffer, value: SqliteValue): void => {
|
|
|
2179
1977
|
}
|
|
2180
1978
|
|
|
2181
1979
|
case "number": {
|
|
2182
|
-
|
|
1980
|
+
// Negative zero is a non-negative integer in JavaScript, but integer
|
|
1981
|
+
// encoding would lose its observable sign.
|
|
1982
|
+
if (!Object.is(value, -0) && NonNegativeInt.is(value)) {
|
|
2183
1983
|
if (isSmallInt(value)) {
|
|
2184
1984
|
encodeNonNegativeInt(buffer, value);
|
|
2185
1985
|
return;
|
|
@@ -2229,8 +2029,12 @@ export const decodeSqliteValue = (buffer: Buffer): SqliteValue => {
|
|
|
2229
2029
|
|
|
2230
2030
|
case ProtocolValueType.Json: {
|
|
2231
2031
|
const length = decodeLength(buffer);
|
|
2232
|
-
const
|
|
2233
|
-
|
|
2032
|
+
const jsonValueBuffer = createBuffer(buffer.shiftN(length));
|
|
2033
|
+
const value = decodeJsonValue(jsonValueBuffer);
|
|
2034
|
+
if (jsonValueBuffer.getLength() !== 0) {
|
|
2035
|
+
throw new ProtocolDecodeError("Invalid JSON MessagePack length");
|
|
2036
|
+
}
|
|
2037
|
+
return JSON.stringify(value);
|
|
2234
2038
|
}
|
|
2235
2039
|
|
|
2236
2040
|
case ProtocolValueType.DateIsoWithNonNegativeTime:
|
|
@@ -2258,26 +2062,7 @@ export const decodeSqliteValue = (buffer: Buffer): SqliteValue => {
|
|
|
2258
2062
|
}
|
|
2259
2063
|
};
|
|
2260
2064
|
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
*
|
|
2266
|
-
* - DecodeVersionAndOwner
|
|
2267
|
-
* - DecodeError or decodeWriteKeys (depending on context)
|
|
2268
|
-
* - DecodeMessages
|
|
2269
|
-
* - DecodeRanges
|
|
2270
|
-
*
|
|
2271
|
-
* If you want to help, please contribute to this function.
|
|
2272
|
-
*/
|
|
2273
|
-
export const decodeProtocolMessageToJson = (
|
|
2274
|
-
_protocolMessage: ProtocolMessage,
|
|
2275
|
-
_isInitiator: boolean,
|
|
2276
|
-
): unknown => {
|
|
2277
|
-
// TODO: Implement using
|
|
2278
|
-
// - decodeVersionAndOwner
|
|
2279
|
-
// -- decodeError or decodeWriteKeys (should be refactored out),
|
|
2280
|
-
// -- decodeMessages, and decodeRanges.
|
|
2281
|
-
// This is a stub for PRs and community contributions.
|
|
2282
|
-
throw new Error("decodeProtocolMessageToJson is not implemented yet.");
|
|
2283
|
-
};
|
|
2065
|
+
const jsonBuffer = createBuffer();
|
|
2066
|
+
|
|
2067
|
+
const isSmallInt: Predicate<number> = (value: number) =>
|
|
2068
|
+
value >= 0 && value < 20;
|