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,239 @@
1
+ import { serve as honoServe } from "@hono/node-server";
2
+ import { createNodeWebSocket, type NodeWebSocket } from "@hono/node-ws";
3
+ import { bundleRequire } from "bundle-require";
4
+ import invariant from "invariant";
5
+ import { describe } from "vitest";
6
+ import type { Transport } from "@/client/mod";
7
+ import { createManagerRouter } from "@/manager/router";
8
+ import type { DriverConfig, Registry, RunConfig } from "@/mod";
9
+ import { RunConfigSchema } from "@/registry/run-config";
10
+ import { getPort } from "@/test/mod";
11
+ import { logger } from "./log";
12
+ import { runActionFeaturesTests } from "./tests/action-features";
13
+ import { runActorConnTests } from "./tests/actor-conn";
14
+ import { runActorConnStateTests } from "./tests/actor-conn-state";
15
+ import {
16
+ runActorDriverTests,
17
+ runActorDriverTestsWithTransport,
18
+ } from "./tests/actor-driver";
19
+ import { runActorErrorHandlingTests } from "./tests/actor-error-handling";
20
+ import { runActorHandleTests } from "./tests/actor-handle";
21
+ import { runActorInlineClientTests } from "./tests/actor-inline-client";
22
+ import { runActorInspectorTests } from "./tests/actor-inspector";
23
+ import { runActorMetadataTests } from "./tests/actor-metadata";
24
+ import { runActorOnStateChangeTests } from "./tests/actor-onstatechange";
25
+ import { runActorVarsTests } from "./tests/actor-vars";
26
+ import { runManagerDriverTests } from "./tests/manager-driver";
27
+ import { runRawHttpTests } from "./tests/raw-http";
28
+ import { runRawHttpRequestPropertiesTests } from "./tests/raw-http-request-properties";
29
+ import { runRawWebSocketTests } from "./tests/raw-websocket";
30
+ import { runRequestAccessTests } from "./tests/request-access";
31
+
32
+ export interface SkipTests {
33
+ schedule?: boolean;
34
+ sleep?: boolean;
35
+ }
36
+
37
+ export interface DriverTestConfig {
38
+ /** Deploys an registry and returns the connection endpoint. */
39
+ start(projectDir: string): Promise<DriverDeployOutput>;
40
+
41
+ /**
42
+ * If we're testing with an external system, we should use real timers
43
+ * instead of Vitest's mocked timers.
44
+ **/
45
+ useRealTimers?: boolean;
46
+
47
+ /** Cloudflare Workers has some bugs with cleanup. */
48
+ HACK_skipCleanupNet?: boolean;
49
+
50
+ skip?: SkipTests;
51
+
52
+ transport?: Transport;
53
+
54
+ clientType: ClientType;
55
+
56
+ cleanup?: () => Promise<void>;
57
+ }
58
+
59
+ /**
60
+ * The type of client to run the test with.
61
+ *
62
+ * The logic for HTTP vs inline is very different, so this helps validate all behavior matches.
63
+ **/
64
+ type ClientType = "http" | "inline";
65
+
66
+ export interface DriverDeployOutput {
67
+ endpoint: string;
68
+ namespace: string;
69
+ runnerName: string;
70
+
71
+ /** Cleans up the test. */
72
+ cleanup(): Promise<void>;
73
+ }
74
+
75
+ /** Runs all Vitest tests against the provided drivers. */
76
+ export function runDriverTests(
77
+ driverTestConfigPartial: Omit<DriverTestConfig, "clientType" | "transport">,
78
+ ) {
79
+ for (const clientType of ["http", "inline"] as ClientType[]) {
80
+ const driverTestConfig: DriverTestConfig = {
81
+ ...driverTestConfigPartial,
82
+ clientType,
83
+ };
84
+
85
+ describe(`client type (${clientType})`, () => {
86
+ runActorDriverTests(driverTestConfig);
87
+ runManagerDriverTests(driverTestConfig);
88
+
89
+ for (const transport of ["websocket", "sse"] as Transport[]) {
90
+ describe(`transport (${transport})`, () => {
91
+ runActorConnTests({
92
+ ...driverTestConfig,
93
+ transport,
94
+ });
95
+
96
+ runActorConnStateTests({ ...driverTestConfig, transport });
97
+
98
+ runRequestAccessTests({ ...driverTestConfig, transport });
99
+
100
+ runActorDriverTestsWithTransport({ ...driverTestConfig, transport });
101
+ });
102
+ }
103
+
104
+ runActorHandleTests(driverTestConfig);
105
+
106
+ runActionFeaturesTests(driverTestConfig);
107
+
108
+ runActorVarsTests(driverTestConfig);
109
+
110
+ runActorMetadataTests(driverTestConfig);
111
+
112
+ runActorOnStateChangeTests(driverTestConfig);
113
+
114
+ runActorErrorHandlingTests(driverTestConfig);
115
+
116
+ runActorInlineClientTests(driverTestConfig);
117
+
118
+ runRawHttpTests(driverTestConfig);
119
+
120
+ runRawHttpRequestPropertiesTests(driverTestConfig);
121
+
122
+ runRawWebSocketTests(driverTestConfig);
123
+
124
+ // TODO: re-expose this once we can have actor queries on the gateway
125
+ // runRawHttpDirectRegistryTests(driverTestConfig);
126
+
127
+ // TODO: re-expose this once we can have actor queries on the gateway
128
+ // runRawWebSocketDirectRegistryTests(driverTestConfig);
129
+
130
+ runActorInspectorTests(driverTestConfig);
131
+ });
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Helper function to adapt the drivers to the Node.js runtime for tests.
137
+ *
138
+ * This is helpful for drivers that run in-process as opposed to drivers that rely on external tools.
139
+ */
140
+ export async function createTestRuntime(
141
+ registryPath: string,
142
+ driverFactory: (registry: Registry<any>) => Promise<{
143
+ rivetEngine?: { endpoint: string; namespace: string; runnerName: string };
144
+ driver: DriverConfig;
145
+ cleanup?: () => Promise<void>;
146
+ }>,
147
+ ): Promise<DriverDeployOutput> {
148
+ const {
149
+ mod: { registry },
150
+ } = await bundleRequire<{ registry: Registry<any> }>({
151
+ filepath: registryPath,
152
+ });
153
+
154
+ // TODO: Find a cleaner way of flagging an registry as test mode (ideally not in the config itself)
155
+ // Force enable test
156
+ registry.config.test.enabled = true;
157
+
158
+ // Build drivers
159
+ const {
160
+ driver,
161
+ cleanup: driverCleanup,
162
+ rivetEngine,
163
+ } = await driverFactory(registry);
164
+
165
+ if (rivetEngine) {
166
+ // TODO: We don't need createTestRuntime fort his
167
+ // Using external Rivet engine
168
+
169
+ const cleanup = async () => {
170
+ await driverCleanup?.();
171
+ };
172
+
173
+ return {
174
+ endpoint: rivetEngine.endpoint,
175
+ namespace: rivetEngine.namespace,
176
+ runnerName: rivetEngine.runnerName,
177
+ cleanup,
178
+ };
179
+ } else {
180
+ // Start server for Rivet engine
181
+
182
+ // Build driver config
183
+ // biome-ignore lint/style/useConst: Assigned later
184
+ let upgradeWebSocket: any;
185
+ const config: RunConfig = RunConfigSchema.parse({
186
+ driver,
187
+ getUpgradeWebSocket: () => upgradeWebSocket!,
188
+ inspector: {
189
+ enabled: true,
190
+ token: () => "token",
191
+ },
192
+ });
193
+
194
+ // Create router
195
+ const managerDriver = driver.manager(registry.config, config);
196
+ const { router } = createManagerRouter(
197
+ registry.config,
198
+ config,
199
+ managerDriver,
200
+ false,
201
+ );
202
+
203
+ // Inject WebSocket
204
+ const nodeWebSocket = createNodeWebSocket({ app: router });
205
+ upgradeWebSocket = nodeWebSocket.upgradeWebSocket;
206
+
207
+ // Start server
208
+ const port = await getPort();
209
+ const server = honoServe({
210
+ fetch: router.fetch,
211
+ hostname: "127.0.0.1",
212
+ port,
213
+ });
214
+ invariant(
215
+ nodeWebSocket.injectWebSocket !== undefined,
216
+ "should have injectWebSocket",
217
+ );
218
+ nodeWebSocket.injectWebSocket(server);
219
+ const serverEndpoint = `http://127.0.0.1:${port}`;
220
+
221
+ logger().info({ msg: "test serer listening", port });
222
+
223
+ // Cleanup
224
+ const cleanup = async () => {
225
+ // Stop server
226
+ await new Promise((resolve) => server.close(() => resolve(undefined)));
227
+
228
+ // Extra cleanup
229
+ await driverCleanup?.();
230
+ };
231
+
232
+ return {
233
+ endpoint: serverEndpoint,
234
+ namespace: "default",
235
+ runnerName: "rivetkit",
236
+ cleanup,
237
+ };
238
+ }
239
+ }
@@ -0,0 +1,136 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import type { ActorError } from "@/client/errors";
3
+ import type { DriverTestConfig } from "../mod";
4
+ import { setupDriverTest } from "../utils";
5
+
6
+ export function runActionFeaturesTests(driverTestConfig: DriverTestConfig) {
7
+ describe("Action Features", () => {
8
+ // TODO: These do not work with fake timers
9
+ describe("Action Timeouts", () => {
10
+ const usesFakeTimers = !driverTestConfig.useRealTimers;
11
+
12
+ test("should timeout actions that exceed the configured timeout", async (c) => {
13
+ const { client } = await setupDriverTest(c, driverTestConfig);
14
+
15
+ // The quick action should complete successfully
16
+ const quickResult = await client.shortTimeoutActor
17
+ .getOrCreate()
18
+ .quickAction();
19
+ expect(quickResult).toBe("quick response");
20
+
21
+ // The slow action should throw a timeout error
22
+ await expect(
23
+ client.shortTimeoutActor.getOrCreate().slowAction(),
24
+ ).rejects.toThrow("Action timed out");
25
+ });
26
+
27
+ test("should respect the default timeout", async (c) => {
28
+ const { client } = await setupDriverTest(c, driverTestConfig);
29
+
30
+ // This action should complete within the default timeout
31
+ const result = await client.defaultTimeoutActor
32
+ .getOrCreate()
33
+ .normalAction();
34
+ expect(result).toBe("normal response");
35
+ });
36
+
37
+ test("non-promise action results should not be affected by timeout", async (c) => {
38
+ const { client } = await setupDriverTest(c, driverTestConfig);
39
+
40
+ // Synchronous action should not be affected by timeout
41
+ const result = await client.syncTimeoutActor.getOrCreate().syncAction();
42
+ expect(result).toBe("sync response");
43
+ });
44
+
45
+ test("should allow configuring different timeouts for different actors", async (c) => {
46
+ const { client } = await setupDriverTest(c, driverTestConfig);
47
+
48
+ // The short timeout actor should fail
49
+ await expect(
50
+ client.shortTimeoutActor.getOrCreate().slowAction(),
51
+ ).rejects.toThrow("Action timed out");
52
+
53
+ // The longer timeout actor should succeed
54
+ const result = await client.longTimeoutActor
55
+ .getOrCreate()
56
+ .delayedAction();
57
+ expect(result).toBe("delayed response");
58
+ });
59
+ });
60
+
61
+ describe("Action Sync & Async", () => {
62
+ test("should support synchronous actions", async (c) => {
63
+ const { client } = await setupDriverTest(c, driverTestConfig);
64
+
65
+ const instance = client.syncActionActor.getOrCreate();
66
+
67
+ // Test increment action
68
+ let result = await instance.increment(5);
69
+ expect(result).toBe(5);
70
+
71
+ result = await instance.increment(3);
72
+ expect(result).toBe(8);
73
+
74
+ // Test getInfo action
75
+ const info = await instance.getInfo();
76
+ expect(info.currentValue).toBe(8);
77
+ expect(typeof info.timestamp).toBe("number");
78
+
79
+ // Test reset action (void return)
80
+ await instance.reset();
81
+ result = await instance.increment(0);
82
+ expect(result).toBe(0);
83
+ });
84
+
85
+ test("should support asynchronous actions", async (c) => {
86
+ const { client } = await setupDriverTest(c, driverTestConfig);
87
+
88
+ const instance = client.asyncActionActor.getOrCreate();
89
+
90
+ // Test delayed increment
91
+ const result = await instance.delayedIncrement(5);
92
+ expect(result).toBe(5);
93
+
94
+ // Test fetch data
95
+ const data = await instance.fetchData("test-123");
96
+ expect(data.id).toBe("test-123");
97
+ expect(typeof data.timestamp).toBe("number");
98
+
99
+ // Test successful async operation
100
+ const success = await instance.asyncWithError(false);
101
+ expect(success).toBe("Success");
102
+
103
+ // Test error in async operation
104
+ try {
105
+ await instance.asyncWithError(true);
106
+ expect.fail("did not error");
107
+ } catch (error) {
108
+ expect((error as ActorError).message).toBe("Intentional error");
109
+ }
110
+ });
111
+
112
+ test("should handle promises returned from actions correctly", async (c) => {
113
+ const { client } = await setupDriverTest(c, driverTestConfig);
114
+
115
+ const instance = client.promiseActor.getOrCreate();
116
+
117
+ // Test resolved promise
118
+ const resolvedValue = await instance.resolvedPromise();
119
+ expect(resolvedValue).toBe("resolved value");
120
+
121
+ // Test delayed promise
122
+ const delayedValue = await instance.delayedPromise();
123
+ expect(delayedValue).toBe("delayed value");
124
+
125
+ // Test rejected promise
126
+ await expect(instance.rejectedPromise()).rejects.toThrow(
127
+ "promised rejection",
128
+ );
129
+
130
+ // Check state was updated by the delayed promise
131
+ const results = await instance.getResults();
132
+ expect(results).toContain("delayed");
133
+ });
134
+ });
135
+ });
136
+ }
@@ -0,0 +1,249 @@
1
+ import { describe, expect, test, vi } from "vitest";
2
+ import type { DriverTestConfig } from "../mod";
3
+ import { setupDriverTest } from "../utils";
4
+
5
+ export function runActorConnStateTests(driverTestConfig: DriverTestConfig) {
6
+ describe("Actor Connection State Tests", () => {
7
+ describe("Connection State Initialization", () => {
8
+ test("should retrieve connection state", async (c) => {
9
+ const { client } = await setupDriverTest(c, driverTestConfig);
10
+
11
+ // Connect to the actor
12
+ const connection = client.connStateActor.getOrCreate().connect();
13
+
14
+ // Get the connection state
15
+ const connState = await connection.getConnectionState();
16
+
17
+ // Verify the connection state structure
18
+ expect(connState.id).toBeDefined();
19
+ expect(connState.username).toBeDefined();
20
+ expect(connState.role).toBeDefined();
21
+ expect(connState.counter).toBeDefined();
22
+ expect(connState.createdAt).toBeDefined();
23
+
24
+ // Clean up
25
+ await connection.dispose();
26
+ });
27
+
28
+ test("should initialize connection state with custom parameters", async (c) => {
29
+ const { client } = await setupDriverTest(c, driverTestConfig);
30
+
31
+ // Connect with custom parameters
32
+ const connection = client.connStateActor
33
+ .getOrCreate([], {
34
+ params: {
35
+ username: "testuser",
36
+ role: "admin",
37
+ },
38
+ })
39
+ .connect();
40
+
41
+ // Get the connection state
42
+ const connState = await connection.getConnectionState();
43
+
44
+ // Verify the connection state was initialized with custom values
45
+ expect(connState.username).toBe("testuser");
46
+ expect(connState.role).toBe("admin");
47
+
48
+ // Clean up
49
+ await connection.dispose();
50
+ });
51
+ });
52
+
53
+ describe("Connection State Management", () => {
54
+ test("should maintain unique state for each connection", async (c) => {
55
+ const { client } = await setupDriverTest(c, driverTestConfig);
56
+
57
+ // Create multiple connections
58
+ const conn1 = client.connStateActor
59
+ .getOrCreate([], {
60
+ params: { username: "user1" },
61
+ })
62
+ .connect();
63
+
64
+ const conn2 = client.connStateActor
65
+ .getOrCreate([], {
66
+ params: { username: "user2" },
67
+ })
68
+ .connect();
69
+
70
+ // Update connection state for each connection
71
+ await conn1.incrementConnCounter(5);
72
+ await conn2.incrementConnCounter(10);
73
+
74
+ // Get state for each connection
75
+ const state1 = await conn1.getConnectionState();
76
+ const state2 = await conn2.getConnectionState();
77
+
78
+ // Verify states are separate
79
+ expect(state1.counter).toBe(5);
80
+ expect(state2.counter).toBe(10);
81
+ expect(state1.username).toBe("user1");
82
+ expect(state2.username).toBe("user2");
83
+
84
+ // Clean up
85
+ await conn1.dispose();
86
+ await conn2.dispose();
87
+ });
88
+
89
+ test("should track connections in shared state", async (c) => {
90
+ const { client } = await setupDriverTest(c, driverTestConfig);
91
+
92
+ // Create two connections
93
+ const handle = client.connStateActor.getOrCreate();
94
+ const conn1 = handle.connect();
95
+ const conn2 = handle.connect();
96
+
97
+ // HACK: Wait for both connections to successfully connect by waiting for a round trip RPC
98
+ await conn1.getConnectionState();
99
+ await conn2.getConnectionState();
100
+
101
+ // Get state1 for reference
102
+ const state1 = await conn1.getConnectionState();
103
+
104
+ // Get connection IDs tracked by the actor
105
+ const connectionIds = await conn1.getConnectionIds();
106
+
107
+ // There should be at least 2 connections tracked
108
+ expect(connectionIds.length).toBeGreaterThanOrEqual(2);
109
+
110
+ // Should include the ID of the first connection
111
+ expect(connectionIds).toContain(state1.id);
112
+
113
+ // Clean up
114
+ await conn1.dispose();
115
+ await conn2.dispose();
116
+ });
117
+
118
+ test("should identify different connections in the same actor", async (c) => {
119
+ const { client } = await setupDriverTest(c, driverTestConfig);
120
+
121
+ // Create two connections to the same actor
122
+ const handle = client.connStateActor.getOrCreate();
123
+ const conn1 = handle.connect();
124
+ const conn2 = handle.connect();
125
+
126
+ // HACK: Wait for both connections to successfully connect by waiting for a round trip RPC
127
+ await conn1.getConnectionState();
128
+ await conn2.getConnectionState();
129
+
130
+ // Get all connection states
131
+ const allStates = await conn1.getAllConnectionStates();
132
+
133
+ // Should have at least 2 states
134
+ expect(allStates.length).toBeGreaterThanOrEqual(2);
135
+
136
+ // IDs should be unique
137
+ const ids = allStates.map((state) => state.id);
138
+ const uniqueIds = [...new Set(ids)];
139
+ expect(uniqueIds.length).toBe(ids.length);
140
+
141
+ // Clean up
142
+ await conn1.dispose();
143
+ await conn2.dispose();
144
+ });
145
+ });
146
+
147
+ describe("Connection Lifecycle", () => {
148
+ test("should track connection and disconnection events", async (c) => {
149
+ const { client } = await setupDriverTest(c, driverTestConfig);
150
+
151
+ // Create a connection
152
+ const handle = client.connStateActor.getOrCreate();
153
+ const conn = handle.connect();
154
+
155
+ // Get the connection state
156
+ const connState = await conn.getConnectionState();
157
+
158
+ // Verify the connection is tracked
159
+ const connectionIds = await conn.getConnectionIds();
160
+ expect(connectionIds).toContain(connState.id);
161
+
162
+ // Initial disconnection count
163
+ const initialDisconnections = await conn.getDisconnectionCount();
164
+
165
+ // Dispose the connection
166
+ await conn.dispose();
167
+
168
+ // Create a new connection to check the disconnection count
169
+ const newConn = handle.connect();
170
+
171
+ // Verify disconnection was tracked
172
+ await vi.waitFor(async () => {
173
+ const newDisconnections = await newConn.getDisconnectionCount();
174
+
175
+ expect(newDisconnections).toBeGreaterThan(initialDisconnections);
176
+ });
177
+
178
+ // Clean up
179
+ await newConn.dispose();
180
+ });
181
+
182
+ test("should update connection state", async (c) => {
183
+ const { client } = await setupDriverTest(c, driverTestConfig);
184
+
185
+ // Create a connection
186
+ const conn = client.connStateActor.getOrCreate().connect();
187
+
188
+ // Get the initial state
189
+ const initialState = await conn.getConnectionState();
190
+ expect(initialState.username).toBe("anonymous");
191
+
192
+ // Update the connection state
193
+ const updatedState = await conn.updateConnection({
194
+ username: "newname",
195
+ role: "moderator",
196
+ });
197
+
198
+ // Verify the state was updated
199
+ expect(updatedState.username).toBe("newname");
200
+ expect(updatedState.role).toBe("moderator");
201
+
202
+ // Get the state again to verify persistence
203
+ const latestState = await conn.getConnectionState();
204
+ expect(latestState.username).toBe("newname");
205
+ expect(latestState.role).toBe("moderator");
206
+
207
+ // Clean up
208
+ await conn.dispose();
209
+ });
210
+ });
211
+
212
+ describe("Connection Communication", () => {
213
+ test("should send messages to specific connections", async (c) => {
214
+ const { client } = await setupDriverTest(c, driverTestConfig);
215
+
216
+ // Create two connections
217
+ const handle = client.connStateActor.getOrCreate();
218
+ const conn1 = handle.connect();
219
+ const conn2 = handle.connect();
220
+
221
+ // Get connection states
222
+ const state1 = await conn1.getConnectionState();
223
+ const state2 = await conn2.getConnectionState();
224
+
225
+ // Set up event listener on second connection
226
+ const receivedMessages: any[] = [];
227
+ conn2.on("directMessage", (data) => {
228
+ receivedMessages.push(data);
229
+ });
230
+
231
+ // Send message from first connection to second
232
+ const success = await conn1.sendToConnection(
233
+ state2.id,
234
+ "Hello from conn1",
235
+ );
236
+ expect(success).toBe(true);
237
+
238
+ // Verify message was received
239
+ expect(receivedMessages.length).toBe(1);
240
+ expect(receivedMessages[0].from).toBe(state1.id);
241
+ expect(receivedMessages[0].message).toBe("Hello from conn1");
242
+
243
+ // Clean up
244
+ await conn1.dispose();
245
+ await conn2.dispose();
246
+ });
247
+ });
248
+ });
249
+ }