rivetkit 2.0.6 → 2.0.7

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 (170) hide show
  1. package/dist/schemas/actor-persist/v1.ts +0 -6
  2. package/dist/tsup/actor-router-consts-B3Lu87yJ.d.cts +28 -0
  3. package/dist/tsup/actor-router-consts-B3Lu87yJ.d.ts +28 -0
  4. package/dist/tsup/{chunk-7OUKNSTU.js → chunk-2NL3KGJ7.js} +17 -14
  5. package/dist/tsup/chunk-2NL3KGJ7.js.map +1 -0
  6. package/dist/tsup/{chunk-6P6RA47N.cjs → chunk-3ALZ7EGX.cjs} +14 -10
  7. package/dist/tsup/chunk-3ALZ7EGX.cjs.map +1 -0
  8. package/dist/tsup/chunk-4EXJ4ITR.cjs +102 -0
  9. package/dist/tsup/chunk-4EXJ4ITR.cjs.map +1 -0
  10. package/dist/tsup/{chunk-ZYLTS2EM.js → chunk-54MAHBLL.js} +2 -2
  11. package/dist/tsup/{chunk-NTCUGYSD.cjs → chunk-7OOBMCQI.cjs} +34 -31
  12. package/dist/tsup/chunk-7OOBMCQI.cjs.map +1 -0
  13. package/dist/tsup/{chunk-VCEHU56K.js → chunk-B6N6VM37.js} +2 -2
  14. package/dist/tsup/{chunk-VPV4MWXR.js → chunk-DIHKN7NM.js} +3 -3
  15. package/dist/tsup/{chunk-MRRT2CZD.cjs → chunk-ETDWYT2P.cjs} +7 -7
  16. package/dist/tsup/{chunk-MRRT2CZD.cjs.map → chunk-ETDWYT2P.cjs.map} +1 -1
  17. package/dist/tsup/{chunk-TWGATZ3X.cjs → chunk-F7YL5G7Q.cjs} +922 -872
  18. package/dist/tsup/chunk-F7YL5G7Q.cjs.map +1 -0
  19. package/dist/tsup/{chunk-UTI5NCES.cjs → chunk-GWJTWY3G.cjs} +6 -6
  20. package/dist/tsup/{chunk-UTI5NCES.cjs.map → chunk-GWJTWY3G.cjs.map} +1 -1
  21. package/dist/tsup/{chunk-W6LN7AF5.js → chunk-KHRZPP5T.js} +866 -816
  22. package/dist/tsup/chunk-KHRZPP5T.js.map +1 -0
  23. package/dist/tsup/{chunk-5JBFVV4C.cjs → chunk-LXAVET4A.cjs} +21 -7
  24. package/dist/tsup/chunk-LXAVET4A.cjs.map +1 -0
  25. package/dist/tsup/{chunk-TCUI5JFE.cjs → chunk-NDCVQZBS.cjs} +45 -18
  26. package/dist/tsup/chunk-NDCVQZBS.cjs.map +1 -0
  27. package/dist/tsup/{chunk-4CKHQRXG.js → chunk-NII4KKHD.js} +515 -240
  28. package/dist/tsup/chunk-NII4KKHD.js.map +1 -0
  29. package/dist/tsup/{chunk-2K3JMDAN.js → chunk-NRELKXIX.js} +40 -13
  30. package/dist/tsup/chunk-NRELKXIX.js.map +1 -0
  31. package/dist/tsup/{chunk-UFWAK3X2.cjs → chunk-NUA6LOOJ.cjs} +660 -385
  32. package/dist/tsup/chunk-NUA6LOOJ.cjs.map +1 -0
  33. package/dist/tsup/{chunk-DIAYNQTE.cjs → chunk-OSK2VSJF.cjs} +12 -12
  34. package/dist/tsup/{chunk-DIAYNQTE.cjs.map → chunk-OSK2VSJF.cjs.map} +1 -1
  35. package/dist/tsup/chunk-PD6HCAJE.js +102 -0
  36. package/dist/tsup/chunk-PD6HCAJE.js.map +1 -0
  37. package/dist/tsup/{chunk-RGQR2J7S.js → chunk-RLBM6D4L.js} +20 -6
  38. package/dist/tsup/chunk-RLBM6D4L.js.map +1 -0
  39. package/dist/tsup/{chunk-KG3C7MKR.cjs → chunk-VAF63BEI.cjs} +3 -3
  40. package/dist/tsup/{chunk-KG3C7MKR.cjs.map → chunk-VAF63BEI.cjs.map} +1 -1
  41. package/dist/tsup/{chunk-G75SVQON.js → chunk-WAT5AE7S.js} +9 -5
  42. package/dist/tsup/chunk-WAT5AE7S.js.map +1 -0
  43. package/dist/tsup/{chunk-WC2PSJWN.js → chunk-YL4VZMMT.js} +2 -2
  44. package/dist/tsup/client/mod.cjs +9 -9
  45. package/dist/tsup/client/mod.d.cts +7 -8
  46. package/dist/tsup/client/mod.d.ts +7 -8
  47. package/dist/tsup/client/mod.js +8 -8
  48. package/dist/tsup/common/log.cjs +3 -3
  49. package/dist/tsup/common/log.js +2 -2
  50. package/dist/tsup/common/websocket.cjs +4 -4
  51. package/dist/tsup/common/websocket.js +3 -3
  52. package/dist/tsup/{connection-BLemxi4f.d.ts → conn-DCSQgIlw.d.ts} +1605 -1353
  53. package/dist/tsup/{connection-CpDIydXf.d.cts → conn-DdzHTm2E.d.cts} +1605 -1353
  54. package/dist/tsup/driver-helpers/mod.cjs +31 -5
  55. package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
  56. package/dist/tsup/driver-helpers/mod.d.cts +7 -8
  57. package/dist/tsup/driver-helpers/mod.d.ts +7 -8
  58. package/dist/tsup/driver-helpers/mod.js +33 -7
  59. package/dist/tsup/driver-test-suite/mod.cjs +317 -222
  60. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  61. package/dist/tsup/driver-test-suite/mod.d.cts +7 -7
  62. package/dist/tsup/driver-test-suite/mod.d.ts +7 -7
  63. package/dist/tsup/driver-test-suite/mod.js +582 -487
  64. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  65. package/dist/tsup/inspector/mod.cjs +16 -6
  66. package/dist/tsup/inspector/mod.cjs.map +1 -1
  67. package/dist/tsup/inspector/mod.d.cts +34 -7
  68. package/dist/tsup/inspector/mod.d.ts +34 -7
  69. package/dist/tsup/inspector/mod.js +17 -7
  70. package/dist/tsup/mod.cjs +10 -20
  71. package/dist/tsup/mod.cjs.map +1 -1
  72. package/dist/tsup/mod.d.cts +9 -7
  73. package/dist/tsup/mod.d.ts +9 -7
  74. package/dist/tsup/mod.js +9 -19
  75. package/dist/tsup/test/mod.cjs +11 -11
  76. package/dist/tsup/test/mod.d.cts +6 -7
  77. package/dist/tsup/test/mod.d.ts +6 -7
  78. package/dist/tsup/test/mod.js +10 -10
  79. package/dist/tsup/utils.cjs +4 -2
  80. package/dist/tsup/utils.cjs.map +1 -1
  81. package/dist/tsup/utils.d.cts +11 -1
  82. package/dist/tsup/utils.d.ts +11 -1
  83. package/dist/tsup/utils.js +3 -1
  84. package/package.json +8 -4
  85. package/src/actor/action.ts +1 -1
  86. package/src/actor/config.ts +1 -1
  87. package/src/actor/conn-drivers.ts +205 -0
  88. package/src/actor/conn-socket.ts +6 -0
  89. package/src/actor/{connection.ts → conn.ts} +78 -84
  90. package/src/actor/context.ts +1 -1
  91. package/src/actor/driver.ts +4 -43
  92. package/src/actor/instance.ts +162 -86
  93. package/src/actor/mod.ts +1 -11
  94. package/src/actor/persisted.ts +2 -5
  95. package/src/actor/protocol/old.ts +1 -1
  96. package/src/actor/router-endpoints.ts +142 -106
  97. package/src/actor/router.ts +81 -45
  98. package/src/actor/utils.ts +5 -1
  99. package/src/client/actor-conn.ts +154 -23
  100. package/src/client/client.ts +1 -1
  101. package/src/client/config.ts +7 -0
  102. package/src/common/actor-router-consts.ts +29 -8
  103. package/src/common/router.ts +2 -1
  104. package/src/common/versioned-data.ts +5 -5
  105. package/src/driver-helpers/mod.ts +14 -1
  106. package/src/driver-test-suite/mod.ts +11 -2
  107. package/src/driver-test-suite/test-inline-client-driver.ts +36 -18
  108. package/src/driver-test-suite/tests/actor-conn-state.ts +66 -22
  109. package/src/driver-test-suite/tests/actor-conn.ts +65 -126
  110. package/src/driver-test-suite/tests/actor-reconnect.ts +160 -0
  111. package/src/driver-test-suite/tests/actor-sleep.ts +0 -1
  112. package/src/driver-test-suite/tests/raw-websocket.ts +0 -35
  113. package/src/driver-test-suite/utils.ts +3 -3
  114. package/src/drivers/default.ts +8 -7
  115. package/src/drivers/engine/actor-driver.ts +53 -31
  116. package/src/drivers/engine/config.ts +4 -0
  117. package/src/drivers/file-system/actor.ts +0 -6
  118. package/src/drivers/file-system/global-state.ts +3 -14
  119. package/src/drivers/file-system/manager.ts +12 -8
  120. package/src/inspector/actor.ts +4 -3
  121. package/src/inspector/config.ts +10 -1
  122. package/src/inspector/mod.ts +1 -0
  123. package/src/inspector/utils.ts +23 -4
  124. package/src/manager/driver.ts +11 -1
  125. package/src/manager/gateway.ts +407 -0
  126. package/src/manager/router.ts +269 -468
  127. package/src/manager-api/actors.ts +61 -0
  128. package/src/manager-api/common.ts +4 -0
  129. package/src/mod.ts +1 -1
  130. package/src/registry/mod.ts +119 -10
  131. package/src/remote-manager-driver/actor-http-client.ts +30 -19
  132. package/src/remote-manager-driver/actor-websocket-client.ts +43 -16
  133. package/src/remote-manager-driver/api-endpoints.ts +19 -21
  134. package/src/remote-manager-driver/api-utils.ts +10 -1
  135. package/src/remote-manager-driver/mod.ts +51 -48
  136. package/src/remote-manager-driver/ws-proxy.ts +2 -9
  137. package/src/test/mod.ts +6 -2
  138. package/src/utils.ts +21 -2
  139. package/dist/tsup/actor-router-consts-BK6arfy8.d.cts +0 -17
  140. package/dist/tsup/actor-router-consts-BK6arfy8.d.ts +0 -17
  141. package/dist/tsup/chunk-2K3JMDAN.js.map +0 -1
  142. package/dist/tsup/chunk-42I3OZ3Q.js +0 -15
  143. package/dist/tsup/chunk-42I3OZ3Q.js.map +0 -1
  144. package/dist/tsup/chunk-4CKHQRXG.js.map +0 -1
  145. package/dist/tsup/chunk-5JBFVV4C.cjs.map +0 -1
  146. package/dist/tsup/chunk-6P6RA47N.cjs.map +0 -1
  147. package/dist/tsup/chunk-7OUKNSTU.js.map +0 -1
  148. package/dist/tsup/chunk-G75SVQON.js.map +0 -1
  149. package/dist/tsup/chunk-KUPQZYUQ.cjs +0 -15
  150. package/dist/tsup/chunk-KUPQZYUQ.cjs.map +0 -1
  151. package/dist/tsup/chunk-NTCUGYSD.cjs.map +0 -1
  152. package/dist/tsup/chunk-RGQR2J7S.js.map +0 -1
  153. package/dist/tsup/chunk-TCUI5JFE.cjs.map +0 -1
  154. package/dist/tsup/chunk-TWGATZ3X.cjs.map +0 -1
  155. package/dist/tsup/chunk-UFWAK3X2.cjs.map +0 -1
  156. package/dist/tsup/chunk-W6LN7AF5.js.map +0 -1
  157. package/dist/tsup/common-CXCe7s6i.d.cts +0 -218
  158. package/dist/tsup/common-CXCe7s6i.d.ts +0 -218
  159. package/src/actor/generic-conn-driver.ts +0 -246
  160. package/src/common/fake-event-source.ts +0 -267
  161. package/src/manager-api/routes/actors-create.ts +0 -16
  162. package/src/manager-api/routes/actors-delete.ts +0 -4
  163. package/src/manager-api/routes/actors-get-by-id.ts +0 -7
  164. package/src/manager-api/routes/actors-get-or-create-by-id.ts +0 -29
  165. package/src/manager-api/routes/actors-get.ts +0 -7
  166. package/src/manager-api/routes/common.ts +0 -18
  167. /package/dist/tsup/{chunk-ZYLTS2EM.js.map → chunk-54MAHBLL.js.map} +0 -0
  168. /package/dist/tsup/{chunk-VCEHU56K.js.map → chunk-B6N6VM37.js.map} +0 -0
  169. /package/dist/tsup/{chunk-VPV4MWXR.js.map → chunk-DIHKN7NM.js.map} +0 -0
  170. /package/dist/tsup/{chunk-WC2PSJWN.js.map → chunk-YL4VZMMT.js.map} +0 -0
