@typokit/plugin-ws 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@typokit/plugin-ws",
3
+ "exports": {
4
+ ".": {
5
+ "import": "./dist/index.js",
6
+ "types": "./dist/index.d.ts"
7
+ }
8
+ },
9
+ "version": "0.1.4",
10
+ "type": "module",
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "dependencies": {
18
+ "@typokit/types": "0.1.4",
19
+ "@typokit/errors": "0.1.4",
20
+ "@typokit/core": "0.1.4"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/KyleBastien/typokit",
25
+ "directory": "packages/plugin-ws"
26
+ },
27
+ "scripts": {
28
+ "test": "rstest run --passWithNoTests"
29
+ }
30
+ }
@@ -0,0 +1,586 @@
1
+ // @typokit/plugin-ws — Tests
2
+
3
+ import { describe, it, expect } from "@rstest/core";
4
+ import {
5
+ wsPlugin,
6
+ defineWsHandlers,
7
+ extractWsChannels,
8
+ generateWsValidators,
9
+ generateWsRouteTable,
10
+ WsConnectionManager,
11
+ validateWsMessage,
12
+ parseWsMessage,
13
+ handleWsUpgrade,
14
+ } from "./index.js";
15
+ import type {
16
+ WsChannels,
17
+ WsValidatorMap,
18
+ WsHandlerDefs,
19
+ WsChannelInfo,
20
+ } from "./index.js";
21
+ import type { SchemaTypeMap, RequestContext } from "@typokit/types";
22
+ import type { AppInstance } from "@typokit/core";
23
+
24
+ // ─── defineWsHandlers ───────────────────────────────────────
25
+
26
+ describe("defineWsHandlers", () => {
27
+ it("returns handlers as-is (identity function for type safety)", () => {
28
+ interface TestChannels extends WsChannels {
29
+ chat: {
30
+ serverToClient: { type: "message"; text: string };
31
+ clientToServer: { type: "send"; text: string };
32
+ };
33
+ }
34
+
35
+ const handlers = defineWsHandlers<TestChannels>({
36
+ chat: {
37
+ onConnect: async () => {},
38
+ onMessage: async () => {},
39
+ onDisconnect: async () => {},
40
+ },
41
+ });
42
+
43
+ expect(handlers).toBeDefined();
44
+ expect(handlers.chat).toBeDefined();
45
+ expect(handlers.chat.onConnect).toBeDefined();
46
+ expect(handlers.chat.onMessage).toBeDefined();
47
+ expect(handlers.chat.onDisconnect).toBeDefined();
48
+ });
49
+
50
+ it("allows partial handler definitions (only onMessage)", () => {
51
+ const handlers = defineWsHandlers({
52
+ notifications: {
53
+ onMessage: async () => {},
54
+ },
55
+ });
56
+
57
+ expect(handlers.notifications.onMessage).toBeDefined();
58
+ expect(handlers.notifications.onConnect).toBeUndefined();
59
+ expect(handlers.notifications.onDisconnect).toBeUndefined();
60
+ });
61
+ });
62
+
63
+ // ─── extractWsChannels ──────────────────────────────────────
64
+
65
+ describe("extractWsChannels", () => {
66
+ it("extracts channel contracts from type map with @channel JSDoc", () => {
67
+ const typeMap: SchemaTypeMap = {
68
+ NotificationChannel: {
69
+ name: "NotificationChannel",
70
+ jsdoc: { channel: "notifications" },
71
+ properties: {
72
+ serverToClient: { type: "ServerMessage", optional: false },
73
+ clientToServer: { type: "ClientMessage", optional: false },
74
+ },
75
+ },
76
+ ServerMessage: {
77
+ name: "ServerMessage",
78
+ properties: {
79
+ type: { type: "string", optional: false },
80
+ payload: { type: "unknown", optional: false },
81
+ },
82
+ },
83
+ ClientMessage: {
84
+ name: "ClientMessage",
85
+ properties: {
86
+ type: { type: "string", optional: false },
87
+ channel: { type: "string", optional: false },
88
+ },
89
+ },
90
+ };
91
+
92
+ const channels = extractWsChannels(typeMap);
93
+ expect(channels.length).toBe(1);
94
+ expect(channels[0].name).toBe("notifications");
95
+ expect(channels[0].serverToClientType).toBe("ServerMessage");
96
+ expect(channels[0].clientToServerType).toBe("ClientMessage");
97
+ });
98
+
99
+ it("extracts channels from @ws tagged type maps", () => {
100
+ const typeMap: SchemaTypeMap = {
101
+ MyWsChannels: {
102
+ name: "MyWsChannels",
103
+ jsdoc: { ws: "true" },
104
+ properties: {
105
+ chat: { type: "ChatContract", optional: false },
106
+ },
107
+ },
108
+ ChatContract: {
109
+ name: "ChatContract",
110
+ properties: {
111
+ serverToClient: { type: "ChatServerMsg", optional: false },
112
+ clientToServer: { type: "ChatClientMsg", optional: false },
113
+ },
114
+ },
115
+ ChatServerMsg: {
116
+ name: "ChatServerMsg",
117
+ properties: { text: { type: "string", optional: false } },
118
+ },
119
+ ChatClientMsg: {
120
+ name: "ChatClientMsg",
121
+ properties: { text: { type: "string", optional: false } },
122
+ },
123
+ };
124
+
125
+ const channels = extractWsChannels(typeMap);
126
+ // Should find "chat" from the ws channels map
127
+ const chatChannel = channels.find((c) => c.name === "chat");
128
+ expect(chatChannel).toBeDefined();
129
+ expect(chatChannel!.serverToClientType).toBe("ChatServerMsg");
130
+ expect(chatChannel!.clientToServerType).toBe("ChatClientMsg");
131
+ });
132
+
133
+ it("returns empty array when no WS channels found", () => {
134
+ const typeMap: SchemaTypeMap = {
135
+ User: {
136
+ name: "User",
137
+ properties: {
138
+ name: { type: "string", optional: false },
139
+ email: { type: "string", optional: false },
140
+ },
141
+ },
142
+ };
143
+
144
+ const channels = extractWsChannels(typeMap);
145
+ expect(channels.length).toBe(0);
146
+ });
147
+ });
148
+
149
+ // ─── generateWsValidators ───────────────────────────────────
150
+
151
+ describe("generateWsValidators", () => {
152
+ it("generates validator code for channels", () => {
153
+ const channels: WsChannelInfo[] = [
154
+ {
155
+ name: "chat",
156
+ serverToClientType: "ChatServerMsg",
157
+ clientToServerType: "ChatClientMsg",
158
+ properties: {
159
+ serverToClient: null,
160
+ clientToServer: {
161
+ name: "ChatClientMsg",
162
+ properties: {
163
+ type: { type: "string", optional: false },
164
+ text: { type: "string", optional: false },
165
+ },
166
+ },
167
+ },
168
+ },
169
+ ];
170
+
171
+ const output = generateWsValidators(channels, ".typokit");
172
+ expect(output.filePath).toBe(".typokit/ws-validators.ts");
173
+ expect(output.overwrite).toBe(true);
174
+ expect(output.content).toContain("wsValidators");
175
+ expect(output.content).toContain('"chat"');
176
+ expect(output.content).toContain("type");
177
+ expect(output.content).toContain("text");
178
+ });
179
+ });
180
+
181
+ // ─── generateWsRouteTable ───────────────────────────────────
182
+
183
+ describe("generateWsRouteTable", () => {
184
+ it("generates route table with channel paths", () => {
185
+ const channels: WsChannelInfo[] = [
186
+ {
187
+ name: "notifications",
188
+ serverToClientType: "NotifServerMsg",
189
+ clientToServerType: "NotifClientMsg",
190
+ properties: { serverToClient: null, clientToServer: null },
191
+ },
192
+ ];
193
+
194
+ const output = generateWsRouteTable(channels, ".typokit", "/ws");
195
+ expect(output.filePath).toBe(".typokit/ws-route-table.ts");
196
+ expect(output.overwrite).toBe(true);
197
+ expect(output.content).toContain('"/ws/notifications"');
198
+ expect(output.content).toContain('"notifications"');
199
+ });
200
+ });
201
+
202
+ // ─── WsConnectionManager ───────────────────────────────────
203
+
204
+ describe("WsConnectionManager", () => {
205
+ it("adds and retrieves connections", () => {
206
+ const mgr = new WsConnectionManager();
207
+ mgr.add({
208
+ id: "conn-1",
209
+ channel: "chat",
210
+ send: () => {},
211
+ close: () => {},
212
+ meta: {},
213
+ isOpen: true,
214
+ });
215
+
216
+ expect(mgr.size).toBe(1);
217
+ expect(mgr.get("conn-1")).toBeDefined();
218
+ expect(mgr.get("conn-1")!.channel).toBe("chat");
219
+ });
220
+
221
+ it("removes connections", () => {
222
+ const mgr = new WsConnectionManager();
223
+ mgr.add({
224
+ id: "conn-1",
225
+ channel: "chat",
226
+ send: () => {},
227
+ close: () => {},
228
+ meta: {},
229
+ isOpen: true,
230
+ });
231
+
232
+ const removed = mgr.remove("conn-1");
233
+ expect(removed).toBeDefined();
234
+ expect(mgr.size).toBe(0);
235
+ expect(mgr.get("conn-1")).toBeUndefined();
236
+ });
237
+
238
+ it("gets connections by channel", () => {
239
+ const mgr = new WsConnectionManager();
240
+ mgr.add({
241
+ id: "c1",
242
+ channel: "chat",
243
+ send: () => {},
244
+ close: () => {},
245
+ meta: {},
246
+ isOpen: true,
247
+ });
248
+ mgr.add({
249
+ id: "c2",
250
+ channel: "chat",
251
+ send: () => {},
252
+ close: () => {},
253
+ meta: {},
254
+ isOpen: true,
255
+ });
256
+ mgr.add({
257
+ id: "c3",
258
+ channel: "notif",
259
+ send: () => {},
260
+ close: () => {},
261
+ meta: {},
262
+ isOpen: true,
263
+ });
264
+
265
+ const chatConns = mgr.getByChannel("chat");
266
+ expect(chatConns.length).toBe(2);
267
+ expect(mgr.channelSize("chat")).toBe(2);
268
+ expect(mgr.channelSize("notif")).toBe(1);
269
+ });
270
+
271
+ it("broadcasts to channel connections", () => {
272
+ const mgr = new WsConnectionManager();
273
+ const sent: unknown[] = [];
274
+ mgr.add({
275
+ id: "c1",
276
+ channel: "chat",
277
+ send: (d) => sent.push(d),
278
+ close: () => {},
279
+ meta: {},
280
+ isOpen: true,
281
+ });
282
+ mgr.add({
283
+ id: "c2",
284
+ channel: "chat",
285
+ send: (d) => sent.push(d),
286
+ close: () => {},
287
+ meta: {},
288
+ isOpen: true,
289
+ });
290
+
291
+ const count = mgr.broadcast("chat", { type: "hello" });
292
+ expect(count).toBe(2);
293
+ expect(sent.length).toBe(2);
294
+ });
295
+
296
+ it("closes all connections", () => {
297
+ const mgr = new WsConnectionManager();
298
+ const closeCalls: Array<{ code?: number; reason?: string }> = [];
299
+ mgr.add({
300
+ id: "c1",
301
+ channel: "chat",
302
+ send: () => {},
303
+ close: (c, r) => closeCalls.push({ code: c, reason: r }),
304
+ meta: {},
305
+ isOpen: true,
306
+ });
307
+ mgr.add({
308
+ id: "c2",
309
+ channel: "notif",
310
+ send: () => {},
311
+ close: (c, r) => closeCalls.push({ code: c, reason: r }),
312
+ meta: {},
313
+ isOpen: true,
314
+ });
315
+
316
+ mgr.closeAll(1001, "shutdown");
317
+ expect(closeCalls.length).toBe(2);
318
+ expect(mgr.size).toBe(0);
319
+ });
320
+ });
321
+
322
+ // ─── validateWsMessage ──────────────────────────────────────
323
+
324
+ describe("validateWsMessage", () => {
325
+ it("returns valid when no validator is registered", () => {
326
+ const result = validateWsMessage("chat", { type: "send" }, {});
327
+ expect(result.valid).toBe(true);
328
+ });
329
+
330
+ it("validates messages against registered validator", () => {
331
+ const validators: WsValidatorMap = {
332
+ chat: (data) => {
333
+ if (typeof data !== "object" || data === null) {
334
+ return { valid: false, errors: ["Must be an object"] };
335
+ }
336
+ const obj = data as Record<string, unknown>;
337
+ if (!obj["type"]) {
338
+ return { valid: false, errors: ["Missing type field"] };
339
+ }
340
+ return { valid: true };
341
+ },
342
+ };
343
+
344
+ expect(validateWsMessage("chat", { type: "send" }, validators).valid).toBe(
345
+ true,
346
+ );
347
+ expect(validateWsMessage("chat", {}, validators).valid).toBe(false);
348
+ expect(validateWsMessage("chat", null, validators).valid).toBe(false);
349
+ });
350
+ });
351
+
352
+ // ─── parseWsMessage ─────────────────────────────────────────
353
+
354
+ describe("parseWsMessage", () => {
355
+ it("parses valid JSON string", () => {
356
+ const result = parseWsMessage('{"type":"hello"}');
357
+ expect(result.error).toBeUndefined();
358
+ expect(result.data).toEqual({ type: "hello" });
359
+ });
360
+
361
+ it("returns error for invalid JSON", () => {
362
+ const result = parseWsMessage("not json");
363
+ expect(result.error).toBeDefined();
364
+ expect(result.data).toBeNull();
365
+ });
366
+
367
+ it("parses ArrayBuffer as JSON", () => {
368
+ const encoder = new TextEncoder();
369
+ const buffer = encoder.encode('{"type":"hello"}').buffer;
370
+ const result = parseWsMessage(buffer as ArrayBuffer);
371
+ expect(result.error).toBeUndefined();
372
+ expect(result.data).toEqual({ type: "hello" });
373
+ });
374
+ });
375
+
376
+ // ─── wsPlugin factory ───────────────────────────────────────
377
+
378
+ describe("wsPlugin", () => {
379
+ it("returns a valid TypoKitPlugin", () => {
380
+ const plugin = wsPlugin();
381
+ expect(plugin.name).toBe("plugin-ws");
382
+ expect(plugin.onBuild).toBeDefined();
383
+ expect(plugin.onStart).toBeDefined();
384
+ expect(plugin.onReady).toBeDefined();
385
+ expect(plugin.onStop).toBeDefined();
386
+ expect(plugin.onError).toBeDefined();
387
+ expect(plugin.onSchemaChange).toBeDefined();
388
+ });
389
+
390
+ it("registers WS service on onStart", async () => {
391
+ const plugin = wsPlugin({ pathPrefix: "/ws", requireAuth: true });
392
+ const app: AppInstance = {
393
+ name: "test-app",
394
+ plugins: [plugin],
395
+ services: {},
396
+ };
397
+
398
+ await plugin.onStart!(app);
399
+
400
+ expect(app.services["_ws"]).toBeDefined();
401
+ const wsService = app.services["_ws"] as Record<string, unknown>;
402
+ expect(wsService.send).toBeDefined();
403
+ expect(wsService.broadcast).toBeDefined();
404
+ expect(wsService.getConnectionCount).toBeDefined();
405
+ expect(wsService.registerValidator).toBeDefined();
406
+ expect(wsService.registerHandlers).toBeDefined();
407
+ expect(wsService.getChannelInfos).toBeDefined();
408
+ expect((wsService.config as Record<string, unknown>).pathPrefix).toBe(
409
+ "/ws",
410
+ );
411
+ expect((wsService.config as Record<string, unknown>).requireAuth).toBe(
412
+ true,
413
+ );
414
+ });
415
+
416
+ it("shuts down cleanly on onStop", async () => {
417
+ const plugin = wsPlugin();
418
+ const app: AppInstance = {
419
+ name: "test-app",
420
+ plugins: [plugin],
421
+ services: {},
422
+ };
423
+
424
+ await plugin.onStart!(app);
425
+ await plugin.onReady!(app);
426
+ await plugin.onStop!(app);
427
+
428
+ // Should not throw
429
+ expect(true).toBe(true);
430
+ });
431
+
432
+ it("clears channel infos on schema change", () => {
433
+ const plugin = wsPlugin();
434
+ plugin.onSchemaChange!([{ type: "modify", entity: "ChatChannel" }]);
435
+ // Should not throw
436
+ expect(true).toBe(true);
437
+ });
438
+ });
439
+
440
+ // ─── handleWsUpgrade ────────────────────────────────────────
441
+
442
+ describe("handleWsUpgrade", () => {
443
+ function makeMockCtx(): RequestContext {
444
+ return {
445
+ log: {
446
+ trace: () => {},
447
+ info: () => {},
448
+ warn: () => {},
449
+ error: () => {},
450
+ debug: () => {},
451
+ fatal: () => {},
452
+ },
453
+ fail: (() => {
454
+ throw new Error("fail");
455
+ }) as never,
456
+ services: {},
457
+ requestId: "test-req-1",
458
+ };
459
+ }
460
+
461
+ it("returns error for unknown channel", () => {
462
+ const mgr = new WsConnectionManager();
463
+ const result = handleWsUpgrade(
464
+ "unknown",
465
+ mgr,
466
+ {},
467
+ {},
468
+ () => {},
469
+ () => {},
470
+ makeMockCtx(),
471
+ );
472
+ expect("error" in result).toBe(true);
473
+ if ("error" in result) {
474
+ expect(result.code).toBe(4004);
475
+ }
476
+ });
477
+
478
+ it("connects and receives messages", () => {
479
+ const mgr = new WsConnectionManager();
480
+ const sent: unknown[] = [];
481
+ const receivedMessages: unknown[] = [];
482
+
483
+ const handlers: WsHandlerDefs = {
484
+ chat: {
485
+ onConnect: async () => {},
486
+ onMessage: async ({ data }) => {
487
+ receivedMessages.push(data);
488
+ },
489
+ onDisconnect: async () => {},
490
+ },
491
+ };
492
+
493
+ const result = handleWsUpgrade(
494
+ "chat",
495
+ mgr,
496
+ handlers,
497
+ {},
498
+ (d) => sent.push(d),
499
+ () => {},
500
+ makeMockCtx(),
501
+ );
502
+
503
+ expect("connectionId" in result).toBe(true);
504
+ if ("connectionId" in result) {
505
+ expect(mgr.size).toBe(1);
506
+
507
+ // Send a message
508
+ result.onMessage('{"type":"send","text":"hello"}');
509
+ expect(receivedMessages.length).toBe(1);
510
+ expect(receivedMessages[0]).toEqual({ type: "send", text: "hello" });
511
+
512
+ // Disconnect
513
+ result.onClose();
514
+ expect(mgr.size).toBe(0);
515
+ }
516
+ });
517
+
518
+ it("validates messages and sends validation errors", () => {
519
+ const mgr = new WsConnectionManager();
520
+ const sent: unknown[] = [];
521
+
522
+ const handlers: WsHandlerDefs = {
523
+ chat: {
524
+ onMessage: async () => {},
525
+ },
526
+ };
527
+
528
+ const validators: WsValidatorMap = {
529
+ chat: (data) => {
530
+ if (typeof data !== "object" || data === null || !("type" in data)) {
531
+ return { valid: false, errors: ["Missing type field"] };
532
+ }
533
+ return { valid: true };
534
+ },
535
+ };
536
+
537
+ const result = handleWsUpgrade(
538
+ "chat",
539
+ mgr,
540
+ handlers,
541
+ validators,
542
+ (d) => sent.push(d),
543
+ () => {},
544
+ makeMockCtx(),
545
+ );
546
+
547
+ if ("connectionId" in result) {
548
+ // Send invalid message (missing type field)
549
+ result.onMessage('{"text":"no type"}');
550
+ expect(sent.length).toBe(1);
551
+ expect((sent[0] as Record<string, unknown>).type).toBe(
552
+ "validation_error",
553
+ );
554
+
555
+ // Send valid message
556
+ result.onMessage('{"type":"send","text":"hello"}');
557
+ // No additional error sent
558
+ expect(sent.length).toBe(1);
559
+ }
560
+ });
561
+
562
+ it("handles parse errors for invalid JSON", () => {
563
+ const mgr = new WsConnectionManager();
564
+ const sent: unknown[] = [];
565
+
566
+ const handlers: WsHandlerDefs = {
567
+ chat: { onMessage: async () => {} },
568
+ };
569
+
570
+ const result = handleWsUpgrade(
571
+ "chat",
572
+ mgr,
573
+ handlers,
574
+ {},
575
+ (d) => sent.push(d),
576
+ () => {},
577
+ makeMockCtx(),
578
+ );
579
+
580
+ if ("connectionId" in result) {
581
+ result.onMessage("not json at all");
582
+ expect(sent.length).toBe(1);
583
+ expect((sent[0] as Record<string, unknown>).type).toBe("error");
584
+ }
585
+ });
586
+ });