@voidhash/mimic-effect 1.0.0-beta.16 → 1.0.0-beta.18

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 (99) hide show
  1. package/dist/ColdStorage.cjs +1 -1
  2. package/dist/ColdStorage.d.cts +2 -2
  3. package/dist/ColdStorage.d.cts.map +1 -1
  4. package/dist/ColdStorage.d.mts +2 -2
  5. package/dist/ColdStorage.d.mts.map +1 -1
  6. package/dist/ColdStorage.mjs +2 -2
  7. package/dist/ColdStorage.mjs.map +1 -1
  8. package/dist/DocumentInstance.cjs +13 -13
  9. package/dist/DocumentInstance.mjs +13 -13
  10. package/dist/DocumentInstance.mjs.map +1 -1
  11. package/dist/Errors.d.cts +8 -8
  12. package/dist/Errors.d.cts.map +1 -1
  13. package/dist/Errors.d.mts +8 -8
  14. package/dist/Errors.d.mts.map +1 -1
  15. package/dist/HotStorage.cjs +1 -1
  16. package/dist/HotStorage.d.cts +2 -2
  17. package/dist/HotStorage.d.mts +2 -2
  18. package/dist/HotStorage.mjs +2 -2
  19. package/dist/HotStorage.mjs.map +1 -1
  20. package/dist/Metrics.cjs +6 -6
  21. package/dist/Metrics.d.cts +21 -23
  22. package/dist/Metrics.d.cts.map +1 -1
  23. package/dist/Metrics.d.mts +21 -23
  24. package/dist/Metrics.d.mts.map +1 -1
  25. package/dist/Metrics.mjs +7 -7
  26. package/dist/Metrics.mjs.map +1 -1
  27. package/dist/MimicAuthService.cjs +1 -1
  28. package/dist/MimicAuthService.d.cts +2 -2
  29. package/dist/MimicAuthService.d.cts.map +1 -1
  30. package/dist/MimicAuthService.d.mts +2 -2
  31. package/dist/MimicAuthService.d.mts.map +1 -1
  32. package/dist/MimicAuthService.mjs +2 -2
  33. package/dist/MimicAuthService.mjs.map +1 -1
  34. package/dist/MimicClusterServerEngine.cjs +38 -41
  35. package/dist/MimicClusterServerEngine.d.cts +1 -1
  36. package/dist/MimicClusterServerEngine.d.mts +1 -1
  37. package/dist/MimicClusterServerEngine.mjs +31 -34
  38. package/dist/MimicClusterServerEngine.mjs.map +1 -1
  39. package/dist/MimicServer.cjs +23 -23
  40. package/dist/MimicServer.d.cts +3 -3
  41. package/dist/MimicServer.d.cts.map +1 -1
  42. package/dist/MimicServer.d.mts +3 -3
  43. package/dist/MimicServer.d.mts.map +1 -1
  44. package/dist/MimicServer.mjs +22 -22
  45. package/dist/MimicServer.mjs.map +1 -1
  46. package/dist/MimicServerEngine.cjs +13 -13
  47. package/dist/MimicServerEngine.d.cts +2 -2
  48. package/dist/MimicServerEngine.d.mts +2 -2
  49. package/dist/MimicServerEngine.mjs +14 -14
  50. package/dist/MimicServerEngine.mjs.map +1 -1
  51. package/dist/PresenceManager.cjs +4 -4
  52. package/dist/PresenceManager.d.cts +2 -2
  53. package/dist/PresenceManager.d.mts +2 -2
  54. package/dist/PresenceManager.mjs +5 -5
  55. package/dist/PresenceManager.mjs.map +1 -1
  56. package/dist/Types.d.cts +1 -1
  57. package/dist/Types.d.mts +1 -1
  58. package/dist/testing/ColdStorageTestSuite.cjs +3 -3
  59. package/dist/testing/ColdStorageTestSuite.mjs +3 -3
  60. package/dist/testing/ColdStorageTestSuite.mjs.map +1 -1
  61. package/dist/testing/HotStorageTestSuite.cjs +13 -13
  62. package/dist/testing/HotStorageTestSuite.mjs +13 -13
  63. package/dist/testing/HotStorageTestSuite.mjs.map +1 -1
  64. package/dist/testing/StorageIntegrationTestSuite.cjs +3 -3
  65. package/dist/testing/StorageIntegrationTestSuite.mjs +3 -3
  66. package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -1
  67. package/dist/testing/types.d.cts +3 -3
  68. package/dist/testing/types.d.cts.map +1 -1
  69. package/dist/testing/types.d.mts +1 -1
  70. package/dist/testing/types.d.mts.map +1 -1
  71. package/package.json +17 -21
  72. package/src/ColdStorage.ts +4 -5
  73. package/src/DocumentInstance.ts +13 -13
  74. package/src/HotStorage.ts +3 -3
  75. package/src/Metrics.ts +22 -16
  76. package/src/MimicAuthService.ts +3 -3
  77. package/src/MimicClusterServerEngine.ts +35 -35
  78. package/src/MimicServer.ts +26 -30
  79. package/src/MimicServerEngine.ts +15 -15
  80. package/src/PresenceManager.ts +6 -6
  81. package/src/Types.ts +1 -1
  82. package/src/testing/ColdStorageTestSuite.ts +3 -3
  83. package/src/testing/HotStorageTestSuite.ts +17 -17
  84. package/src/testing/StorageIntegrationTestSuite.ts +3 -3
  85. package/.turbo/turbo-build.log +0 -154
  86. package/tests/ColdStorage.test.ts +0 -24
  87. package/tests/DocumentInstance.test.ts +0 -669
  88. package/tests/HotStorage.test.ts +0 -24
  89. package/tests/MimicAuthService.test.ts +0 -153
  90. package/tests/MimicClusterServerEngine.test.ts +0 -587
  91. package/tests/MimicServer.test.ts +0 -142
  92. package/tests/MimicServerEngine.test.ts +0 -547
  93. package/tests/PresenceManager.test.ts +0 -380
  94. package/tests/Protocol.test.ts +0 -190
  95. package/tests/StorageIntegration.test.ts +0 -259
  96. package/tsconfig.build.json +0 -24
  97. package/tsconfig.json +0 -8
  98. package/tsdown.config.ts +0 -18
  99. package/vitest.mts +0 -11
