rivetkit 2.0.23 → 2.0.24

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 (228) hide show
  1. package/dist/schemas/actor-persist/v2.ts +3 -3
  2. package/dist/schemas/actor-persist/v3.ts +274 -0
  3. package/dist/schemas/client-protocol/v2.ts +432 -0
  4. package/dist/schemas/file-system-driver/v2.ts +136 -0
  5. package/dist/tsup/actor/errors.cjs +2 -4
  6. package/dist/tsup/actor/errors.cjs.map +1 -1
  7. package/dist/tsup/actor/errors.d.cts +7 -10
  8. package/dist/tsup/actor/errors.d.ts +7 -10
  9. package/dist/tsup/actor/errors.js +9 -11
  10. package/dist/tsup/{actor-router-consts-B3Lu87yJ.d.cts → actor-router-consts-DzI2szci.d.cts} +5 -9
  11. package/dist/tsup/{actor-router-consts-B3Lu87yJ.d.ts → actor-router-consts-DzI2szci.d.ts} +5 -9
  12. package/dist/tsup/{chunk-3JYSUFET.cjs → chunk-3543NCSN.cjs} +45 -57
  13. package/dist/tsup/chunk-3543NCSN.cjs.map +1 -0
  14. package/dist/tsup/chunk-4SHILYS5.cjs +5694 -0
  15. package/dist/tsup/chunk-4SHILYS5.cjs.map +1 -0
  16. package/dist/tsup/{chunk-NCUALX2Q.cjs → chunk-5BZO5XPS.cjs} +3 -3
  17. package/dist/tsup/{chunk-NCUALX2Q.cjs.map → chunk-5BZO5XPS.cjs.map} +1 -1
  18. package/dist/tsup/{chunk-5PKKNNNS.js → chunk-BAIGSF64.js} +189 -187
  19. package/dist/tsup/chunk-BAIGSF64.js.map +1 -0
  20. package/dist/tsup/{chunk-HNYF4T36.cjs → chunk-CHLZBSI2.cjs} +17 -17
  21. package/dist/tsup/chunk-CHLZBSI2.cjs.map +1 -0
  22. package/dist/tsup/chunk-D3SLADUD.cjs +512 -0
  23. package/dist/tsup/chunk-D3SLADUD.cjs.map +1 -0
  24. package/dist/tsup/{chunk-KSRXX3Z4.cjs → chunk-D6762AOA.cjs} +20 -25
  25. package/dist/tsup/chunk-D6762AOA.cjs.map +1 -0
  26. package/dist/tsup/{chunk-C56XVVV4.cjs → chunk-DLK5YCTN.cjs} +187 -185
  27. package/dist/tsup/chunk-DLK5YCTN.cjs.map +1 -0
  28. package/dist/tsup/{chunk-DLYZKFRY.js → chunk-DUJQWGYD.js} +3 -7
  29. package/dist/tsup/chunk-DUJQWGYD.js.map +1 -0
  30. package/dist/tsup/{chunk-5UJQWWO3.js → chunk-EIPANQMF.js} +2 -2
  31. package/dist/tsup/{chunk-54DVMQPT.cjs → chunk-ESMTDP7G.cjs} +6 -6
  32. package/dist/tsup/chunk-ESMTDP7G.cjs.map +1 -0
  33. package/dist/tsup/{chunk-XYK5PY3B.cjs → chunk-FVAKREFB.cjs} +1900 -1737
  34. package/dist/tsup/chunk-FVAKREFB.cjs.map +1 -0
  35. package/dist/tsup/{chunk-PHNIVSG5.js → chunk-I3XT7WOF.js} +44 -56
  36. package/dist/tsup/chunk-I3XT7WOF.js.map +1 -0
  37. package/dist/tsup/{chunk-3I6ZIJVJ.js → chunk-IMDS5T42.js} +3 -3
  38. package/dist/tsup/chunk-IMDS5T42.js.map +1 -0
  39. package/dist/tsup/{chunk-SN4KWTRA.cjs → chunk-J3HZJF2P.cjs} +10 -14
  40. package/dist/tsup/chunk-J3HZJF2P.cjs.map +1 -0
  41. package/dist/tsup/{chunk-NOZSCUPQ.js → chunk-MBBJUHSP.js} +1844 -1681
  42. package/dist/tsup/chunk-MBBJUHSP.js.map +1 -0
  43. package/dist/tsup/{chunk-RVVUS4X6.js → chunk-MO5CB6MD.js} +9 -9
  44. package/dist/tsup/chunk-MO5CB6MD.js.map +1 -0
  45. package/dist/tsup/chunk-OFOTPKAH.js +512 -0
  46. package/dist/tsup/chunk-OFOTPKAH.js.map +1 -0
  47. package/dist/tsup/{chunk-G64QUEDJ.js → chunk-W6RDS6NW.js} +23 -28
  48. package/dist/tsup/chunk-W6RDS6NW.js.map +1 -0
  49. package/dist/tsup/{chunk-XSDSNHSE.cjs → chunk-YC5DUHPM.cjs} +4 -8
  50. package/dist/tsup/chunk-YC5DUHPM.cjs.map +1 -0
  51. package/dist/tsup/{chunk-YAYNBR37.js → chunk-YC7YPM2T.js} +2 -6
  52. package/dist/tsup/chunk-YC7YPM2T.js.map +1 -0
  53. package/dist/tsup/{chunk-FTQ62XTN.js → chunk-ZSPU5R4C.js} +3322 -2251
  54. package/dist/tsup/chunk-ZSPU5R4C.js.map +1 -0
  55. package/dist/tsup/client/mod.cjs +9 -9
  56. package/dist/tsup/client/mod.d.cts +5 -7
  57. package/dist/tsup/client/mod.d.ts +5 -7
  58. package/dist/tsup/client/mod.js +8 -8
  59. package/dist/tsup/common/log.cjs +3 -3
  60. package/dist/tsup/common/log.js +2 -2
  61. package/dist/tsup/common/websocket.cjs +4 -4
  62. package/dist/tsup/common/websocket.js +3 -3
  63. package/dist/tsup/{conn-B3Vhbgnd.d.ts → config-BRDYDraU.d.cts} +1119 -1047
  64. package/dist/tsup/{conn-DJWL3nGx.d.cts → config-Bo-blHpJ.d.ts} +1119 -1047
  65. package/dist/tsup/driver-helpers/mod.cjs +5 -13
  66. package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
  67. package/dist/tsup/driver-helpers/mod.d.cts +11 -9
  68. package/dist/tsup/driver-helpers/mod.d.ts +11 -9
  69. package/dist/tsup/driver-helpers/mod.js +14 -22
  70. package/dist/tsup/driver-test-suite/mod.cjs +474 -303
  71. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  72. package/dist/tsup/driver-test-suite/mod.d.cts +6 -9
  73. package/dist/tsup/driver-test-suite/mod.d.ts +6 -9
  74. package/dist/tsup/driver-test-suite/mod.js +1085 -914
  75. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  76. package/dist/tsup/inspector/mod.cjs +6 -6
  77. package/dist/tsup/inspector/mod.d.cts +5 -7
  78. package/dist/tsup/inspector/mod.d.ts +5 -7
  79. package/dist/tsup/inspector/mod.js +5 -5
  80. package/dist/tsup/mod.cjs +10 -16
  81. package/dist/tsup/mod.cjs.map +1 -1
  82. package/dist/tsup/mod.d.cts +23 -25
  83. package/dist/tsup/mod.d.ts +23 -25
  84. package/dist/tsup/mod.js +17 -23
  85. package/dist/tsup/test/mod.cjs +11 -11
  86. package/dist/tsup/test/mod.d.cts +4 -6
  87. package/dist/tsup/test/mod.d.ts +4 -6
  88. package/dist/tsup/test/mod.js +10 -10
  89. package/dist/tsup/utils.cjs +3 -5
  90. package/dist/tsup/utils.cjs.map +1 -1
  91. package/dist/tsup/utils.d.cts +1 -2
  92. package/dist/tsup/utils.d.ts +1 -2
  93. package/dist/tsup/utils.js +2 -4
  94. package/package.json +13 -6
  95. package/src/actor/config.ts +56 -44
  96. package/src/actor/conn/driver.ts +61 -0
  97. package/src/actor/conn/drivers/http.ts +17 -0
  98. package/src/actor/conn/drivers/raw-request.ts +24 -0
  99. package/src/actor/conn/drivers/raw-websocket.ts +65 -0
  100. package/src/actor/conn/drivers/websocket.ts +129 -0
  101. package/src/actor/conn/mod.ts +232 -0
  102. package/src/actor/conn/persisted.ts +81 -0
  103. package/src/actor/conn/state-manager.ts +196 -0
  104. package/src/actor/contexts/action.ts +23 -0
  105. package/src/actor/{context.ts → contexts/actor.ts} +19 -8
  106. package/src/actor/contexts/conn-init.ts +31 -0
  107. package/src/actor/contexts/conn.ts +48 -0
  108. package/src/actor/contexts/create-conn-state.ts +13 -0
  109. package/src/actor/contexts/on-before-connect.ts +13 -0
  110. package/src/actor/contexts/on-connect.ts +22 -0
  111. package/src/actor/contexts/request.ts +48 -0
  112. package/src/actor/contexts/websocket.ts +48 -0
  113. package/src/actor/definition.ts +3 -3
  114. package/src/actor/driver.ts +36 -5
  115. package/src/actor/errors.ts +19 -24
  116. package/src/actor/instance/connection-manager.ts +465 -0
  117. package/src/actor/instance/event-manager.ts +292 -0
  118. package/src/actor/instance/kv.ts +15 -0
  119. package/src/actor/instance/mod.ts +1107 -0
  120. package/src/actor/instance/persisted.ts +67 -0
  121. package/src/actor/instance/schedule-manager.ts +349 -0
  122. package/src/actor/instance/state-manager.ts +502 -0
  123. package/src/actor/mod.ts +13 -16
  124. package/src/actor/protocol/old.ts +131 -43
  125. package/src/actor/protocol/serde.ts +19 -4
  126. package/src/actor/router-endpoints.ts +61 -586
  127. package/src/actor/router-websocket-endpoints.ts +408 -0
  128. package/src/actor/router.ts +63 -197
  129. package/src/actor/schedule.ts +1 -1
  130. package/src/client/actor-conn.ts +183 -249
  131. package/src/client/actor-handle.ts +29 -6
  132. package/src/client/client.ts +0 -4
  133. package/src/client/config.ts +1 -4
  134. package/src/client/mod.ts +0 -1
  135. package/src/client/raw-utils.ts +3 -3
  136. package/src/client/utils.ts +85 -39
  137. package/src/common/actor-router-consts.ts +5 -12
  138. package/src/common/{inline-websocket-adapter2.ts → inline-websocket-adapter.ts} +26 -48
  139. package/src/common/log.ts +1 -1
  140. package/src/common/router.ts +28 -17
  141. package/src/common/utils.ts +2 -0
  142. package/src/driver-helpers/mod.ts +7 -10
  143. package/src/driver-helpers/utils.ts +18 -9
  144. package/src/driver-test-suite/mod.ts +26 -50
  145. package/src/driver-test-suite/test-inline-client-driver.ts +27 -51
  146. package/src/driver-test-suite/tests/actor-conn-hibernation.ts +150 -0
  147. package/src/driver-test-suite/tests/actor-conn-state.ts +1 -4
  148. package/src/driver-test-suite/tests/actor-conn.ts +5 -9
  149. package/src/driver-test-suite/tests/actor-destroy.ts +294 -0
  150. package/src/driver-test-suite/tests/actor-driver.ts +0 -7
  151. package/src/driver-test-suite/tests/actor-handle.ts +12 -12
  152. package/src/driver-test-suite/tests/actor-metadata.ts +1 -1
  153. package/src/driver-test-suite/tests/manager-driver.ts +1 -1
  154. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +8 -8
  155. package/src/driver-test-suite/tests/raw-http-request-properties.ts +6 -5
  156. package/src/driver-test-suite/tests/raw-http.ts +5 -5
  157. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +7 -7
  158. package/src/driver-test-suite/tests/request-access.ts +4 -4
  159. package/src/driver-test-suite/utils.ts +6 -10
  160. package/src/drivers/engine/actor-driver.ts +614 -424
  161. package/src/drivers/engine/mod.ts +0 -1
  162. package/src/drivers/file-system/actor.ts +24 -12
  163. package/src/drivers/file-system/global-state.ts +427 -37
  164. package/src/drivers/file-system/manager.ts +71 -83
  165. package/src/drivers/file-system/mod.ts +3 -0
  166. package/src/drivers/file-system/utils.ts +18 -8
  167. package/src/engine-process/mod.ts +38 -38
  168. package/src/inspector/utils.ts +7 -5
  169. package/src/manager/driver.ts +11 -4
  170. package/src/manager/gateway.ts +4 -29
  171. package/src/manager/protocol/mod.ts +0 -2
  172. package/src/manager/protocol/query.ts +0 -4
  173. package/src/manager/router.ts +67 -64
  174. package/src/manager-api/actors.ts +13 -0
  175. package/src/mod.ts +1 -3
  176. package/src/registry/mod.ts +20 -20
  177. package/src/registry/serve.ts +9 -14
  178. package/src/remote-manager-driver/actor-websocket-client.ts +1 -16
  179. package/src/remote-manager-driver/api-endpoints.ts +13 -1
  180. package/src/remote-manager-driver/api-utils.ts +8 -0
  181. package/src/remote-manager-driver/metadata.ts +58 -0
  182. package/src/remote-manager-driver/mod.ts +47 -62
  183. package/src/remote-manager-driver/ws-proxy.ts +1 -1
  184. package/src/schemas/actor-persist/mod.ts +1 -1
  185. package/src/schemas/actor-persist/versioned.ts +56 -31
  186. package/src/schemas/client-protocol/mod.ts +1 -1
  187. package/src/schemas/client-protocol/versioned.ts +41 -21
  188. package/src/schemas/client-protocol-zod/mod.ts +103 -0
  189. package/src/schemas/file-system-driver/mod.ts +1 -1
  190. package/src/schemas/file-system-driver/versioned.ts +42 -19
  191. package/src/serde.ts +33 -11
  192. package/src/test/mod.ts +7 -3
  193. package/src/utils/node.ts +173 -0
  194. package/src/utils.ts +0 -4
  195. package/dist/tsup/chunk-3I6ZIJVJ.js.map +0 -1
  196. package/dist/tsup/chunk-3JYSUFET.cjs.map +0 -1
  197. package/dist/tsup/chunk-54DVMQPT.cjs.map +0 -1
  198. package/dist/tsup/chunk-5PKKNNNS.js.map +0 -1
  199. package/dist/tsup/chunk-C56XVVV4.cjs.map +0 -1
  200. package/dist/tsup/chunk-D6PCH7FR.cjs +0 -4623
  201. package/dist/tsup/chunk-D6PCH7FR.cjs.map +0 -1
  202. package/dist/tsup/chunk-DLYZKFRY.js.map +0 -1
  203. package/dist/tsup/chunk-FTQ62XTN.js.map +0 -1
  204. package/dist/tsup/chunk-G64QUEDJ.js.map +0 -1
  205. package/dist/tsup/chunk-HNYF4T36.cjs.map +0 -1
  206. package/dist/tsup/chunk-JMLTKMJ7.cjs +0 -1119
  207. package/dist/tsup/chunk-JMLTKMJ7.cjs.map +0 -1
  208. package/dist/tsup/chunk-KSRXX3Z4.cjs.map +0 -1
  209. package/dist/tsup/chunk-NOZSCUPQ.js.map +0 -1
  210. package/dist/tsup/chunk-PHNIVSG5.js.map +0 -1
  211. package/dist/tsup/chunk-RUTBXBRR.js +0 -1119
  212. package/dist/tsup/chunk-RUTBXBRR.js.map +0 -1
  213. package/dist/tsup/chunk-RVVUS4X6.js.map +0 -1
  214. package/dist/tsup/chunk-SN4KWTRA.cjs.map +0 -1
  215. package/dist/tsup/chunk-XSDSNHSE.cjs.map +0 -1
  216. package/dist/tsup/chunk-XYK5PY3B.cjs.map +0 -1
  217. package/dist/tsup/chunk-YAYNBR37.js.map +0 -1
  218. package/src/actor/action.ts +0 -178
  219. package/src/actor/conn-drivers.ts +0 -216
  220. package/src/actor/conn-socket.ts +0 -8
  221. package/src/actor/conn.ts +0 -272
  222. package/src/actor/instance.ts +0 -2336
  223. package/src/actor/persisted.ts +0 -49
  224. package/src/actor/unstable-react.ts +0 -110
  225. package/src/driver-test-suite/tests/actor-reconnect.ts +0 -170
  226. package/src/drivers/engine/kv.ts +0 -3
  227. package/src/manager/hono-websocket-adapter.ts +0 -393
  228. /package/dist/tsup/{chunk-5UJQWWO3.js.map → chunk-EIPANQMF.js.map} +0 -0
