rivetkit 2.0.2 → 2.0.3

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 (253) hide show
  1. package/dist/schemas/actor-persist/v1.ts +228 -0
  2. package/dist/schemas/client-protocol/v1.ts +429 -0
  3. package/dist/schemas/file-system-driver/v1.ts +102 -0
  4. package/dist/tsup/actor/errors.cjs +69 -0
  5. package/dist/tsup/actor/errors.cjs.map +1 -0
  6. package/dist/tsup/actor/errors.d.cts +143 -0
  7. package/dist/tsup/actor/errors.d.ts +143 -0
  8. package/dist/tsup/actor/errors.js +69 -0
  9. package/dist/tsup/actor/errors.js.map +1 -0
  10. package/dist/tsup/chunk-2CRLFV6Z.cjs +202 -0
  11. package/dist/tsup/chunk-2CRLFV6Z.cjs.map +1 -0
  12. package/dist/tsup/chunk-3H7O2A7I.js +525 -0
  13. package/dist/tsup/chunk-3H7O2A7I.js.map +1 -0
  14. package/dist/tsup/chunk-42I3OZ3Q.js +15 -0
  15. package/dist/tsup/chunk-42I3OZ3Q.js.map +1 -0
  16. package/dist/tsup/chunk-4NSUQZ2H.js +1790 -0
  17. package/dist/tsup/chunk-4NSUQZ2H.js.map +1 -0
  18. package/dist/tsup/chunk-6PDXBYI5.js +132 -0
  19. package/dist/tsup/chunk-6PDXBYI5.js.map +1 -0
  20. package/dist/tsup/chunk-6WKQDDUD.cjs +1790 -0
  21. package/dist/tsup/chunk-6WKQDDUD.cjs.map +1 -0
  22. package/dist/tsup/chunk-CTBOSFUH.cjs +116 -0
  23. package/dist/tsup/chunk-CTBOSFUH.cjs.map +1 -0
  24. package/dist/tsup/chunk-EGVZZFE2.js +2857 -0
  25. package/dist/tsup/chunk-EGVZZFE2.js.map +1 -0
  26. package/dist/tsup/chunk-FCCPJNMA.cjs +132 -0
  27. package/dist/tsup/chunk-FCCPJNMA.cjs.map +1 -0
  28. package/dist/tsup/chunk-FLMTTN27.js +244 -0
  29. package/dist/tsup/chunk-FLMTTN27.js.map +1 -0
  30. package/dist/tsup/chunk-GIR3AFFI.cjs +315 -0
  31. package/dist/tsup/chunk-GIR3AFFI.cjs.map +1 -0
  32. package/dist/tsup/chunk-INGJP237.js +315 -0
  33. package/dist/tsup/chunk-INGJP237.js.map +1 -0
  34. package/dist/tsup/chunk-KJCJLKRM.js +116 -0
  35. package/dist/tsup/chunk-KJCJLKRM.js.map +1 -0
  36. package/dist/tsup/chunk-KUPQZYUQ.cjs +15 -0
  37. package/dist/tsup/chunk-KUPQZYUQ.cjs.map +1 -0
  38. package/dist/tsup/chunk-O2MBYIXO.cjs +2857 -0
  39. package/dist/tsup/chunk-O2MBYIXO.cjs.map +1 -0
  40. package/dist/tsup/chunk-OGAPU3UG.cjs +525 -0
  41. package/dist/tsup/chunk-OGAPU3UG.cjs.map +1 -0
  42. package/dist/tsup/chunk-OV6AYD4S.js +4406 -0
  43. package/dist/tsup/chunk-OV6AYD4S.js.map +1 -0
  44. package/dist/tsup/chunk-PO4VLDWA.js +47 -0
  45. package/dist/tsup/chunk-PO4VLDWA.js.map +1 -0
  46. package/dist/tsup/chunk-R2OPSKIV.cjs +244 -0
  47. package/dist/tsup/chunk-R2OPSKIV.cjs.map +1 -0
  48. package/dist/tsup/chunk-TZJKSBUQ.cjs +47 -0
  49. package/dist/tsup/chunk-TZJKSBUQ.cjs.map +1 -0
  50. package/dist/tsup/chunk-UBUC5C3G.cjs +189 -0
  51. package/dist/tsup/chunk-UBUC5C3G.cjs.map +1 -0
  52. package/dist/tsup/chunk-UIM22YJL.cjs +4406 -0
  53. package/dist/tsup/chunk-UIM22YJL.cjs.map +1 -0
  54. package/dist/tsup/chunk-URVFQMYI.cjs +230 -0
  55. package/dist/tsup/chunk-URVFQMYI.cjs.map +1 -0
  56. package/dist/tsup/chunk-UVUPOS46.js +230 -0
  57. package/dist/tsup/chunk-UVUPOS46.js.map +1 -0
  58. package/dist/tsup/chunk-VRRHBNJC.js +189 -0
  59. package/dist/tsup/chunk-VRRHBNJC.js.map +1 -0
  60. package/dist/tsup/chunk-XFSS33EQ.js +202 -0
  61. package/dist/tsup/chunk-XFSS33EQ.js.map +1 -0
  62. package/dist/tsup/client/mod.cjs +32 -0
  63. package/dist/tsup/client/mod.cjs.map +1 -0
  64. package/dist/tsup/client/mod.d.cts +26 -0
  65. package/dist/tsup/client/mod.d.ts +26 -0
  66. package/dist/tsup/client/mod.js +32 -0
  67. package/dist/tsup/client/mod.js.map +1 -0
  68. package/dist/tsup/common/log.cjs +13 -0
  69. package/dist/tsup/common/log.cjs.map +1 -0
  70. package/dist/tsup/common/log.d.cts +20 -0
  71. package/dist/tsup/common/log.d.ts +20 -0
  72. package/dist/tsup/common/log.js +13 -0
  73. package/dist/tsup/common/log.js.map +1 -0
  74. package/dist/tsup/common/websocket.cjs +10 -0
  75. package/dist/tsup/common/websocket.cjs.map +1 -0
  76. package/dist/tsup/common/websocket.d.cts +3 -0
  77. package/dist/tsup/common/websocket.d.ts +3 -0
  78. package/dist/tsup/common/websocket.js +10 -0
  79. package/dist/tsup/common/websocket.js.map +1 -0
  80. package/dist/tsup/common-CpqORuCq.d.cts +218 -0
  81. package/dist/tsup/common-CpqORuCq.d.ts +218 -0
  82. package/dist/tsup/connection-BR_Ve4ku.d.cts +2117 -0
  83. package/dist/tsup/connection-BwUMoe6n.d.ts +2117 -0
  84. package/dist/tsup/driver-helpers/mod.cjs +33 -0
  85. package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
  86. package/dist/tsup/driver-helpers/mod.d.cts +18 -0
  87. package/dist/tsup/driver-helpers/mod.d.ts +18 -0
  88. package/dist/tsup/driver-helpers/mod.js +33 -0
  89. package/dist/tsup/driver-helpers/mod.js.map +1 -0
  90. package/dist/tsup/driver-test-suite/mod.cjs +4619 -0
  91. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
  92. package/dist/tsup/driver-test-suite/mod.d.cts +57 -0
  93. package/dist/tsup/driver-test-suite/mod.d.ts +57 -0
  94. package/dist/tsup/driver-test-suite/mod.js +4619 -0
  95. package/dist/tsup/driver-test-suite/mod.js.map +1 -0
  96. package/dist/tsup/inspector/mod.cjs +53 -0
  97. package/dist/tsup/inspector/mod.cjs.map +1 -0
  98. package/dist/tsup/inspector/mod.d.cts +408 -0
  99. package/dist/tsup/inspector/mod.d.ts +408 -0
  100. package/dist/tsup/inspector/mod.js +53 -0
  101. package/dist/tsup/inspector/mod.js.map +1 -0
  102. package/dist/tsup/mod.cjs +73 -0
  103. package/dist/tsup/mod.cjs.map +1 -0
  104. package/dist/tsup/mod.d.cts +100 -0
  105. package/dist/tsup/mod.d.ts +100 -0
  106. package/dist/tsup/mod.js +73 -0
  107. package/dist/tsup/mod.js.map +1 -0
  108. package/dist/tsup/router-endpoints-AYkXG8Tl.d.cts +66 -0
  109. package/dist/tsup/router-endpoints-DAbqVFx2.d.ts +66 -0
  110. package/dist/tsup/test/mod.cjs +21 -0
  111. package/dist/tsup/test/mod.cjs.map +1 -0
  112. package/dist/tsup/test/mod.d.cts +27 -0
  113. package/dist/tsup/test/mod.d.ts +27 -0
  114. package/dist/tsup/test/mod.js +21 -0
  115. package/dist/tsup/test/mod.js.map +1 -0
  116. package/dist/tsup/utils-CT0cv4jd.d.cts +17 -0
  117. package/dist/tsup/utils-CT0cv4jd.d.ts +17 -0
  118. package/dist/tsup/utils.cjs +26 -0
  119. package/dist/tsup/utils.cjs.map +1 -0
  120. package/dist/tsup/utils.d.cts +36 -0
  121. package/dist/tsup/utils.d.ts +36 -0
  122. package/dist/tsup/utils.js +26 -0
  123. package/dist/tsup/utils.js.map +1 -0
  124. package/package.json +208 -5
  125. package/src/actor/action.ts +182 -0
  126. package/src/actor/config.ts +765 -0
  127. package/src/actor/connection.ts +260 -0
  128. package/src/actor/context.ts +171 -0
  129. package/src/actor/database.ts +23 -0
  130. package/src/actor/definition.ts +86 -0
  131. package/src/actor/driver.ts +84 -0
  132. package/src/actor/errors.ts +360 -0
  133. package/src/actor/generic-conn-driver.ts +234 -0
  134. package/src/actor/instance.ts +1800 -0
  135. package/src/actor/log.ts +15 -0
  136. package/src/actor/mod.ts +113 -0
  137. package/src/actor/persisted.ts +42 -0
  138. package/src/actor/protocol/old.ts +281 -0
  139. package/src/actor/protocol/serde.ts +131 -0
  140. package/src/actor/router-endpoints.ts +685 -0
  141. package/src/actor/router.ts +263 -0
  142. package/src/actor/schedule.ts +17 -0
  143. package/src/actor/unstable-react.ts +110 -0
  144. package/src/actor/utils.ts +98 -0
  145. package/src/client/actor-common.ts +30 -0
  146. package/src/client/actor-conn.ts +804 -0
  147. package/src/client/actor-handle.ts +208 -0
  148. package/src/client/client.ts +623 -0
  149. package/src/client/errors.ts +41 -0
  150. package/src/client/http-client-driver.ts +326 -0
  151. package/src/client/log.ts +7 -0
  152. package/src/client/mod.ts +56 -0
  153. package/src/client/raw-utils.ts +92 -0
  154. package/src/client/test.ts +44 -0
  155. package/src/client/utils.ts +150 -0
  156. package/src/common/eventsource-interface.ts +47 -0
  157. package/src/common/eventsource.ts +80 -0
  158. package/src/common/fake-event-source.ts +266 -0
  159. package/src/common/inline-websocket-adapter2.ts +445 -0
  160. package/src/common/log-levels.ts +27 -0
  161. package/src/common/log.ts +139 -0
  162. package/src/common/logfmt.ts +228 -0
  163. package/src/common/network.ts +2 -0
  164. package/src/common/router.ts +87 -0
  165. package/src/common/utils.ts +322 -0
  166. package/src/common/versioned-data.ts +95 -0
  167. package/src/common/websocket-interface.ts +49 -0
  168. package/src/common/websocket.ts +43 -0
  169. package/src/driver-helpers/mod.ts +22 -0
  170. package/src/driver-helpers/utils.ts +17 -0
  171. package/src/driver-test-suite/log.ts +7 -0
  172. package/src/driver-test-suite/mod.ts +213 -0
  173. package/src/driver-test-suite/test-inline-client-driver.ts +402 -0
  174. package/src/driver-test-suite/tests/action-features.ts +136 -0
  175. package/src/driver-test-suite/tests/actor-auth.ts +591 -0
  176. package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
  177. package/src/driver-test-suite/tests/actor-conn.ts +349 -0
  178. package/src/driver-test-suite/tests/actor-driver.ts +25 -0
  179. package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
  180. package/src/driver-test-suite/tests/actor-handle.ts +259 -0
  181. package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
  182. package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
  183. package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
  184. package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
  185. package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
  186. package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
  187. package/src/driver-test-suite/tests/actor-state.ts +54 -0
  188. package/src/driver-test-suite/tests/actor-vars.ts +93 -0
  189. package/src/driver-test-suite/tests/manager-driver.ts +365 -0
  190. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +226 -0
  191. package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
  192. package/src/driver-test-suite/tests/raw-http.ts +347 -0
  193. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +392 -0
  194. package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
  195. package/src/driver-test-suite/tests/request-access.ts +244 -0
  196. package/src/driver-test-suite/utils.ts +68 -0
  197. package/src/drivers/default.ts +31 -0
  198. package/src/drivers/engine/actor-driver.ts +360 -0
  199. package/src/drivers/engine/api-endpoints.ts +128 -0
  200. package/src/drivers/engine/api-utils.ts +70 -0
  201. package/src/drivers/engine/config.ts +39 -0
  202. package/src/drivers/engine/keys.test.ts +266 -0
  203. package/src/drivers/engine/keys.ts +89 -0
  204. package/src/drivers/engine/kv.ts +3 -0
  205. package/src/drivers/engine/log.ts +7 -0
  206. package/src/drivers/engine/manager-driver.ts +391 -0
  207. package/src/drivers/engine/mod.ts +36 -0
  208. package/src/drivers/engine/ws-proxy.ts +170 -0
  209. package/src/drivers/file-system/actor.ts +91 -0
  210. package/src/drivers/file-system/global-state.ts +673 -0
  211. package/src/drivers/file-system/log.ts +7 -0
  212. package/src/drivers/file-system/manager.ts +306 -0
  213. package/src/drivers/file-system/mod.ts +48 -0
  214. package/src/drivers/file-system/utils.ts +109 -0
  215. package/src/globals.d.ts +6 -0
  216. package/src/inline-client-driver/log.ts +7 -0
  217. package/src/inline-client-driver/mod.ts +385 -0
  218. package/src/inspector/actor.ts +298 -0
  219. package/src/inspector/config.ts +83 -0
  220. package/src/inspector/log.ts +5 -0
  221. package/src/inspector/manager.ts +86 -0
  222. package/src/inspector/mod.ts +2 -0
  223. package/src/inspector/protocol/actor.ts +10 -0
  224. package/src/inspector/protocol/common.ts +196 -0
  225. package/src/inspector/protocol/manager.ts +10 -0
  226. package/src/inspector/protocol/mod.ts +2 -0
  227. package/src/inspector/utils.ts +76 -0
  228. package/src/manager/auth.ts +121 -0
  229. package/src/manager/driver.ts +80 -0
  230. package/src/manager/hono-websocket-adapter.ts +333 -0
  231. package/src/manager/log.ts +7 -0
  232. package/src/manager/mod.ts +2 -0
  233. package/src/manager/protocol/mod.ts +24 -0
  234. package/src/manager/protocol/query.ts +89 -0
  235. package/src/manager/router.ts +1792 -0
  236. package/src/mod.ts +20 -0
  237. package/src/registry/config.ts +32 -0
  238. package/src/registry/log.ts +7 -0
  239. package/src/registry/mod.ts +124 -0
  240. package/src/registry/run-config.ts +54 -0
  241. package/src/registry/serve.ts +53 -0
  242. package/src/schemas/actor-persist/mod.ts +1 -0
  243. package/src/schemas/actor-persist/versioned.ts +25 -0
  244. package/src/schemas/client-protocol/mod.ts +1 -0
  245. package/src/schemas/client-protocol/versioned.ts +63 -0
  246. package/src/schemas/file-system-driver/mod.ts +1 -0
  247. package/src/schemas/file-system-driver/versioned.ts +28 -0
  248. package/src/serde.ts +84 -0
  249. package/src/test/config.ts +16 -0
  250. package/src/test/log.ts +7 -0
  251. package/src/test/mod.ts +153 -0
  252. package/src/utils.ts +172 -0
  253. package/README.md +0 -13