@@ -145,38 +145,79 @@ export function runActorConnStateTests(driverTestConfig: DriverTestConfig) {
145
145
  });
146
146
 
147
147
  describe("Connection Lifecycle", () => {
148
- test("should track connection and disconnection events", async (c) => {
148
+ test.skipIf(
149
+ driverTestConfig.transport === "sse" &&
150
+ driverTestConfig.clientType === "inline",
151
+ )("should track connection and disconnection events", async (c) => {
149
152
  const { client } = await setupDriverTest(c, driverTestConfig);
150
153
 
154
+ const debugHandle = client.connStateActor.getOrCreate(undefined, {
155
+ params: { noCount: true },
156
+ });
157
+
151
158
  // Create a connection
152
- const handle = client.connStateActor.getOrCreate();
153
- const conn = handle.connect();
159
+ const conn = client.connStateActor.getOrCreate().connect();
154
160
 
155
161
  // Get the connection state
156
162
  const connState = await conn.getConnectionState();
157
163
 
158
164
  // Verify the connection is tracked
159
- const connectionIds = await conn.getConnectionIds();
160
- expect(connectionIds).toContain(connState.id);
165
+ await vi.waitFor(async () => {
166
+ const connectionIds = await debugHandle.getConnectionIds();
167
+ expect(connectionIds).toContain(connState.id);
168
+ });
161
169
 
162
170
  // Initial disconnection count
163
- const initialDisconnections = await conn.getDisconnectionCount();
171
+ await vi.waitFor(async () => {
172
+ const disconnects = await debugHandle.getDisconnectionCount();
173
+ expect(disconnects).toBe(0);
174
+ });
164
175
 
165
176
  // Dispose the connection
166
177
  await conn.dispose();
167
178
 
179
+ // Validate conn count
180
+ await vi.waitFor(
181
+ async () => {
182
+ console.log("disconnects before");
183
+ const disconnects = await debugHandle.getDisconnectionCount();
184
+ console.log("disconnects", disconnects);
185
+ expect(disconnects).toBe(1);
186
+ },
187
+ // SSE takes a long time to disconnect on CF Workers
188
+ {
189
+ timeout: 10_000,
190
+ interval: 100,
191
+ },
192
+ );
193
+
168
194
  // Create a new connection to check the disconnection count
169
- const newConn = handle.connect();
195
+ const newConn = client.connStateActor.getOrCreate().connect();
170
196
 
171
- // Verify disconnection was tracked
197
+ // Verify the connection is tracked
172
198
  await vi.waitFor(async () => {
173
- const newDisconnections = await newConn.getDisconnectionCount();
174
-
175
- expect(newDisconnections).toBeGreaterThan(initialDisconnections);
199
+ const connectionIds = await debugHandle.getConnectionIds();
200
+ console.log("conn ids", connectionIds);
201
+ expect(connectionIds.length).toBe(1);
176
202
  });
177
203
 
178
204
  // Clean up
179
205
  await newConn.dispose();
206
+
207
+ // Verify disconnection was tracked
208
+ await vi.waitFor(
209
+ async () => {
210
+ console.log("A");
211
+ const disconnects = await debugHandle.getDisconnectionCount();
212
+ console.log(`B ${disconnects}`);
213
+ expect(disconnects).toBe(2);
214
+ },
215
+ // SSE takes a long time to disconnect on CF Workers
216
+ {
217
+ timeout: 10_000,
218
+ interval: 100,
219
+ },
220
+ );
180
221
  });
181
222
 
182
223
  test("should update connection state", async (c) => {
@@ -228,17 +269,20 @@ export function runActorConnStateTests(driverTestConfig: DriverTestConfig) {
228
269
  receivedMessages.push(data);
229
270
  });
230
271
 
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");
272
+ // TODO: SSE has race condition between subscrib eand publish message
273
+ await vi.waitFor(async () => {
274
+ // Send message from first connection to second
275
+ const success = await conn1.sendToConnection(
276
+ state2.id,
277
+ "Hello from conn1",
278
+ );
279
+ expect(success).toBe(true);
280
+
281
+ // Verify message was received
282
+ expect(receivedMessages.length).toBe(1);
283
+ expect(receivedMessages[0].from).toBe(state1.id);
284
+ expect(receivedMessages[0].message).toBe("Hello from conn1");
285
+ });
242
286
 
243
287
  // Clean up
244
288
  await conn1.dispose();
@@ -1,4 +1,5 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test, vi } from "vitest";
2
+ import { SSE_PING_INTERVAL } from "@/actor/router-endpoints";
2
3
  import type { DriverTestConfig } from "../mod";
3
4
  import { FAKE_TIME, setupDriverTest, waitFor } from "../utils";
4
5
 
@@ -84,28 +85,27 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
84
85
 
85
86
  // Set up event listener
86
87
  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
- });
88
+ connection.on("newCount", (count: number) => {
89
+ receivedEvents.push(count);
97
90
  });
98
91
 
99
- // Send one RPC call over the connection to ensure it's open
100
- await connection.increment(1);
92
+ // TODO: There is a race condition with opening subscription and sending events on SSE, so we need to wait for a successful round trip on the event
93
+ await vi.waitFor(async () => {
94
+ // Send one RPC call over the connection to ensure it's open
95
+ await connection.setCount(1);
96
+ expect(receivedEvents).includes(1);
97
+ });
101
98
 
102
99
  // Now use stateless RPC calls through the handle (no connection)
103
100
  // These should still trigger events that the connection receives
104
- await handle.increment(5);
105
- await handle.increment(3);
101
+ await handle.setCount(2);
102
+ await handle.setCount(3);
106
103
 
107
104
  // Wait for all events to be received
108
- await receivedEventsPromise;
105
+ await vi.waitFor(() => {
106
+ expect(receivedEvents).includes(2);
107
+ expect(receivedEvents).includes(3);
108
+ });
109
109
 
110
110
  // Clean up
111
111
  await connection.dispose();
@@ -124,13 +124,17 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
124
124
  receivedEvents.push(count);
125
125
  });