@@ -1,380 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { Effect, Stream, Chunk, Fiber } from "effect";
3
- import { PresenceManager, PresenceManagerTag } from "../src/PresenceManager";
4
-
5
- describe("PresenceManager", () => {
6
- describe("getSnapshot", () => {
7
- it("should return empty snapshot for unknown document", async () => {
8
- const result = await Effect.runPromise(
9
- Effect.gen(function* () {
10
- const pm = yield* PresenceManagerTag;
11
- return yield* pm.getSnapshot("unknown-doc");
12
- }).pipe(Effect.provide(PresenceManager.layer))
13
- );
14
-
15
- expect(result.presences).toEqual({});
16
- });
17
-
18
- it("should return presences after set", async () => {
19
- const result = await Effect.runPromise(
20
- Effect.gen(function* () {
21
- const pm = yield* PresenceManagerTag;
22
-
23
- yield* pm.set("doc-1", "conn-1", {
24
- data: { x: 10, y: 20 },
25
- userId: "user-1",
26
- });
27
-
28
- return yield* pm.getSnapshot("doc-1");
29
- }).pipe(Effect.provide(PresenceManager.layer))
30
- );
31
-
32
- expect(result.presences).toEqual({
33
- "conn-1": { data: { x: 10, y: 20 }, userId: "user-1" },
34
- });
35
- });
36
-
37
- it("should return multiple presences", async () => {
38
- const result = await Effect.runPromise(
39
- Effect.gen(function* () {
40
- const pm = yield* PresenceManagerTag;
41
-
42
- yield* pm.set("doc-1", "conn-1", { data: { x: 10, y: 20 } });
43
- yield* pm.set("doc-1", "conn-2", {
44
- data: { x: 30, y: 40 },
45
- userId: "user-2",
46
- });
47
- yield* pm.set("doc-1", "conn-3", { data: { x: 50, y: 60 } });
48
-
49
- return yield* pm.getSnapshot("doc-1");
50
- }).pipe(Effect.provide(PresenceManager.layer))
51
- );
52
-
53
- expect(Object.keys(result.presences).length).toBe(3);
54
- expect(result.presences["conn-1"]).toEqual({ data: { x: 10, y: 20 } });
55
- expect(result.presences["conn-2"]).toEqual({
56
- data: { x: 30, y: 40 },
57
- userId: "user-2",
58
- });
59
- expect(result.presences["conn-3"]).toEqual({ data: { x: 50, y: 60 } });
60
- });
61
- });
62
-
63
- describe("set", () => {
64
- it("should store presence entry", async () => {
65
- const result = await Effect.runPromise(
66
- Effect.gen(function* () {
67
- const pm = yield* PresenceManagerTag;
68
-
69
- yield* pm.set("doc-1", "conn-1", {
70
- data: { cursor: { x: 100, y: 200 } },
71
- });
72
-
73
- return yield* pm.getSnapshot("doc-1");
74
- }).pipe(Effect.provide(PresenceManager.layer))
75
- );
76
-
77
- expect(result.presences["conn-1"]).toEqual({
78
- data: { cursor: { x: 100, y: 200 } },
79
- });
80
- });
81
-
82
- it("should update existing presence entry", async () => {
83
- const result = await Effect.runPromise(
84
- Effect.gen(function* () {
85
- const pm = yield* PresenceManagerTag;
86
-
87
- yield* pm.set("doc-1", "conn-1", { data: { x: 10, y: 20 } });
88
- yield* pm.set("doc-1", "conn-1", { data: { x: 100, y: 200 } });
89
-
90
- return yield* pm.getSnapshot("doc-1");
91
- }).pipe(Effect.provide(PresenceManager.layer))
92
- );
93
-
94
- expect(result.presences["conn-1"]).toEqual({ data: { x: 100, y: 200 } });
95
- });
96
-
97
- it("should broadcast presence_update event", async () => {
98
- const result = await Effect.runPromise(
99
- Effect.scoped(
100
- Effect.gen(function* () {
101
- const pm = yield* PresenceManagerTag;
102
-
103
- // Subscribe first
104
- const eventStream = yield* pm.subscribe("doc-1");
105
-
106
- // Collect events in background
107
- const eventsFiber = yield* Effect.fork(
108
- Stream.runCollect(Stream.take(eventStream, 1))
109
- );
110
-
111
- // Small delay to ensure subscription is ready
112
- yield* Effect.sleep("10 millis");
113
-
114
- // Set presence
115
- yield* pm.set("doc-1", "conn-1", {
116
- data: { x: 10, y: 20 },
117
- userId: "user-1",
118
- });
119
-
120
- // Wait for events
121
- const events = yield* Fiber.join(eventsFiber);
122
-
123
- return Chunk.toArray(events);
124
- })
125
- ).pipe(Effect.provide(PresenceManager.layer))
126
- );
127
-
128
- expect(result.length).toBe(1);
129
- expect(result[0]!.type).toBe("presence_update");
130
- if (result[0]!.type === "presence_update") {
131
- expect(result[0]!.id).toBe("conn-1");
132
- expect(result[0]!.data).toEqual({ x: 10, y: 20 });
133
- expect(result[0]!.userId).toBe("user-1");
134
- }
135
- });
136
- });
137
-
138
- describe("remove", () => {
139
- it("should remove presence entry", async () => {
140
- const result = await Effect.runPromise(
141
- Effect.gen(function* () {
142
- const pm = yield* PresenceManagerTag;
143
-
144
- yield* pm.set("doc-1", "conn-1", { data: { x: 10, y: 20 } });
145
- yield* pm.remove("doc-1", "conn-1");
146
-
147
- return yield* pm.getSnapshot("doc-1");
148
- }).pipe(Effect.provide(PresenceManager.layer))
149
- );
150
-
151
- expect(result.presences).toEqual({});
152
- });
153
-
154
- it("should not error when removing non-existent connection", async () => {
155
- await expect(
156
- Effect.runPromise(
157
- Effect.gen(function* () {
158
- const pm = yield* PresenceManagerTag;
159
- yield* pm.remove("doc-1", "non-existent-conn");
160
- }).pipe(Effect.provide(PresenceManager.layer))
161
- )
162
- ).resolves.toBeUndefined();
163
- });
164
-
165
- it("should not error when removing from non-existent document", async () => {
166
- await expect(
167
- Effect.runPromise(
168
- Effect.gen(function* () {
169
- const pm = yield* PresenceManagerTag;
170
- yield* pm.remove("non-existent-doc", "conn-1");
171
- }).pipe(Effect.provide(PresenceManager.layer))
172
- )
173
- ).resolves.toBeUndefined();
174
- });
175
-
176
- it("should broadcast presence_remove event", async () => {
177
- const result = await Effect.runPromise(
178
- Effect.scoped(
179
- Effect.gen(function* () {
180
- const pm = yield* PresenceManagerTag;
181
-
182
- // Set presence first
183
- yield* pm.set("doc-1", "conn-1", { data: { x: 10, y: 20 } });
184
-
185
- // Subscribe
186
- const eventStream = yield* pm.subscribe("doc-1");
187
-
188
- // Collect events in background
189
- const eventsFiber = yield* Effect.fork(
190
- Stream.runCollect(Stream.take(eventStream, 1))
191
- );
192
-
193
- // Small delay to ensure subscription is ready
194
- yield* Effect.sleep("10 millis");
195
-
196
- // Remove presence
197
- yield* pm.remove("doc-1", "conn-1");
198
-
199
- // Wait for events
200
- const events = yield* Fiber.join(eventsFiber);
201
-
202
- return Chunk.toArray(events);
203
- })
204
- ).pipe(Effect.provide(PresenceManager.layer))
205
- );
206
-
207
- expect(result.length).toBe(1);
208
- expect(result[0]!.type).toBe("presence_remove");
209
- if (result[0]!.type === "presence_remove") {
210
- expect(result[0]!.id).toBe("conn-1");
211
- }
212
- });
213
-
214
- it("should not broadcast event when removing non-existent presence", async () => {
215
- const result = await Effect.runPromise(
216
- Effect.scoped(
217
- Effect.gen(function* () {
218
- const pm = yield* PresenceManagerTag;
219
-
220
- // Subscribe to doc that has no presences
221
- const eventStream = yield* pm.subscribe("doc-1");
222
-
223
- // Collect events in background with a timeout
224
- const eventsFiber = yield* Effect.fork(
225
- Stream.runCollect(
226
- Stream.take(eventStream, 1).pipe(Stream.timeout("50 millis"))
227
- )
228
- );
229
-
230
- // Small delay to ensure subscription is ready
231
- yield* Effect.sleep("10 millis");
232
-
233
- // Remove non-existent presence
234
- yield* pm.remove("doc-1", "non-existent-conn");
235
-
236
- // Wait for events (should timeout with no events)
237
- const events = yield* Fiber.join(eventsFiber);
238
-
239
- return Chunk.toArray(events);
240
- })
241
- ).pipe(Effect.provide(PresenceManager.layer))
242
- );
243
-
244
- expect(result.length).toBe(0);
245
- });
246
- });
247
-
248
- describe("subscribe", () => {
249
- it("should receive update events from stream", async () => {
250
- const result = await Effect.runPromise(
251
- Effect.scoped(
252
- Effect.gen(function* () {
253
- const pm = yield* PresenceManagerTag;
254
-
255
- const eventStream = yield* pm.subscribe("doc-1");
256
-
257
- const eventsFiber = yield* Effect.fork(
258
- Stream.runCollect(Stream.take(eventStream, 2))
259
- );
260
-
261
- yield* Effect.sleep("10 millis");
262
-
263
- yield* pm.set("doc-1", "conn-1", { data: { x: 10 } });
264
- yield* pm.set("doc-1", "conn-2", { data: { x: 20 } });
265
-
266
- const events = yield* Fiber.join(eventsFiber);
267
- return Chunk.toArray(events);
268
- })
269
- ).pipe(Effect.provide(PresenceManager.layer))
270
- );
271
-
272
- expect(result.length).toBe(2);
273
- expect(result[0]!.type).toBe("presence_update");
274
- expect(result[1]!.type).toBe("presence_update");
275
- });
276
-
277
- it("should receive mixed update and remove events", async () => {
278
- const result = await Effect.runPromise(
279
- Effect.scoped(
280
- Effect.gen(function* () {
281
- const pm = yield* PresenceManagerTag;
282
-
283
- // Set up initial presence
284
- yield* pm.set("doc-1", "conn-1", { data: { x: 10 } });
285
-
286
- const eventStream = yield* pm.subscribe("doc-1");
287
-
288
- const eventsFiber = yield* Effect.fork(
289
- Stream.runCollect(Stream.take(eventStream, 3))
290
- );
291
-
292
- yield* Effect.sleep("10 millis");
293
-
294
- yield* pm.set("doc-1", "conn-2", { data: { x: 20 } });
295
- yield* pm.remove("doc-1", "conn-1");
296
- yield* pm.set("doc-1", "conn-3", { data: { x: 30 } });
297
-
298
- const events = yield* Fiber.join(eventsFiber);
299
- return Chunk.toArray(events);
300
- })
301
- ).pipe(Effect.provide(PresenceManager.layer))
302
- );
303
-
304
- expect(result.length).toBe(3);
305
- expect(result[0]!.type).toBe("presence_update");
306
- expect(result[1]!.type).toBe("presence_remove");
307
- expect(result[2]!.type).toBe("presence_update");
308
- });
309
- });
310
-
311
- describe("document isolation", () => {
312
- it("should isolate presences between documents", async () => {
313
- const result = await Effect.runPromise(
314
- Effect.gen(function* () {
315
- const pm = yield* PresenceManagerTag;
316
-
317
- yield* pm.set("doc-1", "conn-1", { data: { x: 10 } });
318
- yield* pm.set("doc-2", "conn-2", { data: { x: 20 } });
319
-
320
- const snapshot1 = yield* pm.getSnapshot("doc-1");
321
- const snapshot2 = yield* pm.getSnapshot("doc-2");
322
-
323
- return { snapshot1, snapshot2 };
324
- }).pipe(Effect.provide(PresenceManager.layer))
325
- );
326
-
327
- expect(Object.keys(result.snapshot1.presences).length).toBe(1);
328
- expect(result.snapshot1.presences["conn-1"]).toEqual({ data: { x: 10 } });
329
- expect(result.snapshot1.presences["conn-2"]).toBeUndefined();
330
-
331
- expect(Object.keys(result.snapshot2.presences).length).toBe(1);
332
- expect(result.snapshot2.presences["conn-2"]).toEqual({ data: { x: 20 } });
333
- expect(result.snapshot2.presences["conn-1"]).toBeUndefined();
334
- });
335
-
336
- it("should isolate events between documents", async () => {
337
- const result = await Effect.runPromise(
338
- Effect.scoped(
339
- Effect.gen(function* () {
340
- const pm = yield* PresenceManagerTag;
341
-
342
- // Subscribe to doc-1 only
343
- const eventStream = yield* pm.subscribe("doc-1");
344
-
345
- const eventsFiber = yield* Effect.fork(
346
- Stream.runCollect(
347
- Stream.take(eventStream, 1).pipe(Stream.timeout("100 millis"))
348
- )
349
- );
350
-
351
- yield* Effect.sleep("10 millis");
352
-
353
- // Set presence on doc-2 (should NOT trigger doc-1 event)
354
- yield* pm.set("doc-2", "conn-1", { data: { x: 10 } });
355
-
356
- // Set presence on doc-1 (should trigger event)
357
- yield* pm.set("doc-1", "conn-2", { data: { x: 20 } });
358
-
359
- const events = yield* Fiber.join(eventsFiber);
360
- return Chunk.toArray(events);
361
- })
362
- ).pipe(Effect.provide(PresenceManager.layer))
363
- );
364
-
365
- expect(result.length).toBe(1);
366
- if (result[0]!.type === "presence_update") {
367
- expect(result[0]!.id).toBe("conn-2");
368
- expect(result[0]!.data).toEqual({ x: 20 });
369
- }
370
- });
371
- });
372
-
373
- describe("Tag", () => {
374
- it("should have correct identifier", () => {
375
- expect(PresenceManagerTag.key).toBe(
376
- "@voidhash/mimic-effect/PresenceManager"
377
- );
378
- });
379
- });
380
- });
@@ -1,190 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { Effect } from "effect";
3
- import * as Protocol from "../src/Protocol";
4
- import { Transaction, Document, Primitive } from "@voidhash/mimic";
5
-
6
- describe("Protocol", () => {
7
- describe("parseClientMessage", () => {
8
- it("should parse auth message", async () => {
9
- const data = JSON.stringify({ type: "auth", token: "test-token" });
10
-
11
- const result = await Effect.runPromise(Protocol.parseClientMessage(data));
12
-
13
- expect(result.type).toBe("auth");
14
- expect((result as Protocol.AuthMessage).token).toBe("test-token");
15
- });
16
-
17
- it("should parse ping message", async () => {
18
- const data = JSON.stringify({ type: "ping" });
19
-
20
- const result = await Effect.runPromise(Protocol.parseClientMessage(data));
21
-
22
- expect(result.type).toBe("ping");
23
- });
24
-
25
- it("should parse request_snapshot message", async () => {
26
- const data = JSON.stringify({ type: "request_snapshot" });
27
-
28
- const result = await Effect.runPromise(Protocol.parseClientMessage(data));
29
-
30
- expect(result.type).toBe("request_snapshot");
31
- });
32
-
33
- it("should parse presence_set message", async () => {
34
- const data = JSON.stringify({
35
- type: "presence_set",
36
- data: { cursor: { x: 10, y: 20 } },
37
- });
38
-
39
- const result = await Effect.runPromise(Protocol.parseClientMessage(data));
40
-
41
- expect(result.type).toBe("presence_set");
42
- expect((result as Protocol.PresenceSetMessage).data).toEqual({
43
- cursor: { x: 10, y: 20 },
44
- });
45
- });
46
-
47
- it("should parse presence_clear message", async () => {
48
- const data = JSON.stringify({ type: "presence_clear" });
49
-
50
- const result = await Effect.runPromise(Protocol.parseClientMessage(data));
51
-
52
- expect(result.type).toBe("presence_clear");
53
- });
54
-
55
- it("should parse submit message with transaction", async () => {
56
- // Create a real transaction using the Document API
57
- const schema = Primitive.Struct({
58
- title: Primitive.String().default(""),
59
- });
60
- const doc = Document.make(schema);
61
- doc.transaction((root) => root.title.set("Test"));
62
- const tx = doc.flush();
63
- const encodedTx = Transaction.encode(tx);
64
-
65
- const data = JSON.stringify({
66
- type: "submit",
67
- transaction: encodedTx,
68
- });
69
-
70
- const result = await Effect.runPromise(Protocol.parseClientMessage(data));
71
-
72
- expect(result.type).toBe("submit");
73
- const submitResult = result as Protocol.SubmitMessage;
74
- expect(submitResult.transaction.id).toBe(tx.id);
75
- });
76
-
77
- it("should fail on invalid JSON", async () => {
78
- const result = await Effect.runPromise(
79
- Effect.either(Protocol.parseClientMessage("not json"))
80
- );
81
-
82
- expect(result._tag).toBe("Left");
83
- });
84
-
85
- it("should handle Uint8Array input", async () => {
86
- const data = new TextEncoder().encode(
87
- JSON.stringify({ type: "ping" })
88
- );
89
-
90
- const result = await Effect.runPromise(Protocol.parseClientMessage(data));
91
-
92
- expect(result.type).toBe("ping");
93
- });
94
- });
95
-
96
- describe("encodeServerMessage", () => {
97
- it("should encode auth_result success", () => {
98
- const message = Protocol.authResultSuccess("user-1", "write");
99
- const encoded = Protocol.encodeServerMessage(message);
100
- const parsed = JSON.parse(encoded);
101
-
102
- expect(parsed.type).toBe("auth_result");
103
- expect(parsed.success).toBe(true);
104
- expect(parsed.userId).toBe("user-1");
105
- expect(parsed.permission).toBe("write");
106
- });
107
-
108
- it("should encode auth_result failure", () => {
109
- const message = Protocol.authResultFailure("Invalid token");
110
- const encoded = Protocol.encodeServerMessage(message);
111
- const parsed = JSON.parse(encoded);
112
-
113
- expect(parsed.type).toBe("auth_result");
114
- expect(parsed.success).toBe(false);
115
- expect(parsed.error).toBe("Invalid token");
116
- });
117
-
118
- it("should encode pong", () => {
119
- const message = Protocol.pong();
120
- const encoded = Protocol.encodeServerMessage(message);
121
- const parsed = JSON.parse(encoded);
122
-
123
- expect(parsed.type).toBe("pong");
124
- });
125
-
126
- it("should encode snapshot", () => {
127
- const message = Protocol.snapshotMessage({ title: "Test" }, 5);
128
- const encoded = Protocol.encodeServerMessage(message);
129
- const parsed = JSON.parse(encoded);
130
-
131
- expect(parsed.type).toBe("snapshot");
132
- expect(parsed.state).toEqual({ title: "Test" });
133
- expect(parsed.version).toBe(5);
134
- });
135
-
136
- it("should encode error", () => {
137
- const message = Protocol.errorMessage("tx-1", "Transaction rejected");
138
- const encoded = Protocol.encodeServerMessage(message);
139
- const parsed = JSON.parse(encoded);
140
-
141
- expect(parsed.type).toBe("error");
142
- expect(parsed.transactionId).toBe("tx-1");
143
- expect(parsed.reason).toBe("Transaction rejected");
144
- });
145
-
146
- it("should encode presence_update", () => {
147
- const message = Protocol.presenceUpdateMessage("conn-1", { x: 10 }, "user-1");
148
- const encoded = Protocol.encodeServerMessage(message);
149
- const parsed = JSON.parse(encoded);
150
-
151
- expect(parsed.type).toBe("presence_update");
152
- expect(parsed.id).toBe("conn-1");
153
- expect(parsed.data).toEqual({ x: 10 });
154
- expect(parsed.userId).toBe("user-1");
155
- });
156
-
157
- it("should encode presence_remove", () => {
158
- const message = Protocol.presenceRemoveMessage("conn-1");
159
- const encoded = Protocol.encodeServerMessage(message);
160
- const parsed = JSON.parse(encoded);
161
-
162
- expect(parsed.type).toBe("presence_remove");
163
- expect(parsed.id).toBe("conn-1");
164
- });
165
-
166
- it("should encode presence_snapshot", () => {
167
- const message = Protocol.presenceSnapshotMessage("self-id", {
168
- "conn-1": { data: { x: 10 } },
169
- });
170
- const encoded = Protocol.encodeServerMessage(message);
171
- const parsed = JSON.parse(encoded);
172
-
173
- expect(parsed.type).toBe("presence_snapshot");
174
- expect(parsed.selfId).toBe("self-id");
175
- expect(parsed.presences["conn-1"].data).toEqual({ x: 10 });
176
- });
177
-
178
- it("should encode transaction with encoded transaction", () => {
179
- const tx = Transaction.make([]);
180
- const message = Protocol.transactionMessage(tx, 3);
181
- const encoded = Protocol.encodeServerMessage(message);
182
- const parsed = JSON.parse(encoded);
183
-
184
- expect(parsed.type).toBe("transaction");
185
- expect(parsed.version).toBe(3);
186
- expect(parsed.transaction).toBeDefined();
187
- expect(parsed.transaction.id).toBe(tx.id);
188
- });
189
- });
190
- });