rivetkit 2.0.5 → 2.0.7-rc.1

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 (178) 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-5YTI25C3.cjs → chunk-3MBP4WNC.cjs} +7 -7
  5. package/dist/tsup/{chunk-5YTI25C3.cjs.map → chunk-3MBP4WNC.cjs.map} +1 -1
  6. package/dist/tsup/chunk-3Y45CIF4.cjs +3726 -0
  7. package/dist/tsup/chunk-3Y45CIF4.cjs.map +1 -0
  8. package/dist/tsup/chunk-4GP7BZSR.js +102 -0
  9. package/dist/tsup/chunk-4GP7BZSR.js.map +1 -0
  10. package/dist/tsup/chunk-5ZOHIKWG.cjs +4071 -0
  11. package/dist/tsup/chunk-5ZOHIKWG.cjs.map +1 -0
  12. package/dist/tsup/{chunk-WADSS5X4.cjs → chunk-6EUWRXLT.cjs} +21 -7
  13. package/dist/tsup/chunk-6EUWRXLT.cjs.map +1 -0
  14. package/dist/tsup/{chunk-D7NWUCRK.cjs → chunk-6OVKCDSH.cjs} +6 -6
  15. package/dist/tsup/{chunk-D7NWUCRK.cjs.map → chunk-6OVKCDSH.cjs.map} +1 -1
  16. package/dist/tsup/{chunk-I5VTWPHW.js → chunk-7N56ZUC7.js} +3 -3
  17. package/dist/tsup/{chunk-LZIBTLEY.cjs → chunk-B3TLRM4Q.cjs} +13 -25
  18. package/dist/tsup/chunk-B3TLRM4Q.cjs.map +1 -0
  19. package/dist/tsup/chunk-BW5DPM6Z.js +4071 -0
  20. package/dist/tsup/chunk-BW5DPM6Z.js.map +1 -0
  21. package/dist/tsup/chunk-DFS77KAA.cjs +1046 -0
  22. package/dist/tsup/chunk-DFS77KAA.cjs.map +1 -0
  23. package/dist/tsup/{chunk-PG3K2LI7.js → chunk-E4UVJKSV.js} +2 -2
  24. package/dist/tsup/chunk-G4ABMAQY.cjs +102 -0
  25. package/dist/tsup/chunk-G4ABMAQY.cjs.map +1 -0
  26. package/dist/tsup/{chunk-CKA54YQN.js → chunk-GZVBFXBI.js} +3 -15
  27. package/dist/tsup/chunk-GZVBFXBI.js.map +1 -0
  28. package/dist/tsup/chunk-HPT3I7UU.js +3726 -0
  29. package/dist/tsup/chunk-HPT3I7UU.js.map +1 -0
  30. package/dist/tsup/chunk-JD54PXWP.js +1046 -0
  31. package/dist/tsup/chunk-JD54PXWP.js.map +1 -0
  32. package/dist/tsup/{chunk-PHSQJ6QI.cjs → chunk-K4ENQCC4.cjs} +3 -3
  33. package/dist/tsup/{chunk-PHSQJ6QI.cjs.map → chunk-K4ENQCC4.cjs.map} +1 -1
  34. package/dist/tsup/{chunk-WNGOBAA7.js → chunk-PUSQNDJG.js} +2 -2
  35. package/dist/tsup/{chunk-CFFKMUYH.js → chunk-RVP5RUSC.js} +20 -6
  36. package/dist/tsup/chunk-RVP5RUSC.js.map +1 -0
  37. package/dist/tsup/chunk-SAZCNSVY.cjs +259 -0
  38. package/dist/tsup/chunk-SAZCNSVY.cjs.map +1 -0
  39. package/dist/tsup/{chunk-YW6Y6VNE.js → chunk-SBKRVQS2.js} +9 -5
  40. package/dist/tsup/chunk-SBKRVQS2.js.map +1 -0
  41. package/dist/tsup/{chunk-FGFT4FVX.cjs → chunk-TZGUSEIJ.cjs} +14 -10
  42. package/dist/tsup/chunk-TZGUSEIJ.cjs.map +1 -0
  43. package/dist/tsup/chunk-YQ4XQYPM.js +259 -0
  44. package/dist/tsup/chunk-YQ4XQYPM.js.map +1 -0
  45. package/dist/tsup/client/mod.cjs +9 -9
  46. package/dist/tsup/client/mod.d.cts +7 -8
  47. package/dist/tsup/client/mod.d.ts +7 -8
  48. package/dist/tsup/client/mod.js +8 -8
  49. package/dist/tsup/common/log.cjs +3 -3
  50. package/dist/tsup/common/log.js +2 -2
  51. package/dist/tsup/common/websocket.cjs +4 -4
  52. package/dist/tsup/common/websocket.js +3 -3
  53. package/dist/tsup/{connection-BvE-Oq7t.d.ts → conn-DCSQgIlw.d.ts} +1605 -1353
  54. package/dist/tsup/{connection-DTzmWwU5.d.cts → conn-DdzHTm2E.d.cts} +1605 -1353
  55. package/dist/tsup/driver-helpers/mod.cjs +31 -5
  56. package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
  57. package/dist/tsup/driver-helpers/mod.d.cts +7 -8
  58. package/dist/tsup/driver-helpers/mod.d.ts +7 -8
  59. package/dist/tsup/driver-helpers/mod.js +33 -7
  60. package/dist/tsup/driver-test-suite/mod.cjs +319 -216
  61. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  62. package/dist/tsup/driver-test-suite/mod.d.cts +7 -7
  63. package/dist/tsup/driver-test-suite/mod.d.ts +7 -7
  64. package/dist/tsup/driver-test-suite/mod.js +588 -485
  65. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  66. package/dist/tsup/inspector/mod.cjs +17 -5
  67. package/dist/tsup/inspector/mod.cjs.map +1 -1
  68. package/dist/tsup/inspector/mod.d.cts +34 -7
  69. package/dist/tsup/inspector/mod.d.ts +34 -7
  70. package/dist/tsup/inspector/mod.js +20 -8
  71. package/dist/tsup/mod.cjs +10 -17
  72. package/dist/tsup/mod.cjs.map +1 -1
  73. package/dist/tsup/mod.d.cts +56 -9
  74. package/dist/tsup/mod.d.ts +56 -9
  75. package/dist/tsup/mod.js +17 -24
  76. package/dist/tsup/test/mod.cjs +11 -9
  77. package/dist/tsup/test/mod.cjs.map +1 -1
  78. package/dist/tsup/test/mod.d.cts +6 -7
  79. package/dist/tsup/test/mod.d.ts +6 -7
  80. package/dist/tsup/test/mod.js +10 -8
  81. package/dist/tsup/utils.cjs +4 -2
  82. package/dist/tsup/utils.cjs.map +1 -1
  83. package/dist/tsup/utils.d.cts +11 -1
  84. package/dist/tsup/utils.d.ts +11 -1
  85. package/dist/tsup/utils.js +3 -1
  86. package/package.json +8 -4
  87. package/src/actor/action.ts +1 -1
  88. package/src/actor/config.ts +1 -1
  89. package/src/actor/conn-drivers.ts +205 -0
  90. package/src/actor/conn-socket.ts +6 -0
  91. package/src/actor/{connection.ts → conn.ts} +78 -84
  92. package/src/actor/context.ts +1 -1
  93. package/src/actor/driver.ts +4 -43
  94. package/src/actor/instance.ts +162 -86
  95. package/src/actor/mod.ts +6 -14
  96. package/src/actor/persisted.ts +2 -5
  97. package/src/actor/protocol/old.ts +1 -1
  98. package/src/actor/router-endpoints.ts +147 -138
  99. package/src/actor/router.ts +89 -52
  100. package/src/actor/utils.ts +5 -1
  101. package/src/client/actor-conn.ts +163 -31
  102. package/src/client/actor-handle.ts +0 -1
  103. package/src/client/client.ts +2 -2
  104. package/src/client/config.ts +7 -0
  105. package/src/client/raw-utils.ts +1 -1
  106. package/src/client/utils.ts +1 -1
  107. package/src/common/actor-router-consts.ts +59 -0
  108. package/src/common/router.ts +2 -1
  109. package/src/common/versioned-data.ts +5 -5
  110. package/src/driver-helpers/mod.ts +15 -2
  111. package/src/driver-test-suite/mod.ts +11 -2
  112. package/src/driver-test-suite/test-inline-client-driver.ts +40 -22
  113. package/src/driver-test-suite/tests/actor-conn-state.ts +66 -22
  114. package/src/driver-test-suite/tests/actor-conn.ts +65 -126
  115. package/src/driver-test-suite/tests/actor-reconnect.ts +160 -0
  116. package/src/driver-test-suite/tests/actor-sleep.ts +0 -1
  117. package/src/driver-test-suite/tests/raw-websocket.ts +0 -35
  118. package/src/driver-test-suite/utils.ts +8 -3
  119. package/src/drivers/default.ts +8 -7
  120. package/src/drivers/engine/actor-driver.ts +67 -44
  121. package/src/drivers/engine/config.ts +4 -0
  122. package/src/drivers/file-system/actor.ts +0 -6
  123. package/src/drivers/file-system/global-state.ts +3 -14
  124. package/src/drivers/file-system/manager.ts +12 -8
  125. package/src/inspector/actor.ts +4 -3
  126. package/src/inspector/config.ts +10 -1
  127. package/src/inspector/mod.ts +1 -0
  128. package/src/inspector/utils.ts +23 -4
  129. package/src/manager/driver.ts +12 -2
  130. package/src/manager/gateway.ts +407 -0
  131. package/src/manager/protocol/query.ts +1 -1
  132. package/src/manager/router.ts +269 -468
  133. package/src/manager-api/actors.ts +61 -0
  134. package/src/manager-api/common.ts +4 -0
  135. package/src/mod.ts +1 -1
  136. package/src/registry/mod.ts +126 -12
  137. package/src/registry/serve.ts +8 -3
  138. package/src/remote-manager-driver/actor-http-client.ts +30 -19
  139. package/src/remote-manager-driver/actor-websocket-client.ts +45 -18
  140. package/src/remote-manager-driver/api-endpoints.ts +19 -21
  141. package/src/remote-manager-driver/api-utils.ts +10 -1
  142. package/src/remote-manager-driver/mod.ts +53 -53
  143. package/src/remote-manager-driver/ws-proxy.ts +2 -9
  144. package/src/test/mod.ts +6 -2
  145. package/src/utils.ts +21 -2
  146. package/dist/tsup/chunk-2MD57QF4.js +0 -1794
  147. package/dist/tsup/chunk-2MD57QF4.js.map +0 -1
  148. package/dist/tsup/chunk-B2QGJGZQ.js +0 -338
  149. package/dist/tsup/chunk-B2QGJGZQ.js.map +0 -1
  150. package/dist/tsup/chunk-CFFKMUYH.js.map +0 -1
  151. package/dist/tsup/chunk-CKA54YQN.js.map +0 -1
  152. package/dist/tsup/chunk-FGFT4FVX.cjs.map +0 -1
  153. package/dist/tsup/chunk-IRMBWX36.cjs +0 -1794
  154. package/dist/tsup/chunk-IRMBWX36.cjs.map +0 -1
  155. package/dist/tsup/chunk-L7QRXNWP.js +0 -6562
  156. package/dist/tsup/chunk-L7QRXNWP.js.map +0 -1
  157. package/dist/tsup/chunk-LZIBTLEY.cjs.map +0 -1
  158. package/dist/tsup/chunk-MRZS2J4X.cjs +0 -6562
  159. package/dist/tsup/chunk-MRZS2J4X.cjs.map +0 -1
  160. package/dist/tsup/chunk-RM2SVURR.cjs +0 -338
  161. package/dist/tsup/chunk-RM2SVURR.cjs.map +0 -1
  162. package/dist/tsup/chunk-WADSS5X4.cjs.map +0 -1
  163. package/dist/tsup/chunk-YW6Y6VNE.js.map +0 -1
  164. package/dist/tsup/common-CXCe7s6i.d.cts +0 -218
  165. package/dist/tsup/common-CXCe7s6i.d.ts +0 -218
  166. package/dist/tsup/router-endpoints-CctffZNL.d.cts +0 -65
  167. package/dist/tsup/router-endpoints-DFm1BglJ.d.ts +0 -65
  168. package/src/actor/generic-conn-driver.ts +0 -246
  169. package/src/common/fake-event-source.ts +0 -267
  170. package/src/manager-api/routes/actors-create.ts +0 -16
  171. package/src/manager-api/routes/actors-delete.ts +0 -4
  172. package/src/manager-api/routes/actors-get-by-id.ts +0 -7
  173. package/src/manager-api/routes/actors-get-or-create-by-id.ts +0 -29
  174. package/src/manager-api/routes/actors-get.ts +0 -7
  175. package/src/manager-api/routes/common.ts +0 -18
  176. /package/dist/tsup/{chunk-I5VTWPHW.js.map → chunk-7N56ZUC7.js.map} +0 -0
  177. /package/dist/tsup/{chunk-PG3K2LI7.js.map → chunk-E4UVJKSV.js.map} +0 -0
  178. /package/dist/tsup/{chunk-WNGOBAA7.js.map → chunk-PUSQNDJG.js.map} +0 -0
