rivetkit 2.0.2 → 2.0.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.
Files changed (246) hide show
  1. package/README.md +3 -5
  2. package/dist/schemas/actor-persist/v1.ts +225 -0
  3. package/dist/schemas/client-protocol/v1.ts +435 -0
  4. package/dist/schemas/file-system-driver/v1.ts +102 -0
  5. package/dist/tsup/actor/errors.cjs +77 -0
  6. package/dist/tsup/actor/errors.cjs.map +1 -0
  7. package/dist/tsup/actor/errors.d.cts +156 -0
  8. package/dist/tsup/actor/errors.d.ts +156 -0
  9. package/dist/tsup/actor/errors.js +77 -0
  10. package/dist/tsup/actor/errors.js.map +1 -0
  11. package/dist/tsup/chunk-3F2YSRJL.js +117 -0
  12. package/dist/tsup/chunk-3F2YSRJL.js.map +1 -0
  13. package/dist/tsup/chunk-4CXBCT26.cjs +250 -0
  14. package/dist/tsup/chunk-4CXBCT26.cjs.map +1 -0
  15. package/dist/tsup/chunk-4R73YDN3.cjs +20 -0
  16. package/dist/tsup/chunk-4R73YDN3.cjs.map +1 -0
  17. package/dist/tsup/chunk-6LJT3QRL.cjs +539 -0
  18. package/dist/tsup/chunk-6LJT3QRL.cjs.map +1 -0
  19. package/dist/tsup/chunk-GICQ3YCU.cjs +1792 -0
  20. package/dist/tsup/chunk-GICQ3YCU.cjs.map +1 -0
  21. package/dist/tsup/chunk-H26RP6GD.js +251 -0
  22. package/dist/tsup/chunk-H26RP6GD.js.map +1 -0
  23. package/dist/tsup/chunk-HI3HWJRC.js +20 -0
  24. package/dist/tsup/chunk-HI3HWJRC.js.map +1 -0
  25. package/dist/tsup/chunk-HLLF4B4Q.js +1792 -0
  26. package/dist/tsup/chunk-HLLF4B4Q.js.map +1 -0
  27. package/dist/tsup/chunk-IH6CKNDW.cjs +117 -0
  28. package/dist/tsup/chunk-IH6CKNDW.cjs.map +1 -0
  29. package/dist/tsup/chunk-LV2S3OU3.js +250 -0
  30. package/dist/tsup/chunk-LV2S3OU3.js.map +1 -0
  31. package/dist/tsup/chunk-LWNKVZG5.cjs +251 -0
  32. package/dist/tsup/chunk-LWNKVZG5.cjs.map +1 -0
  33. package/dist/tsup/chunk-NFU2BBT5.js +374 -0
  34. package/dist/tsup/chunk-NFU2BBT5.js.map +1 -0
  35. package/dist/tsup/chunk-PQY7KKTL.js +539 -0
  36. package/dist/tsup/chunk-PQY7KKTL.js.map +1 -0
  37. package/dist/tsup/chunk-QK72M5JB.js +45 -0
  38. package/dist/tsup/chunk-QK72M5JB.js.map +1 -0
  39. package/dist/tsup/chunk-QNNXFOQV.cjs +45 -0
  40. package/dist/tsup/chunk-QNNXFOQV.cjs.map +1 -0
  41. package/dist/tsup/chunk-SBHHJ6QS.cjs +374 -0
  42. package/dist/tsup/chunk-SBHHJ6QS.cjs.map +1 -0
  43. package/dist/tsup/chunk-TQ62L3X7.js +325 -0
  44. package/dist/tsup/chunk-TQ62L3X7.js.map +1 -0
  45. package/dist/tsup/chunk-VO7ZRVVD.cjs +6293 -0
  46. package/dist/tsup/chunk-VO7ZRVVD.cjs.map +1 -0
  47. package/dist/tsup/chunk-WHBPJNGW.cjs +325 -0
  48. package/dist/tsup/chunk-WHBPJNGW.cjs.map +1 -0
  49. package/dist/tsup/chunk-XJQHKJ4P.js +6293 -0
  50. package/dist/tsup/chunk-XJQHKJ4P.js.map +1 -0
  51. package/dist/tsup/client/mod.cjs +32 -0
  52. package/dist/tsup/client/mod.cjs.map +1 -0
  53. package/dist/tsup/client/mod.d.cts +20 -0
  54. package/dist/tsup/client/mod.d.ts +20 -0
  55. package/dist/tsup/client/mod.js +32 -0
  56. package/dist/tsup/client/mod.js.map +1 -0
  57. package/dist/tsup/common/log.cjs +21 -0
  58. package/dist/tsup/common/log.cjs.map +1 -0
  59. package/dist/tsup/common/log.d.cts +26 -0
  60. package/dist/tsup/common/log.d.ts +26 -0
  61. package/dist/tsup/common/log.js +21 -0
  62. package/dist/tsup/common/log.js.map +1 -0
  63. package/dist/tsup/common/websocket.cjs +10 -0
  64. package/dist/tsup/common/websocket.cjs.map +1 -0
  65. package/dist/tsup/common/websocket.d.cts +3 -0
  66. package/dist/tsup/common/websocket.d.ts +3 -0
  67. package/dist/tsup/common/websocket.js +10 -0
  68. package/dist/tsup/common/websocket.js.map +1 -0
  69. package/dist/tsup/common-CXCe7s6i.d.cts +218 -0
  70. package/dist/tsup/common-CXCe7s6i.d.ts +218 -0
  71. package/dist/tsup/connection-BI-6UIBJ.d.ts +2087 -0
  72. package/dist/tsup/connection-Dyd4NLGW.d.cts +2087 -0
  73. package/dist/tsup/driver-helpers/mod.cjs +30 -0
  74. package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
  75. package/dist/tsup/driver-helpers/mod.d.cts +17 -0
  76. package/dist/tsup/driver-helpers/mod.d.ts +17 -0
  77. package/dist/tsup/driver-helpers/mod.js +30 -0
  78. package/dist/tsup/driver-helpers/mod.js.map +1 -0
  79. package/dist/tsup/driver-test-suite/mod.cjs +3411 -0
  80. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
  81. package/dist/tsup/driver-test-suite/mod.d.cts +63 -0
  82. package/dist/tsup/driver-test-suite/mod.d.ts +63 -0
  83. package/dist/tsup/driver-test-suite/mod.js +3411 -0
  84. package/dist/tsup/driver-test-suite/mod.js.map +1 -0
  85. package/dist/tsup/inspector/mod.cjs +51 -0
  86. package/dist/tsup/inspector/mod.cjs.map +1 -0
  87. package/dist/tsup/inspector/mod.d.cts +408 -0
  88. package/dist/tsup/inspector/mod.d.ts +408 -0
  89. package/dist/tsup/inspector/mod.js +51 -0
  90. package/dist/tsup/inspector/mod.js.map +1 -0
  91. package/dist/tsup/mod.cjs +67 -0
  92. package/dist/tsup/mod.cjs.map +1 -0
  93. package/dist/tsup/mod.d.cts +105 -0
  94. package/dist/tsup/mod.d.ts +105 -0
  95. package/dist/tsup/mod.js +67 -0
  96. package/dist/tsup/mod.js.map +1 -0
  97. package/dist/tsup/router-endpoints-BTe_Rsdn.d.cts +65 -0
  98. package/dist/tsup/router-endpoints-CBSrKHmo.d.ts +65 -0
  99. package/dist/tsup/test/mod.cjs +17 -0
  100. package/dist/tsup/test/mod.cjs.map +1 -0
  101. package/dist/tsup/test/mod.d.cts +26 -0
  102. package/dist/tsup/test/mod.d.ts +26 -0
  103. package/dist/tsup/test/mod.js +17 -0
  104. package/dist/tsup/test/mod.js.map +1 -0
  105. package/dist/tsup/utils-fwx3o3K9.d.cts +18 -0
  106. package/dist/tsup/utils-fwx3o3K9.d.ts +18 -0
  107. package/dist/tsup/utils.cjs +26 -0
  108. package/dist/tsup/utils.cjs.map +1 -0
  109. package/dist/tsup/utils.d.cts +36 -0
  110. package/dist/tsup/utils.d.ts +36 -0
  111. package/dist/tsup/utils.js +26 -0
  112. package/dist/tsup/utils.js.map +1 -0
  113. package/package.json +208 -5
  114. package/src/actor/action.ts +178 -0
  115. package/src/actor/config.ts +497 -0
  116. package/src/actor/connection.ts +257 -0
  117. package/src/actor/context.ts +168 -0
  118. package/src/actor/database.ts +23 -0
  119. package/src/actor/definition.ts +82 -0
  120. package/src/actor/driver.ts +84 -0
  121. package/src/actor/errors.ts +422 -0
  122. package/src/actor/generic-conn-driver.ts +246 -0
  123. package/src/actor/instance.ts +1844 -0
  124. package/src/actor/keys.test.ts +266 -0
  125. package/src/actor/keys.ts +89 -0
  126. package/src/actor/log.ts +6 -0
  127. package/src/actor/mod.ts +108 -0
  128. package/src/actor/persisted.ts +42 -0
  129. package/src/actor/protocol/old.ts +297 -0
  130. package/src/actor/protocol/serde.ts +131 -0
  131. package/src/actor/router-endpoints.ts +688 -0
  132. package/src/actor/router.ts +265 -0
  133. package/src/actor/schedule.ts +17 -0
  134. package/src/actor/unstable-react.ts +110 -0
  135. package/src/actor/utils.ts +102 -0
  136. package/src/client/actor-common.ts +30 -0
  137. package/src/client/actor-conn.ts +865 -0
  138. package/src/client/actor-handle.ts +268 -0
  139. package/src/client/actor-query.ts +65 -0
  140. package/src/client/client.ts +554 -0
  141. package/src/client/config.ts +44 -0
  142. package/src/client/errors.ts +42 -0
  143. package/src/client/log.ts +5 -0
  144. package/src/client/mod.ts +60 -0
  145. package/src/client/raw-utils.ts +149 -0
  146. package/src/client/test.ts +44 -0
  147. package/src/client/utils.ts +152 -0
  148. package/src/common/eventsource-interface.ts +47 -0
  149. package/src/common/eventsource.ts +80 -0
  150. package/src/common/fake-event-source.ts +267 -0
  151. package/src/common/inline-websocket-adapter2.ts +454 -0
  152. package/src/common/log-levels.ts +27 -0
  153. package/src/common/log.ts +214 -0
  154. package/src/common/logfmt.ts +219 -0
  155. package/src/common/network.ts +2 -0
  156. package/src/common/router.ts +80 -0
  157. package/src/common/utils.ts +336 -0
  158. package/src/common/versioned-data.ts +95 -0
  159. package/src/common/websocket-interface.ts +49 -0
  160. package/src/common/websocket.ts +42 -0
  161. package/src/driver-helpers/mod.ts +22 -0
  162. package/src/driver-helpers/utils.ts +17 -0
  163. package/src/driver-test-suite/log.ts +5 -0
  164. package/src/driver-test-suite/mod.ts +239 -0
  165. package/src/driver-test-suite/tests/action-features.ts +136 -0
  166. package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
  167. package/src/driver-test-suite/tests/actor-conn.ts +349 -0
  168. package/src/driver-test-suite/tests/actor-driver.ts +25 -0
  169. package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
  170. package/src/driver-test-suite/tests/actor-handle.ts +292 -0
  171. package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
  172. package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
  173. package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
  174. package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
  175. package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
  176. package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
  177. package/src/driver-test-suite/tests/actor-state.ts +54 -0
  178. package/src/driver-test-suite/tests/actor-vars.ts +93 -0
  179. package/src/driver-test-suite/tests/manager-driver.ts +367 -0
  180. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +227 -0
  181. package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
  182. package/src/driver-test-suite/tests/raw-http.ts +347 -0
  183. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +393 -0
  184. package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
  185. package/src/driver-test-suite/tests/request-access.ts +230 -0
  186. package/src/driver-test-suite/utils.ts +71 -0
  187. package/src/drivers/default.ts +34 -0
  188. package/src/drivers/engine/actor-driver.ts +369 -0
  189. package/src/drivers/engine/config.ts +31 -0
  190. package/src/drivers/engine/kv.ts +3 -0
  191. package/src/drivers/engine/log.ts +5 -0
  192. package/src/drivers/engine/mod.ts +35 -0
  193. package/src/drivers/file-system/actor.ts +91 -0
  194. package/src/drivers/file-system/global-state.ts +686 -0
  195. package/src/drivers/file-system/log.ts +5 -0
  196. package/src/drivers/file-system/manager.ts +329 -0
  197. package/src/drivers/file-system/mod.ts +48 -0
  198. package/src/drivers/file-system/utils.ts +109 -0
  199. package/src/globals.d.ts +6 -0
  200. package/src/inspector/actor.ts +298 -0
  201. package/src/inspector/config.ts +88 -0
  202. package/src/inspector/log.ts +5 -0
  203. package/src/inspector/manager.ts +86 -0
  204. package/src/inspector/mod.ts +2 -0
  205. package/src/inspector/protocol/actor.ts +10 -0
  206. package/src/inspector/protocol/common.ts +196 -0
  207. package/src/inspector/protocol/manager.ts +10 -0
  208. package/src/inspector/protocol/mod.ts +2 -0
  209. package/src/inspector/utils.ts +76 -0
  210. package/src/manager/driver.ts +88 -0
  211. package/src/manager/hono-websocket-adapter.ts +342 -0
  212. package/src/manager/log.ts +5 -0
  213. package/src/manager/mod.ts +2 -0
  214. package/src/manager/protocol/mod.ts +24 -0
  215. package/src/manager/protocol/query.ts +89 -0
  216. package/src/manager/router.ts +412 -0
  217. package/src/manager-api/routes/actors-create.ts +16 -0
  218. package/src/manager-api/routes/actors-delete.ts +4 -0
  219. package/src/manager-api/routes/actors-get-by-id.ts +7 -0
  220. package/src/manager-api/routes/actors-get-or-create-by-id.ts +29 -0
  221. package/src/manager-api/routes/actors-get.ts +7 -0
  222. package/src/manager-api/routes/common.ts +18 -0
  223. package/src/mod.ts +18 -0
  224. package/src/registry/config.ts +32 -0
  225. package/src/registry/log.ts +5 -0
  226. package/src/registry/mod.ts +157 -0
  227. package/src/registry/run-config.ts +52 -0
  228. package/src/registry/serve.ts +52 -0
  229. package/src/remote-manager-driver/actor-http-client.ts +72 -0
  230. package/src/remote-manager-driver/actor-websocket-client.ts +63 -0
  231. package/src/remote-manager-driver/api-endpoints.ts +79 -0
  232. package/src/remote-manager-driver/api-utils.ts +43 -0
  233. package/src/remote-manager-driver/log.ts +5 -0
  234. package/src/remote-manager-driver/mod.ts +274 -0
  235. package/src/remote-manager-driver/ws-proxy.ts +180 -0
  236. package/src/schemas/actor-persist/mod.ts +1 -0
  237. package/src/schemas/actor-persist/versioned.ts +25 -0
  238. package/src/schemas/client-protocol/mod.ts +1 -0
  239. package/src/schemas/client-protocol/versioned.ts +63 -0
  240. package/src/schemas/file-system-driver/mod.ts +1 -0
  241. package/src/schemas/file-system-driver/versioned.ts +28 -0
  242. package/src/serde.ts +90 -0
  243. package/src/test/config.ts +16 -0
  244. package/src/test/log.ts +5 -0
  245. package/src/test/mod.ts +154 -0
  246. package/src/utils.ts +172 -0
