@evolu/web 3.0.0-next.0 → 3.0.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.
@@ -1,7 +1,84 @@
1
- import { assert, createConsole, createConsoleStoreOutput } from "@evolu/common";
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
53
+ import { assert, createConsole, createConsoleStoreOutput, disposable, } from "@evolu/common";
2
54
  /** Creates a {@link Worker} from a Web Worker. */
3
55
  export const createWorker = (nativeWorker) => wrap(nativeWorker);
4
- /** Creates an Evolu {@link SharedWorker} from a Web SharedWorker. */
56
+ /**
57
+ * Installs a one-tab SharedWorker polyfill backed by a Web Worker.
58
+ *
59
+ * Use it before constructing a SharedWorker in browsers without native
60
+ * SharedWorker support.
61
+ */
62
+ export const installOneTabSharedWorkerPolyfill = () => {
63
+ if (typeof globalThis.SharedWorker === "function")
64
+ return;
65
+ Object.defineProperty(globalThis, "SharedWorker", {
66
+ configurable: true,
67
+ writable: true,
68
+ value: class {
69
+ port;
70
+ constructor(scriptURL, options) {
71
+ this.port = new globalThis.Worker(scriptURL, options);
72
+ }
73
+ },
74
+ });
75
+ };
76
+ /**
77
+ * Creates a {@link SharedWorker} from a Web SharedWorker.
78
+ *
79
+ * Call {@link installOneTabSharedWorkerPolyfill} first to support browsers
80
+ * without native SharedWorker support.
81
+ */
5
82
  export const createSharedWorker = (nativeSharedWorker) => {
6
83
  const port = wrap(nativeSharedWorker.port);
7
84
  return {
@@ -21,15 +98,26 @@ export const createSharedWorker = (nativeSharedWorker) => {
21
98
  * ```
22
99
  */
23
100
  export const createMessageChannel = () => {
24
- const channel = new globalThis.MessageChannel();
25
- const stack = new DisposableStack();
26
- return {
27
- port1: stack.use(wrap(channel.port1)),
28
- port2: stack.use(wrap(channel.port2)),
29
- [Symbol.dispose]: () => {
30
- stack.dispose();
31
- },
32
- };
101
+ const env_1 = { stack: [], error: void 0, hasError: false };
102
+ try {
103
+ const channel = new globalThis.MessageChannel();
104
+ const disposer = __addDisposableResource(env_1, new DisposableStack(), false);
105
+ const port1 = disposer.use(wrap(channel.port1));
106
+ const port2 = disposer.use(wrap(channel.port2));
107
+ const disposables = disposer.move();
108
+ return {
109
+ port1,
110
+ port2,
111
+ [Symbol.dispose]: () => disposables.dispose(),
112
+ };
113
+ }
114
+ catch (e_1) {
115
+ env_1.error = e_1;
116
+ env_1.hasError = true;
117
+ }
118
+ finally {
119
+ __disposeResources(env_1);
120
+ }
33
121
  };
34
122
  /**
35
123
  * Creates an Evolu {@link MessagePort} from a Web MessagePort.
@@ -37,6 +125,46 @@ export const createMessageChannel = () => {
37
125
  * Use this for ports received via postMessage transfer.
38
126
  */
39
127
  export const createMessagePort = (nativePort) => wrap(nativePort);
128
+ /** Creates an Evolu {@link BroadcastChannel} from a Web BroadcastChannel. */
129
+ export const createBroadcastChannel = (name) => {
130
+ const env_2 = { stack: [], error: void 0, hasError: false };
131
+ try {
132
+ const nativeBroadcastChannel = new globalThis.BroadcastChannel(name);
133
+ const disposer = __addDisposableResource(env_2, new DisposableStack(), false);
134
+ let disposed = false;
135
+ disposer.defer(() => {
136
+ disposed = true;
137
+ nativeBroadcastChannel.onmessage = null;
138
+ nativeBroadcastChannel.close();
139
+ });
140
+ let onMessageHandler = null;
141
+ return disposable({
142
+ postMessage: (message) => {
143
+ nativeBroadcastChannel.postMessage(message);
144
+ },
145
+ get onMessage() {
146
+ return disposed ? null : onMessageHandler;
147
+ },
148
+ set onMessage(fn) {
149
+ if (disposed)
150
+ return;
151
+ onMessageHandler = fn;
152
+ nativeBroadcastChannel.onmessage = fn
153
+ ? (event) => {
154
+ fn(event.data);
155
+ }
156
+ : null;
157
+ },
158
+ }, disposer);
159
+ }
160
+ catch (e_2) {
161
+ env_2.error = e_2;
162
+ env_2.hasError = true;
163
+ }
164
+ finally {
165
+ __disposeResources(env_2);
166
+ }
167
+ };
40
168
  /**
41
169
  * Creates an Evolu {@link WorkerSelf} from a Web `DedicatedWorkerGlobalScope`
42
170
  * (`self` inside a dedicated worker).
@@ -62,6 +190,95 @@ export const createSharedWorkerSelf = (nativeSelf) => {
62
190
  };
63
191
  return self;
64
192
  };
193
+ /**
194
+ * Creates a one-tab {@link SharedWorkerSelf} polyfill for browsers without
195
+ * native SharedWorker support.
196
+ *
197
+ * Delivers one synthetic `onConnect` port, queues startup messages until
198
+ * `onMessage` is set, and does not share state across tabs.
199
+ */
200
+ export const createOneTabSharedWorkerSelfPolyfill = (nativeSelf) => {
201
+ const env_3 = { stack: [], error: void 0, hasError: false };
202
+ try {
203
+ const disposer = __addDisposableResource(env_3, new DisposableStack(), false);
204
+ let onConnectHandler = null;
205
+ let onMessageHandler = null;
206
+ const messages = [];
207
+ let connected = false;
208
+ disposer.defer(() => {
209
+ messages.length = 0;
210
+ onConnectHandler = null;
211
+ onMessageHandler = null;
212
+ nativeSelf.onmessage = null;
213
+ nativeSelf.close();
214
+ });
215
+ const disposables = disposer.move();
216
+ nativeSelf.onmessage = (event) => {
217
+ if (disposables.disposed)
218
+ return;
219
+ const handler = onMessageHandler;
220
+ if (handler)
221
+ handler(event.data);
222
+ else
223
+ messages.push(event.data);
224
+ };
225
+ const flushMessages = () => {
226
+ for (const message of messages.splice(0)) {
227
+ const handler = onMessageHandler;
228
+ if (!handler)
229
+ return;
230
+ handler(message);
231
+ }
232
+ };
233
+ const port = {
234
+ postMessage: (message, transfer) => {
235
+ if (disposables.disposed)
236
+ return;
237
+ if (transfer == null)
238
+ nativeSelf.postMessage(message);
239
+ else
240
+ nativeSelf.postMessage(message, [...transfer]);
241
+ },
242
+ get onMessage() {
243
+ return disposables.disposed ? null : onMessageHandler;
244
+ },
245
+ set onMessage(fn) {
246
+ if (disposables.disposed)
247
+ return;
248
+ onMessageHandler = fn;
249
+ if (fn)
250
+ flushMessages();
251
+ },
252
+ native: nativeSelf,
253
+ [Symbol.dispose]: () => disposables.dispose(),
254
+ };
255
+ const connect = () => {
256
+ if (connected || !onConnectHandler)
257
+ return;
258
+ connected = true;
259
+ onConnectHandler(port);
260
+ };
261
+ return {
262
+ get onConnect() {
263
+ return onConnectHandler;
264
+ },
265
+ set onConnect(fn) {
266
+ if (disposables.disposed)
267
+ return;
268
+ onConnectHandler = fn;
269
+ connect();
270
+ },
271
+ [Symbol.dispose]: () => disposables.dispose(),
272
+ };
273
+ }
274
+ catch (e_3) {
275
+ env_3.error = e_3;
276
+ env_3.hasError = true;
277
+ }
278
+ finally {
279
+ __disposeResources(env_3);
280
+ }
281
+ };
65
282
  /** Creates deps shared by web worker entry points. */
66
283
  export const createWorkerDeps = () => {
67
284
  const consoleStoreOutput = createConsoleStoreOutput();
@@ -69,6 +286,8 @@ export const createWorkerDeps = () => {
69
286
  return {
70
287
  console,
71
288
  consoleStoreOutputEntry: consoleStoreOutput.entry,
289
+ createBroadcastChannel,
290
+ createMessageChannel,
72
291
  createMessagePort,
73
292
  };
74
293
  };
@@ -99,7 +318,7 @@ const wrap = (native) => {
99
318
  native: native,
100
319
  [Symbol.dispose]: () => {
101
320
  native.onmessage = null;
102
- if (native instanceof globalThis.Worker)
321
+ if ("terminate" in native)
103
322
  native.terminate();
104
323
  else
105
324
  native.close();
@@ -1,5 +1,6 @@
1
- export * from "./local-first/index.js";
2
- export * from "./Sqlite.js";
3
- export * from "./Task.js";
4
- export * from "./Worker.js";
1
+ export * from "./local-first/index.ts";
2
+ export { availableParallelism } from "./Platform.ts";
3
+ export * from "./Sqlite.ts";
4
+ export * from "./Task.ts";
5
+ export * from "./Worker.ts";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
package/dist/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./local-first/index.js";
2
+ export { availableParallelism } from "./Platform.js";
2
3
  export * from "./Sqlite.js";
3
4
  export * from "./Task.js";
4
5
  export * from "./Worker.js";
@@ -4,13 +4,12 @@ installPolyfills();
4
4
  import { createRandomBytes } from "@evolu/common";
5
5
  import { startDbWorker } from "@evolu/common/local-first";
6
6
  import { createWasmSqliteDriver } from "../Sqlite.js";
7
- import { createLeaderLock, createRun } from "../Task.js";
7
+ import { createRun } from "../Task.js";
8
8
  import { createWorkerDeps, createWorkerSelf } from "../Worker.js";
9
- // TODO: Disposal.
10
9
  const run = createRun({
11
10
  ...createWorkerDeps(),
12
11
  createSqliteDriver: createWasmSqliteDriver,
13
- leaderLock: createLeaderLock(),
12
+ lockManager: globalThis.navigator.locks,
14
13
  randomBytes: createRandomBytes(),
15
14
  });
16
- run(startDbWorker(createWorkerSelf(self)));
15
+ void run(startDbWorker(createWorkerSelf(self)));
@@ -1,5 +1,11 @@
1
- import type { ConsoleDep } from "@evolu/common";
1
+ import { type ConsoleDep } from "@evolu/common";
2
2
  import type { EvoluDeps } from "@evolu/common/local-first";
3
+ export interface SharedWorkerUnsupported {
4
+ readonly type: "SharedWorkerUnsupported";
5
+ }
6
+ export interface SharedWorkerUnsupportedDep {
7
+ readonly onSharedWorkerUnsupported: () => void;
8
+ }
3
9
  /** Creates Evolu dependencies for the web platform. */
4
- export declare const createEvoluDeps: (deps?: Partial<ConsoleDep>) => EvoluDeps;
10
+ export declare const createEvoluDeps: (deps?: Partial<ConsoleDep> & Partial<SharedWorkerUnsupportedDep>) => EvoluDeps;
5
11
  //# sourceMappingURL=Evolu.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Evolu.d.ts","sourceRoot":"","sources":["../../../src/local-first/Evolu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAGV,SAAS,EAEV,MAAM,2BAA2B,CAAC;AAgBnC,uDAAuD;AACvD,eAAO,MAAM,eAAe,GAAI,OAAM,OAAO,CAAC,UAAU,CAAM,KAAG,SAqBhE,CAAC"}
1
+ {"version":3,"file":"Evolu.d.ts","sourceRoot":"","sources":["../../../src/local-first/Evolu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,KAAK,EAIV,SAAS,EAGV,MAAM,2BAA2B,CAAC;AAkBnC,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;CAC1C;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,yBAAyB,EAAE,MAAM,IAAI,CAAC;CAChD;AAED,uDAAuD;AACvD,eAAO,MAAM,eAAe,UACpB,OAAO,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,0BAA0B,CAAC,KAC9D,SAkEF,CAAC"}
@@ -1,24 +1,56 @@
1
+ import { exhaustiveCheck } from "@evolu/common";
1
2
  import { createEvoluDeps as createCommonEvoluDeps } from "@evolu/common/local-first";
2
3
  import { reloadApp } from "../Platform.js";
3
- import { createMessageChannel, createSharedWorker, createWorker, } from "../Worker.js";
4
- // // TODO: Redesign.
5
- // // eslint-disable-next-line evolu/require-pure-annotation
6
- // export const localAuth = createLocalAuth({
7
- // randomBytes: createRandomBytes(),
8
- // secureStorage: createWebAuthnStore({ randomBytes: createRandomBytes() }),
9
- // });
4
+ import { createBroadcastChannel, createMessageChannel, createSharedWorker, createWorker, installOneTabSharedWorkerPolyfill, } from "../Worker.js";
10
5
  /** Creates Evolu dependencies for the web platform. */
11
6
  export const createEvoluDeps = (deps = {}) => {
7
+ installOneTabSharedWorkerPolyfill();
12
8
  const createDbWorker = () => createWorker(new Worker(new URL("Db.worker.js", import.meta.url), {
13
9
  type: "module",
14
10
  }));
15
- const sharedWorker = createSharedWorker(new SharedWorker(new URL("Shared.worker.js", import.meta.url), {
11
+ const webSharedWorker = createSharedWorker(new SharedWorker(new URL("Shared.worker.js", import.meta.url), {
16
12
  type: "module",
17
13
  }));
14
+ let onSharedWorkerMessage = null;
15
+ const sharedWorker = {
16
+ ...webSharedWorker,
17
+ port: {
18
+ ...webSharedWorker.port,
19
+ get onMessage() {
20
+ return onSharedWorkerMessage;
21
+ },
22
+ set onMessage(fn) {
23
+ onSharedWorkerMessage = fn;
24
+ webSharedWorker.port.onMessage = fn
25
+ ? (message) => {
26
+ switch (message.type) {
27
+ case "DbWorkerInit": {
28
+ fn(message);
29
+ break;
30
+ }
31
+ case "SharedWorkerUnsupported": {
32
+ if (deps.onSharedWorkerUnsupported) {
33
+ deps.onSharedWorkerUnsupported();
34
+ }
35
+ else {
36
+ globalThis.alert("This browser supports Evolu in one tab only. Close this tab and use the already open tab.");
37
+ }
38
+ break;
39
+ }
40
+ default:
41
+ exhaustiveCheck(message);
42
+ }
43
+ }
44
+ : null;
45
+ },
46
+ },
47
+ };
18
48
  return createCommonEvoluDeps({
19
49
  ...deps,
20
50
  createDbWorker,
51
+ createBroadcastChannel,
21
52
  createMessageChannel,
53
+ lockManager: globalThis.navigator.locks,
22
54
  reloadApp,
23
55
  sharedWorker,
24
56
  });
@@ -1 +1 @@
1
- {"version":3,"file":"LocalAuth.d.ts","sourceRoot":"","sources":["../../../src/local-first/LocalAuth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,cAAc,EACd,aAAa,EAEd,MAAM,eAAe,CAAC;AAiBvB,eAAO,MAAM,mBAAmB,GAAI,MAAM,cAAc,KAAG,aA4GzD,CAAC"}
1
+ {"version":3,"file":"LocalAuth.d.ts","sourceRoot":"","sources":["../../../src/local-first/LocalAuth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,cAAc,EACd,aAAa,EAEd,MAAM,eAAe,CAAC;AAiBvB,eAAO,MAAM,mBAAmB,SAAU,cAAc,KAAG,aA4GzD,CAAC"}
@@ -1,13 +1,117 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
1
53
  /// <reference lib="webworker" />
2
54
  import { installPolyfills } from "@evolu/common/polyfills";
3
55
  installPolyfills();
4
- import { createWebSocket } from "@evolu/common";
56
+ import { createWebSocket, ok, waitForAbort } from "@evolu/common";
5
57
  import { initSharedWorker } from "@evolu/common/local-first";
6
58
  import { createRun } from "../Task.js";
7
- import { createSharedWorkerSelf, createWorkerDeps } from "../Worker.js";
8
- // No disposal (`await using`) is needed — a SharedWorker lives forever.
59
+ import { createOneTabSharedWorkerSelfPolyfill, createSharedWorkerSelf, createWorkerDeps, } from "../Worker.js";
9
60
  const run = createRun({
10
61
  ...createWorkerDeps(),
11
62
  createWebSocket,
63
+ lockManager: globalThis.navigator.locks,
64
+ });
65
+ void run(async (run) => {
66
+ const env_1 = { stack: [], error: void 0, hasError: false };
67
+ try {
68
+ if ("onconnect" in self) {
69
+ const env_2 = { stack: [], error: void 0, hasError: false };
70
+ try {
71
+ const _ = __addDisposableResource(env_2, await run.ok(initSharedWorker(createSharedWorkerSelf(self))), true);
72
+ return await run(waitForAbort);
73
+ }
74
+ catch (e_1) {
75
+ env_2.error = e_1;
76
+ env_2.hasError = true;
77
+ }
78
+ finally {
79
+ const result_1 = __disposeResources(env_2);
80
+ if (result_1)
81
+ await result_1;
82
+ }
83
+ }
84
+ const workerSelf = __addDisposableResource(env_1, createOneTabSharedWorkerSelfPolyfill(self), false);
85
+ await globalThis.navigator.locks.request("evolu-one-tab-sharedworker-polyfill", { ifAvailable: true, mode: "exclusive" }, async (lock) => {
86
+ const env_3 = { stack: [], error: void 0, hasError: false };
87
+ try {
88
+ if (!lock) {
89
+ const message = {
90
+ type: "SharedWorkerUnsupported",
91
+ };
92
+ self.postMessage(message);
93
+ return;
94
+ }
95
+ const _ = __addDisposableResource(env_3, await run.ok(initSharedWorker(workerSelf)), true);
96
+ await run(waitForAbort);
97
+ }
98
+ catch (e_3) {
99
+ env_3.error = e_3;
100
+ env_3.hasError = true;
101
+ }
102
+ finally {
103
+ const result_2 = __disposeResources(env_3);
104
+ if (result_2)
105
+ await result_2;
106
+ }
107
+ });
108
+ return ok();
109
+ }
110
+ catch (e_2) {
111
+ env_1.error = e_2;
112
+ env_1.hasError = true;
113
+ }
114
+ finally {
115
+ __disposeResources(env_1);
116
+ }
12
117
  });
13
- run(initSharedWorker(createSharedWorkerSelf(self)));
@@ -1,2 +1,2 @@
1
- export * from "./Evolu.js";
1
+ export * from "./Evolu.ts";
2
2
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evolu/web",
3
- "version": "3.0.0-next.0",
3
+ "version": "3.0.0",
4
4
  "description": "Evolu for web",
5
5
  "keywords": [
6
6
  "evolu",
@@ -8,7 +8,10 @@
8
8
  ],
9
9
  "author": "Daniel Steigerwald <daniel@steigerwald.cz>",
10
10
  "license": "MIT",
11
- "repository": "evoluhq/evolu",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/evoluhq/evolu.git"
14
+ },
12
15
  "bugs": {
13
16
  "url": "https://github.com/evoluhq/evolu/issues"
14
17
  },
@@ -27,22 +30,18 @@
27
30
  "src/**",
28
31
  "README.md"
29
32
  ],
30
- "scripts": {
31
- "build": "tsc --build tsconfig.build.json",
32
- "prepack": "npm run build",
33
- "format": "prettier --write \"src/*.{ts,tsx,md}\""
34
- },
35
33
  "dependencies": {
36
34
  "@evolu/sqlite-wasm": "2.2.4",
37
35
  "idb-keyval": "^6.2.2"
38
36
  },
39
37
  "devDependencies": {
40
- "@evolu/common": "8.0.0-next.0",
41
- "@evolu/typescript-config": "*",
42
- "@types/sharedworker": "^0.0.221",
38
+ "@types/node": "^24.10.9",
39
+ "@types/sharedworker": "^0.0.229",
43
40
  "@types/web-locks-api": "^0.0.5",
44
- "typescript": "^5.9.3",
45
- "user-agent-data-types": "^0.4.2"
41
+ "@typescript/native": "npm:typescript@^7.0.2",
42
+ "user-agent-data-types": "^0.4.2",
43
+ "@evolu/common": "8.0.0",
44
+ "@evolu/typescript-config": "0.0.2"
46
45
  },
47
46
  "peerDependencies": {
48
47
  "@evolu/common": "^8.0.0-next.0"
@@ -53,5 +52,9 @@
53
52
  "engines": {
54
53
  "node": ">=24.0.0"
55
54
  },
56
- "sideEffects": false
57
- }
55
+ "sideEffects": false,
56
+ "scripts": {
57
+ "build": "tsc --build tsconfig.build.json",
58
+ "format": "prettier --write \"src/*.{ts,tsx,md}\""
59
+ }
60
+ }
package/src/Platform.ts CHANGED
@@ -1,4 +1,8 @@
1
- import type { ReloadApp } from "@evolu/common";
1
+ import { PositiveInt, type ReloadApp } from "@evolu/common";
2
+
3
+ /** Returns the amount of logical processors available to the browser. */
4
+ export const availableParallelism = (): PositiveInt =>
5
+ PositiveInt.orThrow(globalThis.navigator.hardwareConcurrency);
2
6
 
3
7
  export const reloadApp: ReloadApp = (url) => {
4
8
  if (typeof document === "undefined") {