@@ -1,78 +1,40 @@
1
1
  import * as cbor from "cbor-x";
2
2
  import type { Context as HonoContext, HonoRequest } from "hono";
3
- import { type SSEStreamingApi, streamSSE } from "hono/streaming";
4
- import type { WSContext } from "hono/ws";
5
- import invariant from "invariant";
6
- import { ActionContext } from "@/actor/action";
7
- import type { AnyConn } from "@/actor/conn";
8
- import {
9
- generateConnId,
10
- generateConnRequestId,
11
- generateConnToken,
12
- } from "@/actor/conn";
13
- import { ConnDriverKind } from "@/actor/conn-drivers";
3
+ import type { AnyConn } from "@/actor/conn/mod";
4
+ import { ActionContext } from "@/actor/contexts/action";
14
5
  import * as errors from "@/actor/errors";
15
- import { type AnyActorInstance, PERSIST_SYMBOL } from "@/actor/instance";
16
- import type { InputData } from "@/actor/protocol/serde";
6
+ import type { AnyActorInstance } from "@/actor/instance/mod";
17
7
  import { type Encoding, EncodingSchema } from "@/actor/protocol/serde";
18
8
  import {
19
9
  HEADER_ACTOR_QUERY,
20
- HEADER_CONN_ID,
21
10
  HEADER_CONN_PARAMS,
22
- HEADER_CONN_TOKEN,
23
11
  HEADER_ENCODING,
12
+ WS_PROTOCOL_CONN_PARAMS,
13
+ WS_PROTOCOL_ENCODING,
24
14
  } from "@/common/actor-router-consts";