@@ -0,0 +1,349 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import type { DriverTestConfig } from "../mod";
3
+ import { FAKE_TIME, setupDriverTest, waitFor } from "../utils";
4
+
5
+ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
6
+ describe("Actor Connection Tests", () => {
7
+ describe("Connection Methods", () => {
8
+ test("should connect using .get().connect()", async (c) => {
9
+ const { client } = await setupDriverTest(c, driverTestConfig);
10
+
11
+ // Create actor
12
+ await client.counter.create(["test-get"]);
13
+
14
+ // Get a handle and connect
15
+ const handle = client.counter.get(["test-get"]);
16
+ const connection = handle.connect();
17
+
18
+ // Verify connection by performing an action
19
+ const count = await connection.increment(5);
20
+ expect(count).toBe(5);
21
+
22
+ // Clean up
23
+ await connection.dispose();
24
+ });
25
+
26
+ test("should connect using .getForId().connect()", async (c) => {
27
+ const { client } = await setupDriverTest(c, driverTestConfig);
28
+
29
+ // Create a actor first to get its ID
30
+ const handle = client.counter.getOrCreate(["test-get-for-id"]);
31
+ await handle.increment(3);
32
+ const actorId = await handle.resolve();
33
+
34
+ // Get a new handle using the actor ID and connect
35
+ const idHandle = client.counter.getForId(actorId);
36
+ const connection = idHandle.connect();
37
+
38
+ // Verify connection works and state is preserved
39
+ const count = await connection.getCount();
40
+ expect(count).toBe(3);
41
+
42
+ // Clean up
43
+ await connection.dispose();
44
+ });
45
+
46
+ test("should connect using .getOrCreate().connect()", async (c) => {
47
+ const { client } = await setupDriverTest(c, driverTestConfig);
48
+
49
+ // Get or create actor and connect
50
+ const handle = client.counter.getOrCreate(["test-get-or-create"]);
51
+ const connection = handle.connect();
52
+
53
+ // Verify connection works
54
+ const count = await connection.increment(7);
55
+ expect(count).toBe(7);
56
+
57
+ // Clean up
58
+ await connection.dispose();
59
+ });
60
+
61
+ test("should connect using (await create()).connect()", async (c) => {
62
+ const { client } = await setupDriverTest(c, driverTestConfig);
63
+
64
+ // Create actor and connect
65
+ const handle = await client.counter.create(["test-create"]);
66
+ const connection = handle.connect();
67
+
68
+ // Verify connection works
69
+ const count = await connection.increment(9);
70
+ expect(count).toBe(9);
71
+
72
+ // Clean up
73
+ await connection.dispose();
74
+ });
75
+ });
76
+
77
+ describe("Event Communication", () => {
78
+ test("should mix RPC calls and WebSocket events", async (c) => {
79
+ const { client } = await setupDriverTest(c, driverTestConfig);
80
+
81
+ // Create actor
82
+ const handle = client.counter.getOrCreate(["test-mixed-rpc-ws"]);
83
+ const connection = handle.connect();
84
+
85
+ // Set up event listener
86
+ const receivedEvents: number[] = [];
87
+ const receivedEventsPromise = new Promise((resolve) => {
88
+ connection.on("newCount", (count: number) => {
89
+ receivedEvents.push(count);
90
+ if (
91
+ receivedEvents.includes(1) &&
92
+ receivedEvents.includes(6) &&
93
+ receivedEvents.includes(9)
94
+ )
95
+ resolve(undefined);
96
+ });
97
+ });
98
+
99
+ // Send one RPC call over the connection to ensure it's open
100
+ await connection.increment(1);
101
+
102
+ // Now use stateless RPC calls through the handle (no connection)
103
+ // These should still trigger events that the connection receives
104
+ await handle.increment(5);
105
+ await handle.increment(3);
106
+
107
+ // Wait for all events to be received
108
+ await receivedEventsPromise;
109
+
110
+ // Clean up
111
+ await connection.dispose();
112
+ });
113
+
114
+ test("should receive events via broadcast", async (c) => {
115
+ const { client } = await setupDriverTest(c, driverTestConfig);
116
+
117
+ // Create actor and connect
118
+ const handle = client.counter.getOrCreate(["test-broadcast"]);
119
+ const connection = handle.connect();
120
+
121
+ // Set up event listener
122
+ const receivedEvents: number[] = [];
123
+ connection.on("newCount", (count: number) => {
124
+ receivedEvents.push(count);
125
+ });
126
+
127
+ // Trigger broadcast events
128
+ await connection.increment(5);
129
+ await connection.increment(3);
130
+
131
+ // Verify events were received
132
+ expect(receivedEvents).toContain(5);
133
+ expect(receivedEvents).toContain(8);
134
+
135
+ // Clean up
136
+ await connection.dispose();
137
+ });
138
+
139
+ test("should handle one-time events with once()", async (c) => {
140
+ const { client } = await setupDriverTest(c, driverTestConfig);
141
+
142
+ // Create actor and connect
143
+ const handle = client.counter.getOrCreate(["test-once"]);
144
+ const connection = handle.connect();
145
+
146
+ // Set up one-time event listener
147
+ const receivedEvents: number[] = [];
148
+ connection.once("newCount", (count: number) => {
149
+ receivedEvents.push(count);
150
+ });
151
+
152
+ // Trigger multiple events, but should only receive the first one
153
+ await connection.increment(5);
154
+ await connection.increment(3);
155
+
156
+ // Verify only the first event was received
157
+ expect(receivedEvents).toEqual([5]);
158
+ expect(receivedEvents).not.toContain(8);
159
+
160
+ // Clean up
161
+ await connection.dispose();
162
+ });
163
+
164
+ test("should unsubscribe from events", async (c) => {
165
+ const { client } = await setupDriverTest(c, driverTestConfig);
166
+
167
+ // Create actor and connect
168
+ const handle = client.counter.getOrCreate(["test-unsubscribe"]);
169
+ const connection = handle.connect();
170
+
171
+ // Set up event listener with unsubscribe
172
+ const receivedEvents: number[] = [];
173
+ const unsubscribe = connection.on("newCount", (count: number) => {
174
+ receivedEvents.push(count);
175
+ });
176
+
177
+ // Trigger first event
178
+ await connection.increment(5);
179
+
180
+ // Unsubscribe
181
+ unsubscribe();
182
+
183
+ // Trigger second event, should not be received
184
+ await connection.increment(3);
185
+
186
+ // Verify only the first event was received
187
+ expect(receivedEvents).toEqual([5]);
188
+ expect(receivedEvents).not.toContain(8);
189
+
190
+ // Clean up
191
+ await connection.dispose();
192
+ });
193
+ });
194
+
195
+ describe("Connection Parameters", () => {
196
+ test("should pass connection parameters", async (c) => {
197
+ const { client } = await setupDriverTest(c, driverTestConfig);
198
+
199
+ // Create two connections with different params
200
+ const handle1 = client.counterWithParams.getOrCreate(["test-params"], {
201
+ params: { name: "user1" },
202
+ });
203
+ const handle2 = client.counterWithParams.getOrCreate(["test-params"], {
204
+ params: { name: "user2" },
205
+ });
206
+
207
+ const conn1 = handle1.connect();
208
+ const conn2 = handle2.connect();
209
+
210
+ // HACK: Call an action to wait for the connections to be established
211
+ await conn1.getInitializers();
212
+ await conn2.getInitializers();
213
+
214
+ // Get initializers to verify connection params were used
215
+ const initializers = await conn1.getInitializers();
216
+
217
+ // Verify both connection names were recorded
218
+ expect(initializers).toContain("user1");
219
+ expect(initializers).toContain("user2");
220
+
221
+ // Clean up
222
+ await conn1.dispose();
223
+ await conn2.dispose();
224
+ });
225
+ });
226
+
227
+ describe("Lifecycle Hooks", () => {
228
+ test("should trigger lifecycle hooks", async (c) => {
229
+ const { client } = await setupDriverTest(c, driverTestConfig);
230
+
231
+ // Create and connect
232
+ const connHandle = client.counterWithLifecycle.getOrCreate(
233
+ ["test-lifecycle"],
234
+ {
235
+ params: { trackLifecycle: true },
236
+ },
237
+ );
238
+ const connection = connHandle.connect();
239
+
240
+ // Verify lifecycle events were triggered
241
+ const events = await connection.getEvents();
242
+ expect(events).toEqual(["onStart", "onBeforeConnect", "onConnect"]);
243
+
244
+ // Disconnect should trigger onDisconnect
245
+ await connection.dispose();
246
+
247
+ // Reconnect to check if onDisconnect was called
248
+ const handle = client.counterWithLifecycle.getOrCreate([
249
+ "test-lifecycle",
250
+ ]);
251
+ const finalEvents = await handle.getEvents();
252
+ expect(finalEvents).toBeOneOf([
253
+ // Still active
254
+ ["onStart", "onBeforeConnect", "onConnect", "onDisconnect"],
255
+ // Went to sleep and woke back up
256
+ [
257
+ "onStart",
258
+ "onBeforeConnect",
259
+ "onConnect",
260
+ "onDisconnect",
261
+ "onStart",
262
+ ],
263
+ ]);
264
+ });
265
+ });
266
+
267
+ describe("Connection Liveness", () => {
268
+ // TODO: KIT-242
269
+ test.skip("should return correct liveness status for connections", async (c) => {
270
+ const { client } = await setupDriverTest(c, driverTestConfig);
271
+
272
+ // Create actor and connection
273
+ const handle = client.connLivenessActor.getOrCreate([
274
+ "test-liveness-status",
275
+ ]);
276
+ const connA = handle.connect();
277
+ const connB = handle.connect();
278
+
279
+ const connAId = await connA.getConnectionId();
280
+ const connBId = await connB.getConnectionId();
281
+
282
+ // Verify connection works initially
283
+ await connA.increment(5);
284
+ await connB.increment(5);
285
+
286
+ const counter = await handle.getCounter();
287
+ expect(counter).toBe(10);
288
+
289
+ const connectionsStatusBeforeKill =
290
+ await handle.getWsConnectionsLiveness();
291
+ expect(connectionsStatusBeforeKill).toHaveLength(2);
292
+ expect(connectionsStatusBeforeKill).toContainEqual(
293
+ expect.objectContaining({
294
+ id: connAId,
295
+ status: "connected",
296
+ lastSeen: FAKE_TIME.getTime(),
297
+ }),
298
+ );
299
+ expect(connectionsStatusBeforeKill).toContainEqual(
300
+ expect.objectContaining({
301
+ id: connBId,
302
+ status: "connected",
303
+ lastSeen: FAKE_TIME.getTime(),
304
+ }),
305
+ );
306
+
307
+ // Kill one connection
308
+ await handle.kill(connAId); // instead of dispose, we use kill to simulate a disconnection (e.g. network failure)
309
+ // connA.dispose();
310
+ // we killed the connection, but the actor instance does not know about it yet
311
+ // it should still be in the list of connections, but with a status of "reconnecting"
312
+ const connectionsStatusAfterKill =
313
+ await handle.getWsConnectionsLiveness();
314
+ expect(connectionsStatusAfterKill).toEqual(
315
+ expect.arrayContaining([
316
+ expect.objectContaining({
317
+ id: connAId,
318
+ status: "reconnecting",
319
+ lastSeen: FAKE_TIME.getTime(),
320
+ }),
321
+ expect.objectContaining({
322
+ id: connBId,
323
+ status: "connected",
324
+ lastSeen: FAKE_TIME.getTime(),
325
+ }),
326
+ ]),
327
+ );
328
+
329
+ // default time to wait for cleanup is 5 seconds
330
+ // check actor options
331
+ await waitFor(driverTestConfig, 5_000);
332
+
333
+ // After timeout, the killed connection should be unavailable, since the manager has cleaned it up
334
+ const connectionsStatusAfterCleanup =
335
+ await handle.getWsConnectionsLiveness();
336
+ expect(connectionsStatusAfterCleanup).not.toContainEqual(
337
+ expect.objectContaining({
338
+ id: connAId,
339
+ }),
340
+ );
341
+ expect(connectionsStatusAfterCleanup).toContainEqual(
342
+ expect.objectContaining({
343
+ id: connBId,
344
+ }),
345
+ );
346
+ });
347
+ });
348
+ });
349
+ }
@@ -0,0 +1,25 @@
1
+ import { describe } from "vitest";
2
+ import type { DriverTestConfig } from "../mod";
3
+ import { runActorScheduleTests } from "./actor-schedule";
4
+ import { runActorSleepTests } from "./actor-sleep";
5
+ import { runActorStateTests } from "./actor-state";
6
+
7
+ export function runActorDriverTests(driverTestConfig: DriverTestConfig) {
8
+ describe("Actor Driver Tests", () => {
9
+ // Run state persistence tests
10
+ runActorStateTests(driverTestConfig);
11
+
12
+ // Run scheduled alarms tests
13
+ runActorScheduleTests(driverTestConfig);
14
+ });
15
+ }
16
+
17
+ /** Actor driver tests that need to be tested for all transport mechanisms. */
18
+ export function runActorDriverTestsWithTransport(
19
+ driverTestConfig: DriverTestConfig,
20
+ ) {
21
+ describe("Actor Driver Tests", () => {
22
+ // Run actor sleep tests
23
+ runActorSleepTests(driverTestConfig);
24
+ });
25
+ }
@@ -0,0 +1,158 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import {
3
+ INTERNAL_ERROR_CODE,
4
+ INTERNAL_ERROR_DESCRIPTION,
5
+ } from "@/actor/errors";
6
+ import { assertUnreachable } from "@/actor/utils";
7
+ import type { DriverTestConfig } from "../mod";
8
+ import { setupDriverTest } from "../utils";
9
+
10
+ export function runActorErrorHandlingTests(driverTestConfig: DriverTestConfig) {
11
+ describe("Actor Error Handling Tests", () => {
12
+ describe("UserError Handling", () => {
13
+ test("should handle simple UserError with message", async (c) => {
14
+ const { client } = await setupDriverTest(c, driverTestConfig);
15
+
16
+ // Try to call an action that throws a simple UserError
17
+ const handle = client.errorHandlingActor.getOrCreate();
18
+
19
+ try {
20
+ await handle.throwSimpleError();
21
+ // If we get here, the test should fail
22
+ expect(true).toBe(false); // This should not be reached
23
+ } catch (error: any) {
24
+ // Verify the error properties
25
+ expect(error.message).toBe("Simple error message");
26
+ // Default code is "user_error" when not specified
27
+ expect(error.code).toBe("user_error");
28
+ // No metadata by default
29
+ expect(error.metadata).toBeUndefined();
30
+ }
31
+ });
32
+
33
+ test("should handle detailed UserError with code and metadata", async (c) => {
34
+ const { client } = await setupDriverTest(c, driverTestConfig);
35
+
36
+ // Try to call an action that throws a detailed UserError
37
+ const handle = client.errorHandlingActor.getOrCreate();
38
+
39
+ try {
40
+ await handle.throwDetailedError();
41
+ // If we get here, the test should fail
42
+ expect(true).toBe(false); // This should not be reached
43
+ } catch (error: any) {
44
+ // Verify the error properties
45
+ expect(error.message).toBe("Detailed error message");
46
+ expect(error.code).toBe("detailed_error");
47
+ expect(error.metadata).toBeDefined();
48
+ expect(error.metadata.reason).toBe("test");
49
+ expect(error.metadata.timestamp).toBeDefined();
50
+ }
51
+ });
52
+ });
53
+
54
+ describe("Internal Error Handling", () => {
55
+ test("should convert internal errors to safe format", async (c) => {
56
+ const { client } = await setupDriverTest(c, driverTestConfig);
57
+
58
+ // Try to call an action that throws an internal error
59
+ const handle = client.errorHandlingActor.getOrCreate();
60
+
61
+ try {
62
+ await handle.throwInternalError();
63
+ // If we get here, the test should fail
64
+ expect(true).toBe(false); // This should not be reached
65
+ } catch (error: any) {
66
+ if (driverTestConfig.clientType === "http") {
67
+ // Verify the error is converted to a safe format
68
+ expect(error.code).toBe(INTERNAL_ERROR_CODE);
69
+ // Original error details should not be exposed
70
+ expect(error.message).toBe(INTERNAL_ERROR_DESCRIPTION);
71
+ } else if (driverTestConfig.clientType === "inline") {
72
+ // Verify that original error is preserved
73
+ expect(error.code).toBe(INTERNAL_ERROR_CODE);
74
+ expect(error.message).toBe("This is an internal error");
75
+ } else {
76
+ assertUnreachable(driverTestConfig.clientType);
77
+ }
78
+ }
79
+ });
80
+ });
81
+
82
+ // TODO: Does not work with fake timers
83
+ describe.skip("Action Timeout", () => {
84
+ test("should handle action timeouts with custom duration", async (c) => {
85
+ const { client } = await setupDriverTest(c, driverTestConfig);
86
+
87
+ // Call an action that should time out
88
+ const handle = client.errorHandlingActor.getOrCreate();
89
+
90
+ // This should throw a timeout error because errorHandlingActor has
91
+ // a 500ms timeout and this action tries to run for much longer
92
+ const timeoutPromise = handle.timeoutAction();
93
+
94
+ try {
95
+ await timeoutPromise;
96
+ // If we get here, the test failed - timeout didn't occur
97
+ expect(true).toBe(false); // This should not be reached
98
+ } catch (error: any) {
99
+ // Verify it's a timeout error
100
+ expect(error.message).toMatch(/timed out/i);
101
+ }
102
+ });
103
+
104
+ test("should successfully run actions within timeout", async (c) => {
105
+ const { client } = await setupDriverTest(c, driverTestConfig);
106
+
107
+ // Call an action with a delay shorter than the timeout
108
+ const handle = client.errorHandlingActor.getOrCreate();
109
+
110
+ // This should succeed because 200ms < 500ms timeout
111
+ const result = await handle.delayedAction(200);
112
+ expect(result).toBe("Completed after 200ms");
113
+ });
114
+
115
+ test("should respect different timeouts for different actors", async (c) => {
116
+ const { client } = await setupDriverTest(c, driverTestConfig);
117
+
118
+ // The following actors have different timeout settings:
119
+ // customTimeoutActor: 200ms timeout
120
+ // standardTimeoutActor: default timeout (much longer)
121
+
122
+ // This should fail - 300ms delay with 200ms timeout
123
+ try {
124
+ await client.customTimeoutActor.getOrCreate().slowAction();
125
+ // Should not reach here
126
+ expect(true).toBe(false);
127
+ } catch (error: any) {
128
+ expect(error.message).toMatch(/timed out/i);
129
+ }
130
+
131
+ // This should succeed - 50ms delay with 200ms timeout
132
+ const quickResult = await client.customTimeoutActor
133
+ .getOrCreate()
134
+ .quickAction();
135
+ expect(quickResult).toBe("Quick action completed");
136
+ });
137
+ });
138
+
139
+ describe("Error Recovery", () => {
140
+ test("should continue working after errors", async (c) => {
141
+ const { client } = await setupDriverTest(c, driverTestConfig);
142
+
143
+ const handle = client.errorHandlingActor.getOrCreate();
144
+
145
+ // Trigger an error
146
+ try {
147
+ await handle.throwSimpleError();
148
+ } catch (error) {
149
+ // Ignore error
150
+ }
151
+
152
+ // Actor should still work after error
153
+ const result = await handle.successfulAction();
154
+ expect(result).toBe("success");
155
+ });
156
+ });
157
+ });
158
+ }