@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/dist/src/Worker.js
CHANGED
|
@@ -1,9 +1,61 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Typed, disposable worker and messaging primitives.
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
7
|
+
if (value !== null && value !== void 0) {
|
|
8
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
9
|
+
var dispose, inner;
|
|
10
|
+
if (async) {
|
|
11
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
12
|
+
dispose = value[Symbol.asyncDispose];
|
|
13
|
+
}
|
|
14
|
+
if (dispose === void 0) {
|
|
15
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
16
|
+
dispose = value[Symbol.dispose];
|
|
17
|
+
if (async) inner = dispose;
|
|
18
|
+
}
|
|
19
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
20
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
21
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
22
|
+
}
|
|
23
|
+
else if (async) {
|
|
24
|
+
env.stack.push({ async: true });
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
};
|
|
28
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
29
|
+
return function (env) {
|
|
30
|
+
function fail(e) {
|
|
31
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
32
|
+
env.hasError = true;
|
|
33
|
+
}
|
|
34
|
+
var r, s = 0;
|
|
35
|
+
function next() {
|
|
36
|
+
while (r = env.stack.pop()) {
|
|
37
|
+
try {
|
|
38
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
39
|
+
if (r.dispose) {
|
|
40
|
+
var result = r.dispose.call(r.value);
|
|
41
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
42
|
+
}
|
|
43
|
+
else s |= 1;
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
fail(e);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
50
|
+
if (env.hasError) throw env.error;
|
|
51
|
+
}
|
|
52
|
+
return next();
|
|
53
|
+
};
|
|
54
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
55
|
+
var e = new Error(message);
|
|
56
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
57
|
+
});
|
|
58
|
+
import { assert, assertNotDisposed } from "./Assert.js";
|
|
7
59
|
import { testWaitForMacrotask } from "./Test.js";
|
|
8
60
|
/**
|
|
9
61
|
* Creates an in-memory {@link Worker}.
|
|
@@ -38,30 +90,55 @@ export const createSharedWorker = (initWorker) => {
|
|
|
38
90
|
* support. Message delivery is asynchronous in-process.
|
|
39
91
|
*/
|
|
40
92
|
export const createMessageChannel = () => {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
93
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
94
|
+
try {
|
|
95
|
+
const state1 = {
|
|
96
|
+
handler: null,
|
|
97
|
+
queue: [],
|
|
98
|
+
flushScheduled: false,
|
|
99
|
+
flushTimeoutId: null,
|
|
100
|
+
ownerCount: 0,
|
|
101
|
+
pendingTransferCount: 0,
|
|
102
|
+
};
|
|
103
|
+
const state2 = {
|
|
104
|
+
handler: null,
|
|
105
|
+
queue: [],
|
|
106
|
+
flushScheduled: false,
|
|
107
|
+
flushTimeoutId: null,
|
|
108
|
+
ownerCount: 0,
|
|
109
|
+
pendingTransferCount: 0,
|
|
110
|
+
};
|
|
111
|
+
const native1 = createNativeMessagePortToken();
|
|
112
|
+
const native2 = createNativeMessagePortToken();
|
|
113
|
+
const port1Registration = {
|
|
114
|
+
receive: state1,
|
|
115
|
+
peerReceive: state2,
|
|
116
|
+
native: native1,
|
|
117
|
+
};
|
|
118
|
+
const port2Registration = {
|
|
119
|
+
receive: state2,
|
|
120
|
+
peerReceive: state1,
|
|
121
|
+
native: native2,
|
|
122
|
+
};
|
|
123
|
+
const disposer = __addDisposableResource(env_1, new DisposableStack(), false);
|
|
124
|
+
const port1 = disposer.use(createTestPort(port1Registration));
|
|
125
|
+
const port2 = disposer.use(createTestPort(port2Registration));
|
|
126
|
+
const disposables = disposer.move();
|
|
127
|
+
nativePortRegistry.set(native1, port1Registration);
|
|
128
|
+
nativePortRegistry.set(native2, port2Registration);
|
|
129
|
+
return {
|
|
130
|
+
port1,
|
|
131
|
+
port2,
|
|
132
|
+
[Symbol.dispose]: () => disposables.dispose(),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
catch (e_1) {
|
|
136
|
+
env_1.error = e_1;
|
|
137
|
+
env_1.hasError = true;
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
__disposeResources(env_1);
|
|
141
|
+
}
|
|
65
142
|
};
|
|
66
143
|
/**
|
|
67
144
|
* Creates an in-memory {@link MessagePort} from a native token.
|
|
@@ -70,10 +147,72 @@ export const createMessageChannel = () => {
|
|
|
70
147
|
* support. Message delivery through returned ports is asynchronous in-process.
|
|
71
148
|
*/
|
|
72
149
|
export const createMessagePort = (nativePort) => {
|
|
73
|
-
const
|
|
74
|
-
assert(
|
|
75
|
-
return
|
|
150
|
+
const registration = nativePortRegistry.get(nativePort);
|
|
151
|
+
assert(registration, "Unknown native port — did you transfer it?");
|
|
152
|
+
return createTestPort(registration);
|
|
76
153
|
};
|
|
154
|
+
/**
|
|
155
|
+
* Creates an in-memory {@link BroadcastChannel}.
|
|
156
|
+
*
|
|
157
|
+
* This is a memory-only fallback for platforms without native BroadcastChannel
|
|
158
|
+
* support. Message delivery is asynchronous in-process.
|
|
159
|
+
*/
|
|
160
|
+
export const createBroadcastChannel = (name) => {
|
|
161
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
162
|
+
try {
|
|
163
|
+
let onMessageHandler = null;
|
|
164
|
+
const dispatch = (message) => {
|
|
165
|
+
onMessageHandler?.(message);
|
|
166
|
+
};
|
|
167
|
+
let dispatches = broadcastChannelDispatchesByName.get(name);
|
|
168
|
+
if (!dispatches) {
|
|
169
|
+
dispatches = new Set();
|
|
170
|
+
broadcastChannelDispatchesByName.set(name, dispatches);
|
|
171
|
+
}
|
|
172
|
+
dispatches.add(dispatch);
|
|
173
|
+
const disposer = __addDisposableResource(env_2, new DisposableStack(), false);
|
|
174
|
+
disposer.defer(() => {
|
|
175
|
+
onMessageHandler = null;
|
|
176
|
+
dispatches.delete(dispatch);
|
|
177
|
+
if (dispatches.size === 0)
|
|
178
|
+
broadcastChannelDispatchesByName.delete(name);
|
|
179
|
+
});
|
|
180
|
+
const disposables = disposer.move();
|
|
181
|
+
return {
|
|
182
|
+
postMessage: (message) => {
|
|
183
|
+
assertNotDisposed(disposables);
|
|
184
|
+
const dispatches = broadcastChannelDispatchesByName.get(name);
|
|
185
|
+
assert(dispatches, "Expected broadcast channel dispatches");
|
|
186
|
+
for (const otherDispatch of [...dispatches]) {
|
|
187
|
+
if (otherDispatch === dispatch)
|
|
188
|
+
continue;
|
|
189
|
+
globalThis.setTimeout(() => {
|
|
190
|
+
if (!dispatches.has(otherDispatch))
|
|
191
|
+
return;
|
|
192
|
+
otherDispatch(message);
|
|
193
|
+
}, 0);
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
get onMessage() {
|
|
197
|
+
return disposables.disposed ? null : onMessageHandler;
|
|
198
|
+
},
|
|
199
|
+
set onMessage(fn) {
|
|
200
|
+
if (disposables.disposed)
|
|
201
|
+
return;
|
|
202
|
+
onMessageHandler = fn;
|
|
203
|
+
},
|
|
204
|
+
[Symbol.dispose]: () => disposables.dispose(),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
catch (e_2) {
|
|
208
|
+
env_2.error = e_2;
|
|
209
|
+
env_2.hasError = true;
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
__disposeResources(env_2);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const broadcastChannelDispatchesByName = new Map();
|
|
77
216
|
/**
|
|
78
217
|
* Creates a connected {@link TestWorker} for testing.
|
|
79
218
|
*
|
|
@@ -110,25 +249,62 @@ export const testCreateSharedWorker = () => {
|
|
|
110
249
|
* {@link testCreateMessagePort} can look them up by their native token.
|
|
111
250
|
*/
|
|
112
251
|
export const testCreateMessageChannel = () => {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
252
|
+
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
253
|
+
try {
|
|
254
|
+
const disposer = __addDisposableResource(env_3, new DisposableStack(), false);
|
|
255
|
+
const channel = disposer.use(createMessageChannel());
|
|
256
|
+
const disposables = disposer.move();
|
|
257
|
+
return {
|
|
258
|
+
port1: channel.port1,
|
|
259
|
+
port2: channel.port2,
|
|
260
|
+
isDisposed: () => disposables.disposed,
|
|
261
|
+
[Symbol.dispose]: () => disposables.dispose(),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
catch (e_3) {
|
|
265
|
+
env_3.error = e_3;
|
|
266
|
+
env_3.hasError = true;
|
|
267
|
+
}
|
|
268
|
+
finally {
|
|
269
|
+
__disposeResources(env_3);
|
|
270
|
+
}
|
|
124
271
|
};
|
|
125
272
|
/** Creates an in-memory {@link CreateMessagePort} for testing. */
|
|
126
273
|
export const testCreateMessagePort = (nativePort) => createMessagePort(nativePort);
|
|
274
|
+
/** Creates an in-memory {@link BroadcastChannel} for testing. */
|
|
275
|
+
export const testCreateBroadcastChannel = (name) => {
|
|
276
|
+
const env_4 = { stack: [], error: void 0, hasError: false };
|
|
277
|
+
try {
|
|
278
|
+
const disposer = __addDisposableResource(env_4, new DisposableStack(), false);
|
|
279
|
+
const channel = disposer.use(createBroadcastChannel(name));
|
|
280
|
+
const disposables = disposer.move();
|
|
281
|
+
return {
|
|
282
|
+
postMessage: channel.postMessage,
|
|
283
|
+
get onMessage() {
|
|
284
|
+
return channel.onMessage;
|
|
285
|
+
},
|
|
286
|
+
set onMessage(value) {
|
|
287
|
+
channel.onMessage = value;
|
|
288
|
+
},
|
|
289
|
+
isDisposed: () => disposables.disposed,
|
|
290
|
+
[Symbol.dispose]: () => disposables.dispose(),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
catch (e_4) {
|
|
294
|
+
env_4.error = e_4;
|
|
295
|
+
env_4.hasError = true;
|
|
296
|
+
}
|
|
297
|
+
finally {
|
|
298
|
+
__disposeResources(env_4);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
127
301
|
/**
|
|
128
|
-
* Waits
|
|
302
|
+
* Waits the minimal time necessary for in-memory worker message delivery in
|
|
303
|
+
* tests.
|
|
129
304
|
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
305
|
+
* This is better than `vi.waitFor` when a test only needs to flush the known
|
|
306
|
+
* in-memory worker/message-port pipeline. It encodes that transport boundary
|
|
307
|
+
* once, avoids polling, and keeps worker-focused tests fast and explicit.
|
|
132
308
|
*/
|
|
133
309
|
export const testWaitForWorkerMessage = async () => {
|
|
134
310
|
await testWaitForMacrotask();
|
|
@@ -184,43 +360,90 @@ const createMemorySharedWorkerPair = () => {
|
|
|
184
360
|
};
|
|
185
361
|
return { worker, self, connect };
|
|
186
362
|
};
|
|
187
|
-
const createPort = (receive, peerReceive, native) => {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
363
|
+
const createPort = ({ receive, peerReceive, native, }) => {
|
|
364
|
+
const env_5 = { stack: [], error: void 0, hasError: false };
|
|
365
|
+
try {
|
|
366
|
+
const disposer = __addDisposableResource(env_5, new DisposableStack(), false);
|
|
367
|
+
if (receive.pendingTransferCount > 0)
|
|
368
|
+
receive.pendingTransferCount -= 1;
|
|
369
|
+
else
|
|
370
|
+
receive.ownerCount += 1;
|
|
371
|
+
disposer.defer(() => {
|
|
372
|
+
receive.ownerCount -= 1;
|
|
373
|
+
if (receive.ownerCount > 0)
|
|
197
374
|
return;
|
|
198
|
-
|
|
199
|
-
|
|
375
|
+
nativePortRegistry.delete(native);
|
|
376
|
+
if (receive.flushTimeoutId != null) {
|
|
377
|
+
globalThis.clearTimeout(receive.flushTimeoutId);
|
|
378
|
+
receive.flushTimeoutId = null;
|
|
200
379
|
}
|
|
201
|
-
}, 0);
|
|
202
|
-
};
|
|
203
|
-
return {
|
|
204
|
-
postMessage: (message) => {
|
|
205
|
-
peerReceive.queue.push(message);
|
|
206
|
-
scheduleFlush(peerReceive);
|
|
207
|
-
},
|
|
208
|
-
get onMessage() {
|
|
209
|
-
return receive.handler;
|
|
210
|
-
},
|
|
211
|
-
set onMessage(fn) {
|
|
212
|
-
receive.handler = fn;
|
|
213
|
-
if (fn)
|
|
214
|
-
scheduleFlush(receive);
|
|
215
|
-
},
|
|
216
|
-
native,
|
|
217
|
-
[Symbol.dispose]: () => {
|
|
218
380
|
receive.handler = null;
|
|
219
381
|
receive.flushScheduled = false;
|
|
220
|
-
|
|
221
|
-
|
|
382
|
+
receive.queue.length = 0;
|
|
383
|
+
});
|
|
384
|
+
const disposables = disposer.move();
|
|
385
|
+
const scheduleFlush = (state) => {
|
|
386
|
+
if (state.flushScheduled || state.ownerCount === 0)
|
|
387
|
+
return;
|
|
388
|
+
state.flushScheduled = true;
|
|
389
|
+
// Native worker messages are task-queued; use macrotask timing.
|
|
390
|
+
state.flushTimeoutId = globalThis.setTimeout(() => {
|
|
391
|
+
state.flushTimeoutId = null;
|
|
392
|
+
state.flushScheduled = false;
|
|
393
|
+
if (state.ownerCount === 0)
|
|
394
|
+
return;
|
|
395
|
+
const firstHandler = state.handler;
|
|
396
|
+
if (!firstHandler)
|
|
397
|
+
return;
|
|
398
|
+
for (const message of state.queue.splice(0)) {
|
|
399
|
+
const handler = state.handler;
|
|
400
|
+
if (!handler)
|
|
401
|
+
return;
|
|
402
|
+
handler(message);
|
|
403
|
+
}
|
|
404
|
+
}, 0);
|
|
405
|
+
};
|
|
406
|
+
return {
|
|
407
|
+
postMessage: (message, transfer) => {
|
|
408
|
+
if (disposables.disposed ||
|
|
409
|
+
receive.ownerCount === 0 ||
|
|
410
|
+
peerReceive.ownerCount === 0)
|
|
411
|
+
return;
|
|
412
|
+
for (const transferable of transfer ?? []) {
|
|
413
|
+
if (transferable instanceof globalThis.ArrayBuffer)
|
|
414
|
+
continue;
|
|
415
|
+
const registration = nativePortRegistry.get(transferable);
|
|
416
|
+
if (!registration)
|
|
417
|
+
continue;
|
|
418
|
+
registration.receive.ownerCount += 1;
|
|
419
|
+
registration.receive.pendingTransferCount += 1;
|
|
420
|
+
}
|
|
421
|
+
peerReceive.queue.push(message);
|
|
422
|
+
scheduleFlush(peerReceive);
|
|
423
|
+
},
|
|
424
|
+
get onMessage() {
|
|
425
|
+
return disposables.disposed ? null : receive.handler;
|
|
426
|
+
},
|
|
427
|
+
set onMessage(fn) {
|
|
428
|
+
if (disposables.disposed || receive.ownerCount === 0)
|
|
429
|
+
return;
|
|
430
|
+
receive.handler = fn;
|
|
431
|
+
if (fn)
|
|
432
|
+
scheduleFlush(receive);
|
|
433
|
+
},
|
|
434
|
+
native,
|
|
435
|
+
[Symbol.dispose]: () => disposables.dispose(),
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
catch (e_5) {
|
|
439
|
+
env_5.error = e_5;
|
|
440
|
+
env_5.hasError = true;
|
|
441
|
+
}
|
|
442
|
+
finally {
|
|
443
|
+
__disposeResources(env_5);
|
|
444
|
+
}
|
|
222
445
|
};
|
|
223
|
-
const createTestPort = (
|
|
446
|
+
const createTestPort = (registration) => createPort(registration);
|
|
224
447
|
const createNativeMessagePortToken = () => ({});
|
|
225
448
|
/**
|
|
226
449
|
* Registry mapping native port tokens to their in-memory port counterparts.
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAG5B,YAAY,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EACV,YAAY,EACZ,KAAK,EACL,WAAW,EACX,SAAS,EACT,UAAU,GACX,MAAM,wBAAwB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,EACT,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,GAAG,GACT,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,cAAc,EACd,yBAAyB,EACzB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAIV,SAAS,GACV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,SAAS,EACT,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,cAAc,EACd,6BAA6B,EAC7B,mBAAmB,EACnB,cAAc,EACd,4BAA4B,GAC7B,MAAM,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAG5B,YAAY,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EACV,YAAY,EACZ,KAAK,EACL,WAAW,EACX,SAAS,EACT,UAAU,GACX,MAAM,wBAAwB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,EACT,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,GAAG,GACT,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,cAAc,EACd,yBAAyB,EACzB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAIV,SAAS,GACV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,SAAS,EACT,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,cAAc,EACd,6BAA6B,EAC7B,mBAAmB,EACnB,cAAc,EACd,4BAA4B,GAC7B,MAAM,4BAA4B,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { ConsoleLevel } from "../Console.js";
|
|
7
7
|
import { EncryptionKey } from "../Crypto.js";
|
|
8
|
+
import type { LockManagerDep } from "../LockManager.js";
|
|
8
9
|
import type { CreateSqliteDriverDep, SqliteSchema } from "../Sqlite.js";
|
|
9
|
-
import { type
|
|
10
|
+
import { type Task } from "../Task.js";
|
|
10
11
|
import type { Name } from "../Type.js";
|
|
11
|
-
import type { NativeMessagePort, Worker, WorkerDeps, WorkerSelf } from "../Worker.js";
|
|
12
|
+
import type { CreateBroadcastChannelDep, NativeMessagePort, Worker, WorkerDeps, WorkerSelf } from "../Worker.js";
|
|
12
13
|
import type { DbWorkerInput, DbWorkerOutput } from "./Shared.js";
|
|
13
14
|
export type DbWorker = Worker<DbWorkerInit>;
|
|
14
15
|
export interface DbWorkerInit {
|
|
15
|
-
readonly type: "
|
|
16
|
+
readonly type: "DbWorkerInit";
|
|
16
17
|
readonly name: Name;
|
|
17
18
|
readonly consoleLevel: ConsoleLevel;
|
|
18
19
|
readonly sqliteSchema: SqliteSchema;
|
|
@@ -24,6 +25,6 @@ export type CreateDbWorker = () => DbWorker;
|
|
|
24
25
|
export interface CreateDbWorkerDep {
|
|
25
26
|
readonly createDbWorker: CreateDbWorker;
|
|
26
27
|
}
|
|
27
|
-
export type DbWorkerDeps = WorkerDeps &
|
|
28
|
+
export type DbWorkerDeps = WorkerDeps & CreateBroadcastChannelDep & LockManagerDep & CreateSqliteDriverDep;
|
|
28
29
|
export declare const startDbWorker: (self: WorkerSelf<DbWorkerInit>) => Task<void, never, DbWorkerDeps>;
|
|
29
30
|
//# sourceMappingURL=Db.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../../src/local-first/Db.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EACL,aAAa,EAGd,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../../src/local-first/Db.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EACL,aAAa,EAGd,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIxD,OAAO,KAAK,EACV,qBAAqB,EAGrB,YAAY,EACb,MAAM,cAAc,CAAC;AAUtB,OAAO,EAAY,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AASvC,OAAO,KAAK,EACV,yBAAyB,EACzB,iBAAiB,EACjB,MAAM,EACN,UAAU,EACV,UAAU,EACX,MAAM,cAAc,CAAC;AAqBtB,OAAO,KAAK,EAEV,aAAa,EACb,cAAc,EAGf,MAAM,aAAa,CAAC;AA+BrB,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAE5C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;CACjE;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;CACzC;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,GACnC,yBAAyB,GACzB,cAAc,GACd,qBAAqB,CAAC;AAExB,eAAO,MAAM,aAAa,GACvB,MAAM,UAAU,CAAC,YAAY,CAAC,KAAG,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CA8O/D,CAAC"}
|
|
@@ -59,6 +59,7 @@ import { appendToArray, firstInArray, } from "../Array.js";
|
|
|
59
59
|
import { assert, assertNonEmptyReadonlyArray, assertType } from "../Assert.js";
|
|
60
60
|
import { EncryptionKey, } from "../Crypto.js";
|
|
61
61
|
import { exhaustiveCheck, lazyFalse, lazyVoid } from "../Function.js";
|
|
62
|
+
import { acquireLeaderLock } from "../LockManager.js";
|
|
62
63
|
import { createRecord, getProperty, objectToEntries } from "../Object.js";
|
|
63
64
|
import { ok } from "../Result.js";
|
|
64
65
|
import { booleanToSqliteBoolean, createSqlite, sql, SqliteBoolean, sqliteBooleanToBoolean, sqliteQueryStringToSqliteQuery, SqliteValue, } from "../Sqlite.js";
|
|
@@ -68,16 +69,18 @@ import { Id, IdBytes, idBytesToId, idToIdBytes, onePositiveInt, } from "../Type.
|
|
|
68
69
|
import { ownerIdBytesToOwnerId, ownerIdToOwnerIdBytes } from "./Owner.js";
|
|
69
70
|
import { applyProtocolMessageAsClient, createProtocolMessageForSync, decryptAndDecodeDbChange, encodeAndEncryptDbChange, protocolVersion, SubscriptionFlags, } from "./Protocol.js";
|
|
70
71
|
import { ensureSqliteSchema, getEvoluSqliteSchema, systemColumns, } from "./Schema.js";
|
|
72
|
+
import { consoleEntryOrErrorBroadcastChannelName } from "./Shared.js";
|
|
71
73
|
import { createBaseSqliteStorage, createBaseSqliteStorageTables, DbChange, getTimestampInsertStrategy, readOwnerUsageOrDefault, updateOwnerUsage, } from "./Storage.js";
|
|
72
74
|
import { createInitialTimestamp, defaultTimestampMaxDrift, receiveTimestamp, sendTimestamp, TimestampBytes, timestampBytesToTimestamp, timestampToTimestampBytes, } from "./Timestamp.js";
|
|
73
|
-
export const startDbWorker = (self) => async (
|
|
75
|
+
export const startDbWorker = (self) => async (run) => {
|
|
74
76
|
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
75
77
|
try {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
const
|
|
78
|
+
const disposer = __addDisposableResource(env_1, new AsyncDisposableStack(), true);
|
|
79
|
+
disposer.use(self);
|
|
80
|
+
const dbWorkerRun = disposer.use(run.create());
|
|
81
|
+
const { deps } = dbWorkerRun;
|
|
79
82
|
let initialized = false;
|
|
80
|
-
const initMessage = await
|
|
83
|
+
const initMessage = await dbWorkerRun.orThrow(callback(({ ok }) => {
|
|
81
84
|
self.onMessage = (message) => {
|
|
82
85
|
assert(!initialized, "DbWorker must be initialized only once");
|
|
83
86
|
initialized = true;
|
|
@@ -86,24 +89,29 @@ export const startDbWorker = (self) => async (_run) => {
|
|
|
86
89
|
}));
|
|
87
90
|
const console = deps.console.child(initMessage.name).child("DbWorker");
|
|
88
91
|
console.setLevel(initMessage.consoleLevel);
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
+
const port = disposer.use(deps.createMessagePort(initMessage.port));
|
|
93
|
+
const consoleEntryOrErrorBroadcastChannel = disposer.use(deps.createBroadcastChannel(consoleEntryOrErrorBroadcastChannelName));
|
|
94
|
+
disposer.defer(deps.consoleStoreOutputEntry.subscribe(() => {
|
|
92
95
|
const entry = deps.consoleStoreOutputEntry.get();
|
|
93
96
|
if (entry)
|
|
94
|
-
|
|
97
|
+
consoleEntryOrErrorBroadcastChannel.postMessage({
|
|
98
|
+
type: "ConsoleEntry",
|
|
99
|
+
entry,
|
|
100
|
+
});
|
|
95
101
|
}));
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return ok();
|
|
102
|
+
console.debug("createDbWorker");
|
|
103
|
+
disposer.use(await dbWorkerRun.orThrow(acquireLeaderLock(initMessage.name)));
|
|
99
104
|
port.postMessage({ type: "LeaderAcquired", name: initMessage.name });
|
|
100
|
-
const sqlite =
|
|
105
|
+
const sqlite = disposer.use(await dbWorkerRun.orThrow(createSqlite(initMessage.name, initMessage.memoryOnly
|
|
101
106
|
? { mode: "memory" }
|
|
102
107
|
: { mode: "encrypted", encryptionKey: initMessage.encryptionKey })));
|
|
103
108
|
console.debug("SQLite created");
|
|
104
|
-
const baseSqliteStorage = createBaseSqliteStorage({
|
|
109
|
+
const baseSqliteStorage = createBaseSqliteStorage({
|
|
110
|
+
sqlite,
|
|
111
|
+
...dbWorkerRun.deps,
|
|
112
|
+
});
|
|
105
113
|
const dbDeps = {
|
|
106
|
-
...
|
|
114
|
+
...dbWorkerRun.deps,
|
|
107
115
|
sqlite,
|
|
108
116
|
sqliteSchema: initMessage.sqliteSchema,
|
|
109
117
|
baseSqliteStorage,
|
|
@@ -120,27 +128,22 @@ export const startDbWorker = (self) => async (_run) => {
|
|
|
120
128
|
});
|
|
121
129
|
const storage = createClientStorage({ ...dbDeps, clock })({
|
|
122
130
|
onError: (error) => {
|
|
123
|
-
|
|
131
|
+
consoleEntryOrErrorBroadcastChannel.postMessage({
|
|
132
|
+
type: "Error",
|
|
133
|
+
error,
|
|
134
|
+
});
|
|
124
135
|
},
|
|
125
136
|
});
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
* The Set intentionally lives for one leader's lifetime. If that leader tab
|
|
134
|
-
* closes, retries go to a new leader with a fresh Set. Revisit this only if
|
|
135
|
-
* memory pressure shows up; even millions of short callback IDs are
|
|
136
|
-
* acceptable here, and naive eviction could let a still-retried request run
|
|
137
|
-
* again.
|
|
138
|
-
*/
|
|
139
|
-
const processedRequestIds = new Set();
|
|
140
|
-
port.onMessage = ({ callbackId, request }) => {
|
|
141
|
-
if (processedRequestIds.has(callbackId))
|
|
137
|
+
const disposables = disposer.move();
|
|
138
|
+
const dbWorkerRunWithStorage = dbWorkerRun.addDeps({ storage });
|
|
139
|
+
port.onMessage = (input) => {
|
|
140
|
+
if (input.type === "Dispose") {
|
|
141
|
+
if (!disposables.disposed)
|
|
142
|
+
console.debug("disposeDbWorker");
|
|
143
|
+
void disposables.disposeAsync();
|
|
142
144
|
return;
|
|
143
|
-
|
|
145
|
+
}
|
|
146
|
+
const { callbackId, request } = input;
|
|
144
147
|
const postQueuedResponse = (response) => {
|
|
145
148
|
port.postMessage({ type: "OnQueuedResponse", callbackId, response }, response.type === "ForEvolu" && response.message.type === "Export"
|
|
146
149
|
? [response.message.file.buffer]
|
|
@@ -152,12 +155,15 @@ export const startDbWorker = (self) => async (_run) => {
|
|
|
152
155
|
case "Mutate": {
|
|
153
156
|
const result = handleMutation({ ...dbDeps, clock })(request.message);
|
|
154
157
|
if (!result.ok) {
|
|
155
|
-
|
|
158
|
+
consoleEntryOrErrorBroadcastChannel.postMessage({
|
|
159
|
+
type: "Error",
|
|
160
|
+
error: result.error,
|
|
161
|
+
});
|
|
156
162
|
}
|
|
157
163
|
else {
|
|
158
164
|
postQueuedResponse({
|
|
159
165
|
type: "ForEvolu",
|
|
160
|
-
|
|
166
|
+
id: request.id,
|
|
161
167
|
message: result.value,
|
|
162
168
|
});
|
|
163
169
|
}
|
|
@@ -166,7 +172,7 @@ export const startDbWorker = (self) => async (_run) => {
|
|
|
166
172
|
case "Query":
|
|
167
173
|
postQueuedResponse({
|
|
168
174
|
type: "ForEvolu",
|
|
169
|
-
|
|
175
|
+
id: request.id,
|
|
170
176
|
message: {
|
|
171
177
|
type: "Query",
|
|
172
178
|
rowsByQuery: loadQueries(dbDeps)(request.message.queries),
|
|
@@ -176,7 +182,7 @@ export const startDbWorker = (self) => async (_run) => {
|
|
|
176
182
|
case "Export":
|
|
177
183
|
postQueuedResponse({
|
|
178
184
|
type: "ForEvolu",
|
|
179
|
-
|
|
185
|
+
id: request.id,
|
|
180
186
|
message: {
|
|
181
187
|
type: "Export",
|
|
182
188
|
file: dbDeps.sqlite.export(),
|
|
@@ -211,7 +217,7 @@ export const startDbWorker = (self) => async (_run) => {
|
|
|
211
217
|
}
|
|
212
218
|
case "ApplySyncMessage": {
|
|
213
219
|
const { owner, inputMessage } = request.message;
|
|
214
|
-
|
|
220
|
+
dbWorkerRunWithStorage(async (run) => {
|
|
215
221
|
storage.setRequestContext(owner.encryptionKey);
|
|
216
222
|
const result = await run(applyProtocolMessageAsClient(inputMessage, {
|
|
217
223
|
writeKey: owner.writeKey,
|