@evolu/web 3.0.0-next.0 → 3.0.0-next.1

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.
@@ -7,14 +7,14 @@ installPolyfills();
7
7
  import { createRandomBytes } from "@evolu/common";
8
8
  import { startDbWorker } from "@evolu/common/local-first";
9
9
  import { createWasmSqliteDriver } from "../Sqlite.js";
10
- import { createLeaderLock, createRun } from "../Task.js";
10
+ import { createRun } from "../Task.js";
11
11
  import { createWorkerDeps, createWorkerSelf } from "../Worker.js";
12
12
 
13
13
  // TODO: Disposal.
14
14
  const run = createRun({
15
15
  ...createWorkerDeps(),
16
16
  createSqliteDriver: createWasmSqliteDriver,
17
- leaderLock: createLeaderLock(),
17
+ lockManager: globalThis.navigator.locks,
18
18
  randomBytes: createRandomBytes(),
19
19
  });
20
20
 
@@ -1,16 +1,20 @@
1
- import type { ConsoleDep } from "@evolu/common";
1
+ import { exhaustiveCheck, type ConsoleDep } from "@evolu/common";
2
2
  import type {
3
+ SharedWorker as CommonSharedWorker,
3
4
  CreateDbWorker,
4
5
  DbWorkerInit,
5
6
  EvoluDeps,
6
7
  SharedWorkerInput,
8
+ SharedWorkerOutput,
7
9
  } from "@evolu/common/local-first";
8
10
  import { createEvoluDeps as createCommonEvoluDeps } from "@evolu/common/local-first";
9
11
  import { reloadApp } from "../Platform.js";
10
12
  import {
13
+ createBroadcastChannel,
11
14
  createMessageChannel,
12
15
  createSharedWorker,
13
16
  createWorker,
17
+ installOneTabSharedWorkerPolyfill,
14
18
  } from "../Worker.js";
15
19
 
16
20
  // // TODO: Redesign.