@@ -2,19 +2,26 @@ import * as cbor from "cbor-x";
2
2
  import type { Context as HonoContext, HonoRequest } from "hono";
3
3
  import { type SSEStreamingApi, streamSSE } from "hono/streaming";
4
4
  import type { WSContext } from "hono/ws";
5
+ import invariant from "invariant";
5
6
  import { ActionContext } from "@/actor/action";
6
- import type { AnyConn } from "@/actor/connection";
7
+ import type { AnyConn } from "@/actor/conn";
7
8
  import {
8
- CONNECTION_DRIVER_HTTP,
9
- CONNECTION_DRIVER_SSE,
10
- CONNECTION_DRIVER_WEBSOCKET,
11
9
  generateConnId,
10
+ generateConnSocketId,
12
11
  generateConnToken,
13
- } from "@/actor/connection";
12
+ } from "@/actor/conn";
13
+ import { ConnDriverKind } from "@/actor/conn-drivers";
14
14
  import * as errors from "@/actor/errors";
15
15
  import type { AnyActorInstance } from "@/actor/instance";
16
16
  import type { InputData } from "@/actor/protocol/serde";
17
17
  import { type Encoding, EncodingSchema } from "@/actor/protocol/serde";
18
+ import {
19
+ HEADER_ACTOR_QUERY,
20
+ HEADER_CONN_ID,
21
+ HEADER_CONN_PARAMS,
22
+ HEADER_CONN_TOKEN,
23
+ HEADER_ENCODING,
24
+ } from "@/common/actor-router-consts";
18
25
  import type { UpgradeWebSocketArgs } from "@/common/inline-websocket-adapter2";
