cojson-transport-ws 0.15.8 → 0.15.9

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.
Files changed (39) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +8 -0
  3. package/dist/BatchedOutgoingMessages.d.ts +17 -6
  4. package/dist/BatchedOutgoingMessages.d.ts.map +1 -1
  5. package/dist/BatchedOutgoingMessages.js +77 -14
  6. package/dist/BatchedOutgoingMessages.js.map +1 -1
  7. package/dist/createWebSocketPeer.d.ts +0 -2
  8. package/dist/createWebSocketPeer.d.ts.map +1 -1
  9. package/dist/createWebSocketPeer.js +27 -84
  10. package/dist/createWebSocketPeer.js.map +1 -1
  11. package/dist/tests/createWebSocketPeer.test.js +64 -22
  12. package/dist/tests/createWebSocketPeer.test.js.map +1 -1
  13. package/dist/tests/syncServer.d.ts +1 -0
  14. package/dist/tests/syncServer.d.ts.map +1 -1
  15. package/dist/tests/syncServer.js +1 -0
  16. package/dist/tests/syncServer.js.map +1 -1
  17. package/dist/tests/webSocket.integration.test.d.ts +2 -0
  18. package/dist/tests/webSocket.integration.test.d.ts.map +1 -0
  19. package/dist/tests/{integration.test.js → webSocket.integration.test.js} +28 -2
  20. package/dist/tests/webSocket.integration.test.js.map +1 -0
  21. package/dist/utils.d.ts +8 -0
  22. package/dist/utils.d.ts.map +1 -0
  23. package/dist/utils.js +24 -0
  24. package/dist/utils.js.map +1 -0
  25. package/package.json +2 -2
  26. package/src/BatchedOutgoingMessages.ts +124 -16
  27. package/src/createWebSocketPeer.ts +33 -118
  28. package/src/tests/createWebSocketPeer.test.ts +87 -37
  29. package/src/tests/syncServer.ts +1 -0
  30. package/src/tests/{integration.test.ts → webSocket.integration.test.ts} +37 -2
  31. package/src/utils.ts +30 -0
  32. package/dist/tests/BatchedOutgoingMessages.test.d.ts +0 -2
  33. package/dist/tests/BatchedOutgoingMessages.test.d.ts.map +0 -1
  34. package/dist/tests/BatchedOutgoingMessages.test.js +0 -112
  35. package/dist/tests/BatchedOutgoingMessages.test.js.map +0 -1
  36. package/dist/tests/integration.test.d.ts +0 -2
  37. package/dist/tests/integration.test.d.ts.map +0 -1
  38. package/dist/tests/integration.test.js.map +0 -1
  39. package/src/tests/BatchedOutgoingMessages.test.ts +0 -146
@@ -88,5 +88,6 @@ export const startSyncServer = async (port?: number) => {
88
88
  syncServer,
89
89
  port: actualPort,
90
90
  localNode,
91
+ wss,
91
92
  };
92
93
  };
@@ -1,3 +1,4 @@
1
+ import { assert } from "node:console";
1
2
  import { ControlledAgent, type CryptoProvider, LocalNode } from "cojson";
2
3
  import { WasmCrypto } from "cojson/crypto/WasmCrypto";
3
4
  import { afterEach, beforeEach, describe, expect, test } from "vitest";
@@ -7,7 +8,7 @@ import { startSyncServer } from "./syncServer";
7
8
  import { waitFor } from "./utils";
8
9
 
