@evolu/common 8.17.0 → 8.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/Bytes.d.ts +31 -14
- package/dist/src/Bytes.d.ts.map +1 -1
- package/dist/src/Bytes.js +48 -8
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +5 -1
- package/dist/src/Polyfills.d.ts.map +1 -1
- package/dist/src/Polyfills.js +3 -2
- package/dist/src/Sqlite.d.ts +1 -1
- package/dist/src/Task.d.ts +4 -3
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +4 -3
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/local-first/Db.d.ts +32 -3
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +30 -9
- package/dist/src/local-first/Evolu.d.ts +21 -6
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +5 -1
- package/dist/src/local-first/Protocol.d.ts +215 -93
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +799 -489
- package/dist/src/local-first/Relay.d.ts +9 -1
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Relay.js +41 -36
- package/dist/src/local-first/Shared.d.ts +79 -53
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +67 -42
- package/dist/src/local-first/Storage.d.ts +80 -18
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +20 -4
- package/package.json +1 -1
- package/src/Bytes.test.ts +212 -0
- package/src/Bytes.ts +67 -17
- package/src/Error.ts +5 -1
- package/src/Polyfills.ts +3 -2
- package/src/Sqlite.ts +1 -1
- package/src/Task.ts +4 -3
- package/src/index.ts +4 -1
- package/src/local-first/Db.ts +76 -17
- package/src/local-first/Evolu.test.ts +43 -12
- package/src/local-first/Evolu.ts +34 -7
- package/src/local-first/Protocol.test.ts +1541 -44
- package/src/local-first/Protocol.ts +1070 -605
- package/src/local-first/Relay.ts +80 -69
- package/src/local-first/Shared.test.ts +37 -1
- package/src/local-first/Shared.ts +124 -73
- package/src/local-first/Storage.ts +100 -27
|
@@ -111,10 +111,10 @@
|
|
|
111
111
|
* whichever instance made it, even one disposed before the database worker
|
|
112
112
|
* answered. When a relay frame stores new messages, the tenant requests a round
|
|
113
113
|
* through each other transport claimed for the owner, so data learned from one
|
|
114
|
-
* relay reaches the others, except through a route that skipped a message
|
|
115
|
-
* described below. A closed transport reconciles
|
|
116
|
-
* replacement leader reconciles every transport again,
|
|
117
|
-
* reporting stored messages may have been lost.
|
|
114
|
+
* relay reaches the others, except through a route that skipped a message it
|
|
115
|
+
* received or could not send, as described below. A closed transport reconciles
|
|
116
|
+
* when it opens, and a replacement leader reconciles every transport again,
|
|
117
|
+
* because a response reporting stored messages may have been lost.
|
|
118
118
|
*
|
|
119
119
|
* Relays omit the sending socket when broadcasting an upload, so the uploader
|
|
120
120
|
* also delivers it as local Broadcast frames to every other tenant with
|
|
@@ -178,17 +178,17 @@
|
|
|
178
178
|
* request, a replacement leader, or storing messages from another transport,
|
|
179
179
|
* unless the route skipped a message. No failed or aborted result has arrived
|
|
180
180
|
* on the route since.
|
|
181
|
-
* - No result that skipped a received message
|
|
182
|
-
* round was last requested through it,
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
* skipped a message.
|
|
181
|
+
* - No result that skipped a received message or a stored change too large to
|
|
182
|
+
* send has arrived on the route since a round was last requested through it,
|
|
183
|
+
* and since that request, no messages have been stored from another
|
|
184
|
+
* transport, directly or through a sibling copy uploaded outside this
|
|
185
|
+
* transport, and no sibling copy has failed to apply or skipped a message.
|
|
186
186
|
*
|
|
187
187
|
* A route is settled when every condition except the last holds, so a complete
|
|
188
188
|
* route is settled too. A settled route that is incomplete has ended its
|
|
189
|
-
* reconciliation, but its relay may offer a message the database skipped,
|
|
190
|
-
*
|
|
191
|
-
* {@link SettledSyncRoute}.
|
|
189
|
+
* reconciliation, but its relay may offer a message the database skipped, the
|
|
190
|
+
* database may store a change too large to send, or messages stored elsewhere
|
|
191
|
+
* may not have reached it; it is published as {@link SettledSyncRoute}.
|
|
192
192
|
*
|
|
193
193
|
* A reconciliation chain ends only with a converged result, a failure, an
|
|
194
194
|
* abort, a dropped frame, or a continuation that finds the socket closed, and
|
|
@@ -207,20 +207,34 @@
|
|
|
207
207
|
* while the database worker creates a round is logged there and fails the
|
|
208
208
|
* round's routes with `SyncFailed` without a retry. A mutation that throws is
|
|
209
209
|
* rolled back and reported as an {@link UnknownError} to the tab that made it,
|
|
210
|
-
* or to every tab when its Evolu instance was disposed first.
|
|
211
|
-
* SQLite
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
210
|
+
* or to every tab when its Evolu instance was disposed first. A received batch
|
|
211
|
+
* SQLite fails to store, for example on a full disk, is rolled back and fails
|
|
212
|
+
* its route with an `UnknownError`. Other unexpected SQLite exceptions remain
|
|
213
|
+
* unsupported and can panic the database worker. A frame the relay silently
|
|
214
|
+
* drops, such as invalid data, leaves the count above zero until the liveness
|
|
215
|
+
* rule below replaces the socket.
|
|
216
|
+
*
|
|
217
|
+
* A result that skipped a message records the error on the route as its
|
|
218
|
+
* `skippedError`, without ending its chain, so it requests no round. A message
|
|
219
|
+
* is skipped in two cases:
|
|
220
|
+
*
|
|
221
|
+
* - The relay offers a message the database could not decrypt, verify, or decode.
|
|
222
|
+
* The relay offers it again in every round through the route until the
|
|
223
|
+
* database stores a message with that timestamp.
|
|
224
|
+
* - The database stores a change it cannot send, a
|
|
225
|
+
* {@link ProtocolChangeTooLargeError}: one saved before `maxMutationSize`
|
|
226
|
+
* existed, or a crafted one received from a relay. Every route through a
|
|
227
|
+
* relay that lacks it skips it on every sync, so each such route stays
|
|
228
|
+
* settled.
|
|
229
|
+
*
|
|
230
|
+
* The messages received elsewhere that the last condition names request no
|
|
231
|
+
* round through such a route, even while a requested round checks it again,
|
|
232
|
+
* because each round would download every skipped message again, or skip again
|
|
233
|
+
* a change too large to send. The next round that an explicit request, a
|
|
234
|
+
* reopen, a replacement leader, or a failure sends through the route reconciles
|
|
235
|
+
* them. So while the database stores a change too large to send, messages from
|
|
236
|
+
* other relays reach a route only through such a round, for example after a
|
|
237
|
+
* reconnect or {@link Evolu.requestSync}.
|
|
224
238
|
*
|
|
225
239
|
* ### Liveness
|
|
226
240
|
*
|
|
@@ -338,7 +352,11 @@ import type {
|
|
|
338
352
|
SharedWorkerSelf,
|
|
339
353
|
WorkerDeps,
|
|
340
354
|
} from "../Worker.ts";
|
|
341
|
-
import type {
|
|
355
|
+
import type {
|
|
356
|
+
DatabaseHeldError,
|
|
357
|
+
DbWorkerInit,
|
|
358
|
+
UnsupportedDbVersionError,
|
|
359
|
+
} from "./Db.ts";
|
|
342
360
|
import type {
|
|
343
361
|
DevicePersistence,
|
|
344
362
|
Evolu,
|
|
@@ -353,6 +371,7 @@ import {
|
|
|
353
371
|
MessageType,
|
|
354
372
|
parseProtocolHeader,
|
|
355
373
|
type ApplyProtocolMessageAsClientResult,
|
|
374
|
+
type ProtocolChangeTooLargeError,
|
|
356
375
|
type ProtocolError,
|
|
357
376
|
type ProtocolInvalidDataError,
|
|
358
377
|
type ProtocolMessage,
|
|
@@ -413,7 +432,10 @@ export type SharedWorkerOutput =
|
|
|
413
432
|
*/
|
|
414
433
|
readonly type: "Error";
|
|
415
434
|
readonly error:
|
|
416
|
-
|
|
435
|
+
| DatabaseHeldError
|
|
436
|
+
| OtherBuildRunningError
|
|
437
|
+
| UnknownError
|
|
438
|
+
| UnsupportedDbVersionError;
|
|
417
439
|
}
|
|
418
440
|
| {
|
|
419
441
|
/**
|
|
@@ -627,7 +649,7 @@ export interface ActiveSyncTenant extends Typed<"Active"> {
|
|
|
627
649
|
*/
|
|
628
650
|
export interface RefusedSyncTenant extends Typed<"Refused"> {
|
|
629
651
|
readonly name: Name;
|
|
630
|
-
readonly error: UnsupportedDbVersionError;
|
|
652
|
+
readonly error: DatabaseHeldError | UnsupportedDbVersionError;
|
|
631
653
|
}
|
|
632
654
|
|
|
633
655
|
/**
|
|
@@ -659,8 +681,9 @@ export interface ReadonlySyncTenantOwner extends Typed<"Readonly"> {
|
|
|
659
681
|
|
|
660
682
|
/**
|
|
661
683
|
* One database's use of one owner through one transport: `Pending` until its
|
|
662
|
-
* reconciliation ends, then `Complete`, or `Settled` while
|
|
663
|
-
*
|
|
684
|
+
* reconciliation ends, then `Complete`, or `Settled` while it skips a change:
|
|
685
|
+
* one its relay offers that the database could not store, or one the database
|
|
686
|
+
* stores but cannot send. See Synchronization completion in this module's
|
|
664
687
|
* documentation.
|
|
665
688
|
*/
|
|
666
689
|
export type SyncRoute = PendingSyncRoute | SettledSyncRoute | CompleteSyncRoute;
|
|
@@ -680,9 +703,12 @@ export interface PendingSyncRoute extends Typed<"Pending"> {
|
|
|
680
703
|
*/
|
|
681
704
|
readonly failure: SyncRouteError | null;
|
|
682
705
|
/**
|
|
683
|
-
* The first change skipped in the latest reply that skipped one, or null.
|
|
684
|
-
* relay offers
|
|
685
|
-
* stores a change with that timestamp.
|
|
706
|
+
* The first change skipped in the latest reply that skipped one, or null. A
|
|
707
|
+
* change the relay offers is offered again in every round through the route
|
|
708
|
+
* until this database stores a change with that timestamp. A
|
|
709
|
+
* {@link ProtocolChangeTooLargeError} is a change this database stores but
|
|
710
|
+
* cannot send, which every route through a relay that lacks it skips on every
|
|
711
|
+
* sync.
|
|
686
712
|
*/
|
|
687
713
|
readonly skippedError: SyncRouteError | null;
|
|
688
714
|
/** When the route last became complete, or null. */
|
|
@@ -697,10 +723,15 @@ export interface PendingSyncRoute extends Typed<"Pending"> {
|
|
|
697
723
|
}
|
|
698
724
|
|
|
699
725
|
/**
|
|
700
|
-
* A route whose reconciliation ended
|
|
701
|
-
*
|
|
702
|
-
*
|
|
703
|
-
* {@link
|
|
726
|
+
* A route whose reconciliation ended with a skipped change, so it is
|
|
727
|
+
* incomplete: its relay offers a change the database could not store, or the
|
|
728
|
+
* database stores a change it cannot send, a
|
|
729
|
+
* {@link ProtocolChangeTooLargeError}. Changes stored from other relays request
|
|
730
|
+
* no round through it; the next round requested through it, such as by
|
|
731
|
+
* {@link Evolu.requestSync} or a reopen, checks it again. Every route through a
|
|
732
|
+
* relay that lacks a change too large to send skips it on every sync, so those
|
|
733
|
+
* routes stay settled, and messages from other relays reach them only through
|
|
734
|
+
* such rounds.
|
|
704
735
|
*/
|
|
705
736
|
export interface SettledSyncRoute extends Typed<"Settled"> {
|
|
706
737
|
readonly transportId: SyncTransportId;
|
|
@@ -734,11 +765,13 @@ export interface CompleteSyncRoute extends Typed<"Complete"> {
|
|
|
734
765
|
*
|
|
735
766
|
* It is the error itself, so it carries its details, such as the expected and
|
|
736
767
|
* actual timestamps of a {@link ProtocolTimestampMismatchError}. A skipped
|
|
737
|
-
* message adds {@link DecryptWithXChaCha20Poly1305Error}
|
|
738
|
-
* {@link
|
|
739
|
-
*
|
|
740
|
-
*
|
|
741
|
-
*
|
|
768
|
+
* message adds {@link DecryptWithXChaCha20Poly1305Error} and
|
|
769
|
+
* {@link ProtocolChangeTooLargeError}. A {@link ProtocolInvalidDataError} leaves
|
|
770
|
+
* out its data, which can be a whole frame. An {@link UnknownError} means SQLite
|
|
771
|
+
* failed to store received messages, for example on a full disk. `WriteFailed`
|
|
772
|
+
* means a `writeMessages` call that threw, logged by the protocol, and
|
|
773
|
+
* `SyncFailed` means a logged failure while creating a round or reconciling
|
|
774
|
+
* ranges.
|
|
742
775
|
*/
|
|
743
776
|
export type SyncRouteError = (
|
|
744
777
|
| Exclude<ProtocolError, ProtocolInvalidDataError>
|
|
@@ -749,6 +782,7 @@ export type SyncRouteError = (
|
|
|
749
782
|
| (Omit<DecryptWithXChaCha20Poly1305Error, "error"> & {
|
|
750
783
|
readonly error: UnknownError;
|
|
751
784
|
})
|
|
785
|
+
| ProtocolChangeTooLargeError
|
|
752
786
|
| Typed<"WriteFailed">
|
|
753
787
|
| Typed<"SyncFailed">
|
|
754
788
|
) & { readonly at: Millis };
|
|
@@ -779,10 +813,10 @@ export interface RelaySyncState {
|
|
|
779
813
|
* - `Synced`: a relay is up to date, and none syncs.
|
|
780
814
|
* - `Offline`: every relay is disconnected. Evolu keeps reconnecting, up to 30
|
|
781
815
|
* seconds apart, so `Offline` can briefly outlast the outage.
|
|
782
|
-
* - `Error`: a relay failed
|
|
783
|
-
*
|
|
784
|
-
*
|
|
785
|
-
* that change.
|
|
816
|
+
* - `Error`: a relay failed, a relay offers a change this database skipped, or
|
|
817
|
+
* this database stores a change too large to send. `error` is the newest
|
|
818
|
+
* failure, or without one, the newest skipped change: a failure stops syncing
|
|
819
|
+
* through its relay, while a skipped change leaves out only that change.
|
|
786
820
|
*
|
|
787
821
|
* Evolu stores changes in the local database before they sync, so sync needs no
|
|
788
822
|
* UI while it works: show nothing for `NoRelays`, `Syncing`, and `Synced`. An
|
|
@@ -1311,7 +1345,7 @@ export type DbWorkerOutput =
|
|
|
1311
1345
|
| {
|
|
1312
1346
|
/** Startup was refused; the worker is releasing its resources. */
|
|
1313
1347
|
readonly type: "LeaderRefused";
|
|
1314
|
-
readonly error: UnsupportedDbVersionError;
|
|
1348
|
+
readonly error: DatabaseHeldError | UnsupportedDbVersionError;
|
|
1315
1349
|
}
|
|
1316
1350
|
| {
|
|
1317
1351
|
readonly type: "OnQueuedResponse";
|
|
@@ -1365,13 +1399,15 @@ export type DbWorkerQueuedResponse =
|
|
|
1365
1399
|
readonly ownerId: OwnerId;
|
|
1366
1400
|
readonly didWriteMessages: boolean;
|
|
1367
1401
|
/**
|
|
1368
|
-
* The first error of a
|
|
1369
|
-
* storing the rest, or
|
|
1402
|
+
* The first error of a message the DbWorker skipped, or null: a
|
|
1403
|
+
* received one it did not store while storing the rest, or a stored
|
|
1404
|
+
* change too large to send. It does not end the round.
|
|
1370
1405
|
*/
|
|
1371
1406
|
readonly skippedError:
|
|
1372
1407
|
| DecryptWithXChaCha20Poly1305Error
|
|
1373
1408
|
| ProtocolInvalidDataError
|
|
1374
1409
|
| ProtocolTimestampMismatchError
|
|
1410
|
+
| ProtocolChangeTooLargeError
|
|
1375
1411
|
| null;
|
|
1376
1412
|
readonly result: Result<
|
|
1377
1413
|
ApplyProtocolMessageAsClientResult,
|
|
@@ -1529,8 +1565,10 @@ interface PendingRoute extends Typed<"Pending"> {
|
|
|
1529
1565
|
}
|
|
1530
1566
|
|
|
1531
1567
|
/**
|
|
1532
|
-
* A message a route skipped
|
|
1533
|
-
*
|
|
1568
|
+
* A message a route skipped: one its relay offers that the database could not
|
|
1569
|
+
* store, which the relay offers again in every round, or one the database
|
|
1570
|
+
* stores but cannot send, which every round skips again. So messages received
|
|
1571
|
+
* elsewhere request no round through the route.
|
|
1534
1572
|
*/
|
|
1535
1573
|
interface RouteSkip {
|
|
1536
1574
|
readonly error: SyncRouteError;
|
|
@@ -1543,8 +1581,9 @@ interface RouteSkip {
|
|
|
1543
1581
|
}
|
|
1544
1582
|
|
|
1545
1583
|
/**
|
|
1546
|
-
* A route whose reconciliation has ended, but
|
|
1547
|
-
* message
|
|
1584
|
+
* A route whose reconciliation has ended, but which is incomplete: its relay
|
|
1585
|
+
* may offer a skipped message, the database may store a change too large to
|
|
1586
|
+
* send, or the relay may lack messages stored elsewhere.
|
|
1548
1587
|
*/
|
|
1549
1588
|
interface SettledRoute extends Typed<"Settled"> {
|
|
1550
1589
|
readonly skippedError: SyncRouteError;
|
|
@@ -1584,6 +1623,7 @@ const errorToSyncRouteError = (
|
|
|
1584
1623
|
| ProtocolError
|
|
1585
1624
|
| StorageWriteMessagesError
|
|
1586
1625
|
| DecryptWithXChaCha20Poly1305Error
|
|
1626
|
+
| ProtocolChangeTooLargeError
|
|
1587
1627
|
| Typed<"WriteFailed">
|
|
1588
1628
|
| Typed<"SyncFailed">,
|
|
1589
1629
|
at: Millis,
|
|
@@ -1773,8 +1813,9 @@ export const initSharedWorker =
|
|
|
1773
1813
|
|
|
1774
1814
|
// Held while this worker runs. Its DbWorkers stop once they can take it,
|
|
1775
1815
|
// because a Dispose posted right before this worker closes can be lost, as
|
|
1776
|
-
// in Firefox. Taken
|
|
1777
|
-
//
|
|
1816
|
+
// in Firefox (https://bugzilla.mozilla.org/show_bug.cgi?id=2077609). Taken
|
|
1817
|
+
// before the build lock, so nothing delays the end of starting once that
|
|
1818
|
+
// lock is held.
|
|
1778
1819
|
disposer.use(await run.ok(acquireLeaderLock(workerId)));
|
|
1779
1820
|
|
|
1780
1821
|
// Released after every tenant is disposed and has told its DbWorker to
|
|
@@ -2302,7 +2343,7 @@ const createEvoluTenant =
|
|
|
2302
2343
|
}
|
|
2303
2344
|
|
|
2304
2345
|
interface RefusedDbWorker extends Typed<"Refused"> {
|
|
2305
|
-
readonly error: UnsupportedDbVersionError;
|
|
2346
|
+
readonly error: DatabaseHeldError | UnsupportedDbVersionError;
|
|
2306
2347
|
}
|
|
2307
2348
|
|
|
2308
2349
|
let dbWorker: DbWorkerState = { type: "Starting" };
|
|
@@ -2405,6 +2446,11 @@ const createEvoluTenant =
|
|
|
2405
2446
|
// tell tabs that connect later without starting another worker.
|
|
2406
2447
|
if (dbWorker.type === "Leading") {
|
|
2407
2448
|
assertNotSame(dbWorker.port, currentDbWorkerPort);
|
|
2449
|
+
// The leader may still hold the database lock: browsers deliver
|
|
2450
|
+
// a refusal before a worker requested later can lead, but the
|
|
2451
|
+
// tenant does not rely on that order. Tell it to dispose, so it
|
|
2452
|
+
// releases the lock.
|
|
2453
|
+
dbWorker.port.postMessage({ type: "Dispose" });
|
|
2408
2454
|
dbWorker.port[Symbol.dispose]();
|
|
2409
2455
|
}
|
|
2410
2456
|
currentDbWorkerPort[Symbol.dispose]();
|
|
@@ -2546,7 +2592,7 @@ const createEvoluTenant =
|
|
|
2546
2592
|
|
|
2547
2593
|
const reportRefusal = (
|
|
2548
2594
|
tabPort: TabPort,
|
|
2549
|
-
error: UnsupportedDbVersionError,
|
|
2595
|
+
error: DatabaseHeldError | UnsupportedDbVersionError,
|
|
2550
2596
|
): void => {
|
|
2551
2597
|
if (refusedTabPorts.has(tabPort)) return;
|
|
2552
2598
|
refusedTabPorts.add(tabPort);
|
|
@@ -2780,7 +2826,8 @@ const createEvoluTenant =
|
|
|
2780
2826
|
!hasQueuedWrite;
|
|
2781
2827
|
// Settling drops the failure, so the next one requests a round
|
|
2782
2828
|
// again. A route with a skip it is not rechecking settles without
|
|
2783
|
-
// completing, because its relay may offer the skipped message
|
|
2829
|
+
// completing, because its relay may offer the skipped message, the
|
|
2830
|
+
// database may store a change too large to send, or the relay may
|
|
2784
2831
|
// lack messages stored elsewhere.
|
|
2785
2832
|
const pending = routeToPending(route.progress);
|
|
2786
2833
|
route.progress =
|
|
@@ -2887,11 +2934,12 @@ const createEvoluTenant =
|
|
|
2887
2934
|
if (!isAborted) route.lastReceivedAt = now;
|
|
2888
2935
|
// A skipped message is recorded as the route's skip, not a
|
|
2889
2936
|
// failure, and does not end the round, whose response below is
|
|
2890
|
-
// still sent, so it requests no round. The relay offers
|
|
2891
|
-
//
|
|
2892
|
-
//
|
|
2893
|
-
//
|
|
2894
|
-
//
|
|
2937
|
+
// still sent, so it requests no round. The relay offers a message
|
|
2938
|
+
// the database could not store again in every later round, and
|
|
2939
|
+
// every round skips a stored change too large to send again, so
|
|
2940
|
+
// the route stays incomplete until a round requested through it
|
|
2941
|
+
// settles without skipping a message and without messages stored
|
|
2942
|
+
// elsewhere since that request.
|
|
2895
2943
|
if (skippedError !== null)
|
|
2896
2944
|
route.progress = {
|
|
2897
2945
|
...routeToPending(route.progress),
|
|
@@ -2918,12 +2966,14 @@ const createEvoluTenant =
|
|
|
2918
2966
|
}
|
|
2919
2967
|
} else if (failure !== null || skippedError !== null) {
|
|
2920
2968
|
// A sibling's copy comes from this worker, not from a relay, so no
|
|
2921
|
-
// route shows its failure.
|
|
2922
|
-
//
|
|
2923
|
-
//
|
|
2924
|
-
//
|
|
2925
|
-
//
|
|
2926
|
-
//
|
|
2969
|
+
// route shows its failure. SQLite can fail to store it, for example
|
|
2970
|
+
// on a full disk, which returns an UnknownError. It is a Broadcast,
|
|
2971
|
+
// which carries no relay error, so any other error or a skip means
|
|
2972
|
+
// a bug, such as databases holding different keys for the owner.
|
|
2973
|
+
// Each is reported as an unexpected failure. A Failed result was
|
|
2974
|
+
// logged, which reports it already. An error is the failure, which
|
|
2975
|
+
// is never an abort, and like a route, the report leaves out its
|
|
2976
|
+
// frame.
|
|
2927
2977
|
const unexpected = error !== null ? failure : skippedError;
|
|
2928
2978
|
if (unexpected !== null)
|
|
2929
2979
|
deps.postConsoleEntryOrError({
|
|
@@ -3043,9 +3093,10 @@ const createEvoluTenant =
|
|
|
3043
3093
|
* `except`, after messages from elsewhere were stored or a sibling copy was
|
|
3044
3094
|
* not fully stored. Rounds toward the same transport coalesce whatever
|
|
3045
3095
|
* their source. A route that skipped a message gets none, because its relay
|
|
3046
|
-
* would offer that message again
|
|
3047
|
-
*
|
|
3048
|
-
*
|
|
3096
|
+
* would offer that message again or the round would skip a stored change
|
|
3097
|
+
* too large to send again. A route rechecking one stops rechecking, because
|
|
3098
|
+
* its round may have read the database before this event. A later requested
|
|
3099
|
+
* round through such a route reconciles it.
|
|
3049
3100
|
*/
|
|
3050
3101
|
const requestRoundsForReceivedMessages = (
|
|
3051
3102
|
ownerId: OwnerId,
|