25
- import type { UpgradeWebSocketArgs } from "@/common/inline-websocket-adapter2";
26
- import { deconstructError, stringifyError } from "@/common/utils";
27
- import type { UniversalWebSocket } from "@/common/websocket-interface";
28
- import { HonoWebSocketAdapter } from "@/manager/hono-websocket-adapter";
15
+ import { stringifyError } from "@/common/utils";
29
16
  import type { RunnerConfig } from "@/registry/run-config";
30
17
  import type * as protocol from "@/schemas/client-protocol/mod";
31
18
  import {
32
19
  HTTP_ACTION_REQUEST_VERSIONED,
33
20
  HTTP_ACTION_RESPONSE_VERSIONED,
34
- TO_SERVER_VERSIONED,
35
21
  } from "@/schemas/client-protocol/versioned";
22
+ import {
23
+ type HttpActionRequest as HttpActionRequestJson,
24
+ HttpActionRequestSchema,
25
+ type HttpActionResponse as HttpActionResponseJson,
26
+ HttpActionResponseSchema,
27
+ } from "@/schemas/client-protocol-zod/mod";
36
28
  import {
37
29
  contentTypeForEncoding,
38
30
  deserializeWithEncoding,
39
31
  serializeWithEncoding,
40
32
  } from "@/serde";