@@ -0,0 +1,484 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import type { DriverTestConfig } from "../mod";
3
+ import { setupDriverTest } from "../utils";
4
+
5
+ export function runRawWebSocketTests(driverTestConfig: DriverTestConfig) {
6
+ describe("raw websocket", () => {
7
+ test("should establish raw WebSocket connection", async (c) => {
8
+ const { client } = await setupDriverTest(c, driverTestConfig);
9
+ const actor = client.rawWebSocketActor.getOrCreate(["basic"]);
10
+
11
+ const ws = await actor.websocket();
12
+
13
+ // The WebSocket should already be open since openWebSocket waits for openPromise
14
+ // But we still need to ensure any buffered events are processed
15
+ await new Promise<void>((resolve) => {
16
+ // If already open, resolve immediately
17
+ if (ws.readyState === WebSocket.OPEN) {
18
+ resolve();
19
+ } else {
20
+ // Otherwise wait for open event
21
+ ws.addEventListener(
22
+ "open",
23
+ () => {
24
+ resolve();
25
+ },
26
+ { once: true },
27
+ );
28
+ }
29
+ });
30
+
31
+ // Should receive welcome message
32
+ const welcomeMessage = await new Promise<any>((resolve, reject) => {
33
+ ws.addEventListener(
34
+ "message",
35
+ (event: any) => {
36
+ resolve(JSON.parse(event.data as string));
37
+ },
38
+ { once: true },
39
+ );
40
+ ws.addEventListener("close", reject);
41
+ });
42
+
43
+ expect(welcomeMessage.type).toBe("welcome");
44
+ expect(welcomeMessage.connectionCount).toBe(1);
45
+
46
+ ws.close();
47
+ });
48
+
49
+ test("should echo messages", async (c) => {
50
+ const { client } = await setupDriverTest(c, driverTestConfig);
51
+ const actor = client.rawWebSocketActor.getOrCreate(["echo"]);
52
+
53
+ const ws = await actor.websocket();
54
+
55
+ // Check if WebSocket is already open
56
+ if (ws.readyState !== WebSocket.OPEN) {
57
+ await new Promise<void>((resolve, reject) => {
58
+ ws.addEventListener("open", () => resolve(), { once: true });
59
+ ws.addEventListener("close", reject);
60
+ });
61
+ }
62
+
63
+ // Skip welcome message
64
+ await new Promise<void>((resolve, reject) => {
65
+ ws.addEventListener("message", () => resolve(), { once: true });
66
+ ws.addEventListener("close", reject);
67
+ });
68
+
69
+ // Send and receive echo
70
+ const testMessage = { test: "data", timestamp: Date.now() };
71
+ ws.send(JSON.stringify(testMessage));
72
+
73
+ const echoMessage = await new Promise<any>((resolve, reject) => {
74
+ ws.addEventListener(
75
+ "message",
76
+ (event: any) => {
77
+ resolve(JSON.parse(event.data as string));
78
+ },
79
+ { once: true },
80
+ );
81
+ ws.addEventListener("close", reject);
82
+ });
83
+
84
+ expect(echoMessage).toEqual(testMessage);
85
+
86
+ ws.close();
87
+ });
88
+
89
+ test("should handle ping/pong protocol", async (c) => {
90
+ const { client } = await setupDriverTest(c, driverTestConfig);
91
+ const actor = client.rawWebSocketActor.getOrCreate(["ping"]);
92
+
93
+ const ws = await actor.websocket();
94
+
95
+ // Check if WebSocket is already open
96
+ if (ws.readyState !== WebSocket.OPEN) {
97
+ await new Promise<void>((resolve, reject) => {
98
+ ws.addEventListener("open", () => resolve(), { once: true });
99
+ ws.addEventListener("close", reject);
100
+ });
101
+ }
102
+
103
+ // Skip welcome message
104
+ await new Promise<void>((resolve, reject) => {
105
+ ws.addEventListener("message", () => resolve(), { once: true });
106
+ ws.addEventListener("close", reject);
107
+ });
108
+
109
+ // Send ping
110
+ ws.send(JSON.stringify({ type: "ping" }));
111
+
112
+ const pongMessage = await new Promise<any>((resolve, reject) => {
113
+ ws.addEventListener("message", (event: any) => {
114
+ const data = JSON.parse(event.data as string);
115
+ if (data.type === "pong") {
116
+ resolve(data);
117
+ }
118
+ });
119
+ ws.addEventListener("close", reject);
120
+ });
121
+
122
+ expect(pongMessage.type).toBe("pong");
123
+ expect(pongMessage.timestamp).toBeDefined();
124
+
125
+ ws.close();
126
+ });
127
+
128
+ test("should track stats across connections", async (c) => {
129
+ const { client } = await setupDriverTest(c, driverTestConfig);
130
+ const actor1 = client.rawWebSocketActor.getOrCreate(["stats"]);
131
+
132
+ // Create first connection to ensure actor exists
133
+ const ws1 = await actor1.websocket();
134
+ const ws1MessagePromise = new Promise<void>((resolve, reject) => {
135
+ ws1.addEventListener("message", () => resolve(), { once: true });
136
+ ws1.addEventListener("close", reject);
137
+ });
138
+
139
+ // Wait for first connection to establish before getting the actor
140
+ await ws1MessagePromise;
141
+
142
+ // Now get reference to same actor
143
+ const actor2 = client.rawWebSocketActor.get(["stats"]);
144
+ const ws2 = await actor2.websocket();
145
+ const ws2MessagePromise = new Promise<void>((resolve, reject) => {
146
+ ws2.addEventListener("message", () => resolve(), { once: true });
147
+ ws2.addEventListener("close", reject);
148
+ });
149
+
150
+ // Wait for welcome messages
151
+ await Promise.all([ws1MessagePromise, ws2MessagePromise]);
152
+
153
+ // Send some messages
154
+ const pingPromise = new Promise<any>((resolve, reject) => {
155
+ ws2.addEventListener("message", (event: any) => {
156
+ const data = JSON.parse(event.data as string);
157
+ if (data.type === "pong") {
158
+ resolve(undefined);
159
+ }
160
+ });
161
+ ws2.addEventListener("close", reject);
162
+ });
163
+ ws1.send(JSON.stringify({ data: "test1" }));
164
+ ws1.send(JSON.stringify({ data: "test3" }));
165
+ ws2.send(JSON.stringify({ type: "ping" }));
166
+ await pingPromise;
167
+
168
+ // Get stats
169
+ const statsPromise = new Promise<any>((resolve, reject) => {
170
+ ws1.addEventListener("message", (event: any) => {
171
+ const data = JSON.parse(event.data as string);
172
+ if (data.type === "stats") {
173
+ resolve(data);
174
+ }
175
+ });
176
+ ws1.addEventListener("close", reject);
177
+ });
178
+ ws1.send(JSON.stringify({ type: "getStats" }));
179
+ const stats = await statsPromise;
180
+ expect(stats.connectionCount).toBe(2);
181
+ expect(stats.messageCount).toBe(4);
182
+
183
+ // Verify via action
184
+ const actionStats = await actor1.getStats();
185
+ expect(actionStats.connectionCount).toBe(2);
186
+ expect(actionStats.messageCount).toBe(4);
187
+
188
+ ws1.close();
189
+ ws2.close();
190
+ });
191
+
192
+ test("should handle binary data", async (c) => {
193
+ const { client } = await setupDriverTest(c, driverTestConfig);
194
+ const actor = client.rawWebSocketBinaryActor.getOrCreate(["binary"]);
195
+
196
+ const ws = await actor.websocket();
197
+
198
+ // Check if WebSocket is already open
199
+ if (ws.readyState !== WebSocket.OPEN) {
200
+ await new Promise<void>((resolve, reject) => {
201
+ ws.addEventListener("open", () => resolve(), { once: true });
202
+ ws.addEventListener("close", reject);
203
+ });
204
+ }
205
+
206
+ // Helper to receive and convert binary message
207
+ const receiveBinaryMessage = async (): Promise<Uint8Array> => {
208
+ const response = await new Promise<ArrayBuffer | Blob>(
209
+ (resolve, reject) => {
210
+ ws.addEventListener(
211
+ "message",
212
+ (event: any) => {
213
+ resolve(event.data);
214
+ },
215
+ { once: true },
216
+ );
217
+ ws.addEventListener("close", reject);
218
+ },
219
+ );
220
+
221
+ // Convert Blob to ArrayBuffer if needed
222
+ const buffer =
223
+ response instanceof Blob ? await response.arrayBuffer() : response;
224
+
225
+ return new Uint8Array(buffer);
226
+ };
227
+
228
+ // Test 1: Small binary data
229
+ const smallData = new Uint8Array([1, 2, 3, 4, 5]);
230
+ ws.send(smallData);
231
+ const smallReversed = await receiveBinaryMessage();
232
+ expect(Array.from(smallReversed)).toEqual([5, 4, 3, 2, 1]);
233
+
234
+ // Test 2: Large binary data (1KB)
235
+ const largeData = new Uint8Array(1024);
236
+ for (let i = 0; i < largeData.length; i++) {
237
+ largeData[i] = i % 256;
238
+ }
239
+ ws.send(largeData);
240
+ const largeReversed = await receiveBinaryMessage();
241
+
242
+ // Verify it's reversed correctly
243
+ for (let i = 0; i < largeData.length; i++) {
244
+ expect(largeReversed[i]).toBe(largeData[largeData.length - 1 - i]);
245
+ }
246
+
247
+ ws.close();
248
+ });
249
+
250
+ test("should work with custom paths", async (c) => {
251
+ const { client } = await setupDriverTest(c, driverTestConfig);
252
+ const actor = client.rawWebSocketActor.getOrCreate(["paths"]);
253
+
254
+ const ws = await actor.websocket("custom/path");
255
+
256
+ await new Promise<void>((resolve, reject) => {
257
+ ws.addEventListener("open", () => {
258
+ resolve();
259
+ });
260
+ ws.addEventListener("error", reject);
261
+ ws.addEventListener("close", reject);
262
+ });
263
+
264
+ // Should still work
265
+ const welcomeMessage = await new Promise<any>((resolve) => {
266
+ ws.addEventListener(
267
+ "message",
268
+ (event: any) => {
269
+ resolve(JSON.parse(event.data as string));
270
+ },
271
+ { once: true },
272
+ );
273
+ });
274
+
275
+ expect(welcomeMessage.type).toBe("welcome");
276
+
277
+ ws.close();
278
+ });
279
+
280
+ test("should pass connection parameters through subprotocols", async (c) => {
281
+ const { client } = await setupDriverTest(c, driverTestConfig);
282
+
283
+ // Create actor with connection parameters
284
+ const testParams = { userId: "test123", role: "admin" };
285
+ const actor = client.rawWebSocketActor.getOrCreate(["params"], {
286
+ params: testParams,
287
+ });
288
+
289
+ const ws = await actor.websocket();
290
+
291
+ await new Promise<void>((resolve) => {
292
+ ws.addEventListener("open", () => resolve(), { once: true });
293
+ });
294
+
295
+ // Send a request to echo the auth data (which should include conn params from auth)
296
+ ws.send(JSON.stringify({ type: "getAuthData" }));
297
+
298
+ const response = await new Promise<any>((resolve, reject) => {
299
+ ws.addEventListener("message", (event: any) => {
300
+ const data = JSON.parse(event.data as string);
301
+ if (data.type === "authData") {
302
+ resolve(data);
303
+ }
304
+ });
305
+ ws.addEventListener("close", reject);
306
+ });
307
+
308
+ // For now, just verify we get a response
309
+ // The actual connection params handling needs to be implemented
310
+ expect(response).toBeDefined();
311
+
312
+ ws.close();
313
+ });
314
+
315
+ test("should handle connection close properly", async (c) => {
316
+ const { client } = await setupDriverTest(c, driverTestConfig);
317
+ const actor = client.rawWebSocketActor.getOrCreate(["close-test"]);
318
+
319
+ const ws = await actor.websocket();
320
+
321
+ // Check if WebSocket is already open
322
+ if (ws.readyState !== WebSocket.OPEN) {
323
+ await new Promise<void>((resolve, reject) => {
324
+ ws.addEventListener("open", () => resolve(), { once: true });
325
+ ws.addEventListener("close", reject);
326
+ });
327
+ }
328
+
329
+ // Get initial stats
330
+ const initialStats = await actor.getStats();
331
+ expect(initialStats.connectionCount).toBe(1);
332
+
333
+ // Wait for close event on client side
334
+ const closePromise = new Promise<void>((resolve) => {
335
+ ws.addEventListener("close", () => resolve(), { once: true });
336
+ });
337
+
338
+ // Close connection
339
+ ws.close();
340
+ await closePromise;
341
+
342
+ // Poll getStats until connection count is 0
343
+ let finalStats: any;
344
+ for (let i = 0; i < 20; i++) {
345
+ finalStats = await actor.getStats();
346
+ if (finalStats.connectionCount === 0) {
347
+ break;
348
+ }
349
+ await new Promise((resolve) => setTimeout(resolve, 50));
350
+ }
351
+
352
+ // Check stats after close
353
+ expect(finalStats?.connectionCount).toBe(0);
354
+ });
355
+
356
+ test("should properly handle onWebSocket open and close events", async (c) => {
357
+ const { client } = await setupDriverTest(c, driverTestConfig);
358
+ const actor = client.rawWebSocketActor.getOrCreate(["open-close-test"]);
359
+
360
+ // Create first connection
361
+ const ws1 = await actor.websocket();
362
+
363
+ // Wait for open event
364
+ await new Promise<void>((resolve, reject) => {
365
+ ws1.addEventListener("open", () => resolve(), { once: true });
366
+ ws1.addEventListener("close", reject);
367
+ });
368
+
369
+ // Wait for welcome message which confirms onWebSocket was called
370
+ const welcome1 = await new Promise<any>((resolve, reject) => {
371
+ ws1.addEventListener(
372
+ "message",
373
+ (event: any) => {
374
+ resolve(JSON.parse(event.data as string));
375
+ },
376
+ { once: true },
377
+ );
378
+ ws1.addEventListener("close", reject);
379
+ });
380
+
381
+ expect(welcome1.type).toBe("welcome");
382
+ expect(welcome1.connectionCount).toBe(1);
383
+
384
+ // Create second connection to same actor
385
+ const ws2 = await actor.websocket();
386
+
387
+ await new Promise<void>((resolve, reject) => {
388
+ ws2.addEventListener("open", () => resolve(), { once: true });
389
+ ws2.addEventListener("close", reject);
390
+ });
391
+
392
+ const welcome2 = await new Promise<any>((resolve, reject) => {
393
+ ws2.addEventListener(
394
+ "message",
395
+ (event: any) => {
396
+ resolve(JSON.parse(event.data as string));
397
+ },
398
+ { once: true },
399
+ );
400
+ ws2.addEventListener("close", reject);
401
+ });
402
+
403
+ expect(welcome2.type).toBe("welcome");
404
+ expect(welcome2.connectionCount).toBe(2);
405
+
406
+ // Verify stats
407
+ const midStats = await actor.getStats();
408
+ expect(midStats.connectionCount).toBe(2);
409
+
410
+ // Close first connection
411
+ ws1.close();
412
+ await new Promise<void>((resolve) => {
413
+ ws1.addEventListener("close", () => resolve(), { once: true });
414
+ });
415
+
416
+ // Poll getStats until connection count decreases to 1
417
+ let afterFirstClose: any;
418
+ for (let i = 0; i < 20; i++) {
419
+ afterFirstClose = await actor.getStats();
420
+ if (afterFirstClose.connectionCount === 1) {
421
+ break;
422
+ }
423
+ await new Promise((resolve) => setTimeout(resolve, 50));
424
+ }
425
+
426
+ // Verify connection count decreased
427
+ expect(afterFirstClose?.connectionCount).toBe(1);
428
+
429
+ // Close second connection
430
+ ws2.close();
431
+ await new Promise<void>((resolve) => {
432
+ ws2.addEventListener("close", () => resolve(), { once: true });
433
+ });
434
+
435
+ // Poll getStats until connection count is 0
436
+ let finalStats: any;
437
+ for (let i = 0; i < 20; i++) {
438
+ finalStats = await actor.getStats();
439
+ if (finalStats.connectionCount === 0) {
440
+ break;
441
+ }
442
+ await new Promise((resolve) => setTimeout(resolve, 50));
443
+ }
444
+
445
+ // Verify final state
446
+ expect(finalStats?.connectionCount).toBe(0);
447
+ });
448
+
449
+ test("should handle query parameters in websocket paths", async (c) => {
450
+ const { client } = await setupDriverTest(c, driverTestConfig);
451
+ const actor = client.rawWebSocketActor.getOrCreate(["query-params"]);
452
+
453
+ // Test WebSocket with query parameters
454
+ const ws = await actor.websocket("api/v1/stream?token=abc123&user=test");
455
+
456
+ await new Promise<void>((resolve, reject) => {
457
+ ws.addEventListener("open", () => resolve(), { once: true });
458
+ ws.addEventListener("error", reject);
459
+ });
460
+
461
+ const requestInfoPromise = new Promise<any>((resolve, reject) => {
462
+ ws.addEventListener("message", (event: any) => {
463
+ const data = JSON.parse(event.data as string);
464
+ if (data.type === "requestInfo") {
465
+ resolve(data);
466
+ }
467
+ });
468
+ ws.addEventListener("close", reject);
469
+ });
470
+
471
+ // Send request to get the request info
472
+ ws.send(JSON.stringify({ type: "getRequestInfo" }));
473
+
474
+ const requestInfo = await requestInfoPromise;
475
+
476
+ // Verify the path and query parameters were preserved
477
+ expect(requestInfo.url).toContain("api/v1/stream");
478
+ expect(requestInfo.url).toContain("token=abc123");
479
+ expect(requestInfo.url).toContain("user=test");
480
+
481
+ ws.close();
482
+ });
483
+ });
484
+ }