@evolu/common 6.0.1-preview.20 → 6.0.1-preview.22
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/Evolu/Db.d.ts +23 -1
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.d.ts +21 -25
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +15 -135
- package/dist/src/Evolu/Owner.d.ts +60 -0
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +33 -0
- package/dist/src/Evolu/Protocol.d.ts +91 -30
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +80 -25
- package/dist/src/Evolu/Relay.d.ts +70 -3
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +74 -1
- package/dist/src/Evolu/Sync.d.ts +2 -11
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +7 -46
- package/dist/src/Result.d.ts +45 -16
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +23 -0
- package/dist/src/Task.js +1 -1
- package/dist/src/Type.d.ts +12 -0
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +12 -0
- package/package.json +1 -1
- package/src/Evolu/Db.ts +24 -1
- package/src/Evolu/Evolu.ts +21 -259
- package/src/Evolu/Owner.ts +70 -1
- package/src/Evolu/Protocol.ts +117 -36
- package/src/Evolu/Relay.ts +180 -6
- package/src/Evolu/Sync.ts +7 -57
- package/src/Result.ts +47 -16
- package/src/Task.ts +3 -3
- package/src/Type.ts +12 -0
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* transfer, ownership, real-time broadcasting, request-response semantics, and
|
|
21
21
|
* error handling.
|
|
22
22
|
*
|
|
23
|
-
* ### Message
|
|
23
|
+
* ### Message structure
|
|
24
24
|
*
|
|
25
25
|
* | Field | Notes |
|
|
26
26
|
* | :----------------------------- | :------------------------ |
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
* | - {@link NonNegativeInt} | Number of ranges. |
|
|
44
44
|
* | - {@link Range} | |
|
|
45
45
|
*
|
|
46
|
-
* ### WriteKey
|
|
46
|
+
* ### WriteKey validation
|
|
47
47
|
*
|
|
48
48
|
* The initiator sends a hasWriteKey flag and optionally a WriteKey. The
|
|
49
49
|
* WriteKey is required when sending messages as a secure token proving the
|
|
@@ -79,33 +79,33 @@
|
|
|
79
79
|
* initiator. In relay-to-relay or P2P sync, both sides may require the
|
|
80
80
|
* {@link OwnerWriteKey} depending on who is the initiator.
|
|
81
81
|
*
|
|
82
|
-
* ### Protocol
|
|
82
|
+
* ### Protocol errors
|
|
83
83
|
*
|
|
84
84
|
* The protocol uses error codes in the header to signal issues:
|
|
85
85
|
*
|
|
86
86
|
* - {@link ProtocolWriteKeyError}: The provided WriteKey is invalid or missing.
|
|
87
|
-
* - {@link ProtocolWriteError}: A write
|
|
88
|
-
*
|
|
89
|
-
* - {@link ProtocolSyncError}: A generic or unexpected synchronization failure
|
|
87
|
+
* - {@link ProtocolWriteError}: A serious relay-side write failure occurred.
|
|
88
|
+
* - {@link ProtocolSyncError}: A serious relay-side synchronization failure
|
|
90
89
|
* occurred.
|
|
90
|
+
* - {@link ProtocolQuotaExceededError}: Storage or billing quota exceeded.
|
|
91
91
|
* - {@link ProtocolUnsupportedVersionError}: Protocol version mismatch.
|
|
92
92
|
* - {@link ProtocolInvalidDataError}: The message is malformed or corrupted.
|
|
93
93
|
*
|
|
94
94
|
* All protocol errors except `ProtocolInvalidDataError` include the `OwnerId`
|
|
95
95
|
* to allow clients to associate errors with the correct owner.
|
|
96
96
|
*
|
|
97
|
-
* ### Message
|
|
97
|
+
* ### Message size limit
|
|
98
98
|
*
|
|
99
99
|
* The protocol enforces a strict maximum size for all messages, defined by
|
|
100
|
-
* {@link
|
|
100
|
+
* {@link ProtocolMessageMaxSize}. This ensures every {@link ProtocolMessage} is
|
|
101
101
|
* less than or equal to this limit, enabling stateless transports, simplified
|
|
102
102
|
* relay implementation, and predictable memory usage. When all messages don't
|
|
103
103
|
* fit within the limit, the protocol automatically continues synchronization in
|
|
104
104
|
* subsequent rounds using range-based reconciliation.
|
|
105
105
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* {@link
|
|
106
|
+
* Database mutations are limited to 640KB, which is smaller than the protocol
|
|
107
|
+
* message limit to ensure efficient sync with
|
|
108
|
+
* {@link defaultProtocolMessageRangesMaxSize}.
|
|
109
109
|
*
|
|
110
110
|
* ### Why Binary?
|
|
111
111
|
*
|
|
@@ -148,6 +148,15 @@
|
|
|
148
148
|
* Version negotiation is per-owner, allowing Evolu Protocol to evolve safely
|
|
149
149
|
* over time and provide clear feedback about version mismatches.
|
|
150
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
|
+
*
|
|
151
160
|
* @module
|
|
152
161
|
*/
|
|
153
162
|
import { NonEmptyReadonlyArray } from "../Array.js";
|
|
@@ -160,10 +169,51 @@ import { NonNegativeInt, PositiveInt } from "../Type.js";
|
|
|
160
169
|
import { Owner, OwnerId, OwnerWriteKey } from "./Owner.js";
|
|
161
170
|
import { BaseRange, CrdtMessage, DbChange, EncryptedCrdtMessage, EncryptedDbChange, FingerprintRange, RangeType, SkipRange, StorageDep } from "./Storage.js";
|
|
162
171
|
import { NodeId, Timestamp } from "./Timestamp.js";
|
|
163
|
-
/**
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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;
|
|
167
217
|
/** Evolu Protocol Message. */
|
|
168
218
|
export type ProtocolMessage = Uint8Array & Brand<"ProtocolMessage">;
|
|
169
219
|
/** Evolu Protocol version. */
|
|
@@ -194,9 +244,11 @@ export declare const ProtocolErrorCode: {
|
|
|
194
244
|
readonly WriteError: 2;
|
|
195
245
|
/** A code for {@link ProtocolSyncError}. */
|
|
196
246
|
readonly SyncError: 3;
|
|
247
|
+
/** A code for {@link ProtocolQuotaExceededError}. */
|
|
248
|
+
readonly QuotaExceededError: 4;
|
|
197
249
|
};
|
|
198
250
|
type ProtocolErrorCode = (typeof ProtocolErrorCode)[keyof typeof ProtocolErrorCode];
|
|
199
|
-
export type ProtocolError = ProtocolUnsupportedVersionError | ProtocolInvalidDataError | ProtocolWriteKeyError | ProtocolWriteError | ProtocolSyncError | ProtocolTimestampMismatchError;
|
|
251
|
+
export type ProtocolError = ProtocolUnsupportedVersionError | ProtocolInvalidDataError | ProtocolWriteKeyError | ProtocolWriteError | ProtocolSyncError | ProtocolQuotaExceededError | ProtocolTimestampMismatchError;
|
|
200
252
|
/** Base interface for all protocol errors. */
|
|
201
253
|
export interface ProtocolErrorBase {
|
|
202
254
|
readonly ownerId: OwnerId;
|
|
@@ -222,19 +274,29 @@ export interface ProtocolWriteKeyError extends ProtocolErrorBase {
|
|
|
222
274
|
readonly type: "ProtocolWriteKeyError";
|
|
223
275
|
}
|
|
224
276
|
/**
|
|
225
|
-
* Error
|
|
226
|
-
*
|
|
277
|
+
* Error indicating a serious relay-side write failure. Clients should log this
|
|
278
|
+
* error and show a generic sync error to the user.
|
|
227
279
|
*/
|
|
228
280
|
export interface ProtocolWriteError extends ProtocolErrorBase {
|
|
229
281
|
readonly type: "ProtocolWriteError";
|
|
230
282
|
}
|
|
231
283
|
/**
|
|
232
|
-
* Error indicating a synchronization failure
|
|
233
|
-
*
|
|
284
|
+
* Error indicating a serious relay-side synchronization failure. Clients should
|
|
285
|
+
* log this error and show a generic sync error to the user.
|
|
234
286
|
*/
|
|
235
287
|
export interface ProtocolSyncError extends ProtocolErrorBase {
|
|
236
288
|
readonly type: "ProtocolSyncError";
|
|
237
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* Error when storage or billing quota is exceeded. Clients should prompt the
|
|
292
|
+
* user to upgrade their plan or expand capacity.
|
|
293
|
+
*
|
|
294
|
+
* TODO: Add callback to relay config to check quota and return this error when
|
|
295
|
+
* limits are reached.
|
|
296
|
+
*/
|
|
297
|
+
export interface ProtocolQuotaExceededError extends ProtocolErrorBase {
|
|
298
|
+
readonly type: "ProtocolQuotaExceededError";
|
|
299
|
+
}
|
|
238
300
|
/**
|
|
239
301
|
* Error when embedded timestamp doesn't match expected timestamp in
|
|
240
302
|
* EncryptedDbChange. Indicates potential tampering or corruption of CRDT
|
|
@@ -248,11 +310,11 @@ export interface ProtocolTimestampMismatchError {
|
|
|
248
310
|
/**
|
|
249
311
|
* Creates a {@link ProtocolMessage} from CRDT messages.
|
|
250
312
|
*
|
|
251
|
-
* If the message size would exceed {@link
|
|
252
|
-
* ensures all messages will be sent in the next round(s) even over
|
|
313
|
+
* If the message size would exceed {@link defaultProtocolMessageMaxSize}, the
|
|
314
|
+
* protocol ensures all messages will be sent in the next round(s) even over
|
|
253
315
|
* unidirectional and stateless transports.
|
|
254
316
|
*/
|
|
255
|
-
export declare const createProtocolMessageFromCrdtMessages: (deps: RandomBytesDep & SymmetricCryptoDep) => (owner: Owner, messages: NonEmptyReadonlyArray<CrdtMessage>, maxSize?:
|
|
317
|
+
export declare const createProtocolMessageFromCrdtMessages: (deps: RandomBytesDep & SymmetricCryptoDep) => (owner: Owner, messages: NonEmptyReadonlyArray<CrdtMessage>, maxSize?: ProtocolMessageMaxSize) => ProtocolMessage;
|
|
256
318
|
/** Creates a {@link ProtocolMessage} for sync. */
|
|
257
319
|
export declare const createProtocolMessageForSync: (deps: StorageDep) => (ownerId: OwnerId, subscriptionFlag?: SubscriptionFlag) => ProtocolMessage | null;
|
|
258
320
|
export declare const createProtocolMessageForUnsubscribe: (ownerId: OwnerId) => ProtocolMessage;
|
|
@@ -270,8 +332,8 @@ export interface ProtocolMessageBuffer {
|
|
|
270
332
|
readonly getSize: () => PositiveInt;
|
|
271
333
|
}
|
|
272
334
|
export declare const createProtocolMessageBuffer: (ownerId: OwnerId, options: {
|
|
273
|
-
readonly totalMaxSize?:
|
|
274
|
-
readonly rangesMaxSize?:
|
|
335
|
+
readonly totalMaxSize?: ProtocolMessageMaxSize | undefined;
|
|
336
|
+
readonly rangesMaxSize?: ProtocolMessageRangesMaxSize | undefined;
|
|
275
337
|
readonly version?: NonNegativeInt;
|
|
276
338
|
} & ({
|
|
277
339
|
readonly messageType: typeof MessageType.Request;
|
|
@@ -299,8 +361,7 @@ export interface ApplyProtocolMessageAsClientOptions {
|
|
|
299
361
|
getWriteKey?: (ownerId: OwnerId) => OwnerWriteKey | null;
|
|
300
362
|
/** For testing purposes only; should not be used in production. */
|
|
301
363
|
version?: NonNegativeInt;
|
|
302
|
-
|
|
303
|
-
rangesMaxSize?: PositiveInt;
|
|
364
|
+
rangesMaxSize?: ProtocolMessageRangesMaxSize;
|
|
304
365
|
}
|
|
305
366
|
/**
|
|
306
367
|
* Result type for {@link applyProtocolMessageAsClient} that distinguishes
|
|
@@ -314,7 +375,7 @@ export type ApplyProtocolMessageAsClientResult = {
|
|
|
314
375
|
} | {
|
|
315
376
|
readonly type: "broadcast";
|
|
316
377
|
};
|
|
317
|
-
export declare const applyProtocolMessageAsClient: (deps: StorageDep) => (inputMessage: Uint8Array, options?: ApplyProtocolMessageAsClientOptions) => Promise<Result<ApplyProtocolMessageAsClientResult, ProtocolInvalidDataError | ProtocolSyncError | ProtocolUnsupportedVersionError | ProtocolWriteError | ProtocolWriteKeyError>>;
|
|
378
|
+
export declare const applyProtocolMessageAsClient: (deps: StorageDep) => (inputMessage: Uint8Array, options?: ApplyProtocolMessageAsClientOptions) => Promise<Result<ApplyProtocolMessageAsClientResult, ProtocolInvalidDataError | ProtocolSyncError | ProtocolUnsupportedVersionError | ProtocolWriteError | ProtocolWriteKeyError | ProtocolQuotaExceededError>>;
|
|
318
379
|
export interface ApplyProtocolMessageAsRelayOptions {
|
|
319
380
|
/** To subscribe an owner for broadcasting. */
|
|
320
381
|
subscribe?: (ownerId: OwnerId) => void;
|
|
@@ -322,8 +383,8 @@ export interface ApplyProtocolMessageAsRelayOptions {
|
|
|
322
383
|
unsubscribe?: (ownerId: OwnerId) => void;
|
|
323
384
|
/** To broadcast a protocol message to all subscribers. */
|
|
324
385
|
broadcast?: (ownerId: OwnerId, message: ProtocolMessage) => void;
|
|
325
|
-
totalMaxSize?:
|
|
326
|
-
rangesMaxSize?:
|
|
386
|
+
totalMaxSize?: ProtocolMessageMaxSize;
|
|
387
|
+
rangesMaxSize?: ProtocolMessageRangesMaxSize;
|
|
327
388
|
}
|
|
328
389
|
/**
|
|
329
390
|
* Result type for {@link applyProtocolMessageAsRelay}.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Protocol.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Protocol.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Protocol.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable jsdoc/no-undefined-types */
|
|
2
1
|
/**
|
|
3
2
|
* Evolu Protocol
|
|
4
3
|
*
|
|
@@ -21,7 +20,7 @@
|
|
|
21
20
|
* transfer, ownership, real-time broadcasting, request-response semantics, and
|
|
22
21
|
* error handling.
|
|
23
22
|
*
|
|
24
|
-
* ### Message
|
|
23
|
+
* ### Message structure
|
|
25
24
|
*
|
|
26
25
|
* | Field | Notes |
|
|
27
26
|
* | :----------------------------- | :------------------------ |
|
|
@@ -44,7 +43,7 @@
|
|
|
44
43
|
* | - {@link NonNegativeInt} | Number of ranges. |
|
|
45
44
|
* | - {@link Range} | |
|
|
46
45
|
*
|
|
47
|
-
* ### WriteKey
|
|
46
|
+
* ### WriteKey validation
|
|
48
47
|
*
|
|
49
48
|
* The initiator sends a hasWriteKey flag and optionally a WriteKey. The
|
|
50
49
|
* WriteKey is required when sending messages as a secure token proving the
|
|
@@ -80,33 +79,33 @@
|
|
|
80
79
|
* initiator. In relay-to-relay or P2P sync, both sides may require the
|
|
81
80
|
* {@link OwnerWriteKey} depending on who is the initiator.
|
|
82
81
|
*
|
|
83
|
-
* ### Protocol
|
|
82
|
+
* ### Protocol errors
|
|
84
83
|
*
|
|
85
84
|
* The protocol uses error codes in the header to signal issues:
|
|
86
85
|
*
|
|
87
86
|
* - {@link ProtocolWriteKeyError}: The provided WriteKey is invalid or missing.
|
|
88
|
-
* - {@link ProtocolWriteError}: A write
|
|
89
|
-
*
|
|
90
|
-
* - {@link ProtocolSyncError}: A generic or unexpected synchronization failure
|
|
87
|
+
* - {@link ProtocolWriteError}: A serious relay-side write failure occurred.
|
|
88
|
+
* - {@link ProtocolSyncError}: A serious relay-side synchronization failure
|
|
91
89
|
* occurred.
|
|
90
|
+
* - {@link ProtocolQuotaExceededError}: Storage or billing quota exceeded.
|
|
92
91
|
* - {@link ProtocolUnsupportedVersionError}: Protocol version mismatch.
|
|
93
92
|
* - {@link ProtocolInvalidDataError}: The message is malformed or corrupted.
|
|
94
93
|
*
|
|
95
94
|
* All protocol errors except `ProtocolInvalidDataError` include the `OwnerId`
|
|
96
95
|
* to allow clients to associate errors with the correct owner.
|
|
97
96
|
*
|
|
98
|
-
* ### Message
|
|
97
|
+
* ### Message size limit
|
|
99
98
|
*
|
|
100
99
|
* The protocol enforces a strict maximum size for all messages, defined by
|
|
101
|
-
* {@link
|
|
100
|
+
* {@link ProtocolMessageMaxSize}. This ensures every {@link ProtocolMessage} is
|
|
102
101
|
* less than or equal to this limit, enabling stateless transports, simplified
|
|
103
102
|
* relay implementation, and predictable memory usage. When all messages don't
|
|
104
103
|
* fit within the limit, the protocol automatically continues synchronization in
|
|
105
104
|
* subsequent rounds using range-based reconciliation.
|
|
106
105
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* {@link
|
|
106
|
+
* Database mutations are limited to 640KB, which is smaller than the protocol
|
|
107
|
+
* message limit to ensure efficient sync with
|
|
108
|
+
* {@link defaultProtocolMessageRangesMaxSize}.
|
|
110
109
|
*
|
|
111
110
|
* ### Why Binary?
|
|
112
111
|
*
|
|
@@ -149,6 +148,15 @@
|
|
|
149
148
|
* Version negotiation is per-owner, allowing Evolu Protocol to evolve safely
|
|
150
149
|
* over time and provide clear feedback about version mismatches.
|
|
151
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
|
+
*
|
|
152
160
|
* @module
|
|
153
161
|
*/
|
|
154
162
|
import { Packr } from "msgpackr";
|
|
@@ -160,21 +168,62 @@ import { eqArrayNumber } from "../Eq.js";
|
|
|
160
168
|
import { computeBalancedBuckets } from "../Number.js";
|
|
161
169
|
import { objectToEntries } from "../Object.js";
|
|
162
170
|
import { err, ok } from "../Result.js";
|
|
163
|
-
import { Base64Url, base64UrlToUint8Array, DateIso, Id, idBytesToId, idBytesTypeValueLength, idToIdBytes, Json, jsonToJsonValue, NonNegativeInt, Number, uint8ArrayToBase64Url, } from "../Type.js";
|
|
171
|
+
import { Base64Url, base64UrlToUint8Array, between, DateIso, Id, idBytesToId, idBytesTypeValueLength, idToIdBytes, Int, Json, jsonToJsonValue, NonNegativeInt, Number, uint8ArrayToBase64Url, } from "../Type.js";
|
|
164
172
|
import { ownerIdToOwnerIdBytes, ownerWriteKeyLength, } from "./Owner.js";
|
|
165
173
|
import { fingerprintSize, InfiniteUpperBound, RangeType, } from "./Storage.js";
|
|
166
174
|
import { Counter, eqTimestamp, Millis, timestampBytesLength, timestampBytesToTimestamp, timestampToTimestampBytes, } from "./Timestamp.js";
|
|
167
175
|
/**
|
|
168
|
-
* MessagePack
|
|
176
|
+
* Evolu uses MessagePack for numbers and JSONs.
|
|
169
177
|
*
|
|
170
178
|
* - `variableMapSize: true` - More compact maps, ~5-10% slower encoding
|
|
171
179
|
* - `useRecords: false` - Standard MessagePack without extensions
|
|
172
180
|
*/
|
|
173
181
|
const packr = new Packr({ variableMapSize: true, useRecords: false });
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
|
|
182
|
+
const minProtocolMessageMaxSize = 1_000_000;
|
|
183
|
+
const maxProtocolMessageMaxSize = 100_000_000;
|
|
184
|
+
/**
|
|
185
|
+
* Protocol message maximum size.
|
|
186
|
+
*
|
|
187
|
+
* Defines the upper limit for how large a single protocol message can be.
|
|
188
|
+
* Implementations must enforce a maximum size between 1MB and 100MB to ensure
|
|
189
|
+
* compatibility across all Evolu implementations (the maximum size of mutation
|
|
190
|
+
* change is hardcoded and enforced hence the maximum size can't be smaller).
|
|
191
|
+
*
|
|
192
|
+
* Larger maximum sizes can be configured by relays to reduce roundtrips. For
|
|
193
|
+
* example, a dedicated relay with ample resources could configure a 100MB
|
|
194
|
+
* maximum to minimize roundtrips for large syncs.
|
|
195
|
+
*
|
|
196
|
+
* Only relays can safely configure larger sizes, as clients will handle them.
|
|
197
|
+
* Increasing this value on the client side would break compatibility with
|
|
198
|
+
* relays that enforce smaller limits.
|
|
199
|
+
*/
|
|
200
|
+
export const ProtocolMessageMaxSize = between(minProtocolMessageMaxSize, maxProtocolMessageMaxSize)(Int);
|
|
201
|
+
/**
|
|
202
|
+
* Default {@link ProtocolMessageMaxSize} (1MB).
|
|
203
|
+
*
|
|
204
|
+
* The standard size used across Evolu implementations. Relays with more
|
|
205
|
+
* resources can configure larger sizes to reduce roundtrips.
|
|
206
|
+
*/
|
|
207
|
+
export const defaultProtocolMessageMaxSize = minProtocolMessageMaxSize;
|
|
208
|
+
/**
|
|
209
|
+
* Protocol message ranges maximum size.
|
|
210
|
+
*
|
|
211
|
+
* Defines the upper limit for how large the ranges section of a protocol
|
|
212
|
+
* message can be. Implementations must enforce a maximum size between 3KB and
|
|
213
|
+
* 100KB to ensure compatibility.
|
|
214
|
+
*
|
|
215
|
+
* The upper bound is set to ensure ranges fit within the default 1MB
|
|
216
|
+
* {@link defaultProtocolMessageMaxSize}, maintaining compatibility between all
|
|
217
|
+
* clients and relays.
|
|
218
|
+
*/
|
|
219
|
+
export const ProtocolMessageRangesMaxSize = between(3_000, 100_000)(Int);
|
|
220
|
+
/**
|
|
221
|
+
* Default {@link ProtocolMessageRangesMaxSize} (30KB).
|
|
222
|
+
*
|
|
223
|
+
* The standard size used across Evolu implementations. Relays with more
|
|
224
|
+
* resources can configure larger sizes to reduce roundtrips.
|
|
225
|
+
*/
|
|
226
|
+
export const defaultProtocolMessageRangesMaxSize = 30_000;
|
|
178
227
|
/** Evolu Protocol version. */
|
|
179
228
|
export const protocolVersion = 0;
|
|
180
229
|
export const MessageType = {
|
|
@@ -201,18 +250,20 @@ export const ProtocolErrorCode = {
|
|
|
201
250
|
WriteError: 2,
|
|
202
251
|
/** A code for {@link ProtocolSyncError}. */
|
|
203
252
|
SyncError: 3,
|
|
253
|
+
/** A code for {@link ProtocolQuotaExceededError}. */
|
|
254
|
+
QuotaExceededError: 4,
|
|
204
255
|
};
|
|
205
256
|
/**
|
|
206
257
|
* Creates a {@link ProtocolMessage} from CRDT messages.
|
|
207
258
|
*
|
|
208
|
-
* If the message size would exceed {@link
|
|
209
|
-
* ensures all messages will be sent in the next round(s) even over
|
|
259
|
+
* If the message size would exceed {@link defaultProtocolMessageMaxSize}, the
|
|
260
|
+
* protocol ensures all messages will be sent in the next round(s) even over
|
|
210
261
|
* unidirectional and stateless transports.
|
|
211
262
|
*/
|
|
212
263
|
export const createProtocolMessageFromCrdtMessages = (deps) => (owner, messages, maxSize) => {
|
|
213
264
|
const buffer = createProtocolMessageBuffer(owner.id, {
|
|
214
265
|
messageType: MessageType.Request,
|
|
215
|
-
totalMaxSize: maxSize ??
|
|
266
|
+
totalMaxSize: maxSize ?? defaultProtocolMessageMaxSize,
|
|
216
267
|
writeKey: owner.writeKey,
|
|
217
268
|
});
|
|
218
269
|
let notAllMessagesSent = false;
|
|
@@ -236,8 +287,8 @@ export const createProtocolMessageFromCrdtMessages = (deps) => (owner, messages,
|
|
|
236
287
|
*
|
|
237
288
|
* The ideal approach would be to send three ranges (skip, fingerprint,
|
|
238
289
|
* skip) where the fingerprint of unsent messages would act as narrow sync
|
|
239
|
-
* probe. I think we can send
|
|
240
|
-
*
|
|
290
|
+
* probe. I think we can send `zeroFingerprint` which can be interpreted
|
|
291
|
+
* as an indication that the other side should reply with
|
|
241
292
|
* {@link TimestampsRange}, so no need to restart syncing.
|
|
242
293
|
*
|
|
243
294
|
* For now, using a random fingerprint avoids extra complexity and is good
|
|
@@ -272,7 +323,7 @@ export const createProtocolMessageForUnsubscribe = (ownerId) => createProtocolMe
|
|
|
272
323
|
subscriptionFlag: SubscriptionFlags.Unsubscribe,
|
|
273
324
|
}).unwrap();
|
|
274
325
|
export const createProtocolMessageBuffer = (ownerId, options) => {
|
|
275
|
-
const { totalMaxSize =
|
|
326
|
+
const { totalMaxSize = defaultProtocolMessageMaxSize, rangesMaxSize = defaultProtocolMessageRangesMaxSize, version = protocolVersion, } = options;
|
|
276
327
|
const buffers = {
|
|
277
328
|
header: createBuffer(),
|
|
278
329
|
messages: {
|
|
@@ -507,6 +558,11 @@ export const applyProtocolMessageAsClient = (deps) => async (inputMessage, optio
|
|
|
507
558
|
type: "ProtocolSyncError",
|
|
508
559
|
ownerId,
|
|
509
560
|
});
|
|
561
|
+
case ProtocolErrorCode.QuotaExceededError:
|
|
562
|
+
return err({
|
|
563
|
+
type: "ProtocolQuotaExceededError",
|
|
564
|
+
ownerId,
|
|
565
|
+
});
|
|
510
566
|
default:
|
|
511
567
|
throw new ProtocolDecodeError(`Invalid ProtocolErrorCode: ${errorCode}`);
|
|
512
568
|
}
|
|
@@ -537,7 +593,6 @@ export const applyProtocolMessageAsClient = (deps) => async (inputMessage, optio
|
|
|
537
593
|
const output = createProtocolMessageBuffer(ownerId, {
|
|
538
594
|
messageType: MessageType.Request,
|
|
539
595
|
writeKey,
|
|
540
|
-
totalMaxSize: options.totalMaxSize,
|
|
541
596
|
rangesMaxSize: options.rangesMaxSize,
|
|
542
597
|
});
|
|
543
598
|
const syncResult = sync(deps)(ranges, output, ownerIdBytes);
|
|
@@ -1,14 +1,81 @@
|
|
|
1
|
-
import { ConsoleConfig } from "../Console.js";
|
|
1
|
+
import { ConsoleConfig, ConsoleDep } from "../Console.js";
|
|
2
2
|
import { TimingSafeEqualDep } from "../Crypto.js";
|
|
3
|
+
import { LazyValue } from "../Function.js";
|
|
3
4
|
import { Result } from "../Result.js";
|
|
4
5
|
import { SqliteError } from "../Sqlite.js";
|
|
5
6
|
import { SimpleName } from "../Type.js";
|
|
7
|
+
import { OwnerId } from "./Owner.js";
|
|
8
|
+
import { ProtocolInvalidDataError } from "./Protocol.js";
|
|
6
9
|
import { CreateSqliteStorageBaseOptions, SqliteStorageDeps, Storage } from "./Storage.js";
|
|
7
10
|
export interface Relay extends Disposable {
|
|
8
11
|
}
|
|
9
12
|
export interface RelayConfig extends ConsoleConfig {
|
|
13
|
+
/**
|
|
14
|
+
* The relay name.
|
|
15
|
+
*
|
|
16
|
+
* Implementations can use this for identification purposes (e.g., database
|
|
17
|
+
* file name, logging).
|
|
18
|
+
*/
|
|
10
19
|
readonly name?: SimpleName;
|
|
20
|
+
/**
|
|
21
|
+
* Optional callback to authenticate an {@link OwnerId} with the relay.
|
|
22
|
+
*
|
|
23
|
+
* If this callback is not provided, all owners are allowed.
|
|
24
|
+
*
|
|
25
|
+
* If provided, the callback receives the OwnerId and should return a promise
|
|
26
|
+
* that resolves to `true` to allow access, or `false` to deny.
|
|
27
|
+
*
|
|
28
|
+
* The callback returns a boolean rather than an error type because error
|
|
29
|
+
* handling and logging are the responsibility of the callback implementation,
|
|
30
|
+
* not the relay. This prevents leaking authentication implementation details
|
|
31
|
+
* into the generic relay interface.
|
|
32
|
+
*
|
|
33
|
+
* OwnerId is used for authentication rather than short-lived tokens because
|
|
34
|
+
* this only controls relay access, not write permissions. Since all data is
|
|
35
|
+
* encrypted on the relay, OwnerId exposure is safe.
|
|
36
|
+
*
|
|
37
|
+
* Owners specify which relays to connect to via {@link TransportConfig}. In
|
|
38
|
+
* WebSocket-based implementations, this check occurs before accepting the
|
|
39
|
+
* connection, with the OwnerId typically extracted from the URL path (e.g.,
|
|
40
|
+
* `ws://localhost:4000/<ownerId>`).
|
|
41
|
+
*
|
|
42
|
+
* ### Example
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* const relay = await createNodeJsRelay(deps)({
|
|
46
|
+
* authenticateOwner: async (ownerId) => {
|
|
47
|
+
* const isRegistered = await db.checkOwner(ownerId);
|
|
48
|
+
* if (!isRegistered) {
|
|
49
|
+
* logger.warn("Unauthorized access attempt", { ownerId });
|
|
50
|
+
* }
|
|
51
|
+
* return isRegistered;
|
|
52
|
+
* },
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
readonly authenticateOwner?: (ownerId: OwnerId) => Promise<boolean>;
|
|
11
57
|
}
|
|
12
|
-
export
|
|
13
|
-
export
|
|
58
|
+
export declare const createRelaySqliteStorage: (deps: SqliteStorageDeps & TimingSafeEqualDep) => (options: CreateSqliteStorageBaseOptions) => Result<Storage, SqliteError>;
|
|
59
|
+
export interface RelayLogger {
|
|
60
|
+
readonly started: (enableLogging: boolean, port: number) => void;
|
|
61
|
+
readonly storageError: (error: unknown) => void;
|
|
62
|
+
readonly upgradeSocketError: (error: Error) => void;
|
|
63
|
+
readonly invalidOrMissingOwnerIdInUrl: (url: string | undefined) => void;
|
|
64
|
+
readonly unauthorizedOwner: (ownerId: OwnerId) => void;
|
|
65
|
+
readonly authenticateOwnerError: (error: unknown) => void;
|
|
66
|
+
readonly connectionEstablished: (totalConnectionCount: number) => void;
|
|
67
|
+
readonly connectionWebSocketError: (error: Error) => void;
|
|
68
|
+
readonly relayOptionSubscribe: (ownerId: OwnerId, getSubscriberCount: LazyValue<number>) => void;
|
|
69
|
+
readonly relayOptionUnsubscribe: (ownerId: OwnerId, getSubscriberCount: LazyValue<number>) => void;
|
|
70
|
+
readonly relayOptionBroadcast: (ownerId: OwnerId, broadcastCount: number, subscriberCount: number) => void;
|
|
71
|
+
readonly messageLength: (messageLength: number) => void;
|
|
72
|
+
readonly applyProtocolMessageAsRelayError: (error: ProtocolInvalidDataError) => void;
|
|
73
|
+
readonly responseLength: (responseLength: number) => void;
|
|
74
|
+
readonly applyProtocolMessageAsRelayUnknownError: (error: unknown) => void;
|
|
75
|
+
readonly connectionClosed: (totalConnectionCount: number) => void;
|
|
76
|
+
readonly shuttingDown: () => void;
|
|
77
|
+
readonly webSocketServerDisposed: () => void;
|
|
78
|
+
readonly httpServerDisposed: () => void;
|
|
79
|
+
}
|
|
80
|
+
export declare const createRelayLogger: (deps: ConsoleDep) => RelayLogger;
|
|
14
81
|
//# sourceMappingURL=Relay.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Relay.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Relay.ts"],"names":[],"mappings":"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"}
|