@livestore/webmesh 0.4.0-dev.12 → 0.4.0-dev.13

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.
@@ -0,0 +1,62 @@
1
+ import { MessageChannel } from 'node:worker_threads';
2
+ import { Effect, Schema, Stream, WebChannel } from '@livestore/utils/effect';
3
+ import { Vitest } from '@livestore/utils-dev/node-vitest';
4
+ import { expect } from 'vitest';
5
+ // This test encodes a minimal reload/reconnect scenario over a single MessagePort where
6
+ // one leader Pong is dropped exactly at the reload handover window. Today, DevTools
7
+ // observations show a single leader timeout near reload while clientSession pings continue
8
+ // to succeed. We assert the desired correct behavior (no timeout for leader), which currently
9
+ // FAILS, documenting the problem and providing a minimal repro target.
10
+ // NOTE: This test uses WebChannel directly (no Mesh) to isolate transport scheduling from Mesh logic.
11
+ // It simulates handover by deliberately dropping one leader Pong.
12
+ const Ping = Schema.TaggedStruct('Ping', { who: Schema.String, id: Schema.String, t0: Schema.Number });
13
+ const Pong = Schema.TaggedStruct('Pong', { who: Schema.String, id: Schema.String, t0: Schema.Number });
14
+ const Msg = Schema.Union(Ping, Pong);
15
+ const sendPing = (channel, who, timeoutMs) => Effect.gen(function* () {
16
+ const id = Math.random().toString(36).slice(2);
17
+ const wait = channel.listen
18
+ .pipe(Stream.flatten(), Stream.filter(Schema.is(Pong)), Stream.filter((m) => m.id === id), Stream.runHead)
19
+ .pipe(Effect.asVoid);
20
+ yield* channel.send(Ping.make({ who, id, t0: Date.now() }));
21
+ const res = yield* wait
22
+ .pipe(Effect.timeout(timeoutMs), Effect.as('ok'), Effect.catchTag('TimeoutException', () => Effect.succeed('timeout')));
23
+ return res;
24
+ });
25
+ Vitest.scopedLive('reload handover: leader ping should not timeout (currently fails)', (test) => Effect.gen(function* () {
26
+ // Timings tuned to force a single leader miss at handover
27
+ const RELOAD_AT_MS = 300;
28
+ const DROP_WINDOW_MS = 80;
29
+ const LEADER_TIMEOUT_MS = 50;
30
+ const CLIENT_TIMEOUT_MS = 400;
31
+ const mc = new MessageChannel();
32
+ const a = yield* WebChannel.messagePortChannel({ port: mc.port1, schema: Msg });
33
+ const b = yield* WebChannel.messagePortChannel({ port: mc.port2, schema: Msg });
34
+ const t0 = Date.now();
35
+ let dropLeaderNext = false;
36
+ // A: responder drop exactly one leader Pong after reload starts
37
+ yield* a.listen
38
+ .pipe(Stream.flatten(), Stream.tap((m) => Effect.gen(function* () {
39
+ if (Schema.is(Ping)(m)) {
40
+ const now = Date.now();
41
+ if (m.who === 'leader' && dropLeaderNext) {
42
+ // Simulate handover gap: drop one leader Pong
43
+ // This models the observed single leader timeout after reload.
44
+ dropLeaderNext = false;
45
+ }
46
+ else {
47
+ yield* a.send(Pong.make({ who: m.who, id: m.id, t0: m.t0 }));
48
+ }
49
+ }
50
+ })), Stream.runDrain, Effect.forkScoped);
51
+ // Schedule reload marker, then leader ping (tight timeout) and client ping (looser timeout)
52
+ yield* Effect.sleep(RELOAD_AT_MS);
53
+ dropLeaderNext = true;
54
+ const leaderRes = yield* sendPing(b, 'leader', LEADER_TIMEOUT_MS);
55
+ const clientRes = yield* sendPing(b, 'clientSession', CLIENT_TIMEOUT_MS);
56
+ // Desired behavior: leader should not timeout across reload handover
57
+ // Current behavior: times out once → This assertion will FAIL, documenting the issue.
58
+ expect(leaderRes).toBe('ok');
59
+ // Client should remain healthy
60
+ expect(clientRes).toBe('ok');
61
+ }).pipe(Vitest.withTestCtx(test)));
62
+ //# sourceMappingURL=reload-reconnect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reload-reconnect.test.js","sourceRoot":"","sources":["../src/reload-reconnect.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livestore/webmesh",
3
- "version": "0.4.0-dev.12",
3
+ "version": "0.4.0-dev.13",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "exports": {
@@ -8,11 +8,11 @@
8
8
  "./websocket-server": "./dist/websocket-server.js"
9
9
  },
10
10
  "dependencies": {
11
- "@livestore/utils": "0.4.0-dev.12"
11
+ "@livestore/utils": "0.4.0-dev.13"
12
12
  },
13
13
  "devDependencies": {
14
14
  "vitest": "3.2.4",
15
- "@livestore/utils-dev": "0.4.0-dev.12"
15
+ "@livestore/utils-dev": "0.4.0-dev.13"
16
16
  },
17
17
  "files": [
18
18
  "package.json",