126
126
 
127
- // Trigger broadcast events
128
- await connection.increment(5);
129
- await connection.increment(3);
130
-
127
+ // HACK: Race condition between subscribing & sending events in SSE
131
128
  // Verify events were received
132
- expect(receivedEvents).toContain(5);
133
- expect(receivedEvents).toContain(8);
129
+ await vi.waitFor(
130
+ async () => {
131
+ await connection.setCount(5);
132
+ await connection.setCount(8);
133
+ expect(receivedEvents).toContain(5);
134
+ expect(receivedEvents).toContain(8);
135
+ },
136
+ { timeout: 10_000 },
137
+ );
134
138
 
135
139
  // Clean up
136
140
  await connection.dispose();
@@ -154,8 +158,10 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
154
158
  await connection.increment(3);
155
159
 
156
160
  // Verify only the first event was received
157
- expect(receivedEvents).toEqual([5]);
158
- expect(receivedEvents).not.toContain(8);
161
+ await vi.waitFor(() => {
162
+ expect(receivedEvents).toEqual([5]);
163
+ expect(receivedEvents).not.toContain(8);
164
+ });
159
165
 
160
166
  // Clean up
161
167
  await connection.dispose();
@@ -174,17 +180,20 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
174
180
  receivedEvents.push(count);
