@evolu/common 6.0.1-preview.8 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/src/Array.d.ts +256 -12
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +215 -9
- package/dist/src/Assert.d.ts +0 -13
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +0 -15
- package/dist/src/Brand.d.ts +75 -0
- package/dist/src/Brand.d.ts.map +1 -0
- package/dist/src/Brand.js +1 -0
- package/dist/src/Buffer.d.ts +1 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +8 -7
- package/dist/src/Cache.d.ts +44 -0
- package/dist/src/Cache.d.ts.map +1 -0
- package/dist/src/Cache.js +52 -0
- package/dist/src/Callbacks.d.ts +45 -12
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Callbacks.js +14 -7
- package/dist/src/Console.d.ts +31 -6
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +72 -9
- package/dist/src/Crypto.d.ts +56 -42
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +40 -53
- package/dist/src/Evolu/Db.d.ts +162 -74
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +284 -702
- package/dist/src/Evolu/Diff.d.ts +3 -3
- package/dist/src/Evolu/Diff.d.ts.map +1 -1
- package/dist/src/Evolu/Diff.js +7 -5
- package/dist/src/Evolu/Evolu.d.ts +214 -134
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +189 -180
- package/dist/src/Evolu/Internal.d.ts +0 -2
- package/dist/src/Evolu/Internal.d.ts.map +1 -1
- package/dist/src/Evolu/Internal.js +0 -2
- package/dist/src/Evolu/LocalAuth.d.ts +150 -0
- package/dist/src/Evolu/LocalAuth.d.ts.map +1 -0
- package/dist/src/Evolu/LocalAuth.js +174 -0
- package/dist/src/Evolu/Owner.d.ts +273 -120
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +130 -104
- package/dist/src/Evolu/Platform.d.ts +9 -7
- package/dist/src/Evolu/Platform.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.d.ts +268 -240
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +600 -454
- package/dist/src/Evolu/Public.d.ts +6 -8
- package/dist/src/Evolu/Public.d.ts.map +1 -1
- package/dist/src/Evolu/Public.js +2 -3
- package/dist/src/Evolu/PublicKysely.d.ts.map +1 -1
- package/dist/src/Evolu/PublicKysely.js +3 -4
- package/dist/src/Evolu/Query.d.ts +2 -1
- package/dist/src/Evolu/Query.d.ts.map +1 -1
- package/dist/src/Evolu/Query.js +1 -1
- package/dist/src/Evolu/Relay.d.ts +91 -8
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +214 -88
- package/dist/src/Evolu/Schema.d.ts +125 -47
- package/dist/src/Evolu/Schema.d.ts.map +1 -1
- package/dist/src/Evolu/Schema.js +175 -31
- package/dist/src/Evolu/Storage.d.ts +249 -27
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +198 -92
- package/dist/src/Evolu/Sync.d.ts +68 -13
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +469 -20
- package/dist/src/Evolu/Timestamp.d.ts +83 -30
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +79 -34
- package/dist/src/Identicon.d.ts +35 -0
- package/dist/src/Identicon.d.ts.map +1 -0
- package/dist/src/Identicon.js +143 -0
- package/dist/src/Instances.d.ts +34 -0
- package/dist/src/Instances.d.ts.map +1 -0
- package/dist/src/Instances.js +44 -0
- package/dist/src/Number.d.ts +4 -3
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +5 -4
- package/dist/src/Object.d.ts +10 -4
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +9 -3
- package/dist/src/Platform.d.ts +20 -0
- package/dist/src/Platform.d.ts.map +1 -0
- package/dist/src/Platform.js +22 -0
- package/dist/src/Random.d.ts +3 -2
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Relation.d.ts +79 -0
- package/dist/src/Relation.d.ts.map +1 -0
- package/dist/src/Relation.js +127 -0
- package/dist/src/Resources.d.ts +118 -0
- package/dist/src/Resources.d.ts.map +1 -0
- package/dist/src/Resources.js +197 -0
- package/dist/src/Result.d.ts +184 -52
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +30 -241
- package/dist/src/Skiplist.js +2 -1
- package/dist/src/Sqlite.d.ts +89 -5
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +136 -9
- package/dist/src/Task.d.ts +586 -0
- package/dist/src/Task.d.ts.map +1 -0
- package/dist/src/Task.js +469 -0
- package/dist/src/Time.d.ts +66 -1
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +99 -5
- package/dist/src/Type.d.ts +676 -343
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +718 -467
- package/dist/src/Types.d.ts +1 -75
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/WebSocket.d.ts +5 -2
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +12 -18
- package/dist/src/Worker.d.ts +39 -11
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +22 -4
- package/dist/src/index.d.ts +8 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -3
- package/package.json +15 -14
- package/src/Array.ts +301 -19
- package/src/Assert.ts +0 -21
- package/src/Brand.ts +75 -0
- package/src/Buffer.ts +7 -7
- package/src/Cache.ts +85 -0
- package/src/Callbacks.ts +62 -22
- package/src/Console.ts +91 -11
- package/src/Crypto.ts +94 -90
- package/src/Evolu/Db.ts +519 -1026
- package/src/Evolu/Diff.ts +7 -5
- package/src/Evolu/Evolu.ts +477 -361
- package/src/Evolu/Internal.ts +0 -2
- package/src/Evolu/LocalAuth.ts +463 -0
- package/src/Evolu/Owner.ts +355 -228
- package/src/Evolu/Platform.ts +9 -9
- package/src/Evolu/Protocol.ts +842 -742
- package/src/Evolu/Public.ts +7 -14
- package/src/Evolu/PublicKysely.ts +4 -5
- package/src/Evolu/Query.ts +3 -2
- package/src/Evolu/Relay.ts +406 -103
- package/src/Evolu/Schema.ts +323 -91
- package/src/Evolu/Storage.ts +559 -137
- package/src/Evolu/Sync.ts +819 -36
- package/src/Evolu/Timestamp.ts +90 -58
- package/src/Identicon.ts +197 -0
- package/src/Instances.ts +90 -0
- package/src/Number.ts +6 -10
- package/src/Object.ts +13 -5
- package/src/Platform.ts +26 -0
- package/src/Random.ts +3 -2
- package/src/Relation.ts +234 -0
- package/src/Resources.ts +367 -0
- package/src/Result.ts +191 -54
- package/src/Skiplist.ts +1 -1
- package/src/Sqlite.ts +152 -17
- package/src/Task.ts +901 -0
- package/src/Time.ts +180 -5
- package/src/Type.ts +1135 -730
- package/src/Types.ts +1 -77
- package/src/WebSocket.ts +27 -25
- package/src/Worker.ts +72 -23
- package/src/index.ts +8 -3
- package/dist/src/Evolu/Config.d.ts +0 -69
- package/dist/src/Evolu/Config.d.ts.map +0 -1
- package/dist/src/Evolu/Config.js +0 -9
- package/dist/src/Evolu/Kysely.d.ts +0 -6
- package/dist/src/Evolu/Kysely.d.ts.map +0 -1
- package/dist/src/Evolu/Kysely.js +0 -21
- package/dist/src/ManyToManyMap.d.ts +0 -26
- package/dist/src/ManyToManyMap.d.ts.map +0 -1
- package/dist/src/ManyToManyMap.js +0 -92
- package/dist/src/NanoId.d.ts +0 -27
- package/dist/src/NanoId.d.ts.map +0 -1
- package/dist/src/NanoId.js +0 -6
- package/dist/src/Promise.d.ts +0 -180
- package/dist/src/Promise.d.ts.map +0 -1
- package/dist/src/Promise.js +0 -176
- package/src/Evolu/Config.ts +0 -83
- package/src/Evolu/Kysely.ts +0 -38
- package/src/ManyToManyMap.ts +0 -140
- package/src/NanoId.ts +0 -39
- package/src/Promise.ts +0 -295
|
@@ -3,29 +3,39 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Evolu Protocol is a local-first, end-to-end encrypted binary synchronization
|
|
5
5
|
* protocol optimized for minimal size and maximum speed. It enables data sync
|
|
6
|
-
* between a client and a relay
|
|
7
|
-
*
|
|
6
|
+
* between a client and a relay. In the future, direct peer-to-peer (P2P) sync
|
|
7
|
+
* between clients will be possible without a relay.
|
|
8
|
+
*
|
|
9
|
+
* Relays don't need to sync with each other—clients using those relays will
|
|
10
|
+
* sync them eventually. If a relay is offline (e.g., for maintenance), it will
|
|
11
|
+
* sync automatically later via client sync logic. For relay backup using
|
|
12
|
+
* SQLite, see https://sqlite.org/rsync.html (uses a similar algorithm to Evolu
|
|
13
|
+
* RBSR).
|
|
8
14
|
*
|
|
9
15
|
* Evolu Protocol is designed for SQLite but can be extended to any database. It
|
|
10
16
|
* implements [Range-Based Set
|
|
11
17
|
* Reconciliation](https://arxiv.org/abs/2212.13567). To learn how RBSR works,
|
|
12
18
|
* check [Negentropy](https://logperiodic.com/rbsr.html). Evolu Protocol is
|
|
13
19
|
* similar to Negentropy but uses different encoding and also provides data
|
|
14
|
-
* transfer and
|
|
20
|
+
* transfer, ownership, real-time broadcasting, request-response semantics, and
|
|
21
|
+
* error handling.
|
|
15
22
|
*
|
|
16
|
-
* ### Message
|
|
23
|
+
* ### Message structure
|
|
17
24
|
*
|
|
18
25
|
* | Field | Notes |
|
|
19
26
|
* | :----------------------------- | :------------------------ |
|
|
20
27
|
* | **Header** | |
|
|
21
28
|
* | - {@link protocolVersion} | |
|
|
22
29
|
* | - {@link OwnerId} | {@link Owner} |
|
|
23
|
-
* |
|
|
24
|
-
* |
|
|
25
|
-
* | -
|
|
26
|
-
* | - {@link
|
|
27
|
-
* |
|
|
30
|
+
* | - messageType | {@link MessageType} |
|
|
31
|
+
* | **Request (messageType=0)** | |
|
|
32
|
+
* | - hasWriteKey | 0 = no, 1 = yes |
|
|
33
|
+
* | - {@link OwnerWriteKey} | If hasWriteKey = 1 |
|
|
34
|
+
* | - subscriptionFlag | {@link SubscriptionFlags} |
|
|
35
|
+
* | **Response (messageType=1)** | |
|
|
28
36
|
* | - {@link ProtocolErrorCode} | |
|
|
37
|
+
* | **Broadcast (messageType=2)** | |
|
|
38
|
+
* | - (no additional fields) | |
|
|
29
39
|
* | **Messages** | |
|
|
30
40
|
* | - {@link NonNegativeInt} | A number of messages. |
|
|
31
41
|
* | - {@link EncryptedCrdtMessage} | |
|
|
@@ -33,21 +43,14 @@
|
|
|
33
43
|
* | - {@link NonNegativeInt} | Number of ranges. |
|
|
34
44
|
* | - {@link Range} | |
|
|
35
45
|
*
|
|
36
|
-
* ### WriteKey
|
|
37
|
-
*
|
|
38
|
-
* The initiator sends WriteKeyMode and optionally one or two WriteKeys. One key
|
|
39
|
-
* for write operations and two for key rotation (current and new). Note that
|
|
40
|
-
* it's ok to not send any key if initiator is going to be synced with readonly
|
|
41
|
-
* owner. The non-initiator validates them immediately after parsing the
|
|
42
|
-
* initiator header, before processing any messages or ranges.
|
|
43
|
-
*
|
|
44
|
-
* ### WriteKey Rotation
|
|
46
|
+
* ### WriteKey validation
|
|
45
47
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
48
|
+
* The initiator sends a hasWriteKey flag and optionally a WriteKey. The
|
|
49
|
+
* WriteKey is required when sending messages as a secure token proving the
|
|
50
|
+
* initiator can write changes. It's ok to not send a WriteKey if the initiator
|
|
51
|
+
* is only syncing (read-only) and not sending messages. The non-initiator
|
|
52
|
+
* validates the WriteKey immediately after parsing the initiator header, before
|
|
53
|
+
* processing any messages or ranges.
|
|
51
54
|
*
|
|
52
55
|
* ### Synchronization
|
|
53
56
|
*
|
|
@@ -61,38 +64,48 @@
|
|
|
61
64
|
* if further sync is needed or possible, continuing until both sides are
|
|
62
65
|
* synchronized.
|
|
63
66
|
*
|
|
67
|
+
* The **non-initiator always responds** to provide sync completion feedback,
|
|
68
|
+
* even with empty messages containing only the header and no error. This allows
|
|
69
|
+
* the initiator to detect when synchronization is complete.
|
|
70
|
+
*
|
|
64
71
|
* Both **Messages** and **Ranges** are optional, allowing each side to send,
|
|
65
72
|
* sync, or only subscribe data as needed.
|
|
66
73
|
*
|
|
67
|
-
* When the initiator sends data, the {@link
|
|
68
|
-
*
|
|
69
|
-
* responds without a {@link
|
|
70
|
-
* signals it wants data. If the non-initiator detects an issue, it
|
|
71
|
-
* error code via the `Error` field in the header back to the
|
|
72
|
-
* relay-to-relay or P2P sync, both sides may require the
|
|
73
|
-
* depending on who is the initiator.
|
|
74
|
+
* When the initiator sends data, the {@link OwnerWriteKey} is required as a
|
|
75
|
+
* secure token proving the initiator can write changes. The non-initiator
|
|
76
|
+
* responds without a {@link OwnerWriteKey}, since the initiator’s request
|
|
77
|
+
* already signals it wants data. If the non-initiator detects an issue, it
|
|
78
|
+
* sends an error code via the `Error` field in the header back to the
|
|
79
|
+
* initiator. In relay-to-relay or P2P sync, both sides may require the
|
|
80
|
+
* {@link OwnerWriteKey} depending on who is the initiator.
|
|
74
81
|
*
|
|
75
|
-
* ### Protocol
|
|
82
|
+
* ### Protocol errors
|
|
76
83
|
*
|
|
77
84
|
* The protocol uses error codes in the header to signal issues:
|
|
78
85
|
*
|
|
79
86
|
* - {@link ProtocolWriteKeyError}: The provided WriteKey is invalid or missing.
|
|
80
|
-
* - {@link ProtocolWriteError}: A write
|
|
81
|
-
*
|
|
82
|
-
* - {@link ProtocolSyncError}: A
|
|
87
|
+
* - {@link ProtocolWriteError}: A serious relay-side write failure occurred.
|
|
88
|
+
* - {@link ProtocolQuotaError}: Storage or billing quota exceeded.
|
|
89
|
+
* - {@link ProtocolSyncError}: A serious relay-side synchronization failure
|
|
83
90
|
* occurred.
|
|
84
|
-
* - {@link
|
|
91
|
+
* - {@link ProtocolVersionError}: Protocol version mismatch.
|
|
85
92
|
* - {@link ProtocolInvalidDataError}: The message is malformed or corrupted.
|
|
86
93
|
*
|
|
87
|
-
* All protocol errors except `ProtocolInvalidDataError` include the `
|
|
94
|
+
* All protocol errors except `ProtocolInvalidDataError` include the `OwnerId`
|
|
88
95
|
* to allow clients to associate errors with the correct owner.
|
|
89
96
|
*
|
|
90
|
-
* ### Message
|
|
97
|
+
* ### Message size limit
|
|
91
98
|
*
|
|
92
99
|
* The protocol enforces a strict maximum size for all messages, defined by
|
|
93
|
-
* {@link
|
|
94
|
-
* less than or equal to this limit,
|
|
95
|
-
*
|
|
100
|
+
* {@link ProtocolMessageMaxSize}. This ensures every {@link ProtocolMessage} is
|
|
101
|
+
* less than or equal to this limit, enabling stateless transports, simplified
|
|
102
|
+
* relay implementation, and predictable memory usage. When all messages don't
|
|
103
|
+
* fit within the limit, the protocol automatically continues synchronization in
|
|
104
|
+
* subsequent rounds using range-based reconciliation.
|
|
105
|
+
*
|
|
106
|
+
* Database mutations are limited to 640KB, which is smaller than the protocol
|
|
107
|
+
* message limit to ensure efficient sync with
|
|
108
|
+
* {@link defaultProtocolMessageRangesMaxSize}.
|
|
96
109
|
*
|
|
97
110
|
* ### Why Binary?
|
|
98
111
|
*
|
|
@@ -100,13 +113,12 @@
|
|
|
100
113
|
*
|
|
101
114
|
* - Encrypted data doesn’t compress well, unlike plain JSON.
|
|
102
115
|
* - Message size must be controlled during creation.
|
|
103
|
-
* - Sequential byte reading is faster than parsing and
|
|
116
|
+
* - Sequential byte reading is faster than parsing and avoids conversions.
|
|
104
117
|
*
|
|
105
118
|
* It uses structure-aware encoding, significantly outperforming generic binary
|
|
106
119
|
* serialization formats with the following optimizations:
|
|
107
120
|
*
|
|
108
121
|
* - **NonNegativeInt:** Up to 33% smaller than MessagePack.
|
|
109
|
-
* - **Base64Url Strings:** Up to 25% size reduction.
|
|
110
122
|
* - **DateIso:** Up to 75% smaller.
|
|
111
123
|
* - **Timestamp Encoding:** Delta encoding for milliseconds and run-length
|
|
112
124
|
* encoding (RLE) for counters and NodeIds.
|
|
@@ -136,161 +148,114 @@
|
|
|
136
148
|
* Version negotiation is per-owner, allowing Evolu Protocol to evolve safely
|
|
137
149
|
* over time and provide clear feedback about version mismatches.
|
|
138
150
|
*
|
|
151
|
+
* ### Credible exit
|
|
152
|
+
*
|
|
153
|
+
* The protocol specification is intentionally non-configurable to ensure
|
|
154
|
+
* universal compatibility. This design allows applications (users) to switch
|
|
155
|
+
* between any compliant relay without negotiation or compatibility checks
|
|
156
|
+
* beyond version matching. Relays are generic infrastructure that any
|
|
157
|
+
* application can use interchangeably making exit from any single provider
|
|
158
|
+
* technically feasible and economically viable.
|
|
159
|
+
*
|
|
139
160
|
* @module
|
|
140
161
|
*/
|
|
141
162
|
import { NonEmptyReadonlyArray } from "../Array.js";
|
|
163
|
+
import { Brand } from "../Brand.js";
|
|
142
164
|
import { Buffer } from "../Buffer.js";
|
|
143
|
-
import {
|
|
165
|
+
import { EncryptionKey, RandomBytesDep, SymmetricCryptoDecryptError, SymmetricCryptoDep } from "../Crypto.js";
|
|
144
166
|
import { Result } from "../Result.js";
|
|
145
167
|
import { SqliteValue } from "../Sqlite.js";
|
|
146
|
-
import {
|
|
147
|
-
import {
|
|
148
|
-
import {
|
|
149
|
-
import {
|
|
150
|
-
/**
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
168
|
+
import { NonNegativeInt, PositiveInt } from "../Type.js";
|
|
169
|
+
import { BaseOwnerError, Owner, OwnerId, OwnerWriteKey } from "./Owner.js";
|
|
170
|
+
import { BaseRange, CrdtMessage, DbChange, EncryptedCrdtMessage, EncryptedDbChange, FingerprintRange, RangeType, SkipRange, StorageDep } from "./Storage.js";
|
|
171
|
+
import { NodeId, Timestamp } from "./Timestamp.js";
|
|
172
|
+
/**
|
|
173
|
+
* Protocol message maximum size.
|
|
174
|
+
*
|
|
175
|
+
* Defines the upper limit for how large a single protocol message can be.
|
|
176
|
+
* Implementations must enforce a maximum size between 1MB and 100MB to ensure
|
|
177
|
+
* compatibility across all Evolu implementations (the maximum size of mutation
|
|
178
|
+
* change is hardcoded and enforced hence the maximum size can't be smaller).
|
|
179
|
+
*
|
|
180
|
+
* Larger maximum sizes can be configured by relays to reduce roundtrips. For
|
|
181
|
+
* example, a dedicated relay with ample resources could configure a 100MB
|
|
182
|
+
* maximum to minimize roundtrips for large syncs.
|
|
183
|
+
*
|
|
184
|
+
* Only relays can safely configure larger sizes, as clients will handle them.
|
|
185
|
+
* Increasing this value on the client side would break compatibility with
|
|
186
|
+
* relays that enforce smaller limits.
|
|
187
|
+
*/
|
|
188
|
+
export declare const ProtocolMessageMaxSize: import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & Brand<"Int">, number, import("../Type.js").IntError, number, import("../Type.js").NumberError>, "Between1000000-100000000", import("../Type.js").BetweenError<1000000, 100000000>, import("../Type.js").IntError | import("../Type.js").NumberError>;
|
|
189
|
+
export type ProtocolMessageMaxSize = typeof ProtocolMessageMaxSize.Type;
|
|
190
|
+
/**
|
|
191
|
+
* Default {@link ProtocolMessageMaxSize} (1MB).
|
|
192
|
+
*
|
|
193
|
+
* The standard size used across Evolu implementations. Relays with more
|
|
194
|
+
* resources can configure larger sizes to reduce roundtrips.
|
|
195
|
+
*/
|
|
196
|
+
export declare const defaultProtocolMessageMaxSize: ProtocolMessageMaxSize;
|
|
197
|
+
/**
|
|
198
|
+
* Protocol message ranges maximum size.
|
|
199
|
+
*
|
|
200
|
+
* Defines the upper limit for how large the ranges section of a protocol
|
|
201
|
+
* message can be. Implementations must enforce a maximum size between 3KB and
|
|
202
|
+
* 100KB to ensure compatibility.
|
|
203
|
+
*
|
|
204
|
+
* The upper bound is set to ensure ranges fit within the default 1MB
|
|
205
|
+
* {@link defaultProtocolMessageMaxSize}, maintaining compatibility between all
|
|
206
|
+
* clients and relays.
|
|
207
|
+
*/
|
|
208
|
+
export declare const ProtocolMessageRangesMaxSize: import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & Brand<"Int">, number, import("../Type.js").IntError, number, import("../Type.js").NumberError>, "Between3000-100000", import("../Type.js").BetweenError<3000, 100000>, import("../Type.js").IntError | import("../Type.js").NumberError>;
|
|
209
|
+
export type ProtocolMessageRangesMaxSize = typeof ProtocolMessageRangesMaxSize.Type;
|
|
210
|
+
/**
|
|
211
|
+
* Default {@link ProtocolMessageRangesMaxSize} (30KB).
|
|
212
|
+
*
|
|
213
|
+
* The standard size used across Evolu implementations. Relays with more
|
|
214
|
+
* resources can configure larger sizes to reduce roundtrips.
|
|
215
|
+
*/
|
|
216
|
+
export declare const defaultProtocolMessageRangesMaxSize: ProtocolMessageRangesMaxSize;
|
|
154
217
|
/** Evolu Protocol Message. */
|
|
155
218
|
export type ProtocolMessage = Uint8Array & Brand<"ProtocolMessage">;
|
|
156
219
|
/** Evolu Protocol version. */
|
|
157
|
-
export declare const protocolVersion:
|
|
220
|
+
export declare const protocolVersion: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
221
|
+
export declare const MessageType: {
|
|
222
|
+
/** Request message from initiator (client) to non-initiator (relay). */
|
|
223
|
+
readonly Request: 0;
|
|
224
|
+
/** Response message from non-initiator (relay) to initiator (client). */
|
|
225
|
+
readonly Response: 1;
|
|
226
|
+
/** Broadcast message from non-initiator (relay) to subscribed clients. */
|
|
227
|
+
readonly Broadcast: 2;
|
|
228
|
+
};
|
|
229
|
+
export type MessageType = (typeof MessageType)[keyof typeof MessageType];
|
|
230
|
+
export declare const SubscriptionFlags: {
|
|
231
|
+
/** No subscription changes for this owner. */
|
|
232
|
+
readonly None: 0;
|
|
233
|
+
/** Subscribe to updates for this owner. */
|
|
234
|
+
readonly Subscribe: 1;
|
|
235
|
+
/** Unsubscribe from updates for this owner. */
|
|
236
|
+
readonly Unsubscribe: 2;
|
|
237
|
+
};
|
|
238
|
+
export type SubscriptionFlag = (typeof SubscriptionFlags)[keyof typeof SubscriptionFlags];
|
|
158
239
|
export declare const ProtocolErrorCode: {
|
|
159
240
|
readonly NoError: 0;
|
|
160
241
|
/** A code for {@link ProtocolWriteKeyError}. */
|
|
161
242
|
readonly WriteKeyError: 1;
|
|
162
243
|
/** A code for {@link ProtocolWriteError}. */
|
|
163
244
|
readonly WriteError: 2;
|
|
245
|
+
/** A code for {@link ProtocolQuotaError}. */
|
|
246
|
+
readonly QuotaError: 3;
|
|
164
247
|
/** A code for {@link ProtocolSyncError}. */
|
|
165
|
-
readonly SyncError:
|
|
248
|
+
readonly SyncError: 4;
|
|
166
249
|
};
|
|
167
250
|
type ProtocolErrorCode = (typeof ProtocolErrorCode)[keyof typeof ProtocolErrorCode];
|
|
168
|
-
export
|
|
169
|
-
readonly None: 0;
|
|
170
|
-
readonly Single: 1;
|
|
171
|
-
readonly Rotation: 2;
|
|
172
|
-
};
|
|
173
|
-
/**
|
|
174
|
-
* Evolu Protocol Storage
|
|
175
|
-
*
|
|
176
|
-
* The protocol is agnostic to storage implementation details—any storage can be
|
|
177
|
-
* plugged in, as long as it implements this interface. Implementations must
|
|
178
|
-
* handle their own errors; return values only indicates overall success or
|
|
179
|
-
* failure.
|
|
180
|
-
*/
|
|
181
|
-
export interface Storage {
|
|
182
|
-
readonly getSize: (ownerId: BinaryOwnerId) => NonNegativeInt | null;
|
|
183
|
-
readonly fingerprint: (ownerId: BinaryOwnerId, begin: NonNegativeInt, end: NonNegativeInt) => Fingerprint | null;
|
|
184
|
-
/**
|
|
185
|
-
* Computes fingerprints with their upper bounds in one call.
|
|
186
|
-
*
|
|
187
|
-
* This function can be replaced with many fingerprint/findLowerBound calls,
|
|
188
|
-
* but implementations can leverage it for batching and more efficient
|
|
189
|
-
* fingerprint computation.
|
|
190
|
-
*/
|
|
191
|
-
readonly fingerprintRanges: (ownerId: BinaryOwnerId, buckets: ReadonlyArray<NonNegativeInt>, upperBound?: RangeUpperBound) => ReadonlyArray<FingerprintRange> | null;
|
|
192
|
-
readonly findLowerBound: (ownerId: BinaryOwnerId, begin: NonNegativeInt, end: NonNegativeInt, upperBound: RangeUpperBound) => NonNegativeInt | null;
|
|
193
|
-
readonly iterate: (ownerId: BinaryOwnerId, begin: NonNegativeInt, end: NonNegativeInt, callback: (timestamp: BinaryTimestamp, index: NonNegativeInt) => boolean) => void;
|
|
194
|
-
/** Validates the {@link WriteKey} for the given {@link Owner}. */
|
|
195
|
-
readonly validateWriteKey: (ownerId: BinaryOwnerId, writeKey: WriteKey) => boolean;
|
|
196
|
-
/** Sets the {@link WriteKey} for the given {@link Owner}. */
|
|
197
|
-
readonly setWriteKey: (ownerId: BinaryOwnerId, writeKey: WriteKey) => boolean;
|
|
198
|
-
/** Write encrypted {@link CrdtMessage}s to storage. */
|
|
199
|
-
readonly writeMessages: (ownerId: BinaryOwnerId, messages: NonEmptyReadonlyArray<EncryptedCrdtMessage>) => boolean;
|
|
200
|
-
/** Read encrypted {@link DbChange}s from storage. */
|
|
201
|
-
readonly readDbChange: (ownerId: BinaryOwnerId, timestamp: BinaryTimestamp) => EncryptedDbChange | null;
|
|
202
|
-
/** Delete all data for the given {@link Owner}. */
|
|
203
|
-
readonly deleteOwner: (ownerId: BinaryOwnerId) => boolean;
|
|
204
|
-
}
|
|
205
|
-
export interface StorageDep {
|
|
206
|
-
readonly storage: Storage;
|
|
207
|
-
}
|
|
208
|
-
/** An encrypted {@link CrdtMessage}. */
|
|
209
|
-
export interface EncryptedCrdtMessage {
|
|
210
|
-
readonly timestamp: Timestamp;
|
|
211
|
-
readonly change: EncryptedDbChange;
|
|
212
|
-
}
|
|
213
|
-
/** Encrypted DbChange */
|
|
214
|
-
export type EncryptedDbChange = Uint8Array & Brand<"EncryptedDbChange">;
|
|
215
|
-
/**
|
|
216
|
-
* A CRDT message that combines a unique {@link Timestamp} with a
|
|
217
|
-
* {@link DbChange}.
|
|
218
|
-
*/
|
|
219
|
-
export interface CrdtMessage {
|
|
220
|
-
readonly timestamp: Timestamp;
|
|
221
|
-
readonly change: DbChange;
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Base64Url string with maximum length of 256 characters. Encoding strings as
|
|
225
|
-
* Base64UrlString saves up to 25% in size compared to regular strings.
|
|
226
|
-
*/
|
|
227
|
-
export declare const Base64Url256: import("../Type.js").BrandType<import("../Type.js").Type<"Brand", string & Brand<"Base64Url">, string, import("../Type.js").RegexError<"Base64Url">, string, import("../Type.js").StringError>, "MaxLength256", import("../Type.js").MaxLengthError<256>, import("../Type.js").StringError | import("../Type.js").RegexError<"Base64Url">>;
|
|
228
|
-
export type Base64Url256 = typeof Base64Url256.Type;
|
|
229
|
-
/**
|
|
230
|
-
* A DbChange is a change to a table row. Together with a unique
|
|
231
|
-
* {@link Timestamp}, it forms a {@link CrdtMessage}.
|
|
232
|
-
*/
|
|
233
|
-
export declare const DbChange: import("../Type.js").ObjectType<{
|
|
234
|
-
table: import("../Type.js").BrandType<import("../Type.js").Type<"Brand", string & Brand<"Base64Url">, string, import("../Type.js").RegexError<"Base64Url">, string, import("../Type.js").StringError>, "MaxLength256", import("../Type.js").MaxLengthError<256>, import("../Type.js").StringError | import("../Type.js").RegexError<"Base64Url">>;
|
|
235
|
-
id: import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "Id", import("../Type.js").RegexError<"Id">, import("../Type.js").StringError>;
|
|
236
|
-
values: import("../Type.js").RecordType<"Brand", string & Brand<"Base64Url"> & Brand<"MaxLength256">, string, import("../Type.js").MaxLengthError<256>, string & Brand<"Base64Url">, import("../Type.js").StringError | import("../Type.js").RegexError<"Base64Url">, import("../Type.js").UnionType<[import("../Type.js").Type<"Null", null, null, import("../Type.js").NullError, null, import("../Type.js").NullError>, import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, import("../Type.js").Type<"Number", number, number, import("../Type.js").NumberError, number, import("../Type.js").NumberError>, import("../Type.js").Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError, Uint8Array<ArrayBufferLike>, import("../Type.js").Uint8ArrayError>]>>;
|
|
237
|
-
}>;
|
|
238
|
-
export type DbChange = typeof DbChange.Type;
|
|
239
|
-
export declare const RangeType: {
|
|
240
|
-
readonly Fingerprint: 1;
|
|
241
|
-
readonly Skip: 0;
|
|
242
|
-
readonly Timestamps: 2;
|
|
243
|
-
};
|
|
244
|
-
export type RangeType = (typeof RangeType)[keyof typeof RangeType];
|
|
245
|
-
export declare const InfiniteUpperBound: unique symbol;
|
|
246
|
-
export type InfiniteUpperBound = typeof InfiniteUpperBound;
|
|
247
|
-
/**
|
|
248
|
-
* Union type for Range's upperBound: either a {@link BinaryTimestamp} or
|
|
249
|
-
* {@link InfiniteUpperBound}.
|
|
250
|
-
*/
|
|
251
|
-
export type RangeUpperBound = BinaryTimestamp | InfiniteUpperBound;
|
|
252
|
-
interface BaseRange {
|
|
253
|
-
readonly upperBound: RangeUpperBound;
|
|
254
|
-
}
|
|
255
|
-
export interface SkipRange extends BaseRange {
|
|
256
|
-
readonly type: typeof RangeType.Skip;
|
|
257
|
-
}
|
|
258
|
-
export interface FingerprintRange extends BaseRange {
|
|
259
|
-
readonly type: typeof RangeType.Fingerprint;
|
|
260
|
-
readonly fingerprint: Fingerprint;
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* A cryptographic hash used for efficiently comparing collections of
|
|
264
|
-
* {@link BinaryTimestamp}s.
|
|
265
|
-
*
|
|
266
|
-
* It consists of the first {@link fingerprintSize} bytes of the SHA-256 hash of
|
|
267
|
-
* one or more timestamps.
|
|
268
|
-
*/
|
|
269
|
-
export type Fingerprint = Uint8Array & Brand<"Fingerprint">;
|
|
270
|
-
export declare const fingerprintSize: NonNegativeInt;
|
|
271
|
-
/** A fingerprint of an empty range. */
|
|
272
|
-
export declare const zeroFingerprint: Fingerprint;
|
|
273
|
-
export interface TimestampsRange extends BaseRange {
|
|
274
|
-
readonly type: typeof RangeType.Timestamps;
|
|
275
|
-
readonly timestamps: ReadonlyArray<BinaryTimestamp>;
|
|
276
|
-
}
|
|
277
|
-
export interface TimestampsRangeWithTimestampsBuffer extends BaseRange {
|
|
278
|
-
readonly type: typeof RangeType.Timestamps;
|
|
279
|
-
readonly timestamps: TimestampsBuffer;
|
|
280
|
-
}
|
|
281
|
-
export type Range = SkipRange | FingerprintRange | TimestampsRange;
|
|
282
|
-
export type ProtocolError = ProtocolUnsupportedVersionError | ProtocolInvalidDataError | ProtocolWriteKeyError | ProtocolWriteError | ProtocolSyncError;
|
|
283
|
-
/** Base interface for all protocol errors. */
|
|
284
|
-
export interface ProtocolErrorBase {
|
|
285
|
-
readonly ownerId: OwnerId;
|
|
286
|
-
}
|
|
251
|
+
export type ProtocolError = ProtocolVersionError | ProtocolInvalidDataError | ProtocolWriteKeyError | ProtocolWriteError | ProtocolSyncError | ProtocolQuotaError | ProtocolTimestampMismatchError;
|
|
287
252
|
/**
|
|
288
253
|
* Represents a version mismatch in the Evolu Protocol. Occurs when the
|
|
289
254
|
* initiator and non-initiator are using incompatible protocol versions.
|
|
290
255
|
*/
|
|
291
|
-
export interface
|
|
292
|
-
readonly type: "
|
|
293
|
-
readonly
|
|
256
|
+
export interface ProtocolVersionError extends BaseOwnerError {
|
|
257
|
+
readonly type: "ProtocolVersionError";
|
|
258
|
+
readonly version: NonNegativeInt;
|
|
294
259
|
/** Indicates which side is obsolete and should update. */
|
|
295
260
|
readonly isInitiator: boolean;
|
|
296
261
|
}
|
|
@@ -300,36 +265,61 @@ export interface ProtocolInvalidDataError {
|
|
|
300
265
|
readonly data: globalThis.Uint8Array;
|
|
301
266
|
readonly error: unknown;
|
|
302
267
|
}
|
|
303
|
-
/** Error when a {@link
|
|
304
|
-
export interface ProtocolWriteKeyError extends
|
|
268
|
+
/** Error when a {@link OwnerWriteKey} is invalid, missing, or fails validation. */
|
|
269
|
+
export interface ProtocolWriteKeyError extends BaseOwnerError {
|
|
305
270
|
readonly type: "ProtocolWriteKeyError";
|
|
306
271
|
}
|
|
307
272
|
/**
|
|
308
|
-
* Error
|
|
309
|
-
*
|
|
273
|
+
* Error indicating a serious relay-side write failure. Clients should log this
|
|
274
|
+
* error and show a generic sync error to the user.
|
|
310
275
|
*/
|
|
311
|
-
export interface ProtocolWriteError extends
|
|
276
|
+
export interface ProtocolWriteError extends BaseOwnerError {
|
|
312
277
|
readonly type: "ProtocolWriteError";
|
|
313
278
|
}
|
|
314
279
|
/**
|
|
315
|
-
* Error
|
|
316
|
-
*
|
|
280
|
+
* Error when storage or billing quota is exceeded.
|
|
281
|
+
*
|
|
282
|
+
* When relay rejects writes due to quota, the affected device stops syncing
|
|
283
|
+
* because RBSR requires both sides to converge—if the relay won't accept the
|
|
284
|
+
* client's data, they can never reach the same state. Only the device with
|
|
285
|
+
* excess local data is affected. Other devices that haven't exceeded quota can
|
|
286
|
+
* still sync normally.
|
|
287
|
+
*
|
|
288
|
+
* Clients should prompt the user to contact the relay provider or upgrade their
|
|
289
|
+
* plan. Quota monitoring and management is the relay provider's
|
|
290
|
+
* responsibility.
|
|
291
|
+
*/
|
|
292
|
+
export interface ProtocolQuotaError extends BaseOwnerError {
|
|
293
|
+
readonly type: "ProtocolQuotaError";
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Error indicating a serious relay-side synchronization failure. Clients should
|
|
297
|
+
* log this error and show a generic sync error to the user.
|
|
317
298
|
*/
|
|
318
|
-
export interface ProtocolSyncError extends
|
|
299
|
+
export interface ProtocolSyncError extends BaseOwnerError {
|
|
319
300
|
readonly type: "ProtocolSyncError";
|
|
320
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* Error when embedded timestamp doesn't match expected timestamp in
|
|
304
|
+
* EncryptedDbChange. Indicates potential tampering or corruption of CRDT
|
|
305
|
+
* messages.
|
|
306
|
+
*/
|
|
307
|
+
export interface ProtocolTimestampMismatchError {
|
|
308
|
+
readonly type: "ProtocolTimestampMismatchError";
|
|
309
|
+
readonly expected: Timestamp;
|
|
310
|
+
readonly timestamp: Timestamp;
|
|
311
|
+
}
|
|
321
312
|
/**
|
|
322
313
|
* Creates a {@link ProtocolMessage} from CRDT messages.
|
|
323
314
|
*
|
|
324
|
-
* If the message size would exceed {@link
|
|
325
|
-
* ensures all messages will be sent in the next round(s) even over
|
|
315
|
+
* If the message size would exceed {@link defaultProtocolMessageMaxSize}, the
|
|
316
|
+
* protocol ensures all messages will be sent in the next round(s) even over
|
|
326
317
|
* unidirectional and stateless transports.
|
|
327
318
|
*/
|
|
328
|
-
export declare const createProtocolMessageFromCrdtMessages: (deps:
|
|
319
|
+
export declare const createProtocolMessageFromCrdtMessages: (deps: RandomBytesDep & SymmetricCryptoDep) => (owner: Owner, messages: NonEmptyReadonlyArray<CrdtMessage>, maxSize?: ProtocolMessageMaxSize) => ProtocolMessage;
|
|
329
320
|
/** Creates a {@link ProtocolMessage} for sync. */
|
|
330
|
-
export declare const createProtocolMessageForSync: (deps: StorageDep) => (ownerId: OwnerId) => ProtocolMessage | null;
|
|
331
|
-
|
|
332
|
-
export declare const createProtocolMessageForWriteKeyRotation: (ownerId: OwnerId, currentWriteKey: WriteKey, newWriteKey: WriteKey) => ProtocolMessage;
|
|
321
|
+
export declare const createProtocolMessageForSync: (deps: StorageDep) => (ownerId: OwnerId, subscriptionFlag?: SubscriptionFlag) => ProtocolMessage | null;
|
|
322
|
+
export declare const createProtocolMessageForUnsubscribe: (ownerId: OwnerId) => ProtocolMessage;
|
|
333
323
|
/**
|
|
334
324
|
* Mutable builder for constructing {@link ProtocolMessage} respecting size
|
|
335
325
|
* limits.
|
|
@@ -344,17 +334,23 @@ export interface ProtocolMessageBuffer {
|
|
|
344
334
|
readonly getSize: () => PositiveInt;
|
|
345
335
|
}
|
|
346
336
|
export declare const createProtocolMessageBuffer: (ownerId: OwnerId, options: {
|
|
347
|
-
readonly totalMaxSize?:
|
|
348
|
-
readonly rangesMaxSize?:
|
|
337
|
+
readonly totalMaxSize?: ProtocolMessageMaxSize | undefined;
|
|
338
|
+
readonly rangesMaxSize?: ProtocolMessageRangesMaxSize | undefined;
|
|
349
339
|
readonly version?: NonNegativeInt;
|
|
350
340
|
} & ({
|
|
351
|
-
readonly
|
|
352
|
-
|
|
353
|
-
readonly
|
|
341
|
+
readonly messageType: typeof MessageType.Request;
|
|
342
|
+
readonly writeKey?: OwnerWriteKey;
|
|
343
|
+
readonly subscriptionFlag?: SubscriptionFlag;
|
|
354
344
|
} | {
|
|
355
|
-
readonly
|
|
345
|
+
readonly messageType: typeof MessageType.Response;
|
|
356
346
|
readonly errorCode: ProtocolErrorCode;
|
|
347
|
+
} | {
|
|
348
|
+
readonly messageType: typeof MessageType.Broadcast;
|
|
357
349
|
})) => ProtocolMessageBuffer;
|
|
350
|
+
export interface TimestampsRangeWithTimestampsBuffer extends BaseRange {
|
|
351
|
+
readonly type: typeof RangeType.Timestamps;
|
|
352
|
+
readonly timestamps: TimestampsBuffer;
|
|
353
|
+
}
|
|
358
354
|
export interface TimestampsBuffer {
|
|
359
355
|
readonly add: (timestamp: Timestamp) => void;
|
|
360
356
|
readonly addInfinite: () => void;
|
|
@@ -364,61 +360,94 @@ export interface TimestampsBuffer {
|
|
|
364
360
|
}
|
|
365
361
|
export declare const createTimestampsBuffer: () => TimestampsBuffer;
|
|
366
362
|
export interface ApplyProtocolMessageAsClientOptions {
|
|
367
|
-
getWriteKey?: (ownerId: OwnerId) =>
|
|
368
|
-
|
|
363
|
+
getWriteKey?: (ownerId: OwnerId) => OwnerWriteKey | null;
|
|
364
|
+
rangesMaxSize?: ProtocolMessageRangesMaxSize;
|
|
365
|
+
/** For tests only. */
|
|
369
366
|
version?: NonNegativeInt;
|
|
370
|
-
totalMaxSize?: PositiveInt;
|
|
371
|
-
rangesMaxSize?: PositiveInt;
|
|
372
367
|
}
|
|
373
|
-
|
|
368
|
+
/**
|
|
369
|
+
* Result type for {@link applyProtocolMessageAsClient} that distinguishes
|
|
370
|
+
* between responses to client requests and broadcast messages.
|
|
371
|
+
*/
|
|
372
|
+
export type ApplyProtocolMessageAsClientResult = {
|
|
373
|
+
readonly type: "response";
|
|
374
|
+
readonly message: ProtocolMessage;
|
|
375
|
+
} | {
|
|
376
|
+
readonly type: "no-response";
|
|
377
|
+
} | {
|
|
378
|
+
readonly type: "broadcast";
|
|
379
|
+
};
|
|
380
|
+
export declare const applyProtocolMessageAsClient: (deps: StorageDep) => (inputMessage: Uint8Array, options?: ApplyProtocolMessageAsClientOptions) => Promise<Result<ApplyProtocolMessageAsClientResult, ProtocolInvalidDataError | ProtocolSyncError | ProtocolVersionError | ProtocolWriteError | ProtocolWriteKeyError | ProtocolQuotaError>>;
|
|
374
381
|
export interface ApplyProtocolMessageAsRelayOptions {
|
|
375
382
|
/** To subscribe an owner for broadcasting. */
|
|
376
383
|
subscribe?: (ownerId: OwnerId) => void;
|
|
384
|
+
/** To unsubscribe an owner from broadcasting. */
|
|
385
|
+
unsubscribe?: (ownerId: OwnerId) => void;
|
|
377
386
|
/** To broadcast a protocol message to all subscribers. */
|
|
378
387
|
broadcast?: (ownerId: OwnerId, message: ProtocolMessage) => void;
|
|
379
|
-
totalMaxSize?:
|
|
380
|
-
rangesMaxSize?:
|
|
388
|
+
totalMaxSize?: ProtocolMessageMaxSize;
|
|
389
|
+
rangesMaxSize?: ProtocolMessageRangesMaxSize;
|
|
381
390
|
}
|
|
382
|
-
export declare const applyProtocolMessageAsRelay: (deps: StorageDep) => (inputMessage: Uint8Array, { subscribe, broadcast, totalMaxSize, rangesMaxSize, }?: ApplyProtocolMessageAsRelayOptions,
|
|
383
|
-
/** For testing purposes only; should not be used in production. */
|
|
384
|
-
version?: number & Brand<"Int"> & Brand<"NonNegative">) => Result<ProtocolMessage | null, ProtocolInvalidDataError>;
|
|
385
|
-
/** Binary representation of {@link Id}. */
|
|
386
|
-
export type BinaryId = Uint8Array & Brand<"BinaryId">;
|
|
387
|
-
export declare const binaryIdLength: NonNegativeInt;
|
|
388
|
-
export declare const idToBinaryId: (id: Id) => BinaryId;
|
|
389
|
-
export declare const binaryIdToId: (binaryId: BinaryId) => Id;
|
|
390
|
-
/** Binary representation of {@link OwnerId}. */
|
|
391
|
-
export type BinaryOwnerId = Uint8Array & Brand<"BinaryOwnerId">;
|
|
392
|
-
export declare const ownerIdToBinaryOwnerId: (ownerId: OwnerId) => BinaryOwnerId;
|
|
393
|
-
export declare const binaryOwnerIdToOwnerId: (binaryOwnerId: BinaryOwnerId) => OwnerId;
|
|
394
391
|
/**
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
*
|
|
401
|
-
*
|
|
392
|
+
* Result type for {@link applyProtocolMessageAsRelay}.
|
|
393
|
+
*
|
|
394
|
+
* Unlike {@link ApplyProtocolMessageAsClientResult}, relays always respond with
|
|
395
|
+
* a message to provide sync completion feedback. This ensures the initiator can
|
|
396
|
+
* reliably detect when synchronization is complete, even when there's nothing
|
|
397
|
+
* to sync. Clients may choose not to respond in certain cases (like when they
|
|
398
|
+
* receive broadcast messages or when they lack a write key for syncing).
|
|
402
399
|
*/
|
|
403
|
-
export
|
|
404
|
-
|
|
400
|
+
export interface ApplyProtocolMessageAsRelayResult {
|
|
401
|
+
readonly type: "response";
|
|
402
|
+
readonly message: ProtocolMessage;
|
|
403
|
+
}
|
|
404
|
+
export declare const applyProtocolMessageAsRelay: (deps: StorageDep) => (inputMessage: Uint8Array, options?: ApplyProtocolMessageAsRelayOptions,
|
|
405
|
+
/** For tests only. */
|
|
406
|
+
version?: number & Brand<"Int"> & Brand<"NonNegative">) => Promise<Result<ApplyProtocolMessageAsRelayResult, ProtocolInvalidDataError>>;
|
|
405
407
|
/**
|
|
406
408
|
* Evolu uses MessagePack to handle all number variants except for
|
|
407
409
|
* NonNegativeInt. For NonNegativeInt, Evolu provides more efficient encoding.
|
|
408
410
|
*/
|
|
409
411
|
export declare const encodeNumber: (buffer: Buffer, number: number) => void;
|
|
410
412
|
export declare const decodeNumber: (buffer: Buffer) => number;
|
|
411
|
-
|
|
413
|
+
/**
|
|
414
|
+
* Encodes an array of boolean flags into a single byte.
|
|
415
|
+
*
|
|
416
|
+
* Each element in the array corresponds to a bit (0-7). Array can have 0-8
|
|
417
|
+
* elements.
|
|
418
|
+
*
|
|
419
|
+
* ### Example
|
|
420
|
+
*
|
|
421
|
+
* ```ts
|
|
422
|
+
* encodeFlags(buffer, [true, false, true]); // Encodes bits 0, 1, 2
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
425
|
+
export declare const encodeFlags: (buffer: Buffer, flags: ReadonlyArray<boolean>) => void;
|
|
426
|
+
/**
|
|
427
|
+
* Decodes a byte into an array of boolean flags.
|
|
428
|
+
*
|
|
429
|
+
* ### Example
|
|
430
|
+
*
|
|
431
|
+
* ```ts
|
|
432
|
+
* const flags = decodeFlags(buffer, 3); // Decode 3 flags
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
export declare const decodeFlags: (buffer: Buffer, count: PositiveInt) => ReadonlyArray<boolean>;
|
|
412
436
|
/**
|
|
413
437
|
* Encodes and encrypts a {@link DbChange} using the provided owner's encryption
|
|
414
438
|
* key. Returns an encrypted binary representation as {@link EncryptedDbChange}.
|
|
439
|
+
*
|
|
440
|
+
* The format includes the protocol version for backward compatibility and the
|
|
441
|
+
* timestamp for tamper-proof verification that the timestamp matches the change
|
|
442
|
+
* data.
|
|
415
443
|
*/
|
|
416
|
-
export declare const encodeAndEncryptDbChange: (deps: SymmetricCryptoDep) => (
|
|
444
|
+
export declare const encodeAndEncryptDbChange: (deps: SymmetricCryptoDep) => (message: CrdtMessage, key: EncryptionKey) => EncryptedDbChange;
|
|
417
445
|
/**
|
|
418
|
-
* Decrypts and decodes an {@link
|
|
419
|
-
* encryption key.
|
|
446
|
+
* Decrypts and decodes an {@link EncryptedCrdtMessage} using the provided
|
|
447
|
+
* owner's encryption key. Verifies that the embedded timestamp matches the
|
|
448
|
+
* expected timestamp to ensure message integrity.
|
|
420
449
|
*/
|
|
421
|
-
export declare const decryptAndDecodeDbChange: (deps: SymmetricCryptoDep) => (
|
|
450
|
+
export declare const decryptAndDecodeDbChange: (deps: SymmetricCryptoDep) => (message: EncryptedCrdtMessage, key: EncryptionKey) => Result<DbChange, SymmetricCryptoDecryptError | ProtocolInvalidDataError | ProtocolTimestampMismatchError>;
|
|
422
451
|
/**
|
|
423
452
|
* Encodes a non-negative integer into a variable-length integer format. It's
|
|
424
453
|
* more efficient than encoding via {@link encodeNumber}.
|
|
@@ -438,19 +467,18 @@ export declare const encodeString: (buffer: Buffer, value: string) => void;
|
|
|
438
467
|
export declare const decodeString: (buffer: Buffer) => string;
|
|
439
468
|
export declare const encodeNodeId: (buffer: Buffer, nodeId: NodeId) => void;
|
|
440
469
|
export declare const decodeNodeId: (buffer: Buffer) => NodeId;
|
|
441
|
-
export declare const encodeBase64Url256: (buffer: Buffer, string: Base64Url256Variant) => void;
|
|
442
|
-
export declare const decodeBase64Url256WithLength: (buffer: Buffer) => Base64Url256;
|
|
443
470
|
export declare const ProtocolValueType: {
|
|
444
|
-
readonly String:
|
|
445
|
-
readonly Number:
|
|
446
|
-
readonly Null:
|
|
447
|
-
readonly
|
|
448
|
-
readonly
|
|
449
|
-
readonly
|
|
450
|
-
readonly
|
|
451
|
-
readonly
|
|
452
|
-
readonly
|
|
453
|
-
readonly
|
|
471
|
+
readonly String: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
472
|
+
readonly Number: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
473
|
+
readonly Null: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
474
|
+
readonly Bytes: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
475
|
+
readonly NonNegativeInt: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
476
|
+
readonly EmptyString: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
477
|
+
readonly Base64Url: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
478
|
+
readonly Id: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
479
|
+
readonly Json: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
480
|
+
readonly DateIsoWithNonNegativeTime: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
481
|
+
readonly DateIsoWithNegativeTime: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
454
482
|
};
|
|
455
483
|
export declare const encodeSqliteValue: (buffer: Buffer, value: SqliteValue) => void;
|
|
456
484
|
export declare const decodeSqliteValue: (buffer: Buffer) => SqliteValue;
|