41
- import {
42
- arrayBuffersEqual,
43
- bufferToArrayBuffer,
44
- promiseWithResolvers,
45
- } from "@/utils";
33
+ import { bufferToArrayBuffer } from "@/utils";
34
+ import { createHttpDriver } from "./conn/drivers/http";
35
+ import { createRawRequestDriver } from "./conn/drivers/raw-request";
46
36
  import type { ActorDriver } from "./driver";
47
37
  import { loggerWithoutContext } from "./log";
48
- import { parseMessage } from "./protocol/old";
49
-
50
- export const SSE_PING_INTERVAL = 1000;
51
-
52
- export interface ConnectWebSocketOpts {
53
- req?: HonoRequest;
54
- encoding: Encoding;
55
- actorId: string;
56
- params: unknown;
57
- }
58
-
59
- export interface ConnectWebSocketOutput {
60
- onOpen: (ws: WSContext) => void;
61
- onMessage: (message: protocol.ToServer) => void;
62
- onClose: () => void;
63
- }
64
-
65
- export interface ConnectSseOpts {
66
- req?: HonoRequest;
67
- encoding: Encoding;
68
- params: unknown;
69
- actorId: string;
70
- }
71
-
72
- export interface ConnectSseOutput {
73
- onOpen: (stream: SSEStreamingApi) => void;
74
- onClose: () => Promise<void>;
75
- }
76
38
 
