@evolu/common 8.0.0-next.2 → 8.0.0-next.4
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/Assert.d.ts +5 -5
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +4 -4
- package/dist/src/Identicon.js +4 -4
- package/dist/src/LockManager.d.ts +74 -0
- package/dist/src/LockManager.d.ts.map +1 -0
- package/dist/src/LockManager.js +103 -0
- package/dist/src/Microtask.d.ts.map +1 -1
- package/dist/src/Microtask.js +90 -26
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/RefCount.d.ts.map +1 -1
- package/dist/src/RefCount.js +153 -68
- package/dist/src/Resource.d.ts +6 -6
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Resource.js +211 -162
- package/dist/src/Schedule.d.ts +5 -5
- package/dist/src/Schedule.d.ts.map +1 -1
- package/dist/src/Schedule.js +53 -44
- package/dist/src/Sqlite.d.ts +2 -0
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +64 -40
- package/dist/src/Task.d.ts +6 -33
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +213 -204
- package/dist/src/Test.d.ts +4 -4
- package/dist/src/Time.d.ts +5 -0
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +5 -0
- package/dist/src/Type.d.ts +7 -0
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +7 -0
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +7 -6
- package/dist/src/Worker.d.ts +42 -8
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +298 -75
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/local-first/Db.d.ts +5 -4
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +44 -38
- package/dist/src/local-first/Evolu.d.ts +3 -2
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +90 -80
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Shared.d.ts +65 -54
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +387 -373
- package/package.json +1 -1
- package/src/Array.ts +8 -8
- package/src/Assert.ts +5 -5
- package/src/Identicon.ts +4 -4
- package/src/LockManager.ts +181 -0
- package/src/Microtask.ts +17 -11
- package/src/Object.ts +3 -3
- package/src/RefCount.ts +25 -21
- package/src/Resource.ts +63 -56
- package/src/Schedule.ts +70 -48
- package/src/Set.ts +4 -4
- package/src/Sqlite.ts +41 -30
- package/src/Task.ts +77 -120
- package/src/Test.ts +4 -4
- package/src/Time.ts +7 -0
- package/src/Type.ts +9 -0
- package/src/WebSocket.ts +7 -6
- package/src/Worker.ts +240 -49
- package/src/index.ts +1 -0
- package/src/local-first/Db.ts +69 -46
- package/src/local-first/Evolu.ts +74 -68
- package/src/local-first/Owner.ts +1 -1
- package/src/local-first/Query.ts +1 -1
- package/src/local-first/Shared.ts +472 -464
package/src/local-first/Evolu.ts
CHANGED
|
@@ -20,6 +20,11 @@ import type { ConsoleDep } from "../Console.js";
|
|
|
20
20
|
import { createConsole } from "../Console.js";
|
|
21
21
|
import { createUnknownError } from "../Error.js";
|
|
22
22
|
import { exhaustiveCheck, todo } from "../Function.js";
|
|
23
|
+
import {
|
|
24
|
+
acquireLeaderLock,
|
|
25
|
+
acquireLeaderLockCallback,
|
|
26
|
+
type LockManagerDep,
|
|
27
|
+
} from "../LockManager.js";
|
|
23
28
|
import { createMicrotaskBatch } from "../Microtask.js";
|
|
24
29
|
import type { FlushSyncDep, ReloadAppDep } from "../Platform.js";
|
|
25
30
|
import { createRefCountByKey } from "../RefCount.js";
|
|
@@ -38,7 +43,10 @@ import {
|
|
|
38
43
|
UrlSafeString,
|
|
39
44
|
} from "../Type.js";
|
|
40
45
|
import type { ExtractType } from "../Types.js";
|
|
41
|
-
import type {
|
|
46
|
+
import type {
|
|
47
|
+
CreateBroadcastChannelDep,
|
|
48
|
+
CreateMessageChannelDep,
|
|
49
|
+
} from "../Worker.js";
|
|
42
50
|
import type { CreateDbWorkerDep } from "./Db.js";
|
|
43
51
|
import type { EvoluError } from "./Error.js";
|
|
44
52
|
import type {
|
|
@@ -68,13 +76,12 @@ import type {
|
|
|
68
76
|
} from "./Schema.js";
|
|
69
77
|
import { evoluSchemaToSqliteSchema } from "./Schema.js";
|
|
70
78
|
import type {
|
|
71
|
-
|
|
72
|
-
DbWorkerOutput,
|
|
79
|
+
ConsoleEntryOrError,
|
|
73
80
|
EvoluInput,
|
|
74
81
|
EvoluOutput,
|
|
75
|
-
EvoluTabOutput,
|
|
76
82
|
SharedWorkerDep,
|
|
77
83
|
} from "./Shared.js";
|
|
84
|
+
import { consoleEntryOrErrorBroadcastChannelName } from "./Shared.js";
|
|
78
85
|
import { DbChange } from "./Storage.js";
|
|
79
86
|
import type { Timestamp } from "./Timestamp.js";
|
|
80
87
|
|
|
@@ -547,7 +554,9 @@ export type EvoluDeps = EvoluPlatformDeps & EvoluErrorDep & Disposable;
|
|
|
547
554
|
* logging and synchronous UI flush.
|
|
548
555
|
*/
|
|
549
556
|
export type EvoluPlatformDeps = CreateDbWorkerDep &
|
|
557
|
+
CreateBroadcastChannelDep &
|
|
550
558
|
CreateMessageChannelDep &
|
|
559
|
+
LockManagerDep &
|
|
551
560
|
ReloadAppDep &
|
|
552
561
|
SharedWorkerDep &
|
|
553
562
|
Partial<ConsoleDep> &
|
|
@@ -565,17 +574,21 @@ export type EvoluPlatformDeps = CreateDbWorkerDep &
|
|
|
565
574
|
* Dispose it only during app shutdown.
|
|
566
575
|
*/
|
|
567
576
|
export const createEvoluDeps = (deps: EvoluPlatformDeps): EvoluDeps => {
|
|
568
|
-
const {
|
|
577
|
+
const { createBroadcastChannel, sharedWorker } = deps;
|
|
569
578
|
const console = deps.console ?? createConsole();
|
|
570
579
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
const evoluError =
|
|
580
|
+
using disposer = new DisposableStack();
|
|
581
|
+
disposer.use(sharedWorker);
|
|
582
|
+
const evoluError = disposer.use(createStore<EvoluError | null>(null));
|
|
574
583
|
|
|
575
|
-
const
|
|
576
|
-
|
|
584
|
+
const consoleEntryOrErrorBroadcastChannel = disposer.use(
|
|
585
|
+
createBroadcastChannel<ConsoleEntryOrError>(
|
|
586
|
+
consoleEntryOrErrorBroadcastChannelName,
|
|
587
|
+
),
|
|
588
|
+
);
|
|
589
|
+
consoleEntryOrErrorBroadcastChannel.onMessage = (message) => {
|
|
577
590
|
switch (message.type) {
|
|
578
|
-
case "
|
|
591
|
+
case "ConsoleEntry":
|
|
579
592
|
console.write(message.entry);
|
|
580
593
|
// Fallback channel for unexpected errors without EvoluError typing.
|
|
581
594
|
if (message.entry.method === "error") {
|
|
@@ -583,7 +596,7 @@ export const createEvoluDeps = (deps: EvoluPlatformDeps): EvoluDeps => {
|
|
|
583
596
|
}
|
|
584
597
|
break;
|
|
585
598
|
|
|
586
|
-
case "
|
|
599
|
+
case "Error":
|
|
587
600
|
evoluError.set(message.error);
|
|
588
601
|
// Keep typed errors visible in logs as operational failures.
|
|
589
602
|
console.error(message.error);
|
|
@@ -594,21 +607,25 @@ export const createEvoluDeps = (deps: EvoluPlatformDeps): EvoluDeps => {
|
|
|
594
607
|
}
|
|
595
608
|
};
|
|
596
609
|
|
|
597
|
-
sharedWorker.port.
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
610
|
+
sharedWorker.port.onMessage = (message) => {
|
|
611
|
+
deps.createDbWorker().postMessage(message, [message.port]);
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
disposer.use(
|
|
615
|
+
acquireLeaderLockCallback(deps)("tab", () => {
|
|
616
|
+
sharedWorker.port.postMessage({
|
|
617
|
+
type: "AnnounceTabLeader",
|
|
618
|
+
consoleLevel: console.getLevel(),
|
|
619
|
+
});
|
|
620
|
+
}),
|
|
604
621
|
);
|
|
605
622
|
|
|
606
|
-
const
|
|
623
|
+
const disposables = disposer.move();
|
|
607
624
|
|
|
608
625
|
return {
|
|
609
626
|
...deps,
|
|
610
627
|
evoluError,
|
|
611
|
-
[Symbol.dispose]: () =>
|
|
628
|
+
[Symbol.dispose]: () => disposables.dispose(),
|
|
612
629
|
};
|
|
613
630
|
};
|
|
614
631
|
|
|
@@ -633,12 +650,14 @@ export const createEvolu =
|
|
|
633
650
|
const console = run.deps.console.child(name).child("Evolu");
|
|
634
651
|
console.info("createEvolu");
|
|
635
652
|
|
|
636
|
-
await using
|
|
653
|
+
await using disposer = new AsyncDisposableStack();
|
|
637
654
|
|
|
638
|
-
const rowsByQueryMapStore =
|
|
655
|
+
const rowsByQueryMapStore = disposer.use(
|
|
639
656
|
createStore<RowsByQueryMap>(new Map()),
|
|
640
657
|
);
|
|
641
|
-
const subscribedQueriesRefCount =
|
|
658
|
+
const subscribedQueriesRefCount = disposer.use(
|
|
659
|
+
createRefCountByKey<Query>(),
|
|
660
|
+
);
|
|
642
661
|
|
|
643
662
|
interface LoadingPromise {
|
|
644
663
|
/**
|
|
@@ -662,7 +681,7 @@ export const createEvolu =
|
|
|
662
681
|
* Settle pending query loads during disposal so awaiting callers and React
|
|
663
682
|
* `use` thenables do not hang forever during teardown.
|
|
664
683
|
*/
|
|
665
|
-
const loadingPromisesByQuery =
|
|
684
|
+
const loadingPromisesByQuery = disposer.adopt(
|
|
666
685
|
new Map<Query, LoadingPromise>(),
|
|
667
686
|
(loadingPromisesByQuery) => {
|
|
668
687
|
for (const loadingPromise of loadingPromisesByQuery.values()) {
|
|
@@ -715,18 +734,18 @@ export const createEvolu =
|
|
|
715
734
|
}
|
|
716
735
|
};
|
|
717
736
|
|
|
718
|
-
const onMutateCompleteCallbacks =
|
|
737
|
+
const onMutateCompleteCallbacks = disposer.use(createCallbacks(run.deps));
|
|
719
738
|
|
|
720
739
|
let exportDatabasePending = null as PromiseWithResolvers<
|
|
721
740
|
Uint8Array<ArrayBuffer>
|
|
722
741
|
> | null;
|
|
723
742
|
|
|
724
|
-
|
|
743
|
+
disposer.defer(() => {
|
|
725
744
|
exportDatabasePending?.reject({ type: "EvoluDisposedError" });
|
|
726
745
|
exportDatabasePending = null;
|
|
727
746
|
});
|
|
728
747
|
|
|
729
|
-
const mutateBatch =
|
|
748
|
+
const mutateBatch = disposer.use(
|
|
730
749
|
createMicrotaskBatch<{
|
|
731
750
|
readonly change: MutationChange;
|
|
732
751
|
readonly onComplete: (() => void) | undefined;
|
|
@@ -747,7 +766,7 @@ export const createEvolu =
|
|
|
747
766
|
}),
|
|
748
767
|
);
|
|
749
768
|
|
|
750
|
-
const queryBatch =
|
|
769
|
+
const queryBatch = disposer.use(
|
|
751
770
|
createMicrotaskBatch<Query>((queries) => {
|
|
752
771
|
const dedupedQueries = new Set(queries);
|
|
753
772
|
assert(
|
|
@@ -759,7 +778,7 @@ export const createEvolu =
|
|
|
759
778
|
}),
|
|
760
779
|
);
|
|
761
780
|
|
|
762
|
-
const useOwnerBatch =
|
|
781
|
+
const useOwnerBatch = disposer.use(
|
|
763
782
|
createMicrotaskBatch<
|
|
764
783
|
ExtractType<EvoluInput, "UseOwner">["actions"][number]
|
|
765
784
|
>((actions) => postMessage({ type: "UseOwner", actions })),
|
|
@@ -769,11 +788,11 @@ export const createEvolu =
|
|
|
769
788
|
|
|
770
789
|
// Scope worker/channel wiring and keep only postMessage outside.
|
|
771
790
|
{
|
|
772
|
-
const
|
|
773
|
-
const
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
const evoluChannel =
|
|
791
|
+
const id = createId<"EvoluInstance">(run.deps);
|
|
792
|
+
const { createMessageChannel, sharedWorker } = run.deps;
|
|
793
|
+
disposer.use(await run.orThrow(acquireLeaderLock(id)));
|
|
794
|
+
|
|
795
|
+
const evoluChannel = disposer.use(
|
|
777
796
|
createMessageChannel<EvoluInput, EvoluOutput>(),
|
|
778
797
|
);
|
|
779
798
|
|
|
@@ -858,35 +877,17 @@ export const createEvolu =
|
|
|
858
877
|
{
|
|
859
878
|
type: "CreateEvolu",
|
|
860
879
|
name,
|
|
861
|
-
|
|
862
|
-
dbWorkerPort: dbWorkerChannel.port2.native,
|
|
863
|
-
},
|
|
864
|
-
[evoluChannel.port2.native, dbWorkerChannel.port2.native],
|
|
865
|
-
);
|
|
866
|
-
|
|
867
|
-
/**
|
|
868
|
-
* No stack.use because Evolu instances don't dispose DbWorker because
|
|
869
|
-
* it's SharedWorder responsibility. DbWorker can be used by another tab.
|
|
870
|
-
* That's required because SQLite WASM needs a single web worker.
|
|
871
|
-
*/
|
|
872
|
-
createDbWorker().postMessage(
|
|
873
|
-
{
|
|
874
|
-
type: "Init",
|
|
875
|
-
name,
|
|
880
|
+
id,
|
|
876
881
|
consoleLevel: console.getLevel(),
|
|
877
882
|
sqliteSchema: evoluSchemaToSqliteSchema(schema, config.indexes),
|
|
878
883
|
encryptionKey: appOwner.encryptionKey,
|
|
879
884
|
memoryOnly,
|
|
880
|
-
|
|
885
|
+
evoluPort: evoluChannel.port2.native,
|
|
881
886
|
},
|
|
882
|
-
[
|
|
887
|
+
[evoluChannel.port2.native],
|
|
883
888
|
);
|
|
884
889
|
|
|
885
890
|
postMessage = evoluChannel.port1.postMessage;
|
|
886
|
-
|
|
887
|
-
stack.defer(() => {
|
|
888
|
-
postMessage({ type: "Dispose" });
|
|
889
|
-
});
|
|
890
891
|
}
|
|
891
892
|
|
|
892
893
|
const createMutation =
|
|
@@ -894,7 +895,7 @@ export const createEvolu =
|
|
|
894
895
|
kind: Kind,
|
|
895
896
|
): Mutation<S, Kind> =>
|
|
896
897
|
(table, values, options) => {
|
|
897
|
-
assertNotDisposed(
|
|
898
|
+
assertNotDisposed(disposables);
|
|
898
899
|
|
|
899
900
|
const {
|
|
900
901
|
id = createId(run.deps),
|
|
@@ -928,7 +929,7 @@ export const createEvolu =
|
|
|
928
929
|
const loadQuery = <R extends Row>(
|
|
929
930
|
query: Query<S, R>,
|
|
930
931
|
): Promise<QueryRows<R>> => {
|
|
931
|
-
assertNotDisposed(
|
|
932
|
+
assertNotDisposed(disposables);
|
|
932
933
|
|
|
933
934
|
const loadingPromise = loadingPromisesByQuery.get(query);
|
|
934
935
|
if (loadingPromise) {
|
|
@@ -951,7 +952,7 @@ export const createEvolu =
|
|
|
951
952
|
};
|
|
952
953
|
|
|
953
954
|
const getQueryRows = <R extends Row>(query: Query<S, R>): QueryRows<R> => {
|
|
954
|
-
assertNotDisposed(
|
|
955
|
+
assertNotDisposed(disposables);
|
|
955
956
|
|
|
956
957
|
return (rowsByQueryMapStore.get().get(query) ??
|
|
957
958
|
emptyArray) as QueryRows<R>;
|
|
@@ -961,7 +962,7 @@ export const createEvolu =
|
|
|
961
962
|
owner: ReadonlyOwner | Owner,
|
|
962
963
|
ownerTransports?: NonEmptyReadonlyArray<OwnerTransport>,
|
|
963
964
|
): UnuseOwner => {
|
|
964
|
-
assertNotDisposed(
|
|
965
|
+
assertNotDisposed(disposables);
|
|
965
966
|
|
|
966
967
|
const effectiveTransports = ownerTransports ?? transports;
|
|
967
968
|
assertNonEmptyReadonlyArray(
|
|
@@ -982,6 +983,7 @@ export const createEvolu =
|
|
|
982
983
|
let isUsed = true;
|
|
983
984
|
|
|
984
985
|
return () => {
|
|
986
|
+
if (disposables.disposed) return;
|
|
985
987
|
assert(isUsed, "UnuseOwner can be called only once.");
|
|
986
988
|
isUsed = false;
|
|
987
989
|
useOwnerBatch.push({
|
|
@@ -991,10 +993,14 @@ export const createEvolu =
|
|
|
991
993
|
};
|
|
992
994
|
};
|
|
993
995
|
|
|
994
|
-
const
|
|
996
|
+
const disposables = disposer.move();
|
|
995
997
|
|
|
996
998
|
if (isNonEmptyArray(transports)) useOwner(appOwner);
|
|
997
999
|
|
|
1000
|
+
if (run.signal.aborted) {
|
|
1001
|
+
await disposables.disposeAsync();
|
|
1002
|
+
}
|
|
1003
|
+
|
|
998
1004
|
return ok({
|
|
999
1005
|
name,
|
|
1000
1006
|
appOwner,
|
|
@@ -1012,7 +1018,7 @@ export const createEvolu =
|
|
|
1012
1018
|
],
|
|
1013
1019
|
|
|
1014
1020
|
subscribeQuery: (query) => (listener) => {
|
|
1015
|
-
assertNotDisposed(
|
|
1021
|
+
assertNotDisposed(disposables);
|
|
1016
1022
|
|
|
1017
1023
|
subscribedQueriesRefCount.increment(query);
|
|
1018
1024
|
let isSubscribed = true;
|
|
@@ -1036,7 +1042,7 @@ export const createEvolu =
|
|
|
1036
1042
|
previousRows = null;
|
|
1037
1043
|
unsubscribe();
|
|
1038
1044
|
|
|
1039
|
-
if (
|
|
1045
|
+
if (disposables.disposed) return;
|
|
1040
1046
|
|
|
1041
1047
|
subscribedQueriesRefCount.decrement(query);
|
|
1042
1048
|
};
|
|
@@ -1044,7 +1050,7 @@ export const createEvolu =
|
|
|
1044
1050
|
getQueryRows,
|
|
1045
1051
|
|
|
1046
1052
|
exportDatabase: () => {
|
|
1047
|
-
assertNotDisposed(
|
|
1053
|
+
assertNotDisposed(disposables);
|
|
1048
1054
|
|
|
1049
1055
|
if (!exportDatabasePending) {
|
|
1050
1056
|
exportDatabasePending =
|
|
@@ -1055,12 +1061,12 @@ export const createEvolu =
|
|
|
1055
1061
|
},
|
|
1056
1062
|
|
|
1057
1063
|
deleteDatabase: () => {
|
|
1058
|
-
assertNotDisposed(
|
|
1064
|
+
assertNotDisposed(disposables);
|
|
1059
1065
|
todo();
|
|
1060
1066
|
},
|
|
1061
1067
|
|
|
1062
1068
|
deleteOwner: (owner) => {
|
|
1063
|
-
assertNotDisposed(
|
|
1069
|
+
assertNotDisposed(disposables);
|
|
1064
1070
|
void owner;
|
|
1065
1071
|
todo();
|
|
1066
1072
|
},
|
|
@@ -1068,8 +1074,8 @@ export const createEvolu =
|
|
|
1068
1074
|
useOwner,
|
|
1069
1075
|
|
|
1070
1076
|
[Symbol.asyncDispose]: () => {
|
|
1071
|
-
console.info("
|
|
1072
|
-
return
|
|
1077
|
+
if (!disposables.disposed) console.info("disposeEvolu");
|
|
1078
|
+
return disposables.disposeAsync();
|
|
1073
1079
|
},
|
|
1074
1080
|
} as Evolu<S>);
|
|
1075
1081
|
};
|
package/src/local-first/Owner.ts
CHANGED
|
@@ -100,7 +100,7 @@ export const ownerIdToOwnerIdBytes = (ownerId: OwnerId): OwnerIdBytes =>
|
|
|
100
100
|
|
|
101
101
|
/** Converts {@link OwnerIdBytes} to {@link OwnerId}. */
|
|
102
102
|
export const ownerIdBytesToOwnerId = (ownerIdBytes: OwnerIdBytes): OwnerId =>
|
|
103
|
-
idBytesToId(ownerIdBytes
|
|
103
|
+
idBytesToId(ownerIdBytes) as OwnerId;
|
|
104
104
|
|
|
105
105
|
export const ownerWriteKeyLength = /*#__PURE__*/ NonNegativeInt.orThrow(16);
|
|
106
106
|
|
package/src/local-first/Query.ts
CHANGED