@evolu/common 8.0.0-next.4 → 8.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.
- package/dist/src/Array.d.ts +279 -173
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +105 -101
- package/dist/src/Assert.d.ts +44 -44
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +44 -32
- package/dist/src/BigInt.d.ts +6 -3
- package/dist/src/BigInt.d.ts.map +1 -1
- package/dist/src/BigInt.js +5 -2
- package/dist/src/Brand.d.ts +27 -40
- package/dist/src/Brand.d.ts.map +1 -1
- package/dist/src/Buffer.d.ts +27 -11
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Cache.d.ts +9 -4
- package/dist/src/Cache.d.ts.map +1 -1
- package/dist/src/Cache.js +8 -3
- package/dist/src/Callbacks.d.ts +30 -19
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Console.d.ts +145 -66
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +91 -43
- package/dist/src/Crypto.d.ts +85 -42
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +44 -20
- package/dist/src/Eq.d.ts +87 -21
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +67 -19
- package/dist/src/Error.d.ts +5 -3
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +16 -0
- package/dist/src/Function.d.ts +119 -58
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +86 -43
- package/dist/src/Http.d.ts +394 -0
- package/dist/src/Http.d.ts.map +1 -0
- package/dist/src/Http.js +102 -0
- package/dist/src/Identicon.d.ts +16 -7
- package/dist/src/Identicon.d.ts.map +1 -1
- package/dist/src/Identicon.js +14 -5
- package/dist/src/LeakDetector.d.ts +88 -0
- package/dist/src/LeakDetector.d.ts.map +1 -0
- package/dist/src/LeakDetector.js +86 -0
- package/dist/src/LockManager.d.ts +18 -9
- package/dist/src/LockManager.d.ts.map +1 -1
- package/dist/src/LockManager.js +7 -8
- package/dist/src/Lookup.d.ts +43 -13
- package/dist/src/Lookup.d.ts.map +1 -1
- package/dist/src/Lookup.js +28 -8
- package/dist/src/Microtask.d.ts +1 -1
- package/dist/src/Microtask.d.ts.map +1 -1
- package/dist/src/Microtask.js +3 -7
- package/dist/src/Number.d.ts +49 -13
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +34 -5
- package/dist/src/Object.d.ts +160 -40
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +92 -46
- package/dist/src/Option.d.ts +10 -7
- package/dist/src/Option.d.ts.map +1 -1
- package/dist/src/Option.js +9 -6
- package/dist/src/Order.d.ts +21 -21
- package/dist/src/Order.d.ts.map +1 -1
- package/dist/src/Order.js +18 -21
- package/dist/src/Platform.d.ts +31 -0
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +98 -0
- package/dist/src/Random.d.ts +32 -17
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +12 -8
- package/dist/src/Redacted.d.ts +43 -29
- package/dist/src/Redacted.d.ts.map +1 -1
- package/dist/src/Redacted.js +14 -3
- package/dist/src/Ref.d.ts +11 -3
- package/dist/src/Ref.d.ts.map +1 -1
- package/dist/src/Ref.js +2 -2
- package/dist/src/RefCount.d.ts +2 -6
- package/dist/src/RefCount.d.ts.map +1 -1
- package/dist/src/RefCount.js +33 -90
- package/dist/src/Relation.d.ts +70 -5
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Relation.js +77 -2
- package/dist/src/Resource.d.ts +590 -155
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Resource.js +592 -343
- package/dist/src/Result.d.ts +838 -191
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +163 -102
- package/dist/src/Schedule.d.ts +684 -231
- package/dist/src/Schedule.d.ts.map +1 -1
- package/dist/src/Schedule.js +766 -295
- package/dist/src/Set.d.ts +89 -40
- package/dist/src/Set.d.ts.map +1 -1
- package/dist/src/Set.js +50 -29
- package/dist/src/Sqlite.d.ts +29 -72
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +41 -46
- package/dist/src/StackTrace.d.ts +40 -0
- package/dist/src/StackTrace.d.ts.map +1 -0
- package/dist/src/StackTrace.js +140 -0
- package/dist/src/Store.d.ts +5 -4
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +5 -4
- package/dist/src/String.d.ts +7 -1
- package/dist/src/String.d.ts.map +1 -1
- package/dist/src/String.js +20 -7
- package/dist/src/Task.d.ts +3572 -1770
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +1879 -1274
- package/dist/src/Test.d.ts +17 -125
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +17 -68
- package/dist/src/Time.d.ts +108 -49
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +172 -73
- package/dist/src/Type.d.ts +3542 -1926
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +3070 -1784
- package/dist/src/Types.d.ts +200 -108
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/Types.js +39 -8
- package/dist/src/WebSocket.d.ts +48 -23
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +15 -6
- package/dist/src/Worker.d.ts +94 -36
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +58 -24
- package/dist/src/index.d.ts +55 -52
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/intl/cs.d.ts +94 -0
- package/dist/src/intl/cs.d.ts.map +1 -0
- package/dist/src/intl/cs.js +220 -0
- package/dist/src/intl/index.d.ts +7 -0
- package/dist/src/intl/index.d.ts.map +1 -0
- package/dist/src/intl/index.js +6 -0
- package/dist/src/local-first/Db.d.ts +12 -8
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +109 -132
- package/dist/src/local-first/Error.d.ts +4 -4
- package/dist/src/local-first/Evolu.d.ts +338 -92
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +47 -55
- package/dist/src/local-first/LocalAuth.d.ts +4 -4
- package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
- package/dist/src/local-first/Owner.d.ts +61 -24
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +45 -8
- package/dist/src/local-first/Protocol.d.ts +44 -31
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +36 -13
- package/dist/src/local-first/Query.d.ts +147 -62
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +112 -58
- package/dist/src/local-first/Relay.d.ts +44 -14
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Schema.d.ts +92 -41
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +25 -8
- package/dist/src/local-first/Shared.d.ts +23 -21
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +100 -57
- package/dist/src/local-first/Storage.d.ts +53 -32
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +194 -234
- package/dist/src/local-first/Timestamp.d.ts +21 -21
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +2 -2
- package/dist/src/local-first/index.d.ts +11 -11
- package/package.json +14 -13
- package/src/Array.ts +306 -205
- package/src/Assert.ts +54 -69
- package/src/BigInt.ts +6 -3
- package/src/Brand.ts +27 -40
- package/src/Buffer.ts +28 -12
- package/src/Cache.ts +9 -4
- package/src/Callbacks.ts +30 -19
- package/src/Console.ts +156 -84
- package/src/Crypto.ts +83 -41
- package/src/Eq.ts +95 -22
- package/src/Error.ts +8 -4
- package/src/Function.ts +167 -59
- package/src/Http.ts +549 -0
- package/src/Identicon.ts +16 -7
- package/src/LeakDetector.ts +182 -0
- package/src/LockManager.ts +43 -39
- package/src/Lookup.ts +62 -28
- package/src/Microtask.ts +19 -23
- package/src/Number.ts +64 -12
- package/src/Object.ts +173 -49
- package/src/Option.ts +10 -7
- package/src/Order.ts +23 -21
- package/src/Platform.ts +136 -0
- package/src/Polyfills.ts +6 -12
- package/src/Random.ts +32 -19
- package/src/Redacted.ts +44 -30
- package/src/Ref.ts +14 -6
- package/src/RefCount.ts +38 -80
- package/src/Relation.ts +202 -10
- package/src/Resource.ts +1199 -591
- package/src/Result.ts +930 -271
- package/src/Schedule.ts +859 -343
- package/src/Set.ts +89 -40
- package/src/Sqlite.ts +144 -138
- package/src/StackTrace.ts +230 -0
- package/src/Store.ts +8 -7
- package/src/String.ts +22 -5
- package/src/Task.ts +5101 -2832
- package/src/Test.ts +20 -168
- package/src/Time.ts +293 -90
- package/src/Type.ts +10034 -4117
- package/src/Types.ts +227 -110
- package/src/WebSocket.ts +64 -36
- package/src/Worker.ts +180 -72
- package/src/index.ts +55 -52
- package/src/intl/cs.ts +388 -0
- package/src/intl/index.ts +7 -0
- package/src/local-first/Db.ts +152 -179
- package/src/local-first/Error.ts +4 -4
- package/src/local-first/Evolu.ts +495 -250
- package/src/local-first/LocalAuth.ts +6 -12
- package/src/local-first/Owner.ts +58 -21
- package/src/local-first/Protocol.ts +49 -31
- package/src/local-first/Query.ts +146 -61
- package/src/local-first/Relay.ts +51 -21
- package/src/local-first/Schema.ts +109 -51
- package/src/local-first/Shared.ts +266 -226
- package/src/local-first/Storage.ts +266 -264
- package/src/local-first/Timestamp.ts +25 -18
- package/src/local-first/index.ts +11 -11
- package/dist/src/Skiplist.d.ts +0 -28
- package/dist/src/Skiplist.d.ts.map +0 -1
- package/dist/src/Skiplist.js +0 -64
- package/dist/src/Tracer.d.ts +0 -48
- package/dist/src/Tracer.d.ts.map +0 -1
- package/dist/src/Tracer.js +0 -6
- package/src/Skiplist.ts +0 -108
- package/src/Tracer.ts +0 -54
package/src/WebSocket.ts
CHANGED
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { assert } from "./Assert.
|
|
8
|
-
import {
|
|
9
|
-
import type { Result } from "./Result.
|
|
10
|
-
import { err, ok } from "./Result.
|
|
11
|
-
import type { Schedule } from "./Schedule.
|
|
12
|
-
import { exponential, jitter, maxDelay } from "./Schedule.
|
|
13
|
-
import type { RetryError, Task } from "./Task.
|
|
14
|
-
import { callback, retry } from "./Task.
|
|
15
|
-
import type { Millis } from "./Time.
|
|
16
|
-
import { ArrayBuffer, String, Uint8Array, type Typed } from "./Type.
|
|
7
|
+
import { assert } from "./Assert.ts";
|
|
8
|
+
import { constTrue } from "./Function.ts";
|
|
9
|
+
import type { Result } from "./Result.ts";
|
|
10
|
+
import { err, ok } from "./Result.ts";
|
|
11
|
+
import type { Schedule } from "./Schedule.ts";
|
|
12
|
+
import { exponential, jitter, maxDelay } from "./Schedule.ts";
|
|
13
|
+
import type { RetryError, Task } from "./Task.ts";
|
|
14
|
+
import { callback, retry } from "./Task.ts";
|
|
15
|
+
import type { Millis } from "./Time.ts";
|
|
16
|
+
import { ArrayBuffer, String, Uint8Array, type Typed } from "./Type.ts";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* WebSocket with auto-reconnect.
|
|
@@ -49,20 +49,42 @@ import { ArrayBuffer, String, Uint8Array, type Typed } from "./Type.js";
|
|
|
49
49
|
* - A Blob (default: "blob")
|
|
50
50
|
* - An ArrayBuffer ("arraybuffer")
|
|
51
51
|
*
|
|
52
|
-
* ###
|
|
52
|
+
* ### Connecting and sending
|
|
53
53
|
*
|
|
54
54
|
* ```ts
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
55
|
+
* import {
|
|
56
|
+
* createRun,
|
|
57
|
+
* createWebSocket,
|
|
58
|
+
* testCreateWebSocket,
|
|
59
|
+
* type CreateWebSocket,
|
|
60
|
+
* type Task,
|
|
61
|
+
* type WebSocketSendError,
|
|
62
|
+
* } from "@evolu/common";
|
|
63
|
+
*
|
|
64
|
+
* const connectAndSend =
|
|
65
|
+
* (
|
|
66
|
+
* createSocket: CreateWebSocket = createWebSocket,
|
|
67
|
+
* ): Task<void, WebSocketSendError> =>
|
|
68
|
+
* async (run) => {
|
|
69
|
+
* await using socket = await run.ok(
|
|
70
|
+
* createSocket("wss://example.com", {
|
|
71
|
+
* protocols: ["evolu"],
|
|
72
|
+
* binaryType: "arraybuffer",
|
|
73
|
+
* onOpen: () => console.log("Connected"),
|
|
74
|
+
* onMessage: (data) => console.log("Received:", data),
|
|
75
|
+
* onClose: () => console.log("Disconnected"),
|
|
76
|
+
* }),
|
|
77
|
+
* );
|
|
78
|
+
* return socket.send("Hello");
|
|
79
|
+
* };
|
|
80
|
+
*
|
|
81
|
+
* const socketFactory = testCreateWebSocket();
|
|
82
|
+
* await using run = createRun();
|
|
83
|
+
*
|
|
84
|
+
* expectOk(await run(connectAndSend(socketFactory)), undefined);
|
|
85
|
+
* expect(socketFactory.sentMessages).toEqual([
|
|
86
|
+
* { url: "wss://example.com", data: "Hello" },
|
|
87
|
+
* ]);
|
|
66
88
|
* ```
|
|
67
89
|
*/
|
|
68
90
|
export interface WebSocket extends AsyncDisposable {
|
|
@@ -129,12 +151,8 @@ export interface WebSocketOptions {
|
|
|
129
151
|
readonly onMessage?: (data: string | ArrayBuffer | Blob) => void;
|
|
130
152
|
|
|
131
153
|
/**
|
|
132
|
-
* Retry schedule for reconnection. Defaults to
|
|
133
|
-
*
|
|
134
|
-
* ```ts
|
|
135
|
-
* // A jittered, capped, unlimited exponential backoff.
|
|
136
|
-
* jitter(1)(maxDelay("30s")(exponential("100ms")));
|
|
137
|
-
* ```
|
|
154
|
+
* Retry schedule for reconnection. Defaults to
|
|
155
|
+
* {@link webSocketReconnectSchedule}.
|
|
138
156
|
*/
|
|
139
157
|
readonly schedule?: Schedule<Millis, WebSocketRetryError>;
|
|
140
158
|
|
|
@@ -175,14 +193,24 @@ export interface WebSocketConnectionError extends Typed<"WebSocketConnectionErro
|
|
|
175
193
|
}
|
|
176
194
|
|
|
177
195
|
export type WebSocketRetryError =
|
|
178
|
-
|
|
|
179
|
-
| WebSocketConnectionCloseError;
|
|
196
|
+
WebSocketConnectError | WebSocketConnectionCloseError;
|
|
180
197
|
|
|
181
198
|
/** An error that occurs when the connection is closed by the server. */
|
|
182
199
|
export interface WebSocketConnectionCloseError extends Typed<"WebSocketConnectionCloseError"> {
|
|
183
200
|
readonly event: CloseEvent;
|
|
184
201
|
}
|
|
185
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Default WebSocket reconnect schedule.
|
|
205
|
+
*
|
|
206
|
+
* Uses unlimited exponential backoff with a 100ms base, 30s cap, and full
|
|
207
|
+
* jitter.
|
|
208
|
+
*/
|
|
209
|
+
export const webSocketReconnectSchedule: Schedule<Millis, WebSocketRetryError> =
|
|
210
|
+
/*#__PURE__*/ jitter("100%")(
|
|
211
|
+
/*#__PURE__*/ maxDelay("30s")(/*#__PURE__*/ exponential("100ms")),
|
|
212
|
+
);
|
|
213
|
+
|
|
186
214
|
/** Create a new {@link WebSocket}. */
|
|
187
215
|
export const createWebSocket: CreateWebSocket =
|
|
188
216
|
(
|
|
@@ -192,10 +220,10 @@ export const createWebSocket: CreateWebSocket =
|
|
|
192
220
|
binaryType,
|
|
193
221
|
onOpen,
|
|
194
222
|
onClose,
|
|
195
|
-
shouldRetryOnClose =
|
|
223
|
+
shouldRetryOnClose = constTrue,
|
|
196
224
|
onMessage,
|
|
197
225
|
onError,
|
|
198
|
-
schedule =
|
|
226
|
+
schedule = webSocketReconnectSchedule,
|
|
199
227
|
WebSocketConstructor = globalThis.WebSocket,
|
|
200
228
|
} = {},
|
|
201
229
|
) =>
|
|
@@ -226,7 +254,7 @@ export const createWebSocket: CreateWebSocket =
|
|
|
226
254
|
* A task that connects and stays connected until the connection closes or
|
|
227
255
|
* errors. Returns error to trigger retry.
|
|
228
256
|
*/
|
|
229
|
-
const connect: Task<void, WebSocketRetryError> = callback(({
|
|
257
|
+
const connect: Task<void, WebSocketRetryError> = callback(({ resolve }) => {
|
|
230
258
|
closeSocket();
|
|
231
259
|
|
|
232
260
|
socket = new WebSocketConstructor(
|
|
@@ -246,9 +274,9 @@ export const createWebSocket: CreateWebSocket =
|
|
|
246
274
|
socket.onclose = (event) => {
|
|
247
275
|
onClose?.(event);
|
|
248
276
|
if (shouldRetryOnClose(event)) {
|
|
249
|
-
err({ type: "WebSocketConnectionCloseError", event });
|
|
277
|
+
resolve(err({ type: "WebSocketConnectionCloseError", event }));
|
|
250
278
|
} else {
|
|
251
|
-
ok();
|
|
279
|
+
resolve(ok());
|
|
252
280
|
}
|
|
253
281
|
};
|
|
254
282
|
|
|
@@ -262,7 +290,7 @@ export const createWebSocket: CreateWebSocket =
|
|
|
262
290
|
: { type: "WebSocketConnectError", event };
|
|
263
291
|
onError?.(error);
|
|
264
292
|
|
|
265
|
-
if (error.type === "WebSocketConnectError") err(error);
|
|
293
|
+
if (error.type === "WebSocketConnectError") resolve(err(error));
|
|
266
294
|
};
|
|
267
295
|
|
|
268
296
|
return closeSocket;
|
package/src/Worker.ts
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { assert
|
|
8
|
-
import type { Brand } from "./Brand.
|
|
9
|
-
import type { ConsoleDep, ConsoleStoreOutputEntryDep } from "./Console.
|
|
10
|
-
import {
|
|
7
|
+
import { assert } from "./Assert.ts";
|
|
8
|
+
import type { Brand } from "./Brand.ts";
|
|
9
|
+
import type { ConsoleDep, ConsoleStoreOutputEntryDep } from "./Console.ts";
|
|
10
|
+
import { disposable } from "./Function.ts";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Typed, disposable Worker.
|
|
@@ -60,13 +60,28 @@ export interface MessagePort<Input, Output = never> extends Disposable {
|
|
|
60
60
|
/**
|
|
61
61
|
* The native underlying port for transferring via `postMessage`.
|
|
62
62
|
*
|
|
63
|
-
*
|
|
63
|
+
* Prepare a port for transfer:
|
|
64
64
|
*
|
|
65
65
|
* ```ts
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
66
|
+
* import {
|
|
67
|
+
* createMessageChannel,
|
|
68
|
+
* type NativeMessagePort,
|
|
69
|
+
* } from "@evolu/common";
|
|
70
|
+
*
|
|
71
|
+
* interface ConsoleMessage {
|
|
72
|
+
* readonly type: "ConsoleEntry";
|
|
73
|
+
* readonly text: string;
|
|
74
|
+
* }
|
|
75
|
+
*
|
|
76
|
+
* using consoleChannel = createMessageChannel<ConsoleMessage>();
|
|
77
|
+
* const init = {
|
|
78
|
+
* type: "InitConsole",
|
|
79
|
+
* port: consoleChannel.port1.native,
|
|
80
|
+
* };
|
|
81
|
+
*
|
|
82
|
+
* expectTypeOf(init.port).toEqualTypeOf<
|
|
83
|
+
* NativeMessagePort<ConsoleMessage>
|
|
84
|
+
* >();
|
|
70
85
|
* ```
|
|
71
86
|
*/
|
|
72
87
|
readonly native: NativeMessagePort<Input, Output>;
|
|
@@ -126,36 +141,80 @@ export type WorkerDeps = ConsoleDep &
|
|
|
126
141
|
*
|
|
127
142
|
* For one-way communication, omit `Output` (defaults to `never`).
|
|
128
143
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* Transfer a channel port to a SharedWorker for async initialization:
|
|
144
|
+
* Transfer a channel port to a SharedWorker and use the retained port
|
|
145
|
+
* immediately:
|
|
132
146
|
*
|
|
133
147
|
* ```ts
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* }
|
|
148
|
+
* import {
|
|
149
|
+
* createMessageChannel,
|
|
150
|
+
* createMessagePort,
|
|
151
|
+
* createSharedWorker,
|
|
152
|
+
* type NativeMessagePort,
|
|
153
|
+
* } from "@evolu/common";
|
|
154
|
+
*
|
|
155
|
+
* interface Query {
|
|
156
|
+
* readonly text: string;
|
|
157
|
+
* }
|
|
158
|
+
* interface QueryResult {
|
|
159
|
+
* readonly rows: ReadonlyArray<string>;
|
|
160
|
+
* }
|
|
161
|
+
* interface ConnectToEvolu {
|
|
162
|
+
* readonly port: NativeMessagePort<QueryResult, Query>;
|
|
163
|
+
* }
|
|
164
|
+
*
|
|
165
|
+
* const response = Promise.withResolvers<QueryResult>();
|
|
166
|
+
* using sharedWorker = createSharedWorker<ConnectToEvolu>((self) => {
|
|
167
|
+
* self.onConnect = (controlPort) => {
|
|
168
|
+
* controlPort.onMessage = ({ port }) => {
|
|
169
|
+
* const workerQueries = createMessagePort<QueryResult, Query>(port);
|
|
170
|
+
* workerQueries.onMessage = (query) => {
|
|
171
|
+
* workerQueries.postMessage({ rows: [query.text] });
|
|
172
|
+
* workerQueries[Symbol.dispose]();
|
|
173
|
+
* };
|
|
174
|
+
* };
|
|
175
|
+
* };
|
|
176
|
+
* });
|
|
177
|
+
* using queryChannel = createMessageChannel<Query, QueryResult>();
|
|
178
|
+
* queryChannel.port1.onMessage = response.resolve;
|
|
179
|
+
*
|
|
180
|
+
* // The main thread retains port1 and transfers the worker-facing port2.
|
|
181
|
+
* sharedWorker.port.postMessage({ port: queryChannel.port2.native }, [
|
|
182
|
+
* queryChannel.port2.native,
|
|
183
|
+
* ]);
|
|
184
|
+
* queryChannel.port1.postMessage({ text: "all todos" });
|
|
185
|
+
*
|
|
186
|
+
* expect(await response.promise).toEqual({ rows: ["all todos"] });
|
|
147
187
|
* ```
|
|
148
188
|
*
|
|
189
|
+
* On the worker side, attach the handler after asynchronous initialization;
|
|
190
|
+
* messages sent earlier remain queued:
|
|
191
|
+
*
|
|
149
192
|
* ```ts
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
193
|
+
* import { createMessageChannel, createMessagePort } from "@evolu/common";
|
|
194
|
+
*
|
|
195
|
+
* interface Query {
|
|
196
|
+
* readonly text: string;
|
|
197
|
+
* }
|
|
198
|
+
*
|
|
199
|
+
* using channel = createMessageChannel<Query>();
|
|
200
|
+
* using workerPort = createMessagePort<never, Query>(channel.port2.native);
|
|
201
|
+
* const received: Array<Query> = [];
|
|
202
|
+
* const allReceived = Promise.withResolvers<void>();
|
|
203
|
+
* // The main thread can send several messages while the worker initializes.
|
|
204
|
+
* channel.port1.postMessage({ text: "all todos" });
|
|
205
|
+
* channel.port1.postMessage({ text: "completed todos" });
|
|
206
|
+
*
|
|
207
|
+
* await Promise.resolve();
|
|
208
|
+
* workerPort.onMessage = (query) => {
|
|
209
|
+
* received.push(query);
|
|
210
|
+
* if (received.length === 2) allReceived.resolve();
|
|
157
211
|
* };
|
|
158
|
-
*
|
|
212
|
+
* await allReceived.promise;
|
|
213
|
+
*
|
|
214
|
+
* expect(received).toEqual([
|
|
215
|
+
* { text: "all todos" },
|
|
216
|
+
* { text: "completed todos" },
|
|
217
|
+
* ]);
|
|
159
218
|
* ```
|
|
160
219
|
*
|
|
161
220
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel
|
|
@@ -357,41 +416,41 @@ export const createBroadcastChannel: CreateBroadcastChannel = <
|
|
|
357
416
|
dispatches.add(dispatch as BroadcastChannelDispatch<any>);
|
|
358
417
|
|
|
359
418
|
using disposer = new DisposableStack();
|
|
419
|
+
let disposed = false;
|
|
360
420
|
|
|
361
421
|
disposer.defer(() => {
|
|
422
|
+
disposed = true;
|
|
362
423
|
onMessageHandler = null;
|
|
363
424
|
|
|
364
425
|
dispatches.delete(dispatch as BroadcastChannelDispatch<any>);
|
|
365
426
|
if (dispatches.size === 0) broadcastChannelDispatchesByName.delete(name);
|
|
366
427
|
});
|
|
367
428
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
429
|
+
return disposable<BroadcastChannel<Input, Output>>(
|
|
430
|
+
{
|
|
431
|
+
postMessage: (message) => {
|
|
432
|
+
const dispatches = broadcastChannelDispatchesByName.get(name);
|
|
433
|
+
assert(dispatches, "Expected broadcast channel dispatches");
|
|
434
|
+
|
|
435
|
+
for (const otherDispatch of [...dispatches]) {
|
|
436
|
+
if (otherDispatch === dispatch) continue;
|
|
437
|
+
|
|
438
|
+
scheduleWorkerTask(() => {
|
|
439
|
+
if (!dispatches.has(otherDispatch)) return;
|
|
440
|
+
otherDispatch(message);
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
get onMessage() {
|
|
445
|
+
return disposed ? null : onMessageHandler;
|
|
446
|
+
},
|
|
447
|
+
set onMessage(fn) {
|
|
448
|
+
if (disposed) return;
|
|
449
|
+
onMessageHandler = fn;
|
|
450
|
+
},
|
|
388
451
|
},
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
onMessageHandler = fn;
|
|
392
|
-
},
|
|
393
|
-
[Symbol.dispose]: () => disposables.dispose(),
|
|
394
|
-
};
|
|
452
|
+
disposer,
|
|
453
|
+
);
|
|
395
454
|
};
|
|
396
455
|
|
|
397
456
|
type BroadcastChannelDispatch<T> = (message: T) => void;
|
|
@@ -537,17 +596,17 @@ export const testCreateBroadcastChannel = <Input, Output = Input>(
|
|
|
537
596
|
};
|
|
538
597
|
|
|
539
598
|
/**
|
|
540
|
-
* Waits
|
|
541
|
-
* tests.
|
|
599
|
+
* Waits until scheduled in-memory worker message delivery becomes idle.
|
|
542
600
|
*
|
|
543
|
-
* This
|
|
544
|
-
*
|
|
545
|
-
*
|
|
601
|
+
* This observes actual transport tasks instead of waiting for an arbitrary
|
|
602
|
+
* duration. It also waits through message handlers that schedule more worker
|
|
603
|
+
* tasks before the current microtask checkpoint completes.
|
|
546
604
|
*/
|
|
547
|
-
export const testWaitForWorkerMessage =
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
605
|
+
export const testWaitForWorkerMessage = (): Promise<void> =>
|
|
606
|
+
new Promise((resolve) => {
|
|
607
|
+
workerTaskIdleWaiters.add(resolve);
|
|
608
|
+
notifyWorkerTaskIdle();
|
|
609
|
+
});
|
|
551
610
|
|
|
552
611
|
const createMemoryWorkerPair = <Input, Output = never>(): {
|
|
553
612
|
readonly worker: Worker<Input, Output>;
|
|
@@ -650,7 +709,7 @@ const createPort = <Input, Output>({
|
|
|
650
709
|
nativePortRegistry.delete(native);
|
|
651
710
|
|
|
652
711
|
if (receive.flushTimeoutId != null) {
|
|
653
|
-
|
|
712
|
+
cancelWorkerTask(receive.flushTimeoutId);
|
|
654
713
|
receive.flushTimeoutId = null;
|
|
655
714
|
}
|
|
656
715
|
|
|
@@ -665,8 +724,7 @@ const createPort = <Input, Output>({
|
|
|
665
724
|
if (state.flushScheduled || state.ownerCount === 0) return;
|
|
666
725
|
state.flushScheduled = true;
|
|
667
726
|
|
|
668
|
-
|
|
669
|
-
state.flushTimeoutId = globalThis.setTimeout(() => {
|
|
727
|
+
state.flushTimeoutId = scheduleWorkerTask(() => {
|
|
670
728
|
state.flushTimeoutId = null;
|
|
671
729
|
state.flushScheduled = false;
|
|
672
730
|
if (state.ownerCount === 0) return;
|
|
@@ -680,7 +738,7 @@ const createPort = <Input, Output>({
|
|
|
680
738
|
|
|
681
739
|
handler(message);
|
|
682
740
|
}
|
|
683
|
-
}
|
|
741
|
+
});
|
|
684
742
|
};
|
|
685
743
|
|
|
686
744
|
return {
|
|
@@ -718,6 +776,56 @@ const createPort = <Input, Output>({
|
|
|
718
776
|
};
|
|
719
777
|
};
|
|
720
778
|
|
|
779
|
+
const pendingWorkerTaskIds = new Set<
|
|
780
|
+
ReturnType<typeof globalThis.setTimeout>
|
|
781
|
+
>();
|
|
782
|
+
const workerTaskIdleWaiters = new Set<() => void>();
|
|
783
|
+
let workerTaskIdleCheckTimeoutId:
|
|
784
|
+
ReturnType<typeof globalThis.setTimeout> | undefined;
|
|
785
|
+
|
|
786
|
+
const scheduleWorkerTask = (
|
|
787
|
+
callback: () => void,
|
|
788
|
+
): ReturnType<typeof globalThis.setTimeout> => {
|
|
789
|
+
if (workerTaskIdleCheckTimeoutId != null) {
|
|
790
|
+
globalThis.clearTimeout(workerTaskIdleCheckTimeoutId);
|
|
791
|
+
workerTaskIdleCheckTimeoutId = undefined;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const timeoutId = globalThis.setTimeout(() => {
|
|
795
|
+
pendingWorkerTaskIds.delete(timeoutId);
|
|
796
|
+
try {
|
|
797
|
+
callback();
|
|
798
|
+
} finally {
|
|
799
|
+
queueMicrotask(notifyWorkerTaskIdle);
|
|
800
|
+
}
|
|
801
|
+
}, 0);
|
|
802
|
+
pendingWorkerTaskIds.add(timeoutId);
|
|
803
|
+
return timeoutId;
|
|
804
|
+
};
|
|
805
|
+
|
|
806
|
+
const cancelWorkerTask = (
|
|
807
|
+
timeoutId: ReturnType<typeof globalThis.setTimeout>,
|
|
808
|
+
): void => {
|
|
809
|
+
globalThis.clearTimeout(timeoutId);
|
|
810
|
+
pendingWorkerTaskIds.delete(timeoutId);
|
|
811
|
+
queueMicrotask(notifyWorkerTaskIdle);
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
const notifyWorkerTaskIdle = (): void => {
|
|
815
|
+
if (
|
|
816
|
+
pendingWorkerTaskIds.size > 0 ||
|
|
817
|
+
workerTaskIdleWaiters.size === 0 ||
|
|
818
|
+
workerTaskIdleCheckTimeoutId != null
|
|
819
|
+
)
|
|
820
|
+
return;
|
|
821
|
+
|
|
822
|
+
workerTaskIdleCheckTimeoutId = globalThis.setTimeout(() => {
|
|
823
|
+
workerTaskIdleCheckTimeoutId = undefined;
|
|
824
|
+
for (const resolve of workerTaskIdleWaiters) resolve();
|
|
825
|
+
workerTaskIdleWaiters.clear();
|
|
826
|
+
}, 0);
|
|
827
|
+
};
|
|
828
|
+
|
|
721
829
|
const createTestPort = <Input, Output>(
|
|
722
830
|
registration: PortRegistration<Input, Output>,
|
|
723
831
|
): MessagePort<Input, Output> => createPort(registration);
|
package/src/index.ts
CHANGED
|
@@ -4,60 +4,63 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export * from "./Array.
|
|
8
|
-
export * from "./Assert.
|
|
9
|
-
export * from "./BigInt.
|
|
10
|
-
export * from "./Brand.
|
|
11
|
-
export * from "./Buffer.
|
|
12
|
-
export * from "./Cache.
|
|
13
|
-
export * from "./Callbacks.
|
|
14
|
-
export * from "./Console.
|
|
15
|
-
export * from "./Crypto.
|
|
16
|
-
export * from "./Eq.
|
|
17
|
-
export * from "./Error.
|
|
18
|
-
export * from "./Function.
|
|
19
|
-
export * from "./
|
|
20
|
-
export * from "./
|
|
21
|
-
export * from "./
|
|
22
|
-
export * from "./
|
|
23
|
-
export * from "./
|
|
24
|
-
export * from "./
|
|
25
|
-
export * from "./
|
|
26
|
-
export * from "./
|
|
27
|
-
export * from "./
|
|
28
|
-
export * from "./
|
|
29
|
-
export * from "./
|
|
30
|
-
export * from "./
|
|
31
|
-
export * from "./
|
|
32
|
-
export * from "./
|
|
33
|
-
export * from "./
|
|
34
|
-
export * from "./
|
|
35
|
-
export * from "./
|
|
36
|
-
export * from "./
|
|
37
|
-
export * from "./
|
|
38
|
-
export * from "./
|
|
39
|
-
export * from "./
|
|
40
|
-
export
|
|
41
|
-
export * from "./
|
|
42
|
-
export * from "./
|
|
43
|
-
export * from "./
|
|
44
|
-
export * from "./
|
|
45
|
-
export * from "./
|
|
46
|
-
export * from "./
|
|
7
|
+
export * from "./Array.ts";
|
|
8
|
+
export * from "./Assert.ts";
|
|
9
|
+
export * from "./BigInt.ts";
|
|
10
|
+
export * from "./Brand.ts";
|
|
11
|
+
export * from "./Buffer.ts";
|
|
12
|
+
export * from "./Cache.ts";
|
|
13
|
+
export * from "./Callbacks.ts";
|
|
14
|
+
export * from "./Console.ts";
|
|
15
|
+
export * from "./Crypto.ts";
|
|
16
|
+
export * from "./Eq.ts";
|
|
17
|
+
export * from "./Error.ts";
|
|
18
|
+
export * from "./Function.ts";
|
|
19
|
+
export * from "./Http.ts";
|
|
20
|
+
export * from "./Identicon.ts";
|
|
21
|
+
export * from "./LeakDetector.ts";
|
|
22
|
+
export * from "./LockManager.ts";
|
|
23
|
+
export * from "./Lookup.ts";
|
|
24
|
+
export * from "./Microtask.ts";
|
|
25
|
+
export * from "./Number.ts";
|
|
26
|
+
export * from "./Object.ts";
|
|
27
|
+
export * from "./Option.ts";
|
|
28
|
+
export * from "./Order.ts";
|
|
29
|
+
export * from "./Platform.ts";
|
|
30
|
+
export * from "./Random.ts";
|
|
31
|
+
export * from "./Redacted.ts";
|
|
32
|
+
export * from "./Ref.ts";
|
|
33
|
+
export * from "./RefCount.ts";
|
|
34
|
+
export * from "./Relation.ts";
|
|
35
|
+
export * from "./Resource.ts";
|
|
36
|
+
export * from "./Result.ts";
|
|
37
|
+
export * from "./Schedule.ts";
|
|
38
|
+
export * from "./Set.ts";
|
|
39
|
+
export * from "./Sqlite.ts";
|
|
40
|
+
export type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
41
|
+
export * from "./Store.ts";
|
|
42
|
+
export * from "./String.ts";
|
|
43
|
+
export * from "./Task.ts";
|
|
44
|
+
export * from "./Test.ts";
|
|
45
|
+
export * from "./Time.ts";
|
|
46
|
+
export * from "./Type.ts";
|
|
47
|
+
export * from "./Types.ts";
|
|
48
|
+
export * from "./WebSocket.ts";
|
|
49
|
+
export * from "./Worker.ts";
|
|
47
50
|
|
|
48
51
|
// Local-first essentials.
|
|
49
|
-
export type { EvoluError } from "./local-first/Error.
|
|
50
|
-
export { AppName, createEvolu } from "./local-first/Evolu.
|
|
52
|
+
export type { EvoluError } from "./local-first/Error.ts";
|
|
53
|
+
export { AppName, createEvolu } from "./local-first/Evolu.ts";
|
|
51
54
|
export type {
|
|
52
55
|
AppNameError,
|
|
53
56
|
Evolu,
|
|
54
57
|
EvoluConfig,
|
|
55
58
|
EvoluDeps,
|
|
56
59
|
UnuseOwner,
|
|
57
|
-
} from "./local-first/Evolu.
|
|
58
|
-
export * from "./local-first/LocalAuth.
|
|
59
|
-
export * from "./local-first/Owner.
|
|
60
|
-
export type { SyncOwner } from "./local-first/Owner.
|
|
60
|
+
} from "./local-first/Evolu.ts";
|
|
61
|
+
export * from "./local-first/LocalAuth.ts";
|
|
62
|
+
export * from "./local-first/Owner.ts";
|
|
63
|
+
export type { SyncOwner } from "./local-first/Owner.ts";
|
|
61
64
|
export {
|
|
62
65
|
evoluJsonArrayFrom,
|
|
63
66
|
evoluJsonBuildObject,
|
|
@@ -69,8 +72,8 @@ export {
|
|
|
69
72
|
type Query,
|
|
70
73
|
type QueryRows,
|
|
71
74
|
type Row,
|
|
72
|
-
} from "./local-first/Query.
|
|
73
|
-
export { createQueryBuilder } from "./local-first/Schema.
|
|
75
|
+
} from "./local-first/Query.ts";
|
|
76
|
+
export { createQueryBuilder } from "./local-first/Schema.ts";
|
|
74
77
|
export type {
|
|
75
78
|
AnyStandardSchemaV1,
|
|
76
79
|
EvoluSchema,
|
|
@@ -85,22 +88,22 @@ export type {
|
|
|
85
88
|
TableSchema,
|
|
86
89
|
UpdateValues,
|
|
87
90
|
UpsertValues,
|
|
88
|
-
} from "./local-first/Schema.
|
|
91
|
+
} from "./local-first/Schema.ts";
|
|
89
92
|
export type {
|
|
90
93
|
// NetworkError,
|
|
91
94
|
// PaymentRequiredError,
|
|
92
95
|
// ServerError,
|
|
93
96
|
SyncState,
|
|
94
|
-
} from "./local-first/Shared.
|
|
97
|
+
} from "./local-first/Shared.ts";
|
|
95
98
|
export {
|
|
96
99
|
Timestamp,
|
|
97
100
|
timestampBytesToTimestamp,
|
|
98
101
|
timestampToTimestampBytes,
|
|
99
|
-
} from "./local-first/Timestamp.
|
|
102
|
+
} from "./local-first/Timestamp.ts";
|
|
100
103
|
export type {
|
|
101
104
|
TimestampBytes,
|
|
102
105
|
TimestampCounterOverflowError,
|
|
103
106
|
TimestampDriftError,
|
|
104
107
|
TimestampError,
|
|
105
108
|
TimestampTimeOutOfRangeError,
|
|
106
|
-
} from "./local-first/Timestamp.
|
|
109
|
+
} from "./local-first/Timestamp.ts";
|