77
39
  export interface ActionOpts {
78
40
  req?: HonoRequest;
@@ -89,7 +51,6 @@ export interface ActionOutput {
89
51
  export interface ConnsMessageOpts {
90
52
  req?: HonoRequest;
91
53
  connId: string;
92
- connToken: string;
93
54
  message: protocol.ToServer;
94
55
  actorId: string;
95
56
  }
@@ -99,362 +60,6 @@ export interface FetchOpts {
99
60
  actorId: string;
100
61
  }
101
62
 
102
- export interface WebSocketOpts {
103
- request: Request;
104
- websocket: UniversalWebSocket;
105
- actorId: string;
106
- }
107
-
108
- /**
109
- * Creates a WebSocket connection handler
110
- */
111
- export async function handleWebSocketConnect(
112
- req: Request | undefined,
113
- runConfig: RunnerConfig,
114
- actorDriver: ActorDriver,
115
- actorId: string,
116
- encoding: Encoding,
117
- parameters: unknown,
118
- requestId: string,
119
- requestIdBuf: ArrayBuffer | undefined,
120
- connId: string | undefined,
121
- connToken: string | undefined,
122
- ): Promise<UpgradeWebSocketArgs> {
123
- const exposeInternalError = req
124
- ? getRequestExposeInternalError(req)
125
- : false;
126
-
127
- // Setup promise for the init handlers since all other behavior depends on this
128
- const {
129
- promise: handlersPromise,
130
- resolve: handlersResolve,
131
- reject: handlersReject,
132
- } = promiseWithResolvers<{
133
- conn: AnyConn;
134
- actor: AnyActorInstance;
135
- connId: string;
136
- }>();
137
-
138
- // Pre-load the actor to catch errors early
139
- let actor: AnyActorInstance;
140
- try {
141
- actor = await actorDriver.loadActor(actorId);
142
- } catch (error) {
143
- // Return handler that immediately closes with error
144
- return {
145
- onOpen: (_evt: any, ws: WSContext) => {
146
- const { code } = deconstructError(
147
- error,
148
- actor.rLog,
149
- {
150
- wsEvent: "open",
151
- },
152
- exposeInternalError,
153
- );
154
- ws.close(1011, code);
155
- },
156
- onMessage: (_evt: { data: any }, ws: WSContext) => {
157
- ws.close(1011, "Actor not loaded");
158
- },
159
- onClose: (_event: any, _ws: WSContext) => {},
160
- onError: (_error: unknown) => {},
161
- };
162
- }
163
-
164
- // Promise used to wait for the websocket close in `disconnect`
165
- const closePromise = promiseWithResolvers<void>();
166
-
167
- // Track connection outside of scope for cleanup
168
- let createdConn: AnyConn | undefined;
169
-
170
- return {
171
- onOpen: (_evt: any, ws: WSContext) => {
172
- actor.rLog.debug("actor websocket open");
173
-
174
- // Run async operations in background
175
- (async () => {
176
- try {
177
- let conn: AnyConn;
178
-
179
- // Create or reconnect connection
180
- actor.rLog.debug({
181
- msg: connId
182
- ? "websocket reconnection attempt"
183
- : "new websocket connection",
184
- connId,
185
- actorId,
186
- });
187
-
188
- // Check if this is a hibernatable websocket
189
- const isHibernatable =
190
- !!requestIdBuf &&
191
- actor[PERSIST_SYMBOL].hibernatableWebSocket.findIndex(
192
- (ws) =>
193
- arrayBuffersEqual(ws.requestId, requestIdBuf),
194
- ) !== -1;
195
-
196
- conn = await actor.createConn(
197
- {
198
- requestId: requestId,
199
- requestIdBuf: requestIdBuf,
200
- hibernatable: isHibernatable,
201
- driverState: {
202
- [ConnDriverKind.WEBSOCKET]: {
203
- encoding,
204
- websocket: ws,
205
- closePromise,
206
- },
207
- },
208
- },
209
- parameters,
210
- req,
211
- connId,
212
- connToken,
213
- );
214
-
215
- // Store connection so we can clean on close
216
- createdConn = conn;
217
-
218
- // Unblock other handlers
219
- handlersResolve({ conn, actor, connId: conn.id });
220
- } catch (error) {
221
- handlersReject(error);
222
-
223
- const { code } = deconstructError(
224
- error,
225
- actor.rLog,
226
- {
227
- wsEvent: "open",
228
- },
229
- exposeInternalError,
230
- );
231
- ws.close(1011, code);
232
- }
233
- })();
234
- },
235
- onMessage: (evt: { data: any }, ws: WSContext) => {
236
- // Handle message asynchronously
237
- handlersPromise
238
- .then(({ conn, actor }) => {
239
- actor.rLog.debug({ msg: "received message" });
240
-
241
- const value = evt.data.valueOf() as InputData;
242
- parseMessage(value, {
243
- encoding: encoding,
244
- maxIncomingMessageSize:
245
- runConfig.maxIncomingMessageSize,
246
- })
247
- .then((message) => {
248
- actor
249
- .processMessage(message, conn)
250
- .catch((error) => {
251
- const { code } = deconstructError(
252
- error,
253
- actor.rLog,
254
- {
255
- wsEvent: "message",
256
- },
257
- exposeInternalError,
258
- );
259
- ws.close(1011, code);
260
- });
261
- })
262
- .catch((error) => {
263
- const { code } = deconstructError(
264
- error,
265
- actor.rLog,
266
- {
267
- wsEvent: "message",
268
- },
269
- exposeInternalError,
270
- );
271
- ws.close(1011, code);
272
- });
273
- })
274
- .catch((error) => {
275
- const { code } = deconstructError(
276
- error,
277
- actor.rLog,
278
- {
279
- wsEvent: "message",
280
- },
281
- exposeInternalError,
282
- );
283
- ws.close(1011, code);
284
- });
285
- },
286
- onClose: (
287
- event: {
288
- wasClean: boolean;
289
- code: number;
290
- reason: string;
291
- },
292
- ws: WSContext,
293
- ) => {
294
- handlersReject(`WebSocket closed (${event.code}): ${event.reason}`);
295
-
296
- closePromise.resolve();
297
-
298
- if (event.wasClean) {
299
- actor.rLog.info({
300
- msg: "websocket closed",
301
- code: event.code,
302
- reason: event.reason,
303
- wasClean: event.wasClean,
304
- });
305
- } else {
306
- actor.rLog.warn({
307
- msg: "websocket closed",
308
- code: event.code,
309
- reason: event.reason,
310
- wasClean: event.wasClean,
311
- });
312
- }
313
-
314
- // HACK: Close socket in order to fix bug with Cloudflare leaving WS in closing state
315
- // https://github.com/cloudflare/workerd/issues/2569
316
- ws.close(1000, "hack_force_close");
317
-
318
- // Wait for actor.createConn to finish before removing the connection
319
- handlersPromise.finally(() => {
320
- if (createdConn) {
321
- const wasClean = event.wasClean || event.code === 1000;
322
- actor.__connDisconnected(createdConn, wasClean, requestId);
323
- }
324
- });
325
- },
326
- onError: (_error: unknown) => {
327
- try {
328
- // Actors don't need to know about this, since it's abstracted away
329
- actor.rLog.warn({ msg: "websocket error" });
330
- } catch (error) {
331
- deconstructError(
332
- error,
333
- actor.rLog,
334
- { wsEvent: "error" },
335
- exposeInternalError,
336
- );
337
- }
338
- },
339
- };
340
- }
341
-
342
- /**
343
- * Creates an SSE connection handler
344
- */
345
- export async function handleSseConnect(
346
- c: HonoContext,
347
- _runConfig: RunnerConfig,
348
- actorDriver: ActorDriver,
349
- actorId: string,
350
- ) {
351
- c.header("Content-Encoding", "Identity");
352
-
353
- const encoding = getRequestEncoding(c.req);
354
- const parameters = getRequestConnParams(c.req);
355
- const requestId = generateConnRequestId();
356
-
357
- // Check for reconnection parameters
358
- const connId = c.req.header(HEADER_CONN_ID);
359
- const connToken = c.req.header(HEADER_CONN_TOKEN);
360
-
361
- // Return the main handler with all async work inside
362
- return streamSSE(c, async (stream) => {
363
- let actor: AnyActorInstance | undefined;
364
- let conn: AnyConn | undefined;
365
-
366
- try {
367
- // Do all async work inside the handler
368
- actor = await actorDriver.loadActor(actorId);
369
-
370
- // Create or reconnect connection
371
- actor.rLog.debug({
372
- msg: connId ? "sse reconnection attempt" : "sse open",
373
- connId,
374
- });
375
-
376
- conn = await actor.createConn(
377
- {
378
- requestId: requestId,
379
- hibernatable: false,
380
- driverState: {
381
- [ConnDriverKind.SSE]: {
382
- encoding,
383
- stream: stream,
384
- },
385
- },
386
- },
387
- parameters,
388
- c.req.raw,
389
- connId,
390
- connToken,
391
- );
392
-
393
- // Wait for close
394
- const abortResolver = promiseWithResolvers();
395
-
396
- // HACK: This is required so the abort handler below works
397
- //
398
- // See https://github.com/honojs/hono/issues/1770#issuecomment-2461966225
399
- stream.onAbort(() => {});
400
-
401
- // Handle stream abort (when client closes the connection)
402
- c.req.raw.signal.addEventListener("abort", async () => {
403
- invariant(actor, "actor should exist");
404
- const rLog = actor.rLog ?? loggerWithoutContext();
405
- try {
406
- rLog.debug("sse stream aborted");
407
-
408
- // Cleanup
409
- if (conn) {
410
- actor.__connDisconnected(conn, false, requestId);
411
- }
412
-
413
- abortResolver.resolve(undefined);
414
- } catch (error) {
415
- rLog.error({ msg: "error closing sse connection", error });
416
- abortResolver.resolve(undefined);
417
- }
418
- });
419
-
420
- // // HACK: Will throw if not configured
421
- // try {
422
- // c.executionCtx.waitUntil(abortResolver.promise);
423
- // } catch {}
424
-
425
- // Send ping every second to keep the connection alive
426
- //
427
- // NOTE: This is required on Cloudflare Workers in order to detect when the connection is closed
428
- while (true) {
429
- if (stream.closed || stream.aborted) {
430
- actor?.rLog.debug({
431
- msg: "sse stream closed",
432
- closed: stream.closed,
433
- aborted: stream.aborted,
434
- });
435
- break;
436
- }
437
-
438
- await stream.writeSSE({ event: "ping", data: "" });
439
- await stream.sleep(SSE_PING_INTERVAL);
440
- }
441
- } catch (error) {
442
- loggerWithoutContext().error({
443
- msg: "error in sse connection",
444
- error,
445
- });
446
-
447
- // Cleanup on error
448
- if (conn && actor !== undefined) {
449
- actor.__connDisconnected(conn, false, requestId);
450
- }
451
-
452
- // Close the stream on error
453
- stream.close();
454
- }
455
- });
456
- }
457
-
458
63
  /**
459
64
  * Creates an action handler
460
65
  */
@@ -474,9 +79,14 @@ export async function handleAction(
474
79
  encoding,
475
80
  new Uint8Array(arrayBuffer),
476
81
  HTTP_ACTION_REQUEST_VERSIONED,
82
+ HttpActionRequestSchema,
83
+ // JSON: args is already the decoded value (raw object/array)
84
+ (json: HttpActionRequestJson) => json.args,
85
+ // BARE/CBOR: args is ArrayBuffer that needs CBOR-decoding
86
+ (bare: protocol.HttpActionRequest) =>
87
+ cbor.decode(new Uint8Array(bare.args)),
477
88
  );
478
- const actionArgs = cbor.decode(new Uint8Array(request.args));
479
- const requestId = generateConnRequestId();
89
+ const actionArgs = request;
480
90
 
481
91
  // Invoke the action
482
92
  let actor: AnyActorInstance | undefined;
@@ -488,198 +98,82 @@ export async function handleAction(
488
98
  actor.rLog.debug({ msg: "handling action", actionName, encoding });
489
99
 
490
100
  // Create conn
491
- conn = await actor.createConn(
492
- {
493
- requestId: requestId,
494
- hibernatable: false,
495
- driverState: { [ConnDriverKind.HTTP]: {} },
496
- },
101
+ conn = await actor.connectionManager.prepareAndConnectConn(
102
+ createHttpDriver(),
497
103
  parameters,
498
104
  c.req.raw,
105
+ c.req.path,
106
+ c.req.header(),
499
107
  );
500
108
 
501
109
  // Call action
502
- const ctx = new ActionContext(actor.actorContext!, conn!);
110
+ const ctx = new ActionContext(actor, conn!);
503
111
  output = await actor.executeAction(ctx, actionName, actionArgs);
504
112
  } finally {
505
113
  if (conn) {
506
- // HTTP connections don't have persistent sockets, so no socket ID needed
507
- actor?.__connDisconnected(conn, true, requestId);
114
+ conn.disconnect();
508
115
  }
509
116
  }
510
117
 
511
118
  // Send response
512
- const responseData: protocol.HttpActionResponse = {
513
- output: bufferToArrayBuffer(cbor.encode(output)),
514
- };
515
119
  const serialized = serializeWithEncoding(
516
120
  encoding,
517
- responseData,
121
+ output,
518
122
  HTTP_ACTION_RESPONSE_VERSIONED,
123
+ HttpActionResponseSchema,
124
+ // JSON: output is the raw value (will be serialized by jsonStringifyCompat)
125
+ (value): HttpActionResponseJson => ({ output: value }),
126
+ // BARE/CBOR: output needs to be CBOR-encoded to ArrayBuffer
127
+ (value): protocol.HttpActionResponse => ({
128
+ output: bufferToArrayBuffer(cbor.encode(value)),
129
+ }),
519
130
  );
520
131
 
521
- // TODO: Remvoe any, Hono is being a dumbass
132
+ // TODO: Remove any, Hono is being a dumbass
522
133
  return c.body(serialized as Uint8Array as any, 200, {
523
134
  "Content-Type": contentTypeForEncoding(encoding),
524
135
  });
525
136
  }
526
137
 
527
- /**
528
- * Create a connection message handler
529
- */
530
- export async function handleConnectionMessage(
138
+ export async function handleRawRequest(
531
139
  c: HonoContext,
532
- _runConfig: RunnerConfig,
140
+ req: Request,
533
141
  actorDriver: ActorDriver,
534
- connId: string,
535
- connToken: string,
536
142
  actorId: string,
537
- ) {
538
- const encoding = getRequestEncoding(c.req);
539
-
540
- // Validate incoming request
541
- const arrayBuffer = await c.req.arrayBuffer();
542
- const message = deserializeWithEncoding(
543
- encoding,
544
- new Uint8Array(arrayBuffer),
545
- TO_SERVER_VERSIONED,
546
- );
547
-
143
+ ): Promise<Response> {
548
144
  const actor = await actorDriver.loadActor(actorId);
145
+ const parameters = getRequestConnParams(c.req);
549
146
 
550
- // Find connection
551
- const conn = actor.conns.get(connId);
552
- if (!conn) {
553
- throw new errors.ConnNotFound(connId);
554
- }
555
-
556
- // Authenticate connection
557
- if (conn._token !== connToken) {
558
- throw new errors.IncorrectConnToken();
559
- }
560
-
561
- // Process message
562
- await actor.processMessage(message, conn);
563
-
564
- return c.json({});
565
- }
566
-
567
- export async function handleConnectionClose(
568
- c: HonoContext,
569
- _runConfig: RunnerConfig,
570
- actorDriver: ActorDriver,
571
- connId: string,
572
- connToken: string,
573
- actorId: string,
574
- ) {
575
- const actor = await actorDriver.loadActor(actorId);
576
-
577
- // Find connection
578
- const conn = actor.conns.get(connId);
579
- if (!conn) {
580
- throw new errors.ConnNotFound(connId);
581
- }
582
-
583
- // Authenticate connection
584
- if (conn._token !== connToken) {
585
- throw new errors.IncorrectConnToken();
586
- }
147
+ // Track connection outside of scope for cleanup
148
+ let createdConn: AnyConn | undefined;
587
149
 
588
- // Check if this is an SSE connection
589
- if (
590
- !conn.__socket?.driverState ||
591
- !(ConnDriverKind.SSE in conn.__socket.driverState)
592
- ) {
593
- throw new errors.UserError(
594
- "Connection close is only supported for SSE connections",
150
+ try {
151
+ const conn = await actor.connectionManager.prepareAndConnectConn(
152
+ createRawRequestDriver(),
153
+ parameters,
154
+ req,
155
+ c.req.path,
156
+ c.req.header(),
595
157
  );
596
- }
597
-
598
- // Close the SSE connection
599
- await conn.disconnect("Connection closed by client request");
600
158
 
601
- return c.json({});
602
- }
159
+ createdConn = conn;
603
160
 
604
- export async function handleRawWebSocketHandler(
605
- req: Request | undefined,
606
- path: string,
607
- actorDriver: ActorDriver,
608
- actorId: string,
609
- requestIdBuf: ArrayBuffer | undefined,
610
- ): Promise<UpgradeWebSocketArgs> {
611
- const actor = await actorDriver.loadActor(actorId);
612
-
613
- // Return WebSocket event handlers
614
- return {
615
- onOpen: (evt: any, ws: any) => {
616
- // Extract rivetRequestId provided by engine runner
617
- const rivetRequestId = evt?.rivetRequestId;
618
- const isHibernatable =
619
- actor[PERSIST_SYMBOL].hibernatableWebSocket.findIndex((ws) =>
620
- arrayBuffersEqual(ws.requestId, rivetRequestId),
621
- ) !== -1;
622
-
623
- // Wrap the Hono WebSocket in our adapter
624
- const adapter = new HonoWebSocketAdapter(
625
- ws,
626
- rivetRequestId,
627
- isHibernatable,
628
- );
629
-
630
- // Store adapter reference on the WebSocket for event handlers
631
- (ws as any).__adapter = adapter;
632
-
633
- const newPath = truncateRawWebSocketPathPrefix(path);
634
- let newRequest: Request;
635
- if (req) {
636
- newRequest = new Request(`http://actor${newPath}`, req);
637
- } else {
638
- newRequest = new Request(`http://actor${newPath}`, {
639
- method: "GET",
640
- });
641
- }
642
-
643
- actor.rLog.debug({
644
- msg: "rewriting websocket url",
645
- fromPath: path,
646
- toUrl: newRequest.url,
647
- });
648
-
649
- // Call the actor's onWebSocket handler with the adapted WebSocket
650
- actor.handleWebSocket(adapter, {
651
- request: newRequest,
652
- });
653
- },
654
- onMessage: (event: any, ws: any) => {
655
- // Find the adapter for this WebSocket
656
- const adapter = (ws as any).__adapter;
657
- if (adapter) {
658
- adapter._handleMessage(event);
659
- }
660
- },
661
- onClose: (evt: any, ws: any) => {
662
- // Find the adapter for this WebSocket
663
- const adapter = (ws as any).__adapter;
664
- if (adapter) {
665
- adapter._handleClose(evt?.code || 1006, evt?.reason || "");
666
- }
667
- },
668
- onError: (error: any, ws: any) => {
669
- // Find the adapter for this WebSocket
670
- const adapter = (ws as any).__adapter;
671
- if (adapter) {
672
- adapter._handleError(error);
673
- }
674
- },
675
- };
161
+ return await actor.handleRawRequest(conn, req);
162
+ } finally {
163
+ // Clean up the connection after the request completes
164
+ if (createdConn) {
165
+ createdConn.disconnect();
166
+ }
167
+ }
676
168
  }
677
169
 
678
170
  // Helper to get the connection encoding from a request
171
+ //
172
+ // Defaults to JSON if not provided so we can support vanilla curl requests easily.
679
173
  export function getRequestEncoding(req: HonoRequest): Encoding {
680
174
  const encodingParam = req.header(HEADER_ENCODING);
681
175
  if (!encodingParam) {
682
- throw new errors.InvalidEncoding("undefined");
176
+ return "json";
683
177
  }
684
178
 
685
179
  const result = EncodingSchema.safeParse(encodingParam);
@@ -728,22 +222,3 @@ export function getRequestConnParams(req: HonoRequest): unknown {
728
222
  );
729
223
  }
730
224
  }
731
-
732
- /**
733
- * Truncase the PATH_RAW_WEBSOCKET_PREFIX path prefix in order to pass a clean
734
- * path to the onWebSocket handler.
735
- *
736
- * Example:
737
- * - `/raw/websocket/foo` -> `/foo`
738
- * - `/raw/websocket` -> `/`
739
- */
740
- export function truncateRawWebSocketPathPrefix(path: string): string {
741
- // Extract the path after prefix and preserve query parameters
742
- // Use URL API for cleaner parsing
743
- const url = new URL(path, "http://actor");
744
- const pathname = url.pathname.replace(/^\/raw\/websocket\/?/, "") || "/";
745
- const normalizedPath =
746
- (pathname.startsWith("/") ? pathname : "/" + pathname) + url.search;
747
-
748
- return normalizedPath;
749
- }