19
26
  import { deconstructError, stringifyError } from "@/common/utils";
20
27
  import type { UniversalWebSocket } from "@/common/websocket-interface";
@@ -31,22 +38,18 @@ import {
31
38
  deserializeWithEncoding,
32
39
  serializeWithEncoding,
33
40
  } from "@/serde";
34
- import { bufferToArrayBuffer } from "@/utils";
41
+ import { bufferToArrayBuffer, promiseWithResolvers } from "@/utils";
35
42
  import type { ActorDriver } from "./driver";
36
- import type {
37
- GenericHttpDriverState,
38
- GenericSseDriverState,
39
- GenericWebSocketDriverState,
40
- } from "./generic-conn-driver";
41
43
  import { loggerWithoutContext } from "./log";
42
44
  import { parseMessage } from "./protocol/old";
43
45
 
46
+ export const SSE_PING_INTERVAL = 1000;
47
+
44
48
  export interface ConnectWebSocketOpts {
45
49
  req?: HonoRequest;
46
50
  encoding: Encoding;
47
51
  actorId: string;
48
52
  params: unknown;
49
- authData: unknown;
50
53
  }
51
54
 
52
55
  export interface ConnectWebSocketOutput {
@@ -60,7 +63,6 @@ export interface ConnectSseOpts {
60
63
  encoding: Encoding;
61
64
  params: unknown;
62
65
  actorId: string;
63
- authData: unknown;
64
66
  }
65
67
 
66
68
  export interface ConnectSseOutput {
@@ -74,7 +76,6 @@ export interface ActionOpts {
74
76
  actionName: string;
75
77
  actionArgs: unknown[];
76
78
  actorId: string;
77
- authData: unknown;
78
79
  }
79
80
 
80
81
  export interface ActionOutput {
@@ -92,14 +93,12 @@ export interface ConnsMessageOpts {
92
93
  export interface FetchOpts {
93
94
  request: Request;
94
95
  actorId: string;
95
- authData: unknown;
96
96
  }
97
97
 
98
98
  export interface WebSocketOpts {
99
99
  request: Request;
100
100
  websocket: UniversalWebSocket;
101
101
  actorId: string;
102
- authData: unknown;
103
102
  }
104
103
 
105
104
  /**
@@ -112,7 +111,8 @@ export async function handleWebSocketConnect(
112
111
  actorId: string,
113
112
  encoding: Encoding,
114
113
  parameters: unknown,
115
- authData: unknown,
114
+ connId?: string,
115
+ connToken?: string,
116
116
  ): Promise<UpgradeWebSocketArgs> {
117
117
  const exposeInternalError = req ? getRequestExposeInternalError(req) : false;
118
118
 
@@ -121,7 +121,7 @@ export async function handleWebSocketConnect(
121
121
  promise: handlersPromise,
122
122
  resolve: handlersResolve,
123
123
  reject: handlersReject,
124
- } = Promise.withResolvers<{
124
+ } = promiseWithResolvers<{
125
125
  conn: AnyConn;
126
126
  actor: AnyActorInstance;
127
127
  connId: string;
@@ -153,40 +153,47 @@ export async function handleWebSocketConnect(
153
153
  };
154
154
  }
155
155
 
156
+ // Promise used to wait for the websocket close in `disconnect`
157
+ const closePromise = promiseWithResolvers<void>();
158
+ const socketId = generateConnSocketId();
159
+
156
160
  return {
157
161
  onOpen: (_evt: any, ws: WSContext) => {
158
- actor.rLog.debug("websocket open");
162
+ actor.rLog.debug("actor websocket open");
159
163
 
160
164
  // Run async operations in background
161
165
  (async () => {
162
166
  try {
163
- const connId = generateConnId();
164
- const connToken = generateConnToken();
165
- const connState = await actor.prepareConn(parameters, req);
166
-
167
- // Save socket
168
- const connGlobalState =
169
- actorDriver.getGenericConnGlobalState(actorId);
170
- connGlobalState.websockets.set(connId, ws);
167
+ let conn: AnyConn;
168
+
169
+ // Create or reconnect connection
171
170
  actor.rLog.debug({
172
- msg: "registered websocket for conn",
171
+ msg: connId
172
+ ? "websocket reconnection attempt"
173
+ : "new websocket connection",
174
+ connId,
173
175
  actorId,
174
- totalCount: connGlobalState.websockets.size,
175
176
  });
176
177
 
177
- // Create connection
178
- const conn = await actor.createConn(
178
+ conn = await actor.createConn(
179
+ {
180
+ socketId,
181
+ driverState: {
182
+ [ConnDriverKind.WEBSOCKET]: {
183
+ encoding,
184
+ websocket: ws,
185
+ closePromise,
186
+ },
187
+ },
188
+ },
189
+ parameters,
190
+ req,
179
191
  connId,
180
192
  connToken,
181
- parameters,
182
- connState,
183
- CONNECTION_DRIVER_WEBSOCKET,
184
- { encoding } satisfies GenericWebSocketDriverState,
185
- authData,
186
193
  );
187
194
 
188
195
  // Unblock other handlers
189
- handlersResolve({ conn, actor, connId });
196
+ handlersResolve({ conn, actor, connId: conn.id });
190
197
  } catch (error) {
191
198
  handlersReject(error);
192
199
 
@@ -258,6 +265,10 @@ export async function handleWebSocketConnect(
258
265
  },
259
266
  ws: WSContext,
260
267
  ) => {
268
+ handlersReject(`WebSocket closed (${event.code}): ${event.reason}`);
269
+
270
+ closePromise.resolve();
271
+
261
272
  if (event.wasClean) {
262
273
  actor.rLog.info({
263
274
  msg: "websocket closed",
@@ -280,24 +291,8 @@ export async function handleWebSocketConnect(
280
291
 
281
292
  // Handle cleanup asynchronously
282
293
  handlersPromise
283
- .then(({ conn, actor, connId }) => {
284
- const connGlobalState =
285
- actorDriver.getGenericConnGlobalState(actorId);
286
- const didDelete = connGlobalState.websockets.delete(connId);
287
- if (didDelete) {
288
- actor.rLog.info({
289
- msg: "removing websocket for conn",
290
- totalCount: connGlobalState.websockets.size,
291
- });
292
- } else {
293
- actor.rLog.warn({
294
- msg: "websocket does not exist for conn",
295
- actorId,
296
- totalCount: connGlobalState.websockets.size,
297
- });
298
- }
299
-
300
- actor.__removeConn(conn);
294
+ .then(({ conn, actor }) => {
295
+ actor.__connDisconnected(conn, event.wasClean, socketId);
301
296
  })
302
297
  .catch((error) => {
303
298
  deconstructError(
@@ -332,46 +327,50 @@ export async function handleSseConnect(
332
327
  _runConfig: RunConfig,
333
328
  actorDriver: ActorDriver,
334
329
  actorId: string,
335
- authData: unknown,
336
330
  ) {
331
+ c.header("Content-Encoding", "Identity");
332
+
337
333
  const encoding = getRequestEncoding(c.req);
338
334
  const parameters = getRequestConnParams(c.req);
335
+ const socketId = generateConnSocketId();
336
+
337
+ // Check for reconnection parameters
338
+ const connId = c.req.header(HEADER_CONN_ID);
339
+ const connToken = c.req.header(HEADER_CONN_TOKEN);
339
340
 
340
341
  // Return the main handler with all async work inside
341
342
  return streamSSE(c, async (stream) => {
342
343
  let actor: AnyActorInstance | undefined;
343
- let connId: string | undefined;
344
- let connToken: string | undefined;
345
- let connState: unknown;
346
344
  let conn: AnyConn | undefined;
347
345
 
348
346
  try {
349
347
  // Do all async work inside the handler
350
348
  actor = await actorDriver.loadActor(actorId);
351
- connId = generateConnId();
352
- connToken = generateConnToken();
353
- connState = await actor.prepareConn(parameters, c.req.raw);
354
349
 
355
- actor.rLog.debug("sse open");
356
-
357
- // Save stream
358
- actorDriver
359
- .getGenericConnGlobalState(actorId)
360
- .sseStreams.set(connId, stream);
350
+ // Create or reconnect connection
351
+ actor.rLog.debug({
352
+ msg: connId ? "sse reconnection attempt" : "sse open",
353
+ connId,
354
+ });
361
355
 
362
- // Create connection
363
356
  conn = await actor.createConn(
357
+ {
358
+ socketId,
359
+ driverState: {
360
+ [ConnDriverKind.SSE]: {
361
+ encoding,
362
+ stream: stream,
363
+ },
364
+ },
365
+ },
366
+ parameters,
367
+ c.req.raw,
364
368
  connId,
365
369
  connToken,
366
- parameters,
367
- connState,
368
- CONNECTION_DRIVER_SSE,
369
- { encoding } satisfies GenericSseDriverState,
370
- authData,
371
370
  );
372
371
 
373
372
  // Wait for close
374
- const abortResolver = Promise.withResolvers();
373
+ const abortResolver = promiseWithResolvers();
375
374
 
376
375
  // HACK: This is required so the abort handler below works
377
376
  //
@@ -380,18 +379,14 @@ export async function handleSseConnect(
380
379
 
381
380
  // Handle stream abort (when client closes the connection)
382
381
  c.req.raw.signal.addEventListener("abort", async () => {
383
- const rLog = actor?.rLog ?? loggerWithoutContext();
382
+ invariant(actor, "actor should exist");
383
+ const rLog = actor.rLog ?? loggerWithoutContext();
384
384
  try {
385
385
  rLog.debug("sse stream aborted");
386
386
 
387
387
  // Cleanup
388
- if (connId) {
389
- actorDriver
390
- .getGenericConnGlobalState(actorId)
391
- .sseStreams.delete(connId);
392
- }
393
- if (conn && actor) {
394
- actor.__removeConn(conn);
388
+ if (conn) {
389
+ actor.__connDisconnected(conn, false, socketId);
395
390
  }
396
391
 
397
392
  abortResolver.resolve(undefined);
@@ -401,24 +396,33 @@ export async function handleSseConnect(
401
396
  }
402
397
  });
403
398
 
404
- // HACK: Will throw if not configured
405
- try {
406
- c.executionCtx.waitUntil(abortResolver.promise);
407
- } catch {}
399
+ // // HACK: Will throw if not configured
400
+ // try {
401
+ // c.executionCtx.waitUntil(abortResolver.promise);
402
+ // } catch {}
403
+
404
+ // Send ping every second to keep the connection alive
405
+ //
406
+ // NOTE: This is required on Cloudflare Workers in order to detect when the connection is closed
407
+ while (true) {
408
+ if (stream.closed || stream.aborted) {
409
+ actor?.rLog.debug({
410
+ msg: "sse stream closed",
411
+ closed: stream.closed,
412
+ aborted: stream.aborted,
413
+ });
414
+ break;
415
+ }
408
416
 
409
- // Wait until connection aborted
410
- await abortResolver.promise;
417
+ await stream.writeSSE({ event: "ping", data: "" });
418
+ await stream.sleep(SSE_PING_INTERVAL);
419
+ }
411
420
  } catch (error) {
412
421
  loggerWithoutContext().error({ msg: "error in sse connection", error });
413
422
 
414
423
  // Cleanup on error
415
- if (connId !== undefined) {
416
- actorDriver
417
- .getGenericConnGlobalState(actorId)
418
- .sseStreams.delete(connId);
419
- }
420
424
  if (conn && actor !== undefined) {
421
- actor.__removeConn(conn);
425
+ actor.__connDisconnected(conn, false, socketId);
422
426
  }
423
427
 
424
428
  // Close the stream on error
@@ -436,7 +440,6 @@ export async function handleAction(
436
440
  actorDriver: ActorDriver,
437
441
  actionName: string,
438
442
  actorId: string,
439
- authData: unknown,
440
443
  ) {
441
444
  const encoding = getRequestEncoding(c.req);
442
445
  const parameters = getRequestConnParams(c.req);
@@ -449,6 +452,7 @@ export async function handleAction(
449
452
  HTTP_ACTION_REQUEST_VERSIONED,
450
453
  );
451
454
  const actionArgs = cbor.decode(new Uint8Array(request.args));
455
+ const socketId = generateConnSocketId();
452
456
 
453
457
  // Invoke the action
454
458
  let actor: AnyActorInstance | undefined;
@@ -460,15 +464,13 @@ export async function handleAction(
460
464
  actor.rLog.debug({ msg: "handling action", actionName, encoding });
461
465
 
462
466
  // Create conn
463
- const connState = await actor.prepareConn(parameters, c.req.raw);
464
467
  conn = await actor.createConn(
465
- generateConnId(),
466
- generateConnToken(),
468
+ {
469
+ socketId,
470
+ driverState: { [ConnDriverKind.HTTP]: {} },
471
+ },
467
472
  parameters,
468
- connState,
469
- CONNECTION_DRIVER_HTTP,
470
- {} satisfies GenericHttpDriverState,
471
- authData,
473
+ c.req.raw,
472
474
  );
473
475
 
474
476
  // Call action
@@ -476,7 +478,8 @@ export async function handleAction(
476
478
  output = await actor.executeAction(ctx, actionName, actionArgs);
477
479
  } finally {
478
480
  if (conn) {
479
- actor?.__removeConn(conn);
481
+ // HTTP connections don't have persistent sockets, so no socket ID needed
482
+ actor?.__connDisconnected(conn, true, socketId);
480
483
  }
481
484
  }
482
485
 
@@ -489,7 +492,9 @@ export async function handleAction(
489
492
  responseData,
490
493
  HTTP_ACTION_RESPONSE_VERSIONED,
491
494
  );
492
- return c.body(serialized as Uint8Array, 200, {
495
+
496
+ // TODO: Remvoe any, Hono is being a dumbass
497
+ return c.body(serialized as Uint8Array as any, 200, {
493
498
  "Content-Type": contentTypeForEncoding(encoding),
494
499
  });
495
500
  }
@@ -534,12 +539,48 @@ export async function handleConnectionMessage(
534
539
  return c.json({});
535
540
  }
536
541
 
542
+ export async function handleConnectionClose(
543
+ c: HonoContext,
544
+ _runConfig: RunConfig,
545
+ actorDriver: ActorDriver,
546
+ connId: string,
547
+ connToken: string,
548
+ actorId: string,
549
+ ) {
550
+ const actor = await actorDriver.loadActor(actorId);
551
+
552
+ // Find connection
553
+ const conn = actor.conns.get(connId);
554
+ if (!conn) {
555
+ throw new errors.ConnNotFound(connId);
556
+ }
557
+
558
+ // Authenticate connection
559
+ if (conn._token !== connToken) {
560
+ throw new errors.IncorrectConnToken();
561
+ }
562
+
563
+ // Check if this is an SSE connection
564
+ if (
565
+ !conn.__socket?.driverState ||
566
+ !(ConnDriverKind.SSE in conn.__socket.driverState)
567
+ ) {
568
+ throw new errors.UserError(
569
+ "Connection close is only supported for SSE connections",
570
+ );
571
+ }
572
+
573
+ // Close the SSE connection
574
+ await conn.disconnect("Connection closed by client request");
575
+
576
+ return c.json({});
577
+ }
578
+
537
579
  export async function handleRawWebSocketHandler(
538
580
  req: Request | undefined,
539
581
  path: string,
540
582
  actorDriver: ActorDriver,
541
583
  actorId: string,
542
- authData: unknown,
543
584
  ): Promise<UpgradeWebSocketArgs> {
544
585
  const actor = await actorDriver.loadActor(actorId);
545
586
 
@@ -644,38 +685,6 @@ export function getRequestQuery(c: HonoContext): unknown {
644
685
  }
645
686
  }
646
687
 
647
- export const HEADER_ACTOR_QUERY = "X-RivetKit-Query";
648
-
649
- export const HEADER_ENCODING = "X-RivetKit-Encoding";
650
-
651
- // IMPORTANT: Params must be in headers or in an E2EE part of the request (i.e. NOT the URL or query string) in order to ensure that tokens can be securely passed in params.
652
- export const HEADER_CONN_PARAMS = "X-RivetKit-Conn-Params";
653
-
654
- // Internal header
655
- export const HEADER_AUTH_DATA = "X-RivetKit-Auth-Data";
656
-
657
- export const HEADER_ACTOR_ID = "X-RivetKit-Actor";
658
-
659
- export const HEADER_CONN_ID = "X-RivetKit-Conn";
660
-
661
- export const HEADER_CONN_TOKEN = "X-RivetKit-Conn-Token";
662
-
663
- /**
664
- * Headers that publics can send from public clients.
665
- *
666
- * Used for CORS.
667
- **/
668
- export const ALLOWED_PUBLIC_HEADERS = [
669
- "Content-Type",
670
- "User-Agent",
671
- HEADER_ACTOR_QUERY,
672
- HEADER_ENCODING,
673
- HEADER_CONN_PARAMS,
674
- HEADER_ACTOR_ID,
675
- HEADER_CONN_ID,
676
- HEADER_CONN_TOKEN,
677
- ];
678
-
679
688
  // Helper to get connection parameters for the request
680
689
  export function getRequestConnParams(req: HonoRequest): unknown {
681
690
  const paramsParam = req.header(HEADER_CONN_PARAMS);