175
181
  });
176
182
 
183
+ // TODO: SSE has race condition with subscriptions & publishing messages
177
184
  // Trigger first event
178
- await connection.increment(5);
185
+ await vi.waitFor(async () => {
186
+ await connection.setCount(5);
187
+ expect(receivedEvents).toEqual([5]);
188
+ });
179
189
 
180
190
  // Unsubscribe
181
191
  unsubscribe();
182
192
 
183
193
  // Trigger second event, should not be received
184
- await connection.increment(3);
194
+ await connection.setCount(8);
185
195
 
186
196
  // Verify only the first event was received
187
- expect(receivedEvents).toEqual([5]);
188
197
  expect(receivedEvents).not.toContain(8);
189
198
 
190
199
  // Clean up
@@ -225,7 +234,10 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
225
234
  });
226
235
 
227
236
  describe("Lifecycle Hooks", () => {
228
- test("should trigger lifecycle hooks", async (c) => {
237
+ test.skipIf(
238
+ driverTestConfig.transport === "sse" &&
239
+ driverTestConfig.clientType === "inline",
240
+ )("should trigger lifecycle hooks", async (c) => {
229
241
  const { client } = await setupDriverTest(c, driverTestConfig);
230
242
 
231
243
  // Create and connect
@@ -244,104 +256,31 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
244
256
  // Disconnect should trigger onDisconnect
245
257
  await connection.dispose();
246
258
 
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
- }),
259
+ await vi.waitFor(
260
+ async () => {
261
+ // Reconnect to check if onDisconnect was called
262
+ const handle = client.counterWithLifecycle.getOrCreate([
263
+ "test-lifecycle",
264
+ ]);
265
+ const finalEvents = await handle.getEvents();
266
+ expect(finalEvents).toBeOneOf([
267
+ // Still active
268
+ ["onStart", "onBeforeConnect", "onConnect", "onDisconnect"],
269
+ // Went to sleep and woke back up
270
+ [
271
+ "onStart",
272
+ "onBeforeConnect",
273
+ "onConnect",
274
+ "onDisconnect",
275
+ "onStart",
276
+ ],
277
+ ]);
278
+ },
279
+ // NOTE: High timeout required for Cloudflare Workers
280
+ {
281
+ timeout: 10_000,
282
+ interval: 100,
283
+ },
345
284
  );
346
285
  });
347
286
  });
@@ -0,0 +1,160 @@
1
+ import { describe, expect, test, vi } from "vitest";
2
+ import type { ActorConnRaw } from "@/client/actor-conn";
3
+ import type { DriverTestConfig } from "../mod";
4
+ import { setupDriverTest } from "../utils";
5
+
6
+ export function runActorReconnectTests(driverTestConfig: DriverTestConfig) {
7
+ describe("Actor Reconnection Tests", () => {
8
+ test("should reconnect and preserve connection state after non-clean disconnect", async (c) => {
9
+ const { client, endpoint } = await setupDriverTest(c, driverTestConfig);
10
+
11
+ // Create actor and connect
12
+ const handle = client.counterConn.getOrCreate(["test-reconnect"]);
13
+ const connection = handle.connect();
14
+
15
+ // Set an initial count on the connection
16
+ await connection.increment(5);
17
+
18
+ // Verify connection count is 1
19
+ const connCount1 = await connection.getConnectionCount();
20
+ expect(connCount1).toBe(1);
21
+
22
+ // Force disconnect (non-clean) - simulates network failure
23
+ const connRaw = connection as unknown as ActorConnRaw;
24
+ await forceUncleanDisconnect(
25
+ endpoint,
26
+ connRaw.actorId!,
27
+ connRaw.connectionId!,
28
+ );
29
+
30
+ // Wait a bit for the disconnection to be processed
31
+ await vi.waitFor(
32
+ async () => {
33
+ const countAfterReconnect = await connection.getCount();
34
+ expect(countAfterReconnect).toBe(5); // Should preserve the count
35
+ },
36
+ { timeout: 5000, interval: 100 },
37
+ );
38
+
39
+ // Verify connection count is still 1 (same connection reconnected)
40
+ const connCount2 = await connection.getConnectionCount();
41
+ expect(connCount2).toBe(1);
42
+
43
+ // Verify we can still increment the counter
44
+ const newCount = await connection.getCount();
45
+ expect(newCount).toBe(5);
46
+
47
+ // Clean up
48
+ await connection.dispose();
49
+ });
50
+
51
+ test("should not preserve connection state after clean disconnect", async (c) => {
52
+ const { client } = await setupDriverTest(c, driverTestConfig);
53
+
54
+ // Create actor and connect
55
+ const handle = client.counterConn.getOrCreate(["test-clean-disconnect"]);
56
+ const connection = handle.connect();
57
+
58
+ // Set an initial count on the connection
59
+ await connection.increment(10);
60
+
61
+ // Verify connection count is 1
62
+ const connCount1 = await connection.getConnectionCount();
63
+ expect(connCount1).toBe(1);
64
+
65
+ // Clean disconnect
66
+ await connection.dispose();
67
+
68
+ // Wait a bit to ensure disconnection is processed
69
+ await vi.waitFor(
70
+ async () => {
71
+ // Check that connection count is now 0
72
+ const handle2 = client.counterConn.get(["test-clean-disconnect"]);
73
+ const connCount = await handle2.getConnectionCount();
74
+ // This counts the current action caller
75
+ expect(connCount).toBe(1);
76
+ },
77
+ { timeout: 5000 },
78
+ );
79
+
80
+ // Create a new connection
81
+ const connection2 = handle.connect();
82
+
83
+ // The count should be reset since it's a new connection
84
+ const countNewConnection = await connection2.getCount();
85
+ expect(countNewConnection).toBe(0); // Should be reset
86
+
87
+ // Verify connection count is 1 again (new connection)
88
+ const connCount3 = await connection2.getConnectionCount();
89
+ expect(connCount3).toBe(1);
90
+
91
+ // Clean up
92
+ await connection2.dispose();
93
+ });
94
+
95
+ test("should handle multiple non-clean disconnects and reconnects", async (c) => {
96
+ const { client, endpoint } = await setupDriverTest(c, driverTestConfig);
97
+
98
+ // Create actor and connect
99
+ const handle = client.counterConn.getOrCreate([
100
+ "test-multiple-reconnect",
101
+ ]);
102
+ const connection = handle.connect();
103
+
104
+ // Set an initial count
105
+ await connection.setCount(100);
106
+
107
+ // Perform multiple disconnect-reconnect cycles
108
+ for (let i = 0; i < 3; i++) {
109
+ // Increment before disconnect
110
+ await connection.increment(1);
111
+
112
+ // Force disconnect
113
+ const connRaw = connection as unknown as ActorConnRaw;
114
+ await forceUncleanDisconnect(
115
+ endpoint,
116
+ connRaw.actorId!,
117
+ connRaw.connectionId!,
118
+ );
119
+
120
+ // Wait for reconnection and verify state is preserved
121
+ await vi.waitFor(
122
+ async () => {
123
+ const countAfter = await connection.getCount();
124
+ expect(countAfter).toBe(101 + i);
125
+ },
126
+ { timeout: 5000 },
127
+ );
128
+
129
+ // Verify connection count remains 1
130
+ const connCount = await connection.getConnectionCount();
131
+ expect(connCount).toBe(1);
132
+ }
133
+
134
+ // Final verification
135
+ const finalCount = await connection.getCount();
136
+ expect(finalCount).toBe(103);
137
+
138
+ // Clean up
139
+ await connection.dispose();
140
+ });
141
+ });
142
+ }
143
+
144
+ async function forceUncleanDisconnect(
145
+ endpoint: string,
146
+ actorId: string,
147
+ connId: string,
148
+ ): Promise<void> {
149
+ const response = await fetch(
150
+ `${endpoint}/.test/force-disconnect?actor=${actorId}&conn=${connId}`,
151
+ {
152
+ method: "POST",
153
+ },
154
+ );
155
+
156
+ if (!response.ok) {
157
+ const text = await response.text();
158
+ throw new Error(`Failed to force disconnect: ${text}`);
159
+ }
160
+ }
@@ -318,7 +318,6 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
318
318
 