9
10
  describe("WebSocket Peer Integration", () => {
10
- let server: any;
11
+ let server: Awaited<ReturnType<typeof startSyncServer>>;
11
12
  let syncServerUrl: string;
12
13
  let crypto: CryptoProvider;
13
14
 
@@ -93,7 +94,11 @@ describe("WebSocket Peer Integration", () => {
93
94
  const serverNode = server.localNode;
94
95
  const serverMap = await serverNode.load(map.id);
95
96
 
96
- expect(serverMap.get("testKey")).toBe("testValue");
97
+ if (serverMap === "unavailable") {
98
+ throw new Error("Server map is unavailable");
99
+ }
100
+
101
+ expect(serverMap.get("testKey")?.toString()).toBe("testValue");
97
102
  });
98
103
 
99
104
  test("should handle disconnection and cleanup", async () => {
@@ -161,4 +166,34 @@ describe("WebSocket Peer Integration", () => {
161
166
 
162
167
  expect(ws.readyState).toBe(WebSocket.CLOSED);
163
168
  });
169
+
170
+ test("calling terminate on the server should close the connection", async () => {
171
+ const ws = new WebSocket(syncServerUrl);
172
+ let disconnectCalled = false;
173
+
174
+ createWebSocketPeer({
175
+ id: "test-client",
176
+ websocket: ws,
177
+ role: "server",
178
+ onClose: () => {
179
+ disconnectCalled = true;
180
+ },
181
+ });
182
+
183
+ await waitFor(() => {
184
+ expect(server.wss.clients.size).toBe(1);
185
+ });
186
+
187
+ const peerOnServer = server.localNode.syncManager.getPeers()[0];
188
+
189
+ for (const client of server.wss.clients) {
190
+ client.terminate();
191
+ }
192
+
193
+ await waitFor(() => {
194
+ expect(disconnectCalled).toBe(true);
195
+ });
196
+
197
+ expect(peerOnServer?.closed).toBe(true);
198
+ });
164
199
  });
package/src/utils.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type { AnyWebSocket } from "./types.js";
2
+
3
+ export const BUFFER_LIMIT = 100_000;
4
+ export const BUFFER_LIMIT_POLLING_INTERVAL = 10;
5
+
6
+ export function isWebSocketOpen(websocket: AnyWebSocket) {
7
+ return websocket.readyState === 1;
8
+ }
9
+
10
+ export function hasWebSocketTooMuchBufferedData(websocket: AnyWebSocket) {
11
+ return websocket.bufferedAmount > BUFFER_LIMIT && isWebSocketOpen(websocket);
12
+ }
13
+
14
+ export function waitForWebSocketOpen(websocket: AnyWebSocket) {
15
+ return new Promise<void>((resolve) => {
16
+ if (websocket.readyState === 1) {
17
+ resolve();
18
+ } else {
19
+ websocket.addEventListener("open", () => resolve(), { once: true });
20
+ }
21
+ });
22
+ }
23
+
24
+ export async function waitForWebSocketBufferedAmount(websocket: AnyWebSocket) {
25
+ while (hasWebSocketTooMuchBufferedData(websocket)) {
26
+ await new Promise<void>((resolve) =>
27
+ setTimeout(resolve, BUFFER_LIMIT_POLLING_INTERVAL),
28
+ );
29
+ }
30
+ }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=BatchedOutgoingMessages.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BatchedOutgoingMessages.test.d.ts","sourceRoot":"","sources":["../../src/tests/BatchedOutgoingMessages.test.ts"],"names":[],"mappings":""}
@@ -1,112 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
2
- import { BatchedOutgoingMessages, MAX_OUTGOING_MESSAGES_CHUNK_BYTES, } from "../BatchedOutgoingMessages.js";
3
- beforeEach(() => {
4
- vi.useFakeTimers();
5
- });
6
- afterEach(() => {
7
- vi.useRealTimers();
8
- });
9
- describe("BatchedOutgoingMessages", () => {
10
- function setup() {
11
- const sendMock = vi.fn();
12
- const batchedMessages = new BatchedOutgoingMessages(sendMock);
13
- return { sendMock, batchedMessages };
14
- }
15
- test("should batch messages and send them after a timeout", () => {
16
- const { sendMock, batchedMessages } = setup();
17
- const message1 = {
18
- action: "known",
19
- id: "co_z1",
20
- header: false,
21
- sessions: {},
22
- };
23
- const message2 = {
24
- action: "known",
25
- id: "co_z2",
26
- header: false,
27
- sessions: {},
28
- };
29
- batchedMessages.push(message1);
30
- batchedMessages.push(message2);
31
- expect(sendMock).not.toHaveBeenCalled();
32
- vi.runAllTimers();
33
- expect(sendMock).toHaveBeenCalledTimes(1);
34
- expect(sendMock).toHaveBeenCalledWith(`${JSON.stringify(message1)}\n${JSON.stringify(message2)}`);
35
- });
36
- test("should send messages immediately when reaching MAX_OUTGOING_MESSAGES_CHUNK_BYTES", () => {
37
- const { sendMock, batchedMessages } = setup();
38
- const largeMessage = {
39
- action: "known",
40
- id: "co_z_large",
41
- header: false,
42
- sessions: {
43
- // Add a large payload to exceed MAX_OUTGOING_MESSAGES_CHUNK_BYTES
44
- payload: "x".repeat(MAX_OUTGOING_MESSAGES_CHUNK_BYTES),
45
- },
46
- };
47
- batchedMessages.push(largeMessage);
48
- expect(sendMock).toHaveBeenCalledTimes(1);
49
- expect(sendMock).toHaveBeenCalledWith(JSON.stringify(largeMessage));
50
- });
51
- test("should send accumulated messages before a large message", () => {
52
- const { sendMock, batchedMessages } = setup();
53
- const smallMessage = {
54
- action: "known",
55
- id: "co_z_small",
56
- header: false,
57
- sessions: {},
58
- };
59
- const largeMessage = {
60
- action: "known",
61
- id: "co_z_large",
62
- header: false,
63
- sessions: {
64
- // Add a large payload to exceed MAX_OUTGOING_MESSAGES_CHUNK_BYTES
65
- payload: "x".repeat(MAX_OUTGOING_MESSAGES_CHUNK_BYTES),
66
- },
67
- };
68
- batchedMessages.push(smallMessage);
69
- batchedMessages.push(largeMessage);
70
- vi.runAllTimers();
71
- expect(sendMock).toHaveBeenCalledTimes(2);
72
- expect(sendMock).toHaveBeenNthCalledWith(1, JSON.stringify(smallMessage));
73
- expect(sendMock).toHaveBeenNthCalledWith(2, JSON.stringify(largeMessage));
74
- });
75
- test("should send remaining messages on close", () => {
76
- const { sendMock, batchedMessages } = setup();
77
- const message = {
78
- action: "known",
79
- id: "co_z_test",
80
- header: false,
81
- sessions: {},
82
- };
83
- batchedMessages.push(message);
84
- expect(sendMock).not.toHaveBeenCalled();
85
- batchedMessages.close();
86
- expect(sendMock).toHaveBeenCalledTimes(1);
87
- expect(sendMock).toHaveBeenCalledWith(JSON.stringify(message));
88
- });
89
- test("should clear timeout when pushing new messages", () => {
90
- const { sendMock, batchedMessages } = setup();
91
- const message1 = {
92
- action: "known",
93
- id: "co_z1",
94
- header: false,
95
- sessions: {},
96
- };
97
- const message2 = {
98
- action: "known",
99
- id: "co_z2",
100
- header: false,
101
- sessions: {},
102
- };
103
- batchedMessages.push(message1);
104
- const clearTimeoutSpy = vi.spyOn(global, "clearTimeout");
105
- batchedMessages.push(message2);
106
- expect(clearTimeoutSpy).toHaveBeenCalled();
107
- vi.runAllTimers();
108
- expect(sendMock).toHaveBeenCalledTimes(1);
109
- expect(sendMock).toHaveBeenCalledWith(`${JSON.stringify(message1)}\n${JSON.stringify(message2)}`);
110
- });
111
- });
112
- //# sourceMappingURL=BatchedOutgoingMessages.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BatchedOutgoingMessages.test.js","sourceRoot":"","sources":["../../src/tests/BatchedOutgoingMessages.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=integration.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../../src/tests/integration.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../../src/tests/integration.test.ts"],"names":[],"mappings":"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"}
@@ -1,146 +0,0 @@
1
- import type { SyncMessage } from "cojson";
2
- import type { CojsonInternalTypes } from "cojson";
3
- import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
4
- import {
5
- BatchedOutgoingMessages,
6
- MAX_OUTGOING_MESSAGES_CHUNK_BYTES,
7
- } from "../BatchedOutgoingMessages.js";
8
-
9
- beforeEach(() => {
10
- vi.useFakeTimers();
11
- });
12
-
13
- afterEach(() => {
14
- vi.useRealTimers();
15
- });
16
-
17
- describe("BatchedOutgoingMessages", () => {
18
- function setup() {
19
- const sendMock = vi.fn();
20
- const batchedMessages = new BatchedOutgoingMessages(sendMock);
21
- return { sendMock, batchedMessages };
22
- }
23
-
24
- test("should batch messages and send them after a timeout", () => {
25
- const { sendMock, batchedMessages } = setup();
26
- const message1: SyncMessage = {
27
- action: "known",
28
- id: "co_z1",
29
- header: false,
30
- sessions: {},
31
- };
32
- const message2: SyncMessage = {
33
- action: "known",
34
- id: "co_z2",
35
- header: false,
36
- sessions: {},
37
- };
38
-
39
- batchedMessages.push(message1);
40
- batchedMessages.push(message2);
41
-
42
- expect(sendMock).not.toHaveBeenCalled();
43
-
44
- vi.runAllTimers();
45
-
46
- expect(sendMock).toHaveBeenCalledTimes(1);
47
- expect(sendMock).toHaveBeenCalledWith(
48
- `${JSON.stringify(message1)}\n${JSON.stringify(message2)}`,
49
- );
50
- });
51
-
52
- test("should send messages immediately when reaching MAX_OUTGOING_MESSAGES_CHUNK_BYTES", () => {
53
- const { sendMock, batchedMessages } = setup();
54
- const largeMessage: SyncMessage = {
55
- action: "known",
56
- id: "co_z_large",
57
- header: false,
58
- sessions: {
59
- // Add a large payload to exceed MAX_OUTGOING_MESSAGES_CHUNK_BYTES
60
- payload: "x".repeat(MAX_OUTGOING_MESSAGES_CHUNK_BYTES),
61
- } as CojsonInternalTypes.CoValueKnownState["sessions"],
62
- };
63
-
64
- batchedMessages.push(largeMessage);
65
-
66
- expect(sendMock).toHaveBeenCalledTimes(1);
67
- expect(sendMock).toHaveBeenCalledWith(JSON.stringify(largeMessage));
68
- });
69
-
70
- test("should send accumulated messages before a large message", () => {
71
- const { sendMock, batchedMessages } = setup();
72
- const smallMessage: SyncMessage = {
73
- action: "known",
74
- id: "co_z_small",
75
- header: false,
76
- sessions: {},
77
- };
78
- const largeMessage: SyncMessage = {
79
- action: "known",
80
- id: "co_z_large",
81
- header: false,
82
- sessions: {
83
- // Add a large payload to exceed MAX_OUTGOING_MESSAGES_CHUNK_BYTES
84
- payload: "x".repeat(MAX_OUTGOING_MESSAGES_CHUNK_BYTES),
85
- } as CojsonInternalTypes.CoValueKnownState["sessions"],
86
- };
87
-
88
- batchedMessages.push(smallMessage);
89
- batchedMessages.push(largeMessage);
90
-
91
- vi.runAllTimers();
92
-
93
- expect(sendMock).toHaveBeenCalledTimes(2);
94
- expect(sendMock).toHaveBeenNthCalledWith(1, JSON.stringify(smallMessage));
95
- expect(sendMock).toHaveBeenNthCalledWith(2, JSON.stringify(largeMessage));
96
- });
97
-
98
- test("should send remaining messages on close", () => {
99
- const { sendMock, batchedMessages } = setup();
100
- const message: SyncMessage = {
101
- action: "known",
102
- id: "co_z_test",
103
- header: false,
104
- sessions: {},
105
- };
106
-
107
- batchedMessages.push(message);
108
- expect(sendMock).not.toHaveBeenCalled();
109
-
110
- batchedMessages.close();
111
-
112
- expect(sendMock).toHaveBeenCalledTimes(1);
113
- expect(sendMock).toHaveBeenCalledWith(JSON.stringify(message));
114
- });
115
-
116
- test("should clear timeout when pushing new messages", () => {
117
- const { sendMock, batchedMessages } = setup();
118
- const message1: SyncMessage = {
119
- action: "known",
120
- id: "co_z1",
121
- header: false,
122
- sessions: {},
123
- };
124
- const message2: SyncMessage = {
125
- action: "known",
126
- id: "co_z2",
127
- header: false,
128
- sessions: {},
129
- };
130
-
131
- batchedMessages.push(message1);
132
-
133
- const clearTimeoutSpy = vi.spyOn(global, "clearTimeout");
134
-
135
- batchedMessages.push(message2);
136
-
137
- expect(clearTimeoutSpy).toHaveBeenCalled();
138
-
139
- vi.runAllTimers();
140
-
141
- expect(sendMock).toHaveBeenCalledTimes(1);
142
- expect(sendMock).toHaveBeenCalledWith(
143
- `${JSON.stringify(message1)}\n${JSON.stringify(message2)}`,
144
- );
145
- });
146
- });