@@ -20,8 +24,20 @@ import {
20
24
  // secureStorage: createWebAuthnStore({ randomBytes: createRandomBytes() }),
21
25
  // });
22
26
 
27
+ export interface SharedWorkerUnsupported {
28
+ readonly type: "SharedWorkerUnsupported";
29
+ }
30
+
31
+ export interface SharedWorkerUnsupportedDep {
32
+ readonly onSharedWorkerUnsupported: () => void;
33
+ }
34
+
23
35
  /** Creates Evolu dependencies for the web platform. */
24
- export const createEvoluDeps = (deps: Partial<ConsoleDep> = {}): EvoluDeps => {
36
+ export const createEvoluDeps = (
37
+ deps: Partial<ConsoleDep> & Partial<SharedWorkerUnsupportedDep> = {},
38
+ ): EvoluDeps => {
39
+ installOneTabSharedWorkerPolyfill();
40
+
25
41
  const createDbWorker: CreateDbWorker = () =>
26
42
  createWorker<DbWorkerInit, never>(
27
43
  new Worker(new URL("Db.worker.js", import.meta.url), {
@@ -29,16 +45,59 @@ export const createEvoluDeps = (deps: Partial<ConsoleDep> = {}): EvoluDeps => {
29
45
  }),
30
46
  );
31
47
 
32
- const sharedWorker = createSharedWorker<SharedWorkerInput>(
48
+ const webSharedWorker = createSharedWorker<
49
+ SharedWorkerInput,
50
+ SharedWorkerOutput
51
+ >(
33
52
  new SharedWorker(new URL("Shared.worker.js", import.meta.url), {
34
53
  type: "module",
35
54
  }),
36
55
  );
56
+ let onSharedWorkerMessage: ((message: SharedWorkerOutput) => void) | null =
57
+ null;
58
+ const sharedWorker: CommonSharedWorker = {
59
+ ...webSharedWorker,
60
+ port: {
61
+ ...webSharedWorker.port,
62
+ get onMessage() {
63
+ return onSharedWorkerMessage;
64
+ },
65
+ set onMessage(fn) {
66
+ onSharedWorkerMessage = fn;
67
+ webSharedWorker.port.onMessage = fn
68
+ ? (message: SharedWorkerOutput | SharedWorkerUnsupported) => {
69
+ switch (message.type) {
70
+ case "DbWorkerInit": {
71
+ fn(message);
72
+ break;
73
+ }
74
+
75
+ case "SharedWorkerUnsupported": {
76
+ if (deps.onSharedWorkerUnsupported) {
77
+ deps.onSharedWorkerUnsupported();
78
+ } else {
79
+ globalThis.alert(
80
+ "This browser supports Evolu in one tab only. Close this tab and use the already open tab.",
81
+ );
82
+ }
83
+ break;
84
+ }
85
+
86
+ default:
87
+ exhaustiveCheck(message);
88
+ }
89
+ }
90
+ : null;
91
+ },
92
+ },
93
+ };
37
94
 
38
95
  return createCommonEvoluDeps({
39
96
  ...deps,
40
97
  createDbWorker,
98
+ createBroadcastChannel,
41
99
  createMessageChannel,
100
+ lockManager: globalThis.navigator.locks,
42
101
  reloadApp,
43
102
  sharedWorker,
44
103
  });
@@ -1,18 +1,58 @@
1
1
  /// <reference lib="webworker" />
2
- declare const self: SharedWorkerGlobalScope;
2
+ declare const self: DedicatedWorkerGlobalScope | SharedWorkerGlobalScope;
3
3
 
4
4
  import { installPolyfills } from "@evolu/common/polyfills";
5
5
  installPolyfills();
6
6
 
7
- import { createWebSocket } from "@evolu/common";
7
+ import { createWebSocket, ok } from "@evolu/common";
8
+ import type {
9
+ SharedWorkerInput,
10
+ SharedWorkerOutput,
11
+ } from "@evolu/common/local-first";
8
12
  import { initSharedWorker } from "@evolu/common/local-first";
13
+ import type { SharedWorkerUnsupported } from "./Evolu.js";
9
14
  import { createRun } from "../Task.js";
10
- import { createSharedWorkerSelf, createWorkerDeps } from "../Worker.js";
15
+ import {
16
+ createOneTabSharedWorkerSelfPolyfill,
17
+ createSharedWorkerSelf,
18
+ createWorkerDeps,
19
+ } from "../Worker.js";
11
20
 
12
21
  // No disposal (`await using`) is needed — a SharedWorker lives forever.
13
22
  const run = createRun({
14
23
  ...createWorkerDeps(),
15
24
  createWebSocket,
25
+ lockManager: globalThis.navigator.locks,
16
26
  });
17
27
 
18
- run(initSharedWorker(createSharedWorkerSelf(self)));
28
+ void run(async (run) => {
29
+ if ("onconnect" in self) {
30
+ void run(initSharedWorker(createSharedWorkerSelf(self)));
31
+ return ok();
32
+ }
33
+
34
+ using workerSelf = createOneTabSharedWorkerSelfPolyfill<
35
+ SharedWorkerInput,
36
+ SharedWorkerOutput
37
+ >(self);
38
+
39
+ await globalThis.navigator.locks.request(
40
+ "evolu-one-tab-sharedworker-polyfill",
41
+ { ifAvailable: true, mode: "exclusive" },
42
+ async (lock) => {
43
+ if (!lock) {
44
+ const message: SharedWorkerUnsupported = {
45
+ type: "SharedWorkerUnsupported",
46
+ };
47
+ self.postMessage(message);
48
+ return;
49
+ }
50
+
51
+ void run(initSharedWorker(workerSelf));
52
+
53
+ await Promise.withResolvers<never>().promise;
54
+ },
55
+ );
56
+
57
+ return ok();
58
+ });