@evolu/common 8.13.0 → 8.14.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/local-first/Evolu.d.ts +66 -2
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +22 -3
- package/dist/src/local-first/Shared.d.ts +46 -39
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +30 -19
- package/package.json +1 -1
- package/src/local-first/Evolu.test.ts +100 -10
- package/src/local-first/Evolu.ts +95 -5
- package/src/local-first/Shared.test.ts +113 -30
- package/src/local-first/Shared.ts +73 -57
|
@@ -263,6 +263,36 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
|
|
|
263
263
|
readonly name: Name;
|
|
264
264
|
/** {@link AppOwner}. */
|
|
265
265
|
readonly appOwner: AppOwner;
|
|
266
|
+
/**
|
|
267
|
+
* Whether this device keeps the database, resolved once the shared worker
|
|
268
|
+
* serves it, or `Unknown` if this instance is disposed first.
|
|
269
|
+
*
|
|
270
|
+
* Apps tell the user when it is `NotPersisted`, because then data that has
|
|
271
|
+
* not synced is lost when the database closes. Apps must not tell the user
|
|
272
|
+
* that data is saved on the device when it is `Unknown`.
|
|
273
|
+
*
|
|
274
|
+
* ### Example
|
|
275
|
+
*
|
|
276
|
+
* ```ts
|
|
277
|
+
* import { assertEqual } from "@evolu/common";
|
|
278
|
+
* import type { DevicePersistence } from "@evolu/common/local-first";
|
|
279
|
+
*
|
|
280
|
+
* // The notice for `await evolu.devicePersistence`, or null for none.
|
|
281
|
+
* const persistenceNotice = (
|
|
282
|
+
* devicePersistence: DevicePersistence,
|
|
283
|
+
* ): string | null =>
|
|
284
|
+
* devicePersistence === "NotPersisted"
|
|
285
|
+
* ? "Your data isn't kept on this device. Changes that haven't synced are lost when you close this tab."
|
|
286
|
+
* : null;
|
|
287
|
+
*
|
|
288
|
+
* assertEqual(persistenceNotice("Unknown"), null);
|
|
289
|
+
* assertEqual(
|
|
290
|
+
* persistenceNotice("NotPersisted"),
|
|
291
|
+
* "Your data isn't kept on this device. Changes that haven't synced are lost when you close this tab.",
|
|
292
|
+
* );
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
readonly devicePersistence: Promise<DevicePersistence>;
|
|
266
296
|
/**
|
|
267
297
|
* Inserts a row and returns the generated {@link Id}.
|
|
268
298
|
*
|
|
@@ -723,6 +753,27 @@ export interface Evolu<S extends EvoluSchema = EvoluSchema> extends AsyncDisposa
|
|
|
723
753
|
* @group Core
|
|
724
754
|
*/
|
|
725
755
|
export type UnuseOwner = () => void;
|
|
756
|
+
/**
|
|
757
|
+
* Whether this device keeps an {@link Evolu} database, stating only what Evolu
|
|
758
|
+
* knows for sure.
|
|
759
|
+
*
|
|
760
|
+
* - `Persisted`: the platform stores it in the app's own file, as React Native
|
|
761
|
+
* does.
|
|
762
|
+
* - `NotPersisted`: it is kept in memory, because {@link EvoluConfig.memoryOnly}
|
|
763
|
+
* asks for that or the platform offers no persistent storage, as a browser
|
|
764
|
+
* does in Safari's Private Browsing or a Firefox private window. Data that
|
|
765
|
+
* has not synced is lost when the database closes.
|
|
766
|
+
* - `Unknown`: it is stored, but the platform may delete it. A browser can keep
|
|
767
|
+
* storage only for a private session, as Chrome's incognito does without
|
|
768
|
+
* telling the app, delete it after a while or when disk space runs low, and
|
|
769
|
+
* let the user clear it.
|
|
770
|
+
*
|
|
771
|
+
* See [Will my data stay on the
|
|
772
|
+
* device?](https://www.evolu.dev/docs/faq#will-my-data-stay-on-the-device).
|
|
773
|
+
*
|
|
774
|
+
* @group Core
|
|
775
|
+
*/
|
|
776
|
+
export type DevicePersistence = "Persisted" | "NotPersisted" | "Unknown";
|
|
726
777
|
/**
|
|
727
778
|
* Represents app-level errors that can occur in {@link Evolu}.
|
|
728
779
|
*
|
|
@@ -936,6 +987,19 @@ export interface SyncStateDep {
|
|
|
936
987
|
*/
|
|
937
988
|
readonly syncState: ReadonlyStore<SyncState | null>;
|
|
938
989
|
}
|
|
990
|
+
/**
|
|
991
|
+
* Asks the platform to keep stored databases until the user deletes them.
|
|
992
|
+
*
|
|
993
|
+
* Only unsynced local changes exist nowhere else, so each {@link Evolu} instance
|
|
994
|
+
* calls it after its first local mutation, when its
|
|
995
|
+
* {@link Evolu.devicePersistence} is `Unknown`. A platform provides it when its
|
|
996
|
+
* storage can be deleted without the user, as a browser's can.
|
|
997
|
+
*
|
|
998
|
+
* @group Construction
|
|
999
|
+
*/
|
|
1000
|
+
export interface RequestPersistentStorageDep {
|
|
1001
|
+
readonly requestPersistentStorage: () => void;
|
|
1002
|
+
}
|
|
939
1003
|
/**
|
|
940
1004
|
* Shared platform dependencies for creating {@link Evolu} instances.
|
|
941
1005
|
*
|
|
@@ -949,11 +1013,11 @@ export type EvoluDeps = EvoluPlatformDeps & ConsoleDep & EvoluErrorDep & SyncSta
|
|
|
949
1013
|
* Platform-specific dependencies required to create {@link EvoluDeps}.
|
|
950
1014
|
*
|
|
951
1015
|
* Provides worker and channel adapters plus optional platform integrations for
|
|
952
|
-
* logging
|
|
1016
|
+
* logging, synchronous UI flush, and persistent storage requests.
|
|
953
1017
|
*
|
|
954
1018
|
* @group Construction
|
|
955
1019
|
*/
|
|
956
|
-
export type EvoluPlatformDeps = CreateDbWorkerDep & CreateBroadcastChannelDep & CreateMessageChannelDep & LockManagerDep & ReloadAppDep & SharedWorkerDep & Partial<ConsoleDep> & Partial<FlushSyncDep>;
|
|
1020
|
+
export type EvoluPlatformDeps = CreateDbWorkerDep & CreateBroadcastChannelDep & CreateMessageChannelDep & LockManagerDep & ReloadAppDep & SharedWorkerDep & Partial<ConsoleDep> & Partial<FlushSyncDep> & Partial<RequestPersistentStorageDep>;
|
|
957
1021
|
/**
|
|
958
1022
|
* Creates shared dependencies used by all {@link createEvolu} instances on a
|
|
959
1023
|
* platform.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Evolu.d.ts","sourceRoot":"","sources":["../../../src/local-first/Evolu.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,aAAa,CAAC;AAQrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAS3B,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AASjE,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAExE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAML,IAAI,EACJ,WAAW,EACX,KAAK,SAAS,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAEV,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,KAAK,EACV,QAAQ,EACR,KAAK,EACL,OAAO,EACP,cAAc,EACd,aAAa,EAEd,MAAM,YAAY,CAAC;AAUpB,OAAO,KAAK,EACV,OAAO,EACP,0BAA0B,EAC1B,KAAK,EACL,SAAS,EACT,GAAG,EAEJ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,QAAQ,EAGR,cAAc,EACd,cAAc,EACf,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAIV,sBAAsB,EAGtB,eAAe,EACf,SAAS,EAGV,MAAM,aAAa,CAAC;AAKrB;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAE5B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IAEjC;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAExC;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuEG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;CACrD;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,oUASnB,CAAC;AACF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,MAAM,CAAC;AAC5C;;;;GAIG;AACH,MAAM,WAAW,YAAa,SAAQ,SAAS,CAAC,SAAS,CAAC;IACxD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;CAC/B;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,gGAA2C,CAAC;AAEpE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,KAAK,CACpB,CAAC,SAAS,WAAW,GAAG,WAAW,CACnC,SAAQ,eAAe;IACvB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAEpB,wBAAwB;IACxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmDG;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsCG;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,QAAQ,CAAC,eAAe,EAAE,CAAC,SAAS,SAAS,MAAM,CAAC,EAClD,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC,KACpD,WAAW,CAAC;IAEjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8CG;IACH,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,EAChC,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KACf,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;IACH,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,EACzC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,KACZ,CAAC,GAAG,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;IAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,QAAQ,CAAC,cAAc,EAAE,CACvB,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KACZ,CAAC,QAAQ,EAAE,QAAQ,KAAK,WAAW,CAAC;IAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,SAAS,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC;IAE3E;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;IAIhE;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC;IAEpC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyDG;IACH,QAAQ,CAAC,QAAQ,EAAE,CACjB,KAAK,EAAE,aAAa,GAAG,KAAK,EAC5B,UAAU,CAAC,EAAE,qBAAqB,CAAC,cAAc,CAAC,KAC/C,UAAU,CAAC;IAEhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACH,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,MAAM,UAAU,GACpB,sBAAsB,GAAG,YAAY,GAAG,yBAAyB,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,EAAE,WACc,CAAC;AAmC7C;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsEG;IACH,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;CACvD;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsDG;IACH,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;CACrD;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,iBAAiB,GACvC,UAAU,GACV,aAAa,GACb,YAAY,GACZ,UAAU,CAAC;AAEb;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAC/C,yBAAyB,GACzB,uBAAuB,GACvB,cAAc,GACd,YAAY,GACZ,eAAe,GACf,OAAO,CAAC,UAAU,CAAC,GACnB,OAAO,CAAC,YAAY,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"Evolu.d.ts","sourceRoot":"","sources":["../../../src/local-first/Evolu.ts"],"names":[],"mappings":"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"}
|
|
@@ -210,9 +210,7 @@ export const createEvoluDeps = (deps) => {
|
|
|
210
210
|
console.error(message.error);
|
|
211
211
|
break;
|
|
212
212
|
case "Waiting":
|
|
213
|
-
|
|
214
|
-
// Platform adapters act on these; see Builds and Storage in the Shared
|
|
215
|
-
// module.
|
|
213
|
+
// Platform adapters act on it; see Builds in the Shared module.
|
|
216
214
|
break;
|
|
217
215
|
case "Connected": {
|
|
218
216
|
assert(!syncStateBroadcastChannel, "The shared worker connects once.");
|
|
@@ -344,6 +342,12 @@ export const createEvolu = (schema, config) => async (run) => {
|
|
|
344
342
|
exportDatabasePending?.reject({ type: "EvoluDisposedError" });
|
|
345
343
|
exportDatabasePending = null;
|
|
346
344
|
});
|
|
345
|
+
const devicePersistence = Promise.withResolvers();
|
|
346
|
+
// A disposed instance never hears from its tenant, so awaiters settle.
|
|
347
|
+
disposer.defer(() => {
|
|
348
|
+
devicePersistence.resolve("Unknown");
|
|
349
|
+
});
|
|
350
|
+
let isPersistentStorageRequested = false;
|
|
347
351
|
let postMessage;
|
|
348
352
|
// Scope worker/channel wiring and keep only postMessage outside.
|
|
349
353
|
{
|
|
@@ -412,6 +416,9 @@ export const createEvolu = (schema, config) => async (run) => {
|
|
|
412
416
|
}
|
|
413
417
|
break;
|
|
414
418
|
}
|
|
419
|
+
case "OnDevicePersistence":
|
|
420
|
+
devicePersistence.resolve(message.devicePersistence);
|
|
421
|
+
break;
|
|
415
422
|
default:
|
|
416
423
|
exhaustiveCheck(message);
|
|
417
424
|
}
|
|
@@ -497,6 +504,17 @@ export const createEvolu = (schema, config) => async (run) => {
|
|
|
497
504
|
const size = measureMutation(dbChange.table, dbChange.values);
|
|
498
505
|
assert(size <= maxMutationSize, `The mutation of table '${dbChange.table}' is ${size} bytes, over maxMutationSize (${maxMutationSize}). Bound the Types of its columns or check it with evolu.getMutationSize.`);
|
|
499
506
|
}
|
|
507
|
+
// Only unsynced local changes exist nowhere else, so the first one is
|
|
508
|
+
// when asking the platform to keep them starts to matter. Asking on
|
|
509
|
+
// load would show Firefox's permission prompt to every visitor.
|
|
510
|
+
if (!isPersistentStorageRequested) {
|
|
511
|
+
isPersistentStorageRequested = true;
|
|
512
|
+
void devicePersistence.promise.then((persistence) => {
|
|
513
|
+
if (persistence === "Unknown" && !disposed) {
|
|
514
|
+
run.deps.requestPersistentStorage?.();
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
}
|
|
500
518
|
mutateBatch.push({
|
|
501
519
|
change: { ...dbChange, ownerId: options?.ownerId ?? appOwner.id },
|
|
502
520
|
onComplete: options?.onComplete,
|
|
@@ -555,6 +573,7 @@ export const createEvolu = (schema, config) => async (run) => {
|
|
|
555
573
|
return ok(disposable({
|
|
556
574
|
name,
|
|
557
575
|
appOwner,
|
|
576
|
+
devicePersistence: devicePersistence.promise,
|
|
558
577
|
insert: createMutation("insert"),
|
|
559
578
|
update: createMutation("update"),
|
|
560
579
|
upsert: createMutation("upsert"),
|
|
@@ -69,13 +69,20 @@
|
|
|
69
69
|
*
|
|
70
70
|
* ## Storage
|
|
71
71
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* its tabs see one mode, and
|
|
72
|
+
* The platform tells the worker with {@link DevicePersistenceDep} what it can
|
|
73
|
+
* promise about stored databases. The worker asks once, after it takes the
|
|
74
|
+
* build lock and before any DbWorker starts. A browser checks whether it can
|
|
75
|
+
* open the origin private file system, which Safari's Private Browsing and
|
|
76
|
+
* Firefox's private windows refuse. Without persistent storage, every DbWorker
|
|
77
|
+
* the worker starts keeps its database in memory, replacements included. The
|
|
78
|
+
* decision holds for the worker's lifetime, so all its tabs see one mode, and
|
|
79
|
+
* the next worker checks again.
|
|
80
|
+
*
|
|
81
|
+
* A tenant tells each instance it adds its {@link Evolu.devicePersistence}:
|
|
82
|
+
* `NotPersisted` when its database is kept in memory, because of the platform
|
|
83
|
+
* or {@link EvoluConfig.memoryOnly}, otherwise what the platform promised.
|
|
84
|
+
* Instances of one name share the tenant, so a later instance gets the mode the
|
|
85
|
+
* first one chose.
|
|
79
86
|
*
|
|
80
87
|
* The check cannot tell a private session from a storage failure, but memory
|
|
81
88
|
* loses nothing that refusing to start would have kept, and the persistent
|
|
@@ -262,6 +269,7 @@ import { type ExtractTyped, type Id, type InferType, type LiteralType, type Name
|
|
|
262
269
|
import type { CreateWebSocketDep, WebSocketError } from "../WebSocket.ts";
|
|
263
270
|
import type { SharedWorker as CommonSharedWorker, CreateBroadcastChannelDep, CreateMessageChannelDep, NativeMessagePort, SharedWorkerSelf, WorkerDeps } from "../Worker.ts";
|
|
264
271
|
import type { DbWorkerInit, UnsupportedDbVersionError } from "./Db.ts";
|
|
272
|
+
import type { DevicePersistence } from "./Evolu.ts";
|
|
265
273
|
import type { Owner, OwnerId, SyncOwner } from "./Owner.ts";
|
|
266
274
|
import { type ApplyProtocolMessageAsClientResult, type ProtocolError, type ProtocolInvalidDataError, type ProtocolMessage, type ProtocolTimestampMismatchError } from "./Protocol.ts";
|
|
267
275
|
import { type Patch, type Query, type RowsByQueryMap } from "./Query.ts";
|
|
@@ -315,13 +323,6 @@ export type SharedWorkerOutput = DbWorkerInit | {
|
|
|
315
323
|
readonly type: "Connected";
|
|
316
324
|
readonly workerId: SharedWorkerId;
|
|
317
325
|
readonly syncStateChannelName: string;
|
|
318
|
-
} | {
|
|
319
|
-
/**
|
|
320
|
-
* Sent to a connecting tab after `Connected` when the platform offers no
|
|
321
|
-
* persistent storage, so the worker keeps every database in memory; see
|
|
322
|
-
* Storage in this module's documentation.
|
|
323
|
-
*/
|
|
324
|
-
readonly type: "StorageUnavailable";
|
|
325
326
|
};
|
|
326
327
|
export type ConsoleEntryOrError = {
|
|
327
328
|
readonly type: "ConsoleEntry";
|
|
@@ -593,22 +594,23 @@ export interface RelaySyncState {
|
|
|
593
594
|
* stops syncing through its relay, while a skipped change leaves out only
|
|
594
595
|
* that change.
|
|
595
596
|
*
|
|
596
|
-
* Evolu
|
|
597
|
-
* it works: show nothing for `NoRelays`, `Syncing`, and `Synced`. An
|
|
598
|
-
* that changes with every edit distracts, and screen readers announce
|
|
599
|
-
* change.
|
|
597
|
+
* Evolu stores changes in the local database before they sync, so sync needs no
|
|
598
|
+
* UI while it works: show nothing for `NoRelays`, `Syncing`, and `Synced`. An
|
|
599
|
+
* indicator that changes with every edit distracts, and screen readers announce
|
|
600
|
+
* each change.
|
|
600
601
|
*
|
|
601
602
|
* For `Offline` and `Error`, show one quiet line that lasts as long as the
|
|
602
603
|
* status, not a dialog, which interrupts, or a toast, which disappears while
|
|
603
|
-
* the problem lasts.
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
* {@link
|
|
610
|
-
*
|
|
611
|
-
*
|
|
604
|
+
* the problem lasts. Do not say that changes are saved on this device unless
|
|
605
|
+
* {@link Evolu.devicePersistence} is `Persisted`: a browser may keep them only
|
|
606
|
+
* for a private session or delete them later. Evolu reports `Offline` at once;
|
|
607
|
+
* an app may wait a few seconds before showing it, because brief
|
|
608
|
+
* disconnections, such as waking from sleep, reconnect quickly. For `Error`,
|
|
609
|
+
* write actionable text for the error types the app can act on, such as a
|
|
610
|
+
* {@link ProtocolQuotaError}: the relay stores no more data for the owner, so
|
|
611
|
+
* offer more quota, such as a plan upgrade, then call {@link Evolu.requestSync}
|
|
612
|
+
* with the owner's ID. For any other error, show generic text that names the
|
|
613
|
+
* error type, which helps when the user reports it.
|
|
612
614
|
*
|
|
613
615
|
* Render the line inside one element with `role="status"` that stays mounted:
|
|
614
616
|
* screen readers announce changes only in a live region that already exists,
|
|
@@ -637,18 +639,18 @@ export interface RelaySyncState {
|
|
|
637
639
|
* case "Synced":
|
|
638
640
|
* return null;
|
|
639
641
|
* case "Offline":
|
|
640
|
-
* return "Offline.
|
|
642
|
+
* return "Offline. Changes will sync when you're back online.";
|
|
641
643
|
* case "Error":
|
|
642
644
|
* return status.error.type === "ProtocolQuotaError"
|
|
643
|
-
* ? "Sync is paused because the sync server is full.
|
|
644
|
-
* : `Sync error: ${status.error.type}
|
|
645
|
+
* ? "Sync is paused because the sync server is full."
|
|
646
|
+
* : `Sync error: ${status.error.type}.`;
|
|
645
647
|
* }
|
|
646
648
|
* };
|
|
647
649
|
*
|
|
648
650
|
* assertEqual(syncStatusToMessage({ type: "Synced" }), null);
|
|
649
651
|
* assertEqual(
|
|
650
652
|
* syncStatusToMessage({ type: "Offline" }),
|
|
651
|
-
* "Offline.
|
|
653
|
+
* "Offline. Changes will sync when you're back online.",
|
|
652
654
|
* );
|
|
653
655
|
* assertEqual(
|
|
654
656
|
* syncStatusToMessage({
|
|
@@ -659,14 +661,14 @@ export interface RelaySyncState {
|
|
|
659
661
|
* at: Millis.orThrow(1000),
|
|
660
662
|
* },
|
|
661
663
|
* }),
|
|
662
|
-
* "Sync is paused because the sync server is full.
|
|
664
|
+
* "Sync is paused because the sync server is full.",
|
|
663
665
|
* );
|
|
664
666
|
* assertEqual(
|
|
665
667
|
* syncStatusToMessage({
|
|
666
668
|
* type: "Error",
|
|
667
669
|
* error: { type: "SyncFailed", at: Millis.orThrow(1000) },
|
|
668
670
|
* }),
|
|
669
|
-
* "Sync error: SyncFailed.
|
|
671
|
+
* "Sync error: SyncFailed.",
|
|
670
672
|
* );
|
|
671
673
|
* ```
|
|
672
674
|
*/
|
|
@@ -934,6 +936,10 @@ export type EvoluOutput = {
|
|
|
934
936
|
/** The mutation with these onComplete callbacks could not be stored. */
|
|
935
937
|
readonly type: "OnMutateFailed";
|
|
936
938
|
readonly onCompleteIds: ReadonlyArray<Id>;
|
|
939
|
+
} | {
|
|
940
|
+
/** Sent once, when the tenant adds the instance; see Storage. */
|
|
941
|
+
readonly type: "OnDevicePersistence";
|
|
942
|
+
readonly devicePersistence: DevicePersistence;
|
|
937
943
|
};
|
|
938
944
|
export type DbWorkerInput = (Typed<"Request"> & {
|
|
939
945
|
readonly attemptId: Id;
|
|
@@ -1022,15 +1028,16 @@ export type DbWorkerQueuedResponse = {
|
|
|
1022
1028
|
};
|
|
1023
1029
|
};
|
|
1024
1030
|
/**
|
|
1025
|
-
* Tells
|
|
1031
|
+
* Tells what the platform can promise about the databases it stores.
|
|
1026
1032
|
*
|
|
1027
|
-
*
|
|
1028
|
-
* does in Safari's Private Browsing
|
|
1033
|
+
* `NotPersisted` means the platform offers no persistent storage now, as a
|
|
1034
|
+
* browser does in Safari's Private Browsing or a Firefox private window, so the
|
|
1035
|
+
* worker keeps every database in memory; see Storage in the Shared module.
|
|
1029
1036
|
*/
|
|
1030
|
-
export interface
|
|
1031
|
-
readonly
|
|
1037
|
+
export interface DevicePersistenceDep {
|
|
1038
|
+
readonly getDevicePersistence: () => Promise<DevicePersistence>;
|
|
1032
1039
|
}
|
|
1033
|
-
export type SharedWorkerDeps = WorkerDeps & CreateBroadcastChannelDep & CreateMessageChannelDep & CreateWebSocketDep &
|
|
1040
|
+
export type SharedWorkerDeps = WorkerDeps & CreateBroadcastChannelDep & CreateMessageChannelDep & CreateWebSocketDep & DevicePersistenceDep & LockManagerDep;
|
|
1034
1041
|
export type EvoluInstanceId = Id & Brand<"EvoluInstance">;
|
|
1035
1042
|
/**
|
|
1036
1043
|
* Initializes the platform-agnostic Evolu SharedWorker.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Shared.d.ts","sourceRoot":"","sources":["../../../src/local-first/Shared.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Shared.d.ts","sourceRoot":"","sources":["../../../src/local-first/Shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -69,13 +69,20 @@
|
|
|
69
69
|
*
|
|
70
70
|
* ## Storage
|
|
71
71
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* its tabs see one mode, and
|
|
72
|
+
* The platform tells the worker with {@link DevicePersistenceDep} what it can
|
|
73
|
+
* promise about stored databases. The worker asks once, after it takes the
|
|
74
|
+
* build lock and before any DbWorker starts. A browser checks whether it can
|
|
75
|
+
* open the origin private file system, which Safari's Private Browsing and
|
|
76
|
+
* Firefox's private windows refuse. Without persistent storage, every DbWorker
|
|
77
|
+
* the worker starts keeps its database in memory, replacements included. The
|
|
78
|
+
* decision holds for the worker's lifetime, so all its tabs see one mode, and
|
|
79
|
+
* the next worker checks again.
|
|
80
|
+
*
|
|
81
|
+
* A tenant tells each instance it adds its {@link Evolu.devicePersistence}:
|
|
82
|
+
* `NotPersisted` when its database is kept in memory, because of the platform
|
|
83
|
+
* or {@link EvoluConfig.memoryOnly}, otherwise what the platform promised.
|
|
84
|
+
* Instances of one name share the tenant, so a later instance gets the mode the
|
|
85
|
+
* first one chose.
|
|
79
86
|
*
|
|
80
87
|
* The check cannot tell a private session from a storage failure, but memory
|
|
81
88
|
* loses nothing that refusing to start would have kept, and the persistent
|
|
@@ -806,9 +813,6 @@ export const initSharedWorker = (self) => async (run) => {
|
|
|
806
813
|
workerId,
|
|
807
814
|
syncStateChannelName,
|
|
808
815
|
});
|
|
809
|
-
if (isPersistentStorageUnavailable) {
|
|
810
|
-
port.postMessage({ type: "StorageUnavailable" });
|
|
811
|
-
}
|
|
812
816
|
});
|
|
813
817
|
};
|
|
814
818
|
// Held while this worker runs. Its DbWorkers stop once they can take it,
|
|
@@ -821,11 +825,10 @@ export const initSharedWorker = (self) => async (run) => {
|
|
|
821
825
|
// Builds.
|
|
822
826
|
disposer.use(await run.ok(acquireLeaderLock("tab")));
|
|
823
827
|
starting.dispose();
|
|
824
|
-
// Checked once, before any DbWorker starts, so
|
|
825
|
-
// worker, replacements included, keeps its
|
|
826
|
-
// Storage.
|
|
827
|
-
const
|
|
828
|
-
!(await deps.isPersistentStorageAvailable());
|
|
828
|
+
// Checked once, before any DbWorker starts, so without persistent
|
|
829
|
+
// storage every DbWorker of this worker, replacements included, keeps its
|
|
830
|
+
// database in memory; see Storage.
|
|
831
|
+
const platformDevicePersistence = await deps.getDevicePersistence();
|
|
829
832
|
disposer.defer(deps.consoleStoreOutputEntry.subscribe(() => {
|
|
830
833
|
const entry = deps.consoleStoreOutputEntry.get();
|
|
831
834
|
if (entry)
|
|
@@ -1193,9 +1196,11 @@ export const initSharedWorker = (self) => async (run) => {
|
|
|
1193
1196
|
tabLeaderPortStore,
|
|
1194
1197
|
transports,
|
|
1195
1198
|
}));
|
|
1196
|
-
const tenantsByName = disposer.use(await sharedWorkerRun.ok(createSharedResourceByKey((message) =>
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
+
const tenantsByName = disposer.use(await sharedWorkerRun.ok(createSharedResourceByKey((message) => {
|
|
1200
|
+
const memoryOnly = message.memoryOnly ||
|
|
1201
|
+
platformDevicePersistence === "NotPersisted";
|
|
1202
|
+
return createEvoluTenant({ ...message, memoryOnly }, memoryOnly ? "NotPersisted" : platformDevicePersistence, currentTenantsByName, workerId);
|
|
1203
|
+
}, {
|
|
1199
1204
|
idleDisposeAfter: "3s",
|
|
1200
1205
|
lookup: (message) => message.name,
|
|
1201
1206
|
})));
|
|
@@ -1216,7 +1221,7 @@ export const initSharedWorker = (self) => async (run) => {
|
|
|
1216
1221
|
await result_1;
|
|
1217
1222
|
}
|
|
1218
1223
|
};
|
|
1219
|
-
const createEvoluTenant = ({ name, consoleLevel, sqliteSchema, encryptionKey, memoryOnly, }, currentTenantsByName, workerId) => async (run) => {
|
|
1224
|
+
const createEvoluTenant = ({ name, consoleLevel, sqliteSchema, encryptionKey, memoryOnly, }, devicePersistence, currentTenantsByName, workerId) => async (run) => {
|
|
1220
1225
|
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
1221
1226
|
try {
|
|
1222
1227
|
const disposer = __addDisposableResource(env_3, new AsyncDisposableStack(), true);
|
|
@@ -2107,6 +2112,12 @@ const createEvoluTenant = ({ name, consoleLevel, sqliteSchema, encryptionKey, me
|
|
|
2107
2112
|
disposer.defer(() => {
|
|
2108
2113
|
instance.port.onMessage = null;
|
|
2109
2114
|
});
|
|
2115
|
+
// Instances of one name share the tenant, so each learns the mode
|
|
2116
|
+
// the first one chose.
|
|
2117
|
+
instance.port.postMessage({
|
|
2118
|
+
type: "OnDevicePersistence",
|
|
2119
|
+
devicePersistence,
|
|
2120
|
+
});
|
|
2110
2121
|
// The main-thread Evolu instance holds this per-instance leader lock
|
|
2111
2122
|
// while it is alive. Acquiring the same lock here means the main
|
|
2112
2123
|
// thread instance was disposed or its tab closed, so the tenant-side
|
package/package.json
CHANGED
|
@@ -372,16 +372,6 @@ describe("Evolu", () => {
|
|
|
372
372
|
assertSame(setup.deps.evoluError.get(), null);
|
|
373
373
|
});
|
|
374
374
|
|
|
375
|
-
it("says nothing to a worker that reports it keeps databases in memory", async () => {
|
|
376
|
-
using setup = await setupCreateEvoluDeps();
|
|
377
|
-
|
|
378
|
-
setup.sharedWorkerPort.postMessage({ type: "StorageUnavailable" });
|
|
379
|
-
await testWaitForWorkerMessage();
|
|
380
|
-
|
|
381
|
-
assertEqual(setup.messages, []);
|
|
382
|
-
assertSame(setup.deps.evoluError.get(), null);
|
|
383
|
-
});
|
|
384
|
-
|
|
385
375
|
it("announces itself as tab leader with its console level once its worker connects", async () => {
|
|
386
376
|
const testConsole = testCreateConsole();
|
|
387
377
|
using setup = await setupCreateEvoluDeps(testConsole);
|
|
@@ -1502,6 +1492,106 @@ describe("Evolu", () => {
|
|
|
1502
1492
|
});
|
|
1503
1493
|
});
|
|
1504
1494
|
|
|
1495
|
+
describe("device persistence", () => {
|
|
1496
|
+
const setupPersistenceRequests = async () => {
|
|
1497
|
+
let requestCount = 0;
|
|
1498
|
+
const setup = await setupRunWithEvoluDeps({
|
|
1499
|
+
requestPersistentStorage: () => {
|
|
1500
|
+
requestCount += 1;
|
|
1501
|
+
},
|
|
1502
|
+
});
|
|
1503
|
+
return Object.assign(setup, { getRequestCount: () => requestCount });
|
|
1504
|
+
};
|
|
1505
|
+
|
|
1506
|
+
it("resolves devicePersistence to what its tenant sends", async () => {
|
|
1507
|
+
await using setup = await setupRunWithEvoluDeps();
|
|
1508
|
+
const evolu = await setup.run.ok(testCreateEvolu);
|
|
1509
|
+
|
|
1510
|
+
setup.postEvoluOutput({
|
|
1511
|
+
type: "OnDevicePersistence",
|
|
1512
|
+
devicePersistence: "NotPersisted",
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
assertSame(await evolu.devicePersistence, "NotPersisted");
|
|
1516
|
+
});
|
|
1517
|
+
|
|
1518
|
+
it("resolves devicePersistence to Unknown when disposed before its tenant sends it", async () => {
|
|
1519
|
+
await using setup = await setupRunWithEvoluDeps();
|
|
1520
|
+
const evolu = await setup.run.ok(testCreateEvolu);
|
|
1521
|
+
|
|
1522
|
+
await evolu[Symbol.asyncDispose]();
|
|
1523
|
+
|
|
1524
|
+
assertSame(await evolu.devicePersistence, "Unknown");
|
|
1525
|
+
});
|
|
1526
|
+
|
|
1527
|
+
it("requests persistent storage once, after the first mutation, when devicePersistence is Unknown", async () => {
|
|
1528
|
+
await using setup = await setupPersistenceRequests();
|
|
1529
|
+
const evolu = await setup.run.ok(testCreateEvolu);
|
|
1530
|
+
setup.postEvoluOutput({
|
|
1531
|
+
type: "OnDevicePersistence",
|
|
1532
|
+
devicePersistence: "Unknown",
|
|
1533
|
+
});
|
|
1534
|
+
await evolu.devicePersistence;
|
|
1535
|
+
await testWaitForWorkerMessage();
|
|
1536
|
+
assertSame(setup.getRequestCount(), 0);
|
|
1537
|
+
|
|
1538
|
+
evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("A") });
|
|
1539
|
+
evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("B") });
|
|
1540
|
+
await testWaitForWorkerMessage();
|
|
1541
|
+
evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("C") });
|
|
1542
|
+
await testWaitForWorkerMessage();
|
|
1543
|
+
|
|
1544
|
+
assertSame(setup.getRequestCount(), 1);
|
|
1545
|
+
});
|
|
1546
|
+
|
|
1547
|
+
it("requests persistent storage once devicePersistence resolves after the first mutation", async () => {
|
|
1548
|
+
await using setup = await setupPersistenceRequests();
|
|
1549
|
+
const evolu = await setup.run.ok(testCreateEvolu);
|
|
1550
|
+
|
|
1551
|
+
evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("A") });
|
|
1552
|
+
await testWaitForWorkerMessage();
|
|
1553
|
+
assertSame(setup.getRequestCount(), 0);
|
|
1554
|
+
|
|
1555
|
+
setup.postEvoluOutput({
|
|
1556
|
+
type: "OnDevicePersistence",
|
|
1557
|
+
devicePersistence: "Unknown",
|
|
1558
|
+
});
|
|
1559
|
+
await evolu.devicePersistence;
|
|
1560
|
+
await testWaitForWorkerMessage();
|
|
1561
|
+
|
|
1562
|
+
assertSame(setup.getRequestCount(), 1);
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
for (const devicePersistence of ["Persisted", "NotPersisted"] as const) {
|
|
1566
|
+
it(`does not request persistent storage when devicePersistence is ${devicePersistence}`, async () => {
|
|
1567
|
+
await using setup = await setupPersistenceRequests();
|
|
1568
|
+
const evolu = await setup.run.ok(testCreateEvolu);
|
|
1569
|
+
setup.postEvoluOutput({
|
|
1570
|
+
type: "OnDevicePersistence",
|
|
1571
|
+
devicePersistence,
|
|
1572
|
+
});
|
|
1573
|
+
|
|
1574
|
+
evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("A") });
|
|
1575
|
+
await evolu.devicePersistence;
|
|
1576
|
+
await testWaitForWorkerMessage();
|
|
1577
|
+
|
|
1578
|
+
assertSame(setup.getRequestCount(), 0);
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
it("does not request persistent storage after disposal", async () => {
|
|
1583
|
+
await using setup = await setupPersistenceRequests();
|
|
1584
|
+
const evolu = await setup.run.ok(testCreateEvolu);
|
|
1585
|
+
|
|
1586
|
+
evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("A") });
|
|
1587
|
+
await evolu[Symbol.asyncDispose]();
|
|
1588
|
+
await evolu.devicePersistence;
|
|
1589
|
+
await testWaitForWorkerMessage();
|
|
1590
|
+
|
|
1591
|
+
assertSame(setup.getRequestCount(), 0);
|
|
1592
|
+
});
|
|
1593
|
+
});
|
|
1594
|
+
|
|
1505
1595
|
describe("dispose evolu", () => {
|
|
1506
1596
|
it("logs disposeEvolu once", async () => {
|
|
1507
1597
|
const testConsole = testCreateConsole();
|
package/src/local-first/Evolu.ts
CHANGED
|
@@ -385,6 +385,37 @@ export interface Evolu<
|
|
|
385
385
|
/** {@link AppOwner}. */
|
|
386
386
|
readonly appOwner: AppOwner;
|
|
387
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Whether this device keeps the database, resolved once the shared worker
|
|
390
|
+
* serves it, or `Unknown` if this instance is disposed first.
|
|
391
|
+
*
|
|
392
|
+
* Apps tell the user when it is `NotPersisted`, because then data that has
|
|
393
|
+
* not synced is lost when the database closes. Apps must not tell the user
|
|
394
|
+
* that data is saved on the device when it is `Unknown`.
|
|
395
|
+
*
|
|
396
|
+
* ### Example
|
|
397
|
+
*
|
|
398
|
+
* ```ts
|
|
399
|
+
* import { assertEqual } from "@evolu/common";
|
|
400
|
+
* import type { DevicePersistence } from "@evolu/common/local-first";
|
|
401
|
+
*
|
|
402
|
+
* // The notice for `await evolu.devicePersistence`, or null for none.
|
|
403
|
+
* const persistenceNotice = (
|
|
404
|
+
* devicePersistence: DevicePersistence,
|
|
405
|
+
* ): string | null =>
|
|
406
|
+
* devicePersistence === "NotPersisted"
|
|
407
|
+
* ? "Your data isn't kept on this device. Changes that haven't synced are lost when you close this tab."
|
|
408
|
+
* : null;
|
|
409
|
+
*
|
|
410
|
+
* assertEqual(persistenceNotice("Unknown"), null);
|
|
411
|
+
* assertEqual(
|
|
412
|
+
* persistenceNotice("NotPersisted"),
|
|
413
|
+
* "Your data isn't kept on this device. Changes that haven't synced are lost when you close this tab.",
|
|
414
|
+
* );
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
417
|
+
readonly devicePersistence: Promise<DevicePersistence>;
|
|
418
|
+
|
|
388
419
|
/**
|
|
389
420
|
* Inserts a row and returns the generated {@link Id}.
|
|
390
421
|
*
|
|
@@ -873,6 +904,28 @@ export interface Evolu<
|
|
|
873
904
|
*/
|
|
874
905
|
export type UnuseOwner = () => void;
|
|
875
906
|
|
|
907
|
+
/**
|
|
908
|
+
* Whether this device keeps an {@link Evolu} database, stating only what Evolu
|
|
909
|
+
* knows for sure.
|
|
910
|
+
*
|
|
911
|
+
* - `Persisted`: the platform stores it in the app's own file, as React Native
|
|
912
|
+
* does.
|
|
913
|
+
* - `NotPersisted`: it is kept in memory, because {@link EvoluConfig.memoryOnly}
|
|
914
|
+
* asks for that or the platform offers no persistent storage, as a browser
|
|
915
|
+
* does in Safari's Private Browsing or a Firefox private window. Data that
|
|
916
|
+
* has not synced is lost when the database closes.
|
|
917
|
+
* - `Unknown`: it is stored, but the platform may delete it. A browser can keep
|
|
918
|
+
* storage only for a private session, as Chrome's incognito does without
|
|
919
|
+
* telling the app, delete it after a while or when disk space runs low, and
|
|
920
|
+
* let the user clear it.
|
|
921
|
+
*
|
|
922
|
+
* See [Will my data stay on the
|
|
923
|
+
* device?](https://www.evolu.dev/docs/faq#will-my-data-stay-on-the-device).
|
|
924
|
+
*
|
|
925
|
+
* @group Core
|
|
926
|
+
*/
|
|
927
|
+
export type DevicePersistence = "Persisted" | "NotPersisted" | "Unknown";
|
|
928
|
+
|
|
876
929
|
/**
|
|
877
930
|
* Represents app-level errors that can occur in {@link Evolu}.
|
|
878
931
|
*
|
|
@@ -1125,6 +1178,20 @@ export interface SyncStateDep {
|
|
|
1125
1178
|
readonly syncState: ReadonlyStore<SyncState | null>;
|
|
1126
1179
|
}
|
|
1127
1180
|
|
|
1181
|
+
/**
|
|
1182
|
+
* Asks the platform to keep stored databases until the user deletes them.
|
|
1183
|
+
*
|
|
1184
|
+
* Only unsynced local changes exist nowhere else, so each {@link Evolu} instance
|
|
1185
|
+
* calls it after its first local mutation, when its
|
|
1186
|
+
* {@link Evolu.devicePersistence} is `Unknown`. A platform provides it when its
|
|
1187
|
+
* storage can be deleted without the user, as a browser's can.
|
|
1188
|
+
*
|
|
1189
|
+
* @group Construction
|
|
1190
|
+
*/
|
|
1191
|
+
export interface RequestPersistentStorageDep {
|
|
1192
|
+
readonly requestPersistentStorage: () => void;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1128
1195
|
/**
|
|
1129
1196
|
* Shared platform dependencies for creating {@link Evolu} instances.
|
|
1130
1197
|
*
|
|
@@ -1143,7 +1210,7 @@ export type EvoluDeps = EvoluPlatformDeps &
|
|
|
1143
1210
|
* Platform-specific dependencies required to create {@link EvoluDeps}.
|
|
1144
1211
|
*
|
|
1145
1212
|
* Provides worker and channel adapters plus optional platform integrations for
|
|
1146
|
-
* logging
|
|
1213
|
+
* logging, synchronous UI flush, and persistent storage requests.
|
|
1147
1214
|
*
|
|
1148
1215
|
* @group Construction
|
|
1149
1216
|
*/
|
|
@@ -1154,7 +1221,8 @@ export type EvoluPlatformDeps = CreateDbWorkerDep &
|
|
|
1154
1221
|
ReloadAppDep &
|
|
1155
1222
|
SharedWorkerDep &
|
|
1156
1223
|
Partial<ConsoleDep> &
|
|
1157
|
-
Partial<FlushSyncDep
|
|
1224
|
+
Partial<FlushSyncDep> &
|
|
1225
|
+
Partial<RequestPersistentStorageDep>;
|
|
1158
1226
|
|
|
1159
1227
|
/**
|
|
1160
1228
|
* Creates shared dependencies used by all {@link createEvolu} instances on a
|
|
@@ -1234,9 +1302,7 @@ export const createEvoluDeps = (deps: EvoluPlatformDeps): EvoluDeps => {
|
|
|
1234
1302
|
break;
|
|
1235
1303
|
|
|
1236
1304
|
case "Waiting":
|
|
1237
|
-
|
|
1238
|
-
// Platform adapters act on these; see Builds and Storage in the Shared
|
|
1239
|
-
// module.
|
|
1305
|
+
// Platform adapters act on it; see Builds in the Shared module.
|
|
1240
1306
|
break;
|
|
1241
1307
|
|
|
1242
1308
|
case "Connected": {
|
|
@@ -1423,6 +1489,13 @@ export const createEvolu =
|
|
|
1423
1489
|
exportDatabasePending = null;
|
|
1424
1490
|
});
|
|
1425
1491
|
|
|
1492
|
+
const devicePersistence = Promise.withResolvers<DevicePersistence>();
|
|
1493
|
+
// A disposed instance never hears from its tenant, so awaiters settle.
|
|
1494
|
+
disposer.defer(() => {
|
|
1495
|
+
devicePersistence.resolve("Unknown");
|
|
1496
|
+
});
|
|
1497
|
+
let isPersistentStorageRequested = false;
|
|
1498
|
+
|
|
1426
1499
|
let postMessage: (input: EvoluInput) => void;
|
|
1427
1500
|
|
|
1428
1501
|
// Scope worker/channel wiring and keep only postMessage outside.
|
|
@@ -1512,6 +1585,10 @@ export const createEvolu =
|
|
|
1512
1585
|
break;
|
|
1513
1586
|
}
|
|
1514
1587
|
|
|
1588
|
+
case "OnDevicePersistence":
|
|
1589
|
+
devicePersistence.resolve(message.devicePersistence);
|
|
1590
|
+
break;
|
|
1591
|
+
|
|
1515
1592
|
default:
|
|
1516
1593
|
exhaustiveCheck(message);
|
|
1517
1594
|
}
|
|
@@ -1639,6 +1716,18 @@ export const createEvolu =
|
|
|
1639
1716
|
);
|
|
1640
1717
|
}
|
|
1641
1718
|
|
|
1719
|
+
// Only unsynced local changes exist nowhere else, so the first one is
|
|
1720
|
+
// when asking the platform to keep them starts to matter. Asking on
|
|
1721
|
+
// load would show Firefox's permission prompt to every visitor.
|
|
1722
|
+
if (!isPersistentStorageRequested) {
|
|
1723
|
+
isPersistentStorageRequested = true;
|
|
1724
|
+
void devicePersistence.promise.then((persistence) => {
|
|
1725
|
+
if (persistence === "Unknown" && !disposed) {
|
|
1726
|
+
run.deps.requestPersistentStorage?.();
|
|
1727
|
+
}
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1642
1731
|
mutateBatch.push({
|
|
1643
1732
|
change: { ...dbChange, ownerId: options?.ownerId ?? appOwner.id },
|
|
1644
1733
|
onComplete: options?.onComplete,
|
|
@@ -1722,6 +1811,7 @@ export const createEvolu =
|
|
|
1722
1811
|
{
|
|
1723
1812
|
name,
|
|
1724
1813
|
appOwner,
|
|
1814
|
+
devicePersistence: devicePersistence.promise,
|
|
1725
1815
|
|
|
1726
1816
|
insert: createMutation("insert"),
|
|
1727
1817
|
update: createMutation("update"),
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
type ProtocolTimestampMismatchError,
|
|
43
43
|
SubscriptionFlags,
|
|
44
44
|
} from "./Protocol.ts";
|
|
45
|
+
import type { DevicePersistence } from "./Evolu.ts";
|
|
45
46
|
import {
|
|
46
47
|
createQueryBuilder,
|
|
47
48
|
type EvoluSchema,
|
|
@@ -170,11 +171,11 @@ const setupSharedWorker = async ({
|
|
|
170
171
|
createWebSocket = testCreateWebSocket({ throwOnCreate: true }),
|
|
171
172
|
time,
|
|
172
173
|
seed,
|
|
173
|
-
|
|
174
|
+
getDevicePersistence = () => Promise.resolve("Unknown"),
|
|
174
175
|
}: {
|
|
175
176
|
createWebSocket?: CreateWebSocket;
|
|
176
177
|
time?: TestTime;
|
|
177
|
-
|
|
178
|
+
getDevicePersistence?: () => Promise<DevicePersistence>;
|
|
178
179
|
/**
|
|
179
180
|
* Seeds the worker's random bytes, which are otherwise the same for every
|
|
180
181
|
* worker.
|
|
@@ -214,7 +215,7 @@ const setupSharedWorker = async ({
|
|
|
214
215
|
createWebSocket,
|
|
215
216
|
...(time && { time }),
|
|
216
217
|
...(seed && { randomBytes: testCreateDeps({ seed }).randomBytes }),
|
|
217
|
-
|
|
218
|
+
getDevicePersistence,
|
|
218
219
|
}),
|
|
219
220
|
);
|
|
220
221
|
|
|
@@ -239,8 +240,10 @@ const setupSharedWorker = async ({
|
|
|
239
240
|
releaseDbWorkerLeaderOnDispose = true,
|
|
240
241
|
autoDispose = true,
|
|
241
242
|
initialClock = createTimestamp(),
|
|
243
|
+
memoryOnly = false,
|
|
242
244
|
}: {
|
|
243
245
|
tenantName?: Name;
|
|
246
|
+
memoryOnly?: boolean;
|
|
244
247
|
evoluChannel?: TestMessageChannel<EvoluOutput, EvoluInput>;
|
|
245
248
|
releaseDbWorkerLeaderOnDispose?: boolean;
|
|
246
249
|
autoDispose?: boolean;
|
|
@@ -289,7 +292,7 @@ const setupSharedWorker = async ({
|
|
|
289
292
|
consoleLevel: "debug",
|
|
290
293
|
sqliteSchema: testSqliteSchema,
|
|
291
294
|
encryptionKey: testAppOwner.encryptionKey,
|
|
292
|
-
memoryOnly
|
|
295
|
+
memoryOnly,
|
|
293
296
|
evoluPort: evoluChannel.port1.native,
|
|
294
297
|
};
|
|
295
298
|
|
|
@@ -339,7 +342,25 @@ const setupSharedWorker = async ({
|
|
|
339
342
|
) => {
|
|
340
343
|
const instance = await createEvoluBeforeDbWorkerLeader(options);
|
|
341
344
|
await instance.acquireDbWorkerLeader();
|
|
342
|
-
|
|
345
|
+
|
|
346
|
+
// Once the DbWorker starts, the tenant adds the instance and tells it its
|
|
347
|
+
// device persistence first, so tests see only the outputs that follow.
|
|
348
|
+
const firstOutputs: Array<EvoluOutput> = [];
|
|
349
|
+
instance.evoluChannel.port2.onMessage = (output) => {
|
|
350
|
+
firstOutputs.push(output);
|
|
351
|
+
};
|
|
352
|
+
await testWaitForWorkerMessage();
|
|
353
|
+
instance.evoluChannel.port2.onMessage = null;
|
|
354
|
+
assertLength(firstOutputs, 1);
|
|
355
|
+
const [devicePersistenceOutput] = firstOutputs;
|
|
356
|
+
assert(
|
|
357
|
+
devicePersistenceOutput.type === "OnDevicePersistence",
|
|
358
|
+
"Expected the device persistence first.",
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
return Object.assign(instance, {
|
|
362
|
+
devicePersistence: devicePersistenceOutput.devicePersistence,
|
|
363
|
+
});
|
|
343
364
|
};
|
|
344
365
|
|
|
345
366
|
return {
|
|
@@ -607,17 +628,30 @@ describe("storage", () => {
|
|
|
607
628
|
const isMemoryOnly = (output: SharedWorkerOutput | undefined): boolean =>
|
|
608
629
|
getDbWorkerInit(output).memoryOnly;
|
|
609
630
|
|
|
631
|
+
/** Every device persistence the tenant sent to the instance so far. */
|
|
632
|
+
const receiveDevicePersistences = async (
|
|
633
|
+
evoluChannel: TestMessageChannel<EvoluOutput, EvoluInput>,
|
|
634
|
+
): Promise<ReadonlyArray<DevicePersistence>> => {
|
|
635
|
+
const devicePersistences: Array<DevicePersistence> = [];
|
|
636
|
+
evoluChannel.port2.onMessage = (output) => {
|
|
637
|
+
if (output.type === "OnDevicePersistence") {
|
|
638
|
+
devicePersistences.push(output.devicePersistence);
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
await testWaitForWorkerMessage();
|
|
642
|
+
return devicePersistences;
|
|
643
|
+
};
|
|
644
|
+
|
|
610
645
|
it("keeps every database in memory, replacements included, without persistent storage", async () => {
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
});
|
|
646
|
+
const getDevicePersistence = mock.fn(() =>
|
|
647
|
+
Promise.resolve<DevicePersistence>("NotPersisted"),
|
|
648
|
+
);
|
|
649
|
+
await using setup = await setupSharedWorker({ getDevicePersistence });
|
|
615
650
|
using disposer = new DisposableStack();
|
|
616
651
|
|
|
617
|
-
// The first tab heard it right after Connected.
|
|
618
|
-
assertEqual(setup.sharedWorkerOutputs, [{ type: "StorageUnavailable" }]);
|
|
619
652
|
const first = await setup.createEvolu();
|
|
620
|
-
assertTrue(isMemoryOnly(setup.sharedWorkerOutputs.at(
|
|
653
|
+
assertTrue(isMemoryOnly(setup.sharedWorkerOutputs.at(0)));
|
|
654
|
+
assertSame(first.devicePersistence, "NotPersisted");
|
|
621
655
|
|
|
622
656
|
// A replacement DbWorker, as after its tab closed, keeps it in memory too.
|
|
623
657
|
await first.releaseDbWorkerLeader();
|
|
@@ -625,8 +659,7 @@ describe("storage", () => {
|
|
|
625
659
|
tab.port.postMessage({ type: "AnnounceTabLeader", consoleLevel: "debug" });
|
|
626
660
|
await testWaitForWorkerMessage();
|
|
627
661
|
await testWaitForWorkerMessage();
|
|
628
|
-
|
|
629
|
-
const replacement = getDbWorkerInit(tab.outputs.at(1));
|
|
662
|
+
const replacement = getDbWorkerInit(tab.outputs.at(0));
|
|
630
663
|
assertTrue(replacement.memoryOnly);
|
|
631
664
|
using leaderPort = testCreateMessagePort<DbWorkerOutput, DbWorkerInput>(
|
|
632
665
|
replacement.port,
|
|
@@ -638,29 +671,62 @@ describe("storage", () => {
|
|
|
638
671
|
});
|
|
639
672
|
await testWaitForWorkerMessage();
|
|
640
673
|
|
|
641
|
-
assertSame(
|
|
674
|
+
assertSame(getDevicePersistence.mock.callCount(), 1);
|
|
642
675
|
});
|
|
643
676
|
|
|
644
|
-
|
|
677
|
+
for (const devicePersistence of ["Persisted", "Unknown"] as const) {
|
|
678
|
+
it(`stores databases and tells instances ${devicePersistence} where the platform promises it`, async () => {
|
|
679
|
+
await using setup = await setupSharedWorker({
|
|
680
|
+
getDevicePersistence: () => Promise.resolve(devicePersistence),
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
const instance = await setup.createEvolu();
|
|
684
|
+
|
|
685
|
+
assertEqual(
|
|
686
|
+
setup.sharedWorkerOutputs.map(({ type }) => type),
|
|
687
|
+
["DbWorkerInit"],
|
|
688
|
+
);
|
|
689
|
+
assertFalse(isMemoryOnly(setup.sharedWorkerOutputs.at(0)));
|
|
690
|
+
assertSame(instance.devicePersistence, devicePersistence);
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
it("tells an instance configured memoryOnly that its database is not persisted", async () => {
|
|
645
695
|
await using setup = await setupSharedWorker({
|
|
646
|
-
|
|
696
|
+
getDevicePersistence: () => Promise.resolve("Persisted"),
|
|
647
697
|
});
|
|
648
698
|
|
|
649
|
-
await setup.createEvolu();
|
|
699
|
+
const instance = await setup.createEvolu({ memoryOnly: true });
|
|
650
700
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
["DbWorkerInit"],
|
|
654
|
-
);
|
|
655
|
-
assertFalse(isMemoryOnly(setup.sharedWorkerOutputs.at(0)));
|
|
701
|
+
assertTrue(isMemoryOnly(setup.sharedWorkerOutputs.at(0)));
|
|
702
|
+
assertSame(instance.devicePersistence, "NotPersisted");
|
|
656
703
|
});
|
|
657
704
|
|
|
658
|
-
it("
|
|
659
|
-
await using setup = await setupSharedWorker(
|
|
705
|
+
it("tells a later instance of the same name the mode the first one chose", async () => {
|
|
706
|
+
await using setup = await setupSharedWorker({
|
|
707
|
+
getDevicePersistence: () => Promise.resolve("Persisted"),
|
|
708
|
+
});
|
|
709
|
+
const { run, worker } = setup;
|
|
710
|
+
await setup.createEvolu({ memoryOnly: true });
|
|
660
711
|
|
|
661
|
-
|
|
712
|
+
const secondId: EvoluInstanceId = createId(run.deps);
|
|
713
|
+
await using _secondInstanceLock = await run.ok(acquireLeaderLock(secondId));
|
|
714
|
+
using secondChannel = testCreateMessageChannel<EvoluOutput, EvoluInput>();
|
|
715
|
+
worker.port.postMessage({
|
|
716
|
+
type: "CreateEvolu",
|
|
717
|
+
name: testName,
|
|
718
|
+
id: secondId,
|
|
719
|
+
consoleLevel: "debug",
|
|
720
|
+
sqliteSchema: testSqliteSchema,
|
|
721
|
+
encryptionKey: testAppOwner.encryptionKey,
|
|
722
|
+
memoryOnly: false,
|
|
723
|
+
evoluPort: secondChannel.port1.native,
|
|
724
|
+
});
|
|
725
|
+
await testWaitForWorkerMessage();
|
|
662
726
|
|
|
663
|
-
|
|
727
|
+
assertEqual(await receiveDevicePersistences(secondChannel), [
|
|
728
|
+
"NotPersisted",
|
|
729
|
+
]);
|
|
664
730
|
});
|
|
665
731
|
});
|
|
666
732
|
|
|
@@ -681,6 +747,7 @@ describe("builds", () => {
|
|
|
681
747
|
lockManager,
|
|
682
748
|
createMessagePort: testCreateMessagePort,
|
|
683
749
|
createWebSocket: testCreateWebSocket({ throwOnCreate: true }),
|
|
750
|
+
getDevicePersistence: () => Promise.resolve("Unknown" as const),
|
|
684
751
|
}),
|
|
685
752
|
);
|
|
686
753
|
const outputs: Array<SharedWorkerOutput> = [];
|
|
@@ -7265,7 +7332,14 @@ describe("with one evolu instance", () => {
|
|
|
7265
7332
|
memoryOnly: false,
|
|
7266
7333
|
evoluPort: siblingChannel.port1.native,
|
|
7267
7334
|
});
|
|
7335
|
+
const siblingOutputs: Array<EvoluOutput> = [];
|
|
7336
|
+
siblingChannel.port2.onMessage = (output) => {
|
|
7337
|
+
siblingOutputs.push(output);
|
|
7338
|
+
};
|
|
7268
7339
|
await testWaitForWorkerMessage();
|
|
7340
|
+
assertEqual(siblingOutputs, [
|
|
7341
|
+
{ type: "OnDevicePersistence", devicePersistence: "Unknown" },
|
|
7342
|
+
]);
|
|
7269
7343
|
siblingChannel.port2.postMessage({
|
|
7270
7344
|
type: "Mutate",
|
|
7271
7345
|
changes: [
|
|
@@ -9644,6 +9718,10 @@ describe("with one evolu instance", () => {
|
|
|
9644
9718
|
[siblingChannel.port1.native],
|
|
9645
9719
|
);
|
|
9646
9720
|
await testWaitForWorkerMessage();
|
|
9721
|
+
// The tenant keeps the first instance's persistent database.
|
|
9722
|
+
assertEqual(siblingOutputs.splice(0), [
|
|
9723
|
+
{ type: "OnDevicePersistence", devicePersistence: "Unknown" },
|
|
9724
|
+
]);
|
|
9647
9725
|
|
|
9648
9726
|
const bytes = new Uint8Array([1, 2, 3]);
|
|
9649
9727
|
const mutation: ExtractTyped<EvoluInput, "Mutate"> = {
|
|
@@ -10811,10 +10889,13 @@ describe("startup refusal", () => {
|
|
|
10811
10889
|
});
|
|
10812
10890
|
await testWaitForWorkerMessage();
|
|
10813
10891
|
// The tab is told through its own connection, not the broadcast channel,
|
|
10814
|
-
// and its instance
|
|
10892
|
+
// and its instance learns only its device persistence: pending work stays
|
|
10893
|
+
// pending.
|
|
10815
10894
|
assertEqual(firstTabOutputs(), [{ type: "Error", error: refusal }]);
|
|
10816
10895
|
assertEqual(broadcasts, []);
|
|
10817
|
-
assertEqual(evoluOutputs, [
|
|
10896
|
+
assertEqual(evoluOutputs.splice(0), [
|
|
10897
|
+
{ type: "OnDevicePersistence", devicePersistence: "Unknown" },
|
|
10898
|
+
]);
|
|
10818
10899
|
|
|
10819
10900
|
// Later requests are dropped without a response.
|
|
10820
10901
|
instance.evoluChannel.port2.postMessage({
|
|
@@ -10852,7 +10933,9 @@ describe("startup refusal", () => {
|
|
|
10852
10933
|
);
|
|
10853
10934
|
await testWaitForWorkerMessage();
|
|
10854
10935
|
assertEqual(firstTabOutputs(), [{ type: "Error", error: refusal }]);
|
|
10855
|
-
assertEqual(secondOutputs, [
|
|
10936
|
+
assertEqual(secondOutputs, [
|
|
10937
|
+
{ type: "OnDevicePersistence", devicePersistence: "Unknown" },
|
|
10938
|
+
]);
|
|
10856
10939
|
|
|
10857
10940
|
// A tab that connects later is told once, through its own connection.
|
|
10858
10941
|
const laterTab = setupTab(setup, disposer);
|
|
@@ -69,13 +69,20 @@
|
|
|
69
69
|
*
|
|
70
70
|
* ## Storage
|
|
71
71
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* its tabs see one mode, and
|
|
72
|
+
* The platform tells the worker with {@link DevicePersistenceDep} what it can
|
|
73
|
+
* promise about stored databases. The worker asks once, after it takes the
|
|
74
|
+
* build lock and before any DbWorker starts. A browser checks whether it can
|
|
75
|
+
* open the origin private file system, which Safari's Private Browsing and
|
|
76
|
+
* Firefox's private windows refuse. Without persistent storage, every DbWorker
|
|
77
|
+
* the worker starts keeps its database in memory, replacements included. The
|
|
78
|
+
* decision holds for the worker's lifetime, so all its tabs see one mode, and
|
|
79
|
+
* the next worker checks again.
|
|
80
|
+
*
|
|
81
|
+
* A tenant tells each instance it adds its {@link Evolu.devicePersistence}:
|
|
82
|
+
* `NotPersisted` when its database is kept in memory, because of the platform
|
|
83
|
+
* or {@link EvoluConfig.memoryOnly}, otherwise what the platform promised.
|
|
84
|
+
* Instances of one name share the tenant, so a later instance gets the mode the
|
|
85
|
+
* first one chose.
|
|
79
86
|
*
|
|
80
87
|
* The check cannot tell a private session from a storage failure, but memory
|
|
81
88
|
* loses nothing that refusing to start would have kept, and the persistent
|
|
@@ -333,7 +340,12 @@ import type {
|
|
|
333
340
|
WorkerDeps,
|
|
334
341
|
} from "../Worker.ts";
|
|
335
342
|
import type { DbWorkerInit, UnsupportedDbVersionError } from "./Db.ts";
|
|
336
|
-
import type {
|
|
343
|
+
import type {
|
|
344
|
+
DevicePersistence,
|
|
345
|
+
Evolu,
|
|
346
|
+
EvoluConfig,
|
|
347
|
+
SyncStateDep,
|
|
348
|
+
} from "./Evolu.ts";
|
|
337
349
|
import type { Owner, OwnerId, OwnerTransport, SyncOwner } from "./Owner.ts";
|
|
338
350
|
import {
|
|
339
351
|
createProtocolBroadcastMessagesFromCrdtMessages,
|
|
@@ -420,14 +432,6 @@ export type SharedWorkerOutput =
|
|
|
420
432
|
readonly type: "Connected";
|
|
421
433
|
readonly workerId: SharedWorkerId;
|
|
422
434
|
readonly syncStateChannelName: string;
|
|
423
|
-
}
|
|
424
|
-
| {
|
|
425
|
-
/**
|
|
426
|
-
* Sent to a connecting tab after `Connected` when the platform offers no
|
|
427
|
-
* persistent storage, so the worker keeps every database in memory; see
|
|
428
|
-
* Storage in this module's documentation.
|
|
429
|
-
*/
|
|
430
|
-
readonly type: "StorageUnavailable";
|
|
431
435
|
};
|
|
432
436
|
|
|
433
437
|
export type ConsoleEntryOrError =
|
|
@@ -741,22 +745,23 @@ export interface RelaySyncState {
|
|
|
741
745
|
* stops syncing through its relay, while a skipped change leaves out only
|
|
742
746
|
* that change.
|
|
743
747
|
*
|
|
744
|
-
* Evolu
|
|
745
|
-
* it works: show nothing for `NoRelays`, `Syncing`, and `Synced`. An
|
|
746
|
-
* that changes with every edit distracts, and screen readers announce
|
|
747
|
-
* change.
|
|
748
|
+
* Evolu stores changes in the local database before they sync, so sync needs no
|
|
749
|
+
* UI while it works: show nothing for `NoRelays`, `Syncing`, and `Synced`. An
|
|
750
|
+
* indicator that changes with every edit distracts, and screen readers announce
|
|
751
|
+
* each change.
|
|
748
752
|
*
|
|
749
753
|
* For `Offline` and `Error`, show one quiet line that lasts as long as the
|
|
750
754
|
* status, not a dialog, which interrupts, or a toast, which disappears while
|
|
751
|
-
* the problem lasts.
|
|
752
|
-
*
|
|
753
|
-
*
|
|
754
|
-
*
|
|
755
|
-
*
|
|
756
|
-
*
|
|
757
|
-
* {@link
|
|
758
|
-
*
|
|
759
|
-
*
|
|
755
|
+
* the problem lasts. Do not say that changes are saved on this device unless
|
|
756
|
+
* {@link Evolu.devicePersistence} is `Persisted`: a browser may keep them only
|
|
757
|
+
* for a private session or delete them later. Evolu reports `Offline` at once;
|
|
758
|
+
* an app may wait a few seconds before showing it, because brief
|
|
759
|
+
* disconnections, such as waking from sleep, reconnect quickly. For `Error`,
|
|
760
|
+
* write actionable text for the error types the app can act on, such as a
|
|
761
|
+
* {@link ProtocolQuotaError}: the relay stores no more data for the owner, so
|
|
762
|
+
* offer more quota, such as a plan upgrade, then call {@link Evolu.requestSync}
|
|
763
|
+
* with the owner's ID. For any other error, show generic text that names the
|
|
764
|
+
* error type, which helps when the user reports it.
|
|
760
765
|
*
|
|
761
766
|
* Render the line inside one element with `role="status"` that stays mounted:
|
|
762
767
|
* screen readers announce changes only in a live region that already exists,
|
|
@@ -785,18 +790,18 @@ export interface RelaySyncState {
|
|
|
785
790
|
* case "Synced":
|
|
786
791
|
* return null;
|
|
787
792
|
* case "Offline":
|
|
788
|
-
* return "Offline.
|
|
793
|
+
* return "Offline. Changes will sync when you're back online.";
|
|
789
794
|
* case "Error":
|
|
790
795
|
* return status.error.type === "ProtocolQuotaError"
|
|
791
|
-
* ? "Sync is paused because the sync server is full.
|
|
792
|
-
* : `Sync error: ${status.error.type}
|
|
796
|
+
* ? "Sync is paused because the sync server is full."
|
|
797
|
+
* : `Sync error: ${status.error.type}.`;
|
|
793
798
|
* }
|
|
794
799
|
* };
|
|
795
800
|
*
|
|
796
801
|
* assertEqual(syncStatusToMessage({ type: "Synced" }), null);
|
|
797
802
|
* assertEqual(
|
|
798
803
|
* syncStatusToMessage({ type: "Offline" }),
|
|
799
|
-
* "Offline.
|
|
804
|
+
* "Offline. Changes will sync when you're back online.",
|
|
800
805
|
* );
|
|
801
806
|
* assertEqual(
|
|
802
807
|
* syncStatusToMessage({
|
|
@@ -807,14 +812,14 @@ export interface RelaySyncState {
|
|
|
807
812
|
* at: Millis.orThrow(1000),
|
|
808
813
|
* },
|
|
809
814
|
* }),
|
|
810
|
-
* "Sync is paused because the sync server is full.
|
|
815
|
+
* "Sync is paused because the sync server is full.",
|
|
811
816
|
* );
|
|
812
817
|
* assertEqual(
|
|
813
818
|
* syncStatusToMessage({
|
|
814
819
|
* type: "Error",
|
|
815
820
|
* error: { type: "SyncFailed", at: Millis.orThrow(1000) },
|
|
816
821
|
* }),
|
|
817
|
-
* "Sync error: SyncFailed.
|
|
822
|
+
* "Sync error: SyncFailed.",
|
|
818
823
|
* );
|
|
819
824
|
* ```
|
|
820
825
|
*/
|
|
@@ -1210,6 +1215,11 @@ export type EvoluOutput =
|
|
|
1210
1215
|
/** The mutation with these onComplete callbacks could not be stored. */
|
|
1211
1216
|
readonly type: "OnMutateFailed";
|
|
1212
1217
|
readonly onCompleteIds: ReadonlyArray<Id>;
|
|
1218
|
+
}
|
|
1219
|
+
| {
|
|
1220
|
+
/** Sent once, when the tenant adds the instance; see Storage. */
|
|
1221
|
+
readonly type: "OnDevicePersistence";
|
|
1222
|
+
readonly devicePersistence: DevicePersistence;
|
|
1213
1223
|
};
|
|
1214
1224
|
|
|
1215
1225
|
export type DbWorkerInput =
|
|
@@ -1334,21 +1344,22 @@ export type DbWorkerQueuedResponse =
|
|
|
1334
1344
|
};
|
|
1335
1345
|
|
|
1336
1346
|
/**
|
|
1337
|
-
* Tells
|
|
1347
|
+
* Tells what the platform can promise about the databases it stores.
|
|
1338
1348
|
*
|
|
1339
|
-
*
|
|
1340
|
-
* does in Safari's Private Browsing
|
|
1349
|
+
* `NotPersisted` means the platform offers no persistent storage now, as a
|
|
1350
|
+
* browser does in Safari's Private Browsing or a Firefox private window, so the
|
|
1351
|
+
* worker keeps every database in memory; see Storage in the Shared module.
|
|
1341
1352
|
*/
|
|
1342
|
-
export interface
|
|
1343
|
-
readonly
|
|
1353
|
+
export interface DevicePersistenceDep {
|
|
1354
|
+
readonly getDevicePersistence: () => Promise<DevicePersistence>;
|
|
1344
1355
|
}
|
|
1345
1356
|
|
|
1346
1357
|
export type SharedWorkerDeps = WorkerDeps &
|
|
1347
1358
|
CreateBroadcastChannelDep &
|
|
1348
1359
|
CreateMessageChannelDep &
|
|
1349
1360
|
CreateWebSocketDep &
|
|
1350
|
-
|
|
1351
|
-
|
|
1361
|
+
DevicePersistenceDep &
|
|
1362
|
+
LockManagerDep;
|
|
1352
1363
|
|
|
1353
1364
|
/**
|
|
1354
1365
|
* Coordinates all instances of one named local database within a SharedWorker.
|
|
@@ -1748,9 +1759,6 @@ export const initSharedWorker =
|
|
|
1748
1759
|
workerId,
|
|
1749
1760
|
syncStateChannelName,
|
|
1750
1761
|
});
|
|
1751
|
-
if (isPersistentStorageUnavailable) {
|
|
1752
|
-
port.postMessage({ type: "StorageUnavailable" });
|
|
1753
|
-
}
|
|
1754
1762
|
});
|
|
1755
1763
|
};
|
|
1756
1764
|
|
|
@@ -1766,12 +1774,10 @@ export const initSharedWorker =
|
|
|
1766
1774
|
disposer.use(await run.ok(acquireLeaderLock("tab")));
|
|
1767
1775
|
starting.dispose();
|
|
1768
1776
|
|
|
1769
|
-
// Checked once, before any DbWorker starts, so
|
|
1770
|
-
// worker, replacements included, keeps its
|
|
1771
|
-
// Storage.
|
|
1772
|
-
const
|
|
1773
|
-
deps.isPersistentStorageAvailable !== undefined &&
|
|
1774
|
-
!(await deps.isPersistentStorageAvailable());
|
|
1777
|
+
// Checked once, before any DbWorker starts, so without persistent
|
|
1778
|
+
// storage every DbWorker of this worker, replacements included, keeps its
|
|
1779
|
+
// database in memory; see Storage.
|
|
1780
|
+
const platformDevicePersistence = await deps.getDevicePersistence();
|
|
1775
1781
|
|
|
1776
1782
|
disposer.defer(
|
|
1777
1783
|
deps.consoleStoreOutputEntry.subscribe(() => {
|
|
@@ -2233,14 +2239,17 @@ export const initSharedWorker =
|
|
|
2233
2239
|
const tenantsByName = disposer.use(
|
|
2234
2240
|
await sharedWorkerRun.ok(
|
|
2235
2241
|
createSharedResourceByKey(
|
|
2236
|
-
(message: ExtractTyped<SharedWorkerInput, "CreateEvolu">) =>
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2242
|
+
(message: ExtractTyped<SharedWorkerInput, "CreateEvolu">) => {
|
|
2243
|
+
const memoryOnly =
|
|
2244
|
+
message.memoryOnly ||
|
|
2245
|
+
platformDevicePersistence === "NotPersisted";
|
|
2246
|
+
return createEvoluTenant(
|
|
2247
|
+
{ ...message, memoryOnly },
|
|
2248
|
+
memoryOnly ? "NotPersisted" : platformDevicePersistence,
|
|
2241
2249
|
currentTenantsByName,
|
|
2242
2250
|
workerId,
|
|
2243
|
-
)
|
|
2251
|
+
);
|
|
2252
|
+
},
|
|
2244
2253
|
{
|
|
2245
2254
|
idleDisposeAfter: "3s",
|
|
2246
2255
|
lookup: (message) => message.name,
|
|
@@ -2269,6 +2278,7 @@ const createEvoluTenant =
|
|
|
2269
2278
|
encryptionKey,
|
|
2270
2279
|
memoryOnly,
|
|
2271
2280
|
}: ExtractTyped<SharedWorkerInput, "CreateEvolu">,
|
|
2281
|
+
devicePersistence: DevicePersistence,
|
|
2272
2282
|
currentTenantsByName: Map<Name, BorrowedResource<EvoluTenant>>,
|
|
2273
2283
|
workerId: SharedWorkerId,
|
|
2274
2284
|
): Task<EvoluTenant, never, EvoluTenantDeps> =>
|
|
@@ -3404,6 +3414,12 @@ const createEvoluTenant =
|
|
|
3404
3414
|
disposer.defer(() => {
|
|
3405
3415
|
instance.port.onMessage = null;
|
|
3406
3416
|
});
|
|
3417
|
+
// Instances of one name share the tenant, so each learns the mode
|
|
3418
|
+
// the first one chose.
|
|
3419
|
+
instance.port.postMessage({
|
|
3420
|
+
type: "OnDevicePersistence",
|
|
3421
|
+
devicePersistence,
|
|
3422
|
+
});
|
|
3407
3423
|
|
|
3408
3424
|
// The main-thread Evolu instance holds this per-instance leader lock
|
|
3409
3425
|
// while it is alive. Acquiring the same lock here means the main
|