319
319
  // Close WebSocket
320
320
  ws.close();
321
- await new Promise((resolve) => setTimeout(resolve, 100));
322
321
 
323
322
  // Wait for sleep timeout after WebSocket closed
324
323
  await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
@@ -277,41 +277,6 @@ export function runRawWebSocketTests(driverTestConfig: DriverTestConfig) {
277
277
  ws.close();
278
278
  });
279
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
280
  test("should handle connection close properly", async (c) => {
316
281
  const { client } = await setupDriverTest(c, driverTestConfig);
317
282
  const actor = client.rawWebSocketActor.getOrCreate(["close-test"]);
@@ -39,14 +39,14 @@ export async function setupDriverTest(
39
39
  });
40
40
  } else if (driverTestConfig.clientType === "inline") {
41
41
  // Use inline client from driver
42
+ const transport = driverTestConfig.transport ?? "websocket";
42
43
  const managerDriver = createTestInlineClientDriver(
43
44
  endpoint,
44
45
  "bare",
45
- driverTestConfig.transport ?? "websocket",
46
+ transport,
46
47
  );
47
- invariant(driverTestConfig.transport, "missing transport");
48
48
  const runConfig = RunConfigSchema.parse({
49
- transport: driverTestConfig.transport,
49
+ transport: transport,
50
50
  });
51
51
  client = createClientWithDriver(managerDriver, runConfig);
52
52
  } else {
@@ -3,15 +3,12 @@ import { loggerWithoutContext } from "@/actor/log";
3
3
  import { createEngineDriver } from "@/drivers/engine/mod";
4
4
  import { createFileSystemOrMemoryDriver } from "@/drivers/file-system/mod";
5
5
  import type { DriverConfig, RunConfig } from "@/registry/run-config";
6
- import { getEnvUniversal } from "@/utils";
7
6
 
8
7
  /**
9
8
  * Chooses the appropriate driver based on the run configuration.
10
9
  */
11
10
  export function chooseDefaultDriver(runConfig: RunConfig): DriverConfig {
12
- const engineEndpoint = runConfig.endpoint ?? getEnvUniversal("RIVET_ENGINE");
13
-
14
- if (engineEndpoint && runConfig.driver) {
11
+ if (runConfig.endpoint && runConfig.driver) {
15
12
  throw new UserError(
16
13
  "Cannot specify both 'engine' and 'driver' in configuration",
17
14
  );
@@ -21,12 +18,16 @@ export function chooseDefaultDriver(runConfig: RunConfig): DriverConfig {
21
18
  return runConfig.driver;
22
19
  }
23
20
 
24
- if (engineEndpoint) {
21
+ if (runConfig.endpoint) {
25
22
  loggerWithoutContext().debug({
26
23
  msg: "using rivet engine driver",
27
- endpoint: engineEndpoint,
24
+ endpoint: runConfig.endpoint,
25
+ });
26
+ // TODO: Add all properties from config
27
+ return createEngineDriver({
28
+ endpoint: runConfig.endpoint,
29
+ token: runConfig.token,
28
30
  });
29
- return createEngineDriver({ endpoint: engineEndpoint });
30
31
  }
31
32
 
32
33
  loggerWithoutContext().debug({ msg: "using default file system driver" });