@evolu/common 7.4.1 → 8.0.0-next.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 +4 -61
- package/dist/src/Array.d.ts +343 -102
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +181 -85
- package/dist/src/Assert.d.ts +57 -11
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +47 -11
- package/dist/src/BigInt.d.ts +6 -1
- package/dist/src/BigInt.d.ts.map +1 -1
- package/dist/src/BigInt.js +5 -0
- package/dist/src/Brand.d.ts +40 -12
- package/dist/src/Brand.d.ts.map +1 -1
- package/dist/src/Brand.js +5 -0
- package/dist/src/Buffer.d.ts +6 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +7 -2
- package/dist/src/Cache.d.ts +10 -2
- package/dist/src/Cache.d.ts.map +1 -1
- package/dist/src/Cache.js +6 -0
- package/dist/src/Callbacks.d.ts +10 -7
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Callbacks.js +23 -13
- package/dist/src/Console.d.ts +361 -69
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +217 -117
- package/dist/src/Crypto.d.ts +70 -21
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +72 -27
- package/dist/src/Eq.d.ts +22 -2
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +21 -1
- package/dist/src/Error.d.ts +23 -12
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +27 -11
- package/dist/src/Function.d.ts +128 -56
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +118 -14
- package/dist/src/Identicon.d.ts +5 -0
- package/dist/src/Identicon.d.ts.map +1 -1
- package/dist/src/Identicon.js +6 -1
- package/dist/src/Lookup.d.ts +160 -0
- package/dist/src/Lookup.d.ts.map +1 -0
- package/dist/src/Lookup.js +192 -0
- package/dist/src/Microtask.d.ts +21 -0
- package/dist/src/Microtask.d.ts.map +1 -0
- package/dist/src/Microtask.js +37 -0
- package/dist/src/Number.d.ts +18 -4
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +23 -1
- package/dist/src/Object.d.ts +110 -5
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +108 -5
- package/dist/src/Option.d.ts +58 -0
- package/dist/src/Option.d.ts.map +1 -0
- package/dist/src/Option.js +43 -0
- package/dist/src/Order.d.ts +5 -0
- package/dist/src/Order.d.ts.map +1 -1
- package/dist/src/Order.js +8 -3
- package/dist/src/Platform.d.ts +36 -2
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +10 -6
- package/dist/src/Polyfills.d.ts +27 -0
- package/dist/src/Polyfills.d.ts.map +1 -0
- package/dist/src/Polyfills.js +299 -0
- package/dist/src/Random.d.ts +18 -7
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +9 -7
- package/dist/src/Redacted.d.ts +7 -4
- package/dist/src/Redacted.d.ts.map +1 -1
- package/dist/src/Redacted.js +5 -0
- package/dist/src/Ref.d.ts +31 -16
- package/dist/src/Ref.d.ts.map +1 -1
- package/dist/src/Ref.js +35 -7
- package/dist/src/RefCount.d.ts +62 -0
- package/dist/src/RefCount.d.ts.map +1 -0
- package/dist/src/RefCount.js +83 -0
- package/dist/src/Relation.d.ts +84 -29
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Relation.js +83 -105
- package/dist/src/Resource.d.ts +263 -0
- package/dist/src/Resource.d.ts.map +1 -0
- package/dist/src/Resource.js +389 -0
- package/dist/src/Result.d.ts +390 -374
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +142 -70
- package/dist/src/Schedule.d.ts +953 -0
- package/dist/src/Schedule.d.ts.map +1 -0
- package/dist/src/Schedule.js +1199 -0
- package/dist/src/Set.d.ts +181 -0
- package/dist/src/Set.d.ts.map +1 -0
- package/dist/src/Set.js +137 -0
- package/dist/src/Skiplist.d.ts +6 -1
- package/dist/src/Skiplist.d.ts.map +1 -1
- package/dist/src/Skiplist.js +5 -0
- package/dist/src/Sqlite.d.ts +160 -60
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +290 -190
- package/dist/src/Store.d.ts +36 -28
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +55 -15
- package/dist/src/String.d.ts +5 -0
- package/dist/src/String.d.ts.map +1 -1
- package/dist/src/String.js +5 -0
- package/dist/src/Task.d.ts +2263 -423
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +1488 -348
- package/dist/src/Test.d.ts +122 -0
- package/dist/src/Test.d.ts.map +1 -0
- package/dist/src/Test.js +66 -0
- package/dist/src/Time.d.ts +201 -48
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +190 -86
- package/dist/src/Tracer.d.ts +48 -0
- package/dist/src/Tracer.d.ts.map +1 -0
- package/dist/src/Tracer.js +6 -0
- package/dist/src/Type.d.ts +582 -209
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +362 -240
- package/dist/src/Types.d.ts +160 -6
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/Types.js +22 -2
- package/dist/src/WebSocket.d.ts +113 -58
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +210 -118
- package/dist/src/Worker.d.ts +245 -60
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +220 -64
- package/dist/src/index.d.ts +25 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +19 -3
- package/dist/src/local-first/Db.d.ts +24 -213
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +622 -293
- package/dist/src/local-first/Error.d.ts +12 -0
- package/dist/src/local-first/Error.d.ts.map +1 -0
- package/dist/src/local-first/Error.js +6 -0
- package/dist/src/local-first/Evolu.d.ts +330 -285
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +472 -402
- package/dist/src/local-first/LocalAuth.d.ts +10 -10
- package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
- package/dist/src/local-first/LocalAuth.js +6 -1
- package/dist/src/local-first/Owner.d.ts +70 -27
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +27 -14
- package/dist/src/local-first/Protocol.d.ts +58 -50
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +253 -155
- package/dist/src/local-first/Query.d.ts +133 -43
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +139 -90
- package/dist/src/local-first/Relay.d.ts +18 -38
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Relay.js +59 -171
- package/dist/src/local-first/Schema.d.ts +139 -144
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +78 -163
- package/dist/src/local-first/Shared.d.ts +125 -0
- package/dist/src/local-first/Shared.d.ts.map +1 -0
- package/dist/src/local-first/Shared.js +569 -0
- package/dist/src/local-first/Storage.d.ts +50 -53
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +121 -173
- package/dist/src/local-first/Timestamp.d.ts +28 -35
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +24 -25
- package/dist/src/local-first/index.d.ts +2 -15
- package/dist/src/local-first/index.d.ts.map +1 -1
- package/dist/src/local-first/index.js +2 -15
- package/package.json +36 -26
- package/src/Array.ts +467 -106
- package/src/Assert.ts +87 -12
- package/src/BigInt.ts +7 -1
- package/src/Brand.ts +41 -12
- package/src/Buffer.ts +10 -4
- package/src/Cache.ts +11 -2
- package/src/Callbacks.ts +33 -23
- package/src/Console.ts +567 -178
- package/src/Crypto.ts +111 -62
- package/src/Eq.ts +30 -3
- package/src/Error.ts +50 -34
- package/src/Function.ts +140 -68
- package/src/Identicon.ts +7 -1
- package/src/Lookup.ts +415 -0
- package/src/Microtask.ts +58 -0
- package/src/Number.ts +40 -7
- package/src/Object.ts +155 -16
- package/src/Option.ts +74 -0
- package/src/Order.ts +11 -3
- package/src/Platform.ts +43 -7
- package/src/Polyfills.ts +465 -0
- package/src/Random.ts +25 -11
- package/src/Redacted.ts +8 -4
- package/src/Ref.ts +72 -21
- package/src/RefCount.ts +170 -0
- package/src/Relation.ts +188 -136
- package/src/Resource.ts +864 -0
- package/src/Result.ts +548 -381
- package/src/Schedule.ts +1471 -0
- package/src/Set.ts +247 -0
- package/src/Skiplist.ts +7 -1
- package/src/Sqlite.ts +409 -304
- package/src/Store.ts +94 -48
- package/src/String.ts +6 -0
- package/src/Task.ts +3685 -740
- package/src/Test.ts +162 -0
- package/src/Time.ts +348 -145
- package/src/Tracer.ts +54 -0
- package/src/Type.ts +851 -430
- package/src/Types.ts +202 -7
- package/src/WebSocket.ts +311 -178
- package/src/Worker.ts +527 -147
- package/src/index.ts +74 -3
- package/src/local-first/Db.ts +871 -597
- package/src/local-first/Error.ts +17 -0
- package/src/local-first/Evolu.ts +884 -824
- package/src/local-first/LocalAuth.ts +10 -10
- package/src/local-first/Owner.ts +94 -42
- package/src/local-first/Protocol.ts +440 -303
- package/src/local-first/Query.ts +243 -194
- package/src/local-first/Relay.ts +91 -252
- package/src/local-first/Schema.ts +284 -394
- package/src/local-first/Shared.ts +932 -0
- package/src/local-first/Storage.ts +206 -277
- package/src/local-first/Timestamp.ts +38 -45
- package/src/local-first/index.ts +2 -16
- package/LICENSE +0 -21
- package/dist/src/Instances.d.ts +0 -34
- package/dist/src/Instances.d.ts.map +0 -1
- package/dist/src/Instances.js +0 -44
- package/dist/src/Resources.d.ts +0 -118
- package/dist/src/Resources.d.ts.map +0 -1
- package/dist/src/Resources.js +0 -197
- package/dist/src/local-first/Platform.d.ts +0 -25
- package/dist/src/local-first/Platform.d.ts.map +0 -1
- package/dist/src/local-first/Platform.js +0 -1
- package/dist/src/local-first/Public.d.ts +0 -22
- package/dist/src/local-first/Public.d.ts.map +0 -1
- package/dist/src/local-first/Public.js +0 -15
- package/dist/src/local-first/PublicKysely.d.ts +0 -148
- package/dist/src/local-first/PublicKysely.d.ts.map +0 -1
- package/dist/src/local-first/PublicKysely.js +0 -184
- package/dist/src/local-first/Sync.d.ts +0 -112
- package/dist/src/local-first/Sync.d.ts.map +0 -1
- package/dist/src/local-first/Sync.js +0 -526
- package/src/Instances.ts +0 -92
- package/src/Resources.ts +0 -367
- package/src/local-first/Platform.ts +0 -27
- package/src/local-first/Public.ts +0 -42
- package/src/local-first/PublicKysely.ts +0 -239
- package/src/local-first/Sync.ts +0 -949
|
@@ -1,24 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encrypted storage layer for local-first data.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
1
6
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
|
-
import { firstInArray,
|
|
7
|
+
import { firstInArray, isNonEmptyArray } from "../Array.js";
|
|
3
8
|
import { assert } from "../Assert.js";
|
|
4
9
|
import { concatBytes } from "../Buffer.js";
|
|
5
10
|
import { decrement } from "../Number.js";
|
|
6
11
|
import { err, ok } from "../Result.js";
|
|
7
12
|
import { sql, SqliteValue } from "../Sqlite.js";
|
|
13
|
+
import { Millis } from "../Time.js";
|
|
8
14
|
import { Boolean, brand, Id, NonNegativeInt, nullOr, object, PositiveInt, record, String, } from "../Type.js";
|
|
15
|
+
import { OwnerId, OwnerWriteKey } from "./Owner.js";
|
|
9
16
|
import { systemColumnsWithId } from "./Schema.js";
|
|
10
|
-
import { orderTimestampBytes } from "./Timestamp.js";
|
|
11
|
-
export const fingerprintSize = NonNegativeInt.orThrow(12);
|
|
17
|
+
import { createTimestamp, orderTimestampBytes, Timestamp, TimestampBytes, } from "./Timestamp.js";
|
|
18
|
+
export const fingerprintSize = /*#__PURE__*/ NonNegativeInt.orThrow(12);
|
|
12
19
|
/** A fingerprint of an empty range. */
|
|
13
|
-
export const zeroFingerprint = new Uint8Array(fingerprintSize);
|
|
14
|
-
export const InfiniteUpperBound = Symbol("InfiniteUpperBound");
|
|
20
|
+
export const zeroFingerprint = /*#__PURE__*/ new Uint8Array(fingerprintSize);
|
|
21
|
+
export const InfiniteUpperBound = /*#__PURE__*/ Symbol("evolu.local-first.Storage.InfiniteUpperBound");
|
|
15
22
|
export const RangeType = {
|
|
16
23
|
Fingerprint: 1,
|
|
17
24
|
Skip: 0,
|
|
18
25
|
Timestamps: 2,
|
|
19
26
|
};
|
|
20
|
-
|
|
21
|
-
export const
|
|
27
|
+
/** Test helper for creating a simple {@link CrdtMessage}. */
|
|
28
|
+
export const testCreateCrdtMessage = (id, millis, name) => ({
|
|
29
|
+
timestamp: createTimestamp({
|
|
30
|
+
millis: Millis.orThrow(millis),
|
|
31
|
+
counter: 0,
|
|
32
|
+
}),
|
|
33
|
+
change: DbChange.orThrow({
|
|
34
|
+
table: "testTable",
|
|
35
|
+
id,
|
|
36
|
+
values: { name },
|
|
37
|
+
isInsert: true,
|
|
38
|
+
isDelete: false,
|
|
39
|
+
}),
|
|
40
|
+
});
|
|
41
|
+
export const DbChangeValues = /*#__PURE__*/ record(String, SqliteValue);
|
|
42
|
+
export const ValidDbChangeValues = /*#__PURE__*/ brand("ValidDbChangeValues", DbChangeValues, (value) => {
|
|
22
43
|
const invalidColumns = systemColumnsWithId.filter((key) => key in value);
|
|
23
44
|
if (invalidColumns.length > 0)
|
|
24
45
|
return err({
|
|
@@ -32,12 +53,12 @@ export const ValidDbChangeValues = brand("ValidDbChangeValues", DbChangeValues,
|
|
|
32
53
|
* A DbChange is a change to a table row. Together with a unique
|
|
33
54
|
* {@link Timestamp}, it forms a {@link CrdtMessage}.
|
|
34
55
|
*/
|
|
35
|
-
export const DbChange = object({
|
|
56
|
+
export const DbChange = /*#__PURE__*/ object({
|
|
36
57
|
table: String,
|
|
37
58
|
id: Id,
|
|
38
59
|
values: ValidDbChangeValues,
|
|
39
60
|
isInsert: Boolean,
|
|
40
|
-
isDelete: nullOr(Boolean),
|
|
61
|
+
isDelete: /*#__PURE__*/ nullOr(Boolean),
|
|
41
62
|
});
|
|
42
63
|
/**
|
|
43
64
|
* Creates a {@link BaseSqliteStorage} implementation.
|
|
@@ -52,124 +73,80 @@ export const DbChange = object({
|
|
|
52
73
|
* doesn't persist between requests. While not extensively tested in all these
|
|
53
74
|
* environments yet, the stateless design should work well across them.
|
|
54
75
|
*/
|
|
55
|
-
export const createBaseSqliteStorage = (deps) => (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
assertBeginEnd(begin, end);
|
|
121
|
-
const length = end - begin;
|
|
122
|
-
if (length === 0)
|
|
123
|
-
return;
|
|
124
|
-
// This is much faster than SQL limit with offset.
|
|
125
|
-
const first = getTimestampByIndex(deps)(ownerId, begin);
|
|
126
|
-
if (!first.ok) {
|
|
127
|
-
config.onStorageError(first.error);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
if (!callback(first.value, begin))
|
|
131
|
-
return;
|
|
132
|
-
if (length === 1)
|
|
133
|
-
return;
|
|
134
|
-
/**
|
|
135
|
-
* TODO: In rare cases, we might overfetch a lot of rows here, but we
|
|
136
|
-
* don't have real usage numbers yet. Fetching one row at a time would
|
|
137
|
-
* probably be slower in almost all cases. In the future, we should
|
|
138
|
-
* fetch in chunks (e.g., 1,000 rows at a time). For now, consider
|
|
139
|
-
* logging unused rows to gather data and calculate an average, then use
|
|
140
|
-
* that information to determine an optimal chunk size. Before
|
|
141
|
-
* implementing chunking, be sure to run performance tests (including
|
|
142
|
-
* fetching one by one).
|
|
143
|
-
*/
|
|
144
|
-
const result = deps.sqlite.exec(sql `
|
|
145
|
-
select t
|
|
146
|
-
from evolu_timestamp
|
|
147
|
-
where ownerId = ${ownerId} and t > ${first.value}
|
|
148
|
-
order by t
|
|
149
|
-
limit ${length - 1};
|
|
150
|
-
`);
|
|
151
|
-
if (!result.ok) {
|
|
152
|
-
config.onStorageError(result.error);
|
|
76
|
+
export const createBaseSqliteStorage = (deps) => ({
|
|
77
|
+
insertTimestamp: (ownerId, timestamp, strategy) => {
|
|
78
|
+
const level = randomSkiplistLevel(deps);
|
|
79
|
+
insertTimestamp(deps)(ownerId, timestamp, level, strategy);
|
|
80
|
+
},
|
|
81
|
+
getExistingTimestamps: (ownerIdBytes, timestampsBytes) => {
|
|
82
|
+
const concatenatedTimestamps = concatBytes(...timestampsBytes);
|
|
83
|
+
const result = deps.sqlite.exec(sql `
|
|
84
|
+
with recursive
|
|
85
|
+
split_timestamps(timestampBytes, pos) as (
|
|
86
|
+
select
|
|
87
|
+
substr(${concatenatedTimestamps}, 1, 16),
|
|
88
|
+
17 as pos
|
|
89
|
+
union all
|
|
90
|
+
select
|
|
91
|
+
substr(${concatenatedTimestamps}, pos, 16),
|
|
92
|
+
pos + 16
|
|
93
|
+
from split_timestamps
|
|
94
|
+
where pos <= length(${concatenatedTimestamps})
|
|
95
|
+
)
|
|
96
|
+
select s.timestampBytes
|
|
97
|
+
from
|
|
98
|
+
split_timestamps s
|
|
99
|
+
join evolu_timestamp t
|
|
100
|
+
on t.ownerId = ${ownerIdBytes} and s.timestampBytes = t.t;
|
|
101
|
+
`);
|
|
102
|
+
return result.rows.map((row) => row.timestampBytes);
|
|
103
|
+
},
|
|
104
|
+
getSize: getSize(deps),
|
|
105
|
+
fingerprint: (ownerId, begin, end) => {
|
|
106
|
+
assertBeginEnd(begin, end);
|
|
107
|
+
return fingerprint(deps)(ownerId, begin, end);
|
|
108
|
+
},
|
|
109
|
+
fingerprintRanges: fingerprintRanges(deps),
|
|
110
|
+
findLowerBound: (ownerId, begin, end, upperBound) => findLowerBound(deps)(ownerId, begin, end, upperBound),
|
|
111
|
+
iterate: (ownerId, begin, end, callback) => {
|
|
112
|
+
assertBeginEnd(begin, end);
|
|
113
|
+
const length = end - begin;
|
|
114
|
+
if (length === 0)
|
|
115
|
+
return;
|
|
116
|
+
// This is much faster than SQL limit with offset.
|
|
117
|
+
const first = getTimestampByIndex(deps)(ownerId, begin);
|
|
118
|
+
if (!callback(first, begin))
|
|
119
|
+
return;
|
|
120
|
+
if (length === 1)
|
|
121
|
+
return;
|
|
122
|
+
/**
|
|
123
|
+
* TODO: In rare cases, we might overfetch a lot of rows here, but we don't
|
|
124
|
+
* have real usage numbers yet. Fetching one row at a time would probably be
|
|
125
|
+
* slower in almost all cases. In the future, we should fetch in chunks
|
|
126
|
+
* (e.g., 1,000 rows at a time). For now, consider logging unused rows to
|
|
127
|
+
* gather data and calculate an average, then use that information to
|
|
128
|
+
* determine an optimal chunk size. Before implementing chunking, be sure to
|
|
129
|
+
* run performance tests (including fetching one by one).
|
|
130
|
+
*/
|
|
131
|
+
const result = deps.sqlite.exec(sql `
|
|
132
|
+
select t
|
|
133
|
+
from evolu_timestamp
|
|
134
|
+
where ownerId = ${ownerId} and t > ${first}
|
|
135
|
+
order by t
|
|
136
|
+
limit ${length - 1};
|
|
137
|
+
`);
|
|
138
|
+
for (let i = 0; i < result.rows.length; i++) {
|
|
139
|
+
const index = NonNegativeInt.orThrow(begin + 1 + i);
|
|
140
|
+
if (!callback(result.rows[i].t, index))
|
|
153
141
|
return;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const result = deps.sqlite.exec(sql `
|
|
163
|
-
delete from evolu_timestamp where ownerId = ${ownerId};
|
|
164
|
-
`);
|
|
165
|
-
if (!result.ok) {
|
|
166
|
-
config.onStorageError(result.error);
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
return true;
|
|
170
|
-
},
|
|
171
|
-
};
|
|
172
|
-
};
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
deleteOwner: (ownerId) => {
|
|
145
|
+
deps.sqlite.exec(sql `
|
|
146
|
+
delete from evolu_timestamp where ownerId = ${ownerId};
|
|
147
|
+
`);
|
|
148
|
+
},
|
|
149
|
+
});
|
|
173
150
|
const assertBeginEnd = (begin, end) => {
|
|
174
151
|
assert(begin <= end, "invalid begin or end");
|
|
175
152
|
};
|
|
@@ -233,11 +210,8 @@ export const createBaseSqliteStorageTables = (deps) => {
|
|
|
233
210
|
strict;
|
|
234
211
|
`,
|
|
235
212
|
]) {
|
|
236
|
-
|
|
237
|
-
if (!result.ok)
|
|
238
|
-
return result;
|
|
213
|
+
deps.sqlite.exec(query);
|
|
239
214
|
}
|
|
240
|
-
return ok();
|
|
241
215
|
};
|
|
242
216
|
/**
|
|
243
217
|
* Determines the insertion strategy for a timestamp based on its position
|
|
@@ -772,11 +746,8 @@ const insertTimestamp = (deps) => (ownerId, timestamp, level, strategy) => {
|
|
|
772
746
|
break;
|
|
773
747
|
}
|
|
774
748
|
for (const query of queries) {
|
|
775
|
-
|
|
776
|
-
if (!result.ok)
|
|
777
|
-
return result;
|
|
749
|
+
deps.sqlite.exec(query);
|
|
778
750
|
}
|
|
779
|
-
return ok();
|
|
780
751
|
};
|
|
781
752
|
export const timestampBytesToFingerprint = (timestamp) => {
|
|
782
753
|
const hash = sha256(timestamp).slice(0, fingerprintSize);
|
|
@@ -870,14 +841,12 @@ const getSize = (deps) => (ownerId) => {
|
|
|
870
841
|
select sum(c) as size
|
|
871
842
|
from sc;
|
|
872
843
|
`);
|
|
873
|
-
|
|
874
|
-
return result;
|
|
875
|
-
return ok(result.value.rows[0].size);
|
|
844
|
+
return result.rows[0].size;
|
|
876
845
|
};
|
|
877
846
|
const findLowerBound = (deps) => (ownerId, begin, end, upperBound) => {
|
|
878
847
|
assertBeginEnd(begin, end);
|
|
879
848
|
if (end === 0 || begin === end || upperBound === InfiniteUpperBound) {
|
|
880
|
-
return
|
|
849
|
+
return end;
|
|
881
850
|
}
|
|
882
851
|
const result = deps.sqlite.exec(sql.prepared `
|
|
883
852
|
select t
|
|
@@ -886,16 +855,12 @@ const findLowerBound = (deps) => (ownerId, begin, end, upperBound) => {
|
|
|
886
855
|
order by t
|
|
887
856
|
limit 1;
|
|
888
857
|
`);
|
|
889
|
-
if (
|
|
890
|
-
return
|
|
891
|
-
if (result.value.rows.length === 0) {
|
|
892
|
-
return ok(end);
|
|
858
|
+
if (result.rows.length === 0) {
|
|
859
|
+
return end;
|
|
893
860
|
}
|
|
894
|
-
const count = getTimestampCount(deps)(ownerId, result.
|
|
895
|
-
if (!count.ok)
|
|
896
|
-
return count;
|
|
861
|
+
const count = getTimestampCount(deps)(ownerId, result.rows[0].t);
|
|
897
862
|
// `decrement` converts a count to an index.
|
|
898
|
-
return
|
|
863
|
+
return NonNegativeInt.orThrow(decrement(count));
|
|
899
864
|
};
|
|
900
865
|
const getTimestampCount = (deps) => (ownerId, timestamp) => {
|
|
901
866
|
const result = deps.sqlite.exec(sql.prepared `
|
|
@@ -939,9 +904,7 @@ const getTimestampCount = (deps) => (ownerId, timestamp) => {
|
|
|
939
904
|
select sum(tc) as count
|
|
940
905
|
from sc;
|
|
941
906
|
`);
|
|
942
|
-
|
|
943
|
-
return result;
|
|
944
|
-
return ok(result.value.rows[0].count);
|
|
907
|
+
return result.rows[0].count;
|
|
945
908
|
};
|
|
946
909
|
/**
|
|
947
910
|
* TODO: We reuse {@link fingerprintRanges}, which returns upper bound, which we
|
|
@@ -950,19 +913,13 @@ const getTimestampCount = (deps) => (ownerId, timestamp) => {
|
|
|
950
913
|
const fingerprint = (deps) => (ownerId, begin, end) => {
|
|
951
914
|
// There is no need to fingerprint an empty range.
|
|
952
915
|
if (end - begin === 0) {
|
|
953
|
-
return
|
|
916
|
+
return zeroFingerprint;
|
|
954
917
|
}
|
|
955
918
|
if (begin === 0) {
|
|
956
|
-
|
|
957
|
-
if (!result.ok)
|
|
958
|
-
return result;
|
|
959
|
-
return ok(result.value[0].fingerprint);
|
|
919
|
+
return fingerprintRanges(deps)(ownerId, [end])[0].fingerprint;
|
|
960
920
|
}
|
|
961
921
|
// We should have a param to skip the first result.
|
|
962
|
-
|
|
963
|
-
if (!result.ok)
|
|
964
|
-
return result;
|
|
965
|
-
return ok(result.value[1].fingerprint);
|
|
922
|
+
return fingerprintRanges(deps)(ownerId, [begin, end])[1].fingerprint;
|
|
966
923
|
};
|
|
967
924
|
/**
|
|
968
925
|
* First, check this: https://logperiodic.com/rbsr.html#tree-friendly-functions
|
|
@@ -1084,9 +1041,7 @@ const fingerprintRanges = (deps) => (ownerId, buckets, upperBound = InfiniteUppe
|
|
|
1084
1041
|
select b, cast(h1 as text) as h1, cast(h2 as text) as h2
|
|
1085
1042
|
from c3;
|
|
1086
1043
|
`);
|
|
1087
|
-
|
|
1088
|
-
return result;
|
|
1089
|
-
const fingerprintRanges = result.value.rows.map((row, i, arr) => ({
|
|
1044
|
+
const fingerprintRanges = result.rows.map((row, i, arr) => ({
|
|
1090
1045
|
type: RangeType.Fingerprint,
|
|
1091
1046
|
upperBound: i === arr.length - 1 ? upperBound : row.b,
|
|
1092
1047
|
fingerprint: sqliteFingerprintToFingerprint([
|
|
@@ -1094,7 +1049,7 @@ const fingerprintRanges = (deps) => (ownerId, buckets, upperBound = InfiniteUppe
|
|
|
1094
1049
|
row.h2,
|
|
1095
1050
|
]),
|
|
1096
1051
|
}));
|
|
1097
|
-
return
|
|
1052
|
+
return fingerprintRanges;
|
|
1098
1053
|
};
|
|
1099
1054
|
// XOR in SQLite
|
|
1100
1055
|
const x = (a, b) => sql.raw(`(${a} | ${b}) - (${a} & ${b})`);
|
|
@@ -1170,9 +1125,7 @@ export const getTimestampByIndex = (deps) => (ownerId, index) => {
|
|
|
1170
1125
|
from fi
|
|
1171
1126
|
where ic == ${index + 1};
|
|
1172
1127
|
`);
|
|
1173
|
-
|
|
1174
|
-
return result;
|
|
1175
|
-
return ok(result.value.rows[0].pt);
|
|
1128
|
+
return result.rows[0].pt;
|
|
1176
1129
|
};
|
|
1177
1130
|
/** Retrieves usage information for an owner from the evolu_usage table. */
|
|
1178
1131
|
export const getOwnerUsage = (deps) => (ownerIdBytes, initialTimestamp) => {
|
|
@@ -1181,16 +1134,14 @@ export const getOwnerUsage = (deps) => (ownerIdBytes, initialTimestamp) => {
|
|
|
1181
1134
|
from evolu_usage
|
|
1182
1135
|
where ownerId = ${ownerIdBytes};
|
|
1183
1136
|
`);
|
|
1184
|
-
if (!result.
|
|
1185
|
-
return result;
|
|
1186
|
-
if (!isNonEmptyReadonlyArray(result.value.rows)) {
|
|
1137
|
+
if (!isNonEmptyArray(result.rows)) {
|
|
1187
1138
|
return ok({
|
|
1188
1139
|
storedBytes: null,
|
|
1189
1140
|
firstTimestamp: initialTimestamp,
|
|
1190
1141
|
lastTimestamp: initialTimestamp,
|
|
1191
1142
|
});
|
|
1192
1143
|
}
|
|
1193
|
-
const row = firstInArray(result.
|
|
1144
|
+
const row = firstInArray(result.rows);
|
|
1194
1145
|
assert(row.firstTimestamp, "not null");
|
|
1195
1146
|
assert(row.lastTimestamp, "not null");
|
|
1196
1147
|
return ok({
|
|
@@ -1206,7 +1157,7 @@ export const getOwnerUsage = (deps) => (ownerIdBytes, initialTimestamp) => {
|
|
|
1206
1157
|
* processing messages.
|
|
1207
1158
|
*/
|
|
1208
1159
|
export const updateOwnerUsage = (deps) => (ownerIdBytes, storedBytes, firstTimestamp, lastTimestamp) => {
|
|
1209
|
-
|
|
1160
|
+
deps.sqlite.exec(sql `
|
|
1210
1161
|
insert into evolu_usage
|
|
1211
1162
|
("ownerId", "storedBytes", "firstTimestamp", "lastTimestamp")
|
|
1212
1163
|
values
|
|
@@ -1217,7 +1168,4 @@ export const updateOwnerUsage = (deps) => (ownerIdBytes, storedBytes, firstTimes
|
|
|
1217
1168
|
firstTimestamp = ${firstTimestamp},
|
|
1218
1169
|
lastTimestamp = ${lastTimestamp};
|
|
1219
1170
|
`);
|
|
1220
|
-
if (!result.ok)
|
|
1221
|
-
return result;
|
|
1222
|
-
return ok();
|
|
1223
1171
|
};
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid logical clock timestamps for CRDT ordering.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { RandomBytesDep } from "../Crypto.js";
|
|
7
|
+
import type { Order } from "../Order.js";
|
|
8
|
+
import type { Result } from "../Result.js";
|
|
9
|
+
import type { TimeDep } from "../Time.js";
|
|
10
|
+
import { Millis } from "../Time.js";
|
|
11
|
+
import type { DateIso, InferType, Typed } from "../Type.js";
|
|
6
12
|
export interface TimestampConfig {
|
|
7
13
|
/**
|
|
8
14
|
* Maximum physical clock drift allowed in ms.
|
|
@@ -11,38 +17,21 @@ export interface TimestampConfig {
|
|
|
11
17
|
*/
|
|
12
18
|
readonly maxDrift: number;
|
|
13
19
|
}
|
|
20
|
+
/** Default value for {@link TimestampConfig.maxDrift}. */
|
|
21
|
+
export declare const defaultTimestampMaxDrift: number;
|
|
14
22
|
export interface TimestampConfigDep {
|
|
15
23
|
readonly timestampConfig: TimestampConfig;
|
|
16
24
|
}
|
|
17
25
|
export type TimestampError = TimestampDriftError | TimestampCounterOverflowError | TimestampTimeOutOfRangeError;
|
|
18
|
-
export interface TimestampDriftError {
|
|
19
|
-
readonly type: "TimestampDriftError";
|
|
26
|
+
export interface TimestampDriftError extends Typed<"TimestampDriftError"> {
|
|
20
27
|
readonly next: Millis;
|
|
21
28
|
readonly now: Millis;
|
|
22
29
|
}
|
|
23
|
-
export interface TimestampCounterOverflowError {
|
|
24
|
-
readonly type: "TimestampCounterOverflowError";
|
|
30
|
+
export interface TimestampCounterOverflowError extends Typed<"TimestampCounterOverflowError"> {
|
|
25
31
|
}
|
|
26
|
-
export interface TimestampTimeOutOfRangeError {
|
|
27
|
-
readonly type: "TimestampTimeOutOfRangeError";
|
|
32
|
+
export interface TimestampTimeOutOfRangeError extends Typed<"TimestampTimeOutOfRangeError"> {
|
|
28
33
|
}
|
|
29
|
-
|
|
30
|
-
* Millis is a timestamp in milliseconds, like `Date.now()`, but limited to the
|
|
31
|
-
* maximum value representable in 6 bytes (281474976710655) minus 1 (reserved
|
|
32
|
-
* for infinity). This enables more efficient binary serialization, saving 2
|
|
33
|
-
* bytes compared to the typical 8-byte (64-bit) timestamp representation.
|
|
34
|
-
*
|
|
35
|
-
* This limit is enforced to prevent data corruption. If a device's clock
|
|
36
|
-
* exceeds this range, Evolu will stop saving data until the clock is
|
|
37
|
-
* corrected.
|
|
38
|
-
*
|
|
39
|
-
* `new Date(281474976710654).toString()` = Tue Aug 02 10889 07:31:49
|
|
40
|
-
*/
|
|
41
|
-
export declare const Millis: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & import("../Brand.js").Brand<"Int">, import("../Type.js").IntError | import("../Type.js").NumberError>, `LessThanOrEqualTo${number}`, import("../Type.js").LessThanOrEqualToError<number>, import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").NumberError>, "Millis", import("../Type.js").BrandWithoutRefineError<"Millis", import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").NumberError | import("../Type.js").LessThanOrEqualToError<number>>, never>;
|
|
42
|
-
export type Millis = typeof Millis.Type;
|
|
43
|
-
export declare const minMillis: Millis;
|
|
44
|
-
export declare const maxMillis: Millis;
|
|
45
|
-
export declare const Counter: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & import("../Brand.js").Brand<"Int">, import("../Type.js").IntError | import("../Type.js").NumberError>, "LessThanOrEqualTo65535", import("../Type.js").LessThanOrEqualToError<65535>, import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").NumberError>, "Counter", import("../Type.js").BrandWithoutRefineError<"Counter", import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").NumberError | import("../Type.js").LessThanOrEqualToError<65535>>, never>;
|
|
34
|
+
export declare const Counter: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & import("../Brand.js").Brand<"Int">, import("../Type.js").NumberError | import("../Type.js").IntError>, "LessThanOrEqualTo65535", import("../Type.js").LessThanOrEqualToError<65535>, import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError>, "Counter", import("../Type.js").BrandWithoutRefineError<"Counter", import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").LessThanOrEqualToError<65535>>, never>;
|
|
46
35
|
export type Counter = typeof Counter.Type;
|
|
47
36
|
export declare const minCounter: Counter;
|
|
48
37
|
export declare const maxCounter: Counter;
|
|
@@ -81,7 +70,7 @@ export declare const maxNodeId: NodeId;
|
|
|
81
70
|
* Timestamps serve as globally unique, causally ordered identifiers for CRDT
|
|
82
71
|
* messages in Evolu's sync protocol.
|
|
83
72
|
*
|
|
84
|
-
*
|
|
73
|
+
* ## Why Hybrid Logical Clocks
|
|
85
74
|
*
|
|
86
75
|
* Evolu uses Hybrid Logical Clocks (HLC), which combine physical time (millis)
|
|
87
76
|
* with a logical counter. This hybrid approach preserves causality like logical
|
|
@@ -106,14 +95,14 @@ export declare const maxNodeId: NodeId;
|
|
|
106
95
|
* configuration protects against buggy clocks and prevents problematic
|
|
107
96
|
* future-dated entries from propagating through the network.
|
|
108
97
|
*
|
|
109
|
-
*
|
|
98
|
+
* ## References
|
|
110
99
|
*
|
|
111
100
|
* - https://muratbuffalo.blogspot.com/2014/07/hybrid-logical-clocks.html
|
|
112
101
|
* - https://sergeiturukin.com/2017/06/26/hybrid-logical-clocks.html
|
|
113
102
|
* - https://jaredforsyth.com/posts/hybrid-logical-clocks/
|
|
114
103
|
* - https://willowprotocol.org/more/timestamps_really/index.html
|
|
115
104
|
*
|
|
116
|
-
*
|
|
105
|
+
* ## Privacy Considerations
|
|
117
106
|
*
|
|
118
107
|
* Timestamps are metadata visible to relays and collaborators. While it can be
|
|
119
108
|
* considered a privacy leak, let us explain why it's necessary, and how to
|
|
@@ -130,17 +119,21 @@ export declare const maxNodeId: NodeId;
|
|
|
130
119
|
* 2. Periodically and randomly flush messages to sync tables
|
|
131
120
|
*
|
|
132
121
|
* **Trade-off:** It breaks real-time collaboration.
|
|
122
|
+
*
|
|
123
|
+
* Another technique is generating fake random activity (dummy messages) to mask
|
|
124
|
+
* real usage patterns. This preserves real-time collaboration but increases
|
|
125
|
+
* storage and bandwidth usage.
|
|
133
126
|
*/
|
|
134
127
|
export declare const Timestamp: import("../Type.js").ObjectType<{
|
|
135
|
-
millis: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & import("../Brand.js").Brand<"Int">, import("../Type.js").
|
|
136
|
-
counter: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & import("../Brand.js").Brand<"Int">, import("../Type.js").
|
|
128
|
+
millis: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & import("../Brand.js").Brand<"Int">, import("../Type.js").NumberError | import("../Type.js").IntError>, "LessThan281474976710655", import("../Type.js").LessThanError<281474976710655>, import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError>, "Millis", import("../Type.js").BrandWithoutRefineError<"Millis", import("../Type.js").NumberError | import("../Type.js").LessThanError<281474976710655> | import("../Type.js").NonNegativeError | import("../Type.js").IntError>, never>;
|
|
129
|
+
counter: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & import("../Brand.js").Brand<"Int">, import("../Type.js").NumberError | import("../Type.js").IntError>, "LessThanOrEqualTo65535", import("../Type.js").LessThanOrEqualToError<65535>, import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError>, "Counter", import("../Type.js").BrandWithoutRefineError<"Counter", import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").LessThanOrEqualToError<65535>>, never>;
|
|
137
130
|
nodeId: import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "NodeId", import("../Type.js").RegexError<"NodeId">, import("../Type.js").StringError>;
|
|
138
131
|
}>;
|
|
139
132
|
export interface Timestamp extends InferType<typeof Timestamp> {
|
|
140
133
|
}
|
|
141
134
|
/** Equality function for comparing {@link Timestamp}. */
|
|
142
135
|
export declare const eqTimestamp: import("../Eq.js").Eq<{
|
|
143
|
-
readonly millis: number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative"> & import("../Brand.js").Brand
|
|
136
|
+
readonly millis: number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative"> & import("../Brand.js").Brand<"LessThan281474976710655"> & import("../Brand.js").Brand<"Millis">;
|
|
144
137
|
readonly counter: number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative"> & import("../Brand.js").Brand<"LessThanOrEqualTo65535"> & import("../Brand.js").Brand<"Counter">;
|
|
145
138
|
readonly nodeId: string & import("../Brand.js").Brand<"NodeId">;
|
|
146
139
|
}>;
|
|
@@ -149,7 +142,7 @@ export declare const createInitialTimestamp: (deps: RandomBytesDep) => Timestamp
|
|
|
149
142
|
export declare const sendTimestamp: (deps: TimeDep & TimestampConfigDep) => (timestamp: Timestamp) => Result<Timestamp, TimestampDriftError | TimestampCounterOverflowError | TimestampTimeOutOfRangeError>;
|
|
150
143
|
export declare const receiveTimestamp: (deps: TimeDep & TimestampConfigDep) => (local: Timestamp, remote: Timestamp) => Result<Timestamp, TimestampDriftError | TimestampCounterOverflowError | TimestampTimeOutOfRangeError>;
|
|
151
144
|
/** Sortable bytes representation of {@link Timestamp}. */
|
|
152
|
-
export declare const TimestampBytes: import("../Type.js").BrandType<import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>, "TimestampBytes", import("../Type.js").BrandWithoutRefineError<"TimestampBytes", import("../Type.js").Uint8ArrayError
|
|
145
|
+
export declare const TimestampBytes: 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>, "Length16", import("../Type.js").LengthError<16>, import("../Type.js").Uint8ArrayError>, "TimestampBytes", import("../Type.js").BrandWithoutRefineError<"TimestampBytes", import("../Type.js").Uint8ArrayError | import("../Type.js").LengthError<16>>, never>;
|
|
153
146
|
export type TimestampBytes = typeof TimestampBytes.Type;
|
|
154
147
|
export declare const timestampBytesLength: number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative">;
|
|
155
148
|
export declare const timestampToTimestampBytes: (timestamp: Timestamp) => TimestampBytes;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../../src/local-first/Timestamp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../../src/local-first/Timestamp.ts"],"names":[],"mappings":"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"}
|