rivetkit 2.0.2 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/README.md +3 -5
  2. package/dist/schemas/actor-persist/v1.ts +225 -0
  3. package/dist/schemas/client-protocol/v1.ts +435 -0
  4. package/dist/schemas/file-system-driver/v1.ts +102 -0
  5. package/dist/tsup/actor/errors.cjs +77 -0
  6. package/dist/tsup/actor/errors.cjs.map +1 -0
  7. package/dist/tsup/actor/errors.d.cts +156 -0
  8. package/dist/tsup/actor/errors.d.ts +156 -0
  9. package/dist/tsup/actor/errors.js +77 -0
  10. package/dist/tsup/actor/errors.js.map +1 -0
  11. package/dist/tsup/chunk-3F2YSRJL.js +117 -0
  12. package/dist/tsup/chunk-3F2YSRJL.js.map +1 -0
  13. package/dist/tsup/chunk-4CXBCT26.cjs +250 -0
  14. package/dist/tsup/chunk-4CXBCT26.cjs.map +1 -0
  15. package/dist/tsup/chunk-4R73YDN3.cjs +20 -0
  16. package/dist/tsup/chunk-4R73YDN3.cjs.map +1 -0
  17. package/dist/tsup/chunk-6LJT3QRL.cjs +539 -0
  18. package/dist/tsup/chunk-6LJT3QRL.cjs.map +1 -0
  19. package/dist/tsup/chunk-GICQ3YCU.cjs +1792 -0
  20. package/dist/tsup/chunk-GICQ3YCU.cjs.map +1 -0
  21. package/dist/tsup/chunk-H26RP6GD.js +251 -0
  22. package/dist/tsup/chunk-H26RP6GD.js.map +1 -0
  23. package/dist/tsup/chunk-HI3HWJRC.js +20 -0
  24. package/dist/tsup/chunk-HI3HWJRC.js.map +1 -0
  25. package/dist/tsup/chunk-HLLF4B4Q.js +1792 -0
  26. package/dist/tsup/chunk-HLLF4B4Q.js.map +1 -0
  27. package/dist/tsup/chunk-IH6CKNDW.cjs +117 -0
  28. package/dist/tsup/chunk-IH6CKNDW.cjs.map +1 -0
  29. package/dist/tsup/chunk-LV2S3OU3.js +250 -0
  30. package/dist/tsup/chunk-LV2S3OU3.js.map +1 -0
  31. package/dist/tsup/chunk-LWNKVZG5.cjs +251 -0
  32. package/dist/tsup/chunk-LWNKVZG5.cjs.map +1 -0
  33. package/dist/tsup/chunk-NFU2BBT5.js +374 -0
  34. package/dist/tsup/chunk-NFU2BBT5.js.map +1 -0
  35. package/dist/tsup/chunk-PQY7KKTL.js +539 -0
  36. package/dist/tsup/chunk-PQY7KKTL.js.map +1 -0
  37. package/dist/tsup/chunk-QK72M5JB.js +45 -0
  38. package/dist/tsup/chunk-QK72M5JB.js.map +1 -0
  39. package/dist/tsup/chunk-QNNXFOQV.cjs +45 -0
  40. package/dist/tsup/chunk-QNNXFOQV.cjs.map +1 -0
  41. package/dist/tsup/chunk-SBHHJ6QS.cjs +374 -0
  42. package/dist/tsup/chunk-SBHHJ6QS.cjs.map +1 -0
  43. package/dist/tsup/chunk-TQ62L3X7.js +325 -0
  44. package/dist/tsup/chunk-TQ62L3X7.js.map +1 -0
  45. package/dist/tsup/chunk-VO7ZRVVD.cjs +6293 -0
  46. package/dist/tsup/chunk-VO7ZRVVD.cjs.map +1 -0
  47. package/dist/tsup/chunk-WHBPJNGW.cjs +325 -0
  48. package/dist/tsup/chunk-WHBPJNGW.cjs.map +1 -0
  49. package/dist/tsup/chunk-XJQHKJ4P.js +6293 -0
  50. package/dist/tsup/chunk-XJQHKJ4P.js.map +1 -0
  51. package/dist/tsup/client/mod.cjs +32 -0
  52. package/dist/tsup/client/mod.cjs.map +1 -0
  53. package/dist/tsup/client/mod.d.cts +20 -0
  54. package/dist/tsup/client/mod.d.ts +20 -0
  55. package/dist/tsup/client/mod.js +32 -0
  56. package/dist/tsup/client/mod.js.map +1 -0
  57. package/dist/tsup/common/log.cjs +21 -0
  58. package/dist/tsup/common/log.cjs.map +1 -0
  59. package/dist/tsup/common/log.d.cts +26 -0
  60. package/dist/tsup/common/log.d.ts +26 -0
  61. package/dist/tsup/common/log.js +21 -0
  62. package/dist/tsup/common/log.js.map +1 -0
  63. package/dist/tsup/common/websocket.cjs +10 -0
  64. package/dist/tsup/common/websocket.cjs.map +1 -0
  65. package/dist/tsup/common/websocket.d.cts +3 -0
  66. package/dist/tsup/common/websocket.d.ts +3 -0
  67. package/dist/tsup/common/websocket.js +10 -0
  68. package/dist/tsup/common/websocket.js.map +1 -0
  69. package/dist/tsup/common-CXCe7s6i.d.cts +218 -0
  70. package/dist/tsup/common-CXCe7s6i.d.ts +218 -0
  71. package/dist/tsup/connection-BI-6UIBJ.d.ts +2087 -0
  72. package/dist/tsup/connection-Dyd4NLGW.d.cts +2087 -0
  73. package/dist/tsup/driver-helpers/mod.cjs +30 -0
  74. package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
  75. package/dist/tsup/driver-helpers/mod.d.cts +17 -0
  76. package/dist/tsup/driver-helpers/mod.d.ts +17 -0
  77. package/dist/tsup/driver-helpers/mod.js +30 -0
  78. package/dist/tsup/driver-helpers/mod.js.map +1 -0
  79. package/dist/tsup/driver-test-suite/mod.cjs +3411 -0
  80. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
  81. package/dist/tsup/driver-test-suite/mod.d.cts +63 -0
  82. package/dist/tsup/driver-test-suite/mod.d.ts +63 -0
  83. package/dist/tsup/driver-test-suite/mod.js +3411 -0
  84. package/dist/tsup/driver-test-suite/mod.js.map +1 -0
  85. package/dist/tsup/inspector/mod.cjs +51 -0
  86. package/dist/tsup/inspector/mod.cjs.map +1 -0
  87. package/dist/tsup/inspector/mod.d.cts +408 -0
  88. package/dist/tsup/inspector/mod.d.ts +408 -0
  89. package/dist/tsup/inspector/mod.js +51 -0
  90. package/dist/tsup/inspector/mod.js.map +1 -0
  91. package/dist/tsup/mod.cjs +67 -0
  92. package/dist/tsup/mod.cjs.map +1 -0
  93. package/dist/tsup/mod.d.cts +105 -0
  94. package/dist/tsup/mod.d.ts +105 -0
  95. package/dist/tsup/mod.js +67 -0
  96. package/dist/tsup/mod.js.map +1 -0
  97. package/dist/tsup/router-endpoints-BTe_Rsdn.d.cts +65 -0
  98. package/dist/tsup/router-endpoints-CBSrKHmo.d.ts +65 -0
  99. package/dist/tsup/test/mod.cjs +17 -0
  100. package/dist/tsup/test/mod.cjs.map +1 -0
  101. package/dist/tsup/test/mod.d.cts +26 -0
  102. package/dist/tsup/test/mod.d.ts +26 -0
  103. package/dist/tsup/test/mod.js +17 -0
  104. package/dist/tsup/test/mod.js.map +1 -0
  105. package/dist/tsup/utils-fwx3o3K9.d.cts +18 -0
  106. package/dist/tsup/utils-fwx3o3K9.d.ts +18 -0
  107. package/dist/tsup/utils.cjs +26 -0
  108. package/dist/tsup/utils.cjs.map +1 -0
  109. package/dist/tsup/utils.d.cts +36 -0
  110. package/dist/tsup/utils.d.ts +36 -0
  111. package/dist/tsup/utils.js +26 -0
  112. package/dist/tsup/utils.js.map +1 -0
  113. package/package.json +208 -5
  114. package/src/actor/action.ts +178 -0
  115. package/src/actor/config.ts +497 -0
  116. package/src/actor/connection.ts +257 -0
  117. package/src/actor/context.ts +168 -0
  118. package/src/actor/database.ts +23 -0
  119. package/src/actor/definition.ts +82 -0
  120. package/src/actor/driver.ts +84 -0
  121. package/src/actor/errors.ts +422 -0
  122. package/src/actor/generic-conn-driver.ts +246 -0
  123. package/src/actor/instance.ts +1844 -0
  124. package/src/actor/keys.test.ts +266 -0
  125. package/src/actor/keys.ts +89 -0
  126. package/src/actor/log.ts +6 -0
  127. package/src/actor/mod.ts +108 -0
  128. package/src/actor/persisted.ts +42 -0
  129. package/src/actor/protocol/old.ts +297 -0
  130. package/src/actor/protocol/serde.ts +131 -0
  131. package/src/actor/router-endpoints.ts +688 -0
  132. package/src/actor/router.ts +265 -0
  133. package/src/actor/schedule.ts +17 -0
  134. package/src/actor/unstable-react.ts +110 -0
  135. package/src/actor/utils.ts +102 -0
  136. package/src/client/actor-common.ts +30 -0
  137. package/src/client/actor-conn.ts +865 -0
  138. package/src/client/actor-handle.ts +268 -0
  139. package/src/client/actor-query.ts +65 -0
  140. package/src/client/client.ts +554 -0
  141. package/src/client/config.ts +44 -0
  142. package/src/client/errors.ts +42 -0
  143. package/src/client/log.ts +5 -0
  144. package/src/client/mod.ts +60 -0
  145. package/src/client/raw-utils.ts +149 -0
  146. package/src/client/test.ts +44 -0
  147. package/src/client/utils.ts +152 -0
  148. package/src/common/eventsource-interface.ts +47 -0
  149. package/src/common/eventsource.ts +80 -0
  150. package/src/common/fake-event-source.ts +267 -0
  151. package/src/common/inline-websocket-adapter2.ts +454 -0
  152. package/src/common/log-levels.ts +27 -0
  153. package/src/common/log.ts +214 -0
  154. package/src/common/logfmt.ts +219 -0
  155. package/src/common/network.ts +2 -0
  156. package/src/common/router.ts +80 -0
  157. package/src/common/utils.ts +336 -0
  158. package/src/common/versioned-data.ts +95 -0
  159. package/src/common/websocket-interface.ts +49 -0
  160. package/src/common/websocket.ts +42 -0
  161. package/src/driver-helpers/mod.ts +22 -0
  162. package/src/driver-helpers/utils.ts +17 -0
  163. package/src/driver-test-suite/log.ts +5 -0
  164. package/src/driver-test-suite/mod.ts +239 -0
  165. package/src/driver-test-suite/tests/action-features.ts +136 -0
  166. package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
  167. package/src/driver-test-suite/tests/actor-conn.ts +349 -0
  168. package/src/driver-test-suite/tests/actor-driver.ts +25 -0
  169. package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
  170. package/src/driver-test-suite/tests/actor-handle.ts +292 -0
  171. package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
  172. package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
  173. package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
  174. package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
  175. package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
  176. package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
  177. package/src/driver-test-suite/tests/actor-state.ts +54 -0
  178. package/src/driver-test-suite/tests/actor-vars.ts +93 -0
  179. package/src/driver-test-suite/tests/manager-driver.ts +367 -0
  180. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +227 -0
  181. package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
  182. package/src/driver-test-suite/tests/raw-http.ts +347 -0
  183. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +393 -0
  184. package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
  185. package/src/driver-test-suite/tests/request-access.ts +230 -0
  186. package/src/driver-test-suite/utils.ts +71 -0
  187. package/src/drivers/default.ts +34 -0
  188. package/src/drivers/engine/actor-driver.ts +369 -0
  189. package/src/drivers/engine/config.ts +31 -0
  190. package/src/drivers/engine/kv.ts +3 -0
  191. package/src/drivers/engine/log.ts +5 -0
  192. package/src/drivers/engine/mod.ts +35 -0
  193. package/src/drivers/file-system/actor.ts +91 -0
  194. package/src/drivers/file-system/global-state.ts +686 -0
  195. package/src/drivers/file-system/log.ts +5 -0
  196. package/src/drivers/file-system/manager.ts +329 -0
  197. package/src/drivers/file-system/mod.ts +48 -0
  198. package/src/drivers/file-system/utils.ts +109 -0
  199. package/src/globals.d.ts +6 -0
  200. package/src/inspector/actor.ts +298 -0
  201. package/src/inspector/config.ts +88 -0
  202. package/src/inspector/log.ts +5 -0
  203. package/src/inspector/manager.ts +86 -0
  204. package/src/inspector/mod.ts +2 -0
  205. package/src/inspector/protocol/actor.ts +10 -0
  206. package/src/inspector/protocol/common.ts +196 -0
  207. package/src/inspector/protocol/manager.ts +10 -0
  208. package/src/inspector/protocol/mod.ts +2 -0
  209. package/src/inspector/utils.ts +76 -0
  210. package/src/manager/driver.ts +88 -0
  211. package/src/manager/hono-websocket-adapter.ts +342 -0
  212. package/src/manager/log.ts +5 -0
  213. package/src/manager/mod.ts +2 -0
  214. package/src/manager/protocol/mod.ts +24 -0
  215. package/src/manager/protocol/query.ts +89 -0
  216. package/src/manager/router.ts +412 -0
  217. package/src/manager-api/routes/actors-create.ts +16 -0
  218. package/src/manager-api/routes/actors-delete.ts +4 -0
  219. package/src/manager-api/routes/actors-get-by-id.ts +7 -0
  220. package/src/manager-api/routes/actors-get-or-create-by-id.ts +29 -0
  221. package/src/manager-api/routes/actors-get.ts +7 -0
  222. package/src/manager-api/routes/common.ts +18 -0
  223. package/src/mod.ts +18 -0
  224. package/src/registry/config.ts +32 -0
  225. package/src/registry/log.ts +5 -0
  226. package/src/registry/mod.ts +157 -0
  227. package/src/registry/run-config.ts +52 -0
  228. package/src/registry/serve.ts +52 -0
  229. package/src/remote-manager-driver/actor-http-client.ts +72 -0
  230. package/src/remote-manager-driver/actor-websocket-client.ts +63 -0
  231. package/src/remote-manager-driver/api-endpoints.ts +79 -0
  232. package/src/remote-manager-driver/api-utils.ts +43 -0
  233. package/src/remote-manager-driver/log.ts +5 -0
  234. package/src/remote-manager-driver/mod.ts +274 -0
  235. package/src/remote-manager-driver/ws-proxy.ts +180 -0
  236. package/src/schemas/actor-persist/mod.ts +1 -0
  237. package/src/schemas/actor-persist/versioned.ts +25 -0
  238. package/src/schemas/client-protocol/mod.ts +1 -0
  239. package/src/schemas/client-protocol/versioned.ts +63 -0
  240. package/src/schemas/file-system-driver/mod.ts +1 -0
  241. package/src/schemas/file-system-driver/versioned.ts +28 -0
  242. package/src/serde.ts +90 -0
  243. package/src/test/config.ts +16 -0
  244. package/src/test/log.ts +5 -0
  245. package/src/test/mod.ts +154 -0
  246. package/src/utils.ts +172 -0
@@ -0,0 +1,688 @@
1
+ import * as cbor from "cbor-x";
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 { ActionContext } from "@/actor/action";
6
+ import type { AnyConn } from "@/actor/connection";
7
+ import {
8
+ CONNECTION_DRIVER_HTTP,
9
+ CONNECTION_DRIVER_SSE,
10
+ CONNECTION_DRIVER_WEBSOCKET,
11
+ generateConnId,
12
+ generateConnToken,
13
+ } from "@/actor/connection";
14
+ import * as errors from "@/actor/errors";
15
+ import type { AnyActorInstance } from "@/actor/instance";
16
+ import type { InputData } from "@/actor/protocol/serde";
17
+ import { type Encoding, EncodingSchema } from "@/actor/protocol/serde";
18
+ import type { UpgradeWebSocketArgs } from "@/common/inline-websocket-adapter2";
19
+ import { deconstructError, stringifyError } from "@/common/utils";
20
+ import type { UniversalWebSocket } from "@/common/websocket-interface";
21
+ import { HonoWebSocketAdapter } from "@/manager/hono-websocket-adapter";
22
+ import type { RunConfig } from "@/registry/run-config";
23
+ import type * as protocol from "@/schemas/client-protocol/mod";
24
+ import {
25
+ HTTP_ACTION_REQUEST_VERSIONED,
26
+ HTTP_ACTION_RESPONSE_VERSIONED,
27
+ TO_SERVER_VERSIONED,
28
+ } from "@/schemas/client-protocol/versioned";
29
+ import {
30
+ contentTypeForEncoding,
31
+ deserializeWithEncoding,
32
+ serializeWithEncoding,
33
+ } from "@/serde";
34
+ import { bufferToArrayBuffer } from "@/utils";
35
+ import type { ActorDriver } from "./driver";
36
+ import type {
37
+ GenericHttpDriverState,
38
+ GenericSseDriverState,
39
+ GenericWebSocketDriverState,
40
+ } from "./generic-conn-driver";
41
+ import { loggerWithoutContext } from "./log";
42
+ import { parseMessage } from "./protocol/old";
43
+
44
+ export interface ConnectWebSocketOpts {
45
+ req?: HonoRequest;
46
+ encoding: Encoding;
47
+ actorId: string;
48
+ params: unknown;
49
+ authData: unknown;
50
+ }
51
+
52
+ export interface ConnectWebSocketOutput {
53
+ onOpen: (ws: WSContext) => void;
54
+ onMessage: (message: protocol.ToServer) => void;
55
+ onClose: () => void;
56
+ }
57
+
58
+ export interface ConnectSseOpts {
59
+ req?: HonoRequest;
60
+ encoding: Encoding;
61
+ params: unknown;
62
+ actorId: string;
63
+ authData: unknown;
64
+ }
65
+
66
+ export interface ConnectSseOutput {
67
+ onOpen: (stream: SSEStreamingApi) => void;
68
+ onClose: () => Promise<void>;
69
+ }
70
+
71
+ export interface ActionOpts {
72
+ req?: HonoRequest;
73
+ params: unknown;
74
+ actionName: string;
75
+ actionArgs: unknown[];
76
+ actorId: string;
77
+ authData: unknown;
78
+ }
79
+
80
+ export interface ActionOutput {
81
+ output: unknown;
82
+ }
83
+
84
+ export interface ConnsMessageOpts {
85
+ req?: HonoRequest;
86
+ connId: string;
87
+ connToken: string;
88
+ message: protocol.ToServer;
89
+ actorId: string;
90
+ }
91
+
92
+ export interface FetchOpts {
93
+ request: Request;
94
+ actorId: string;
95
+ authData: unknown;
96
+ }
97
+
98
+ export interface WebSocketOpts {
99
+ request: Request;
100
+ websocket: UniversalWebSocket;
101
+ actorId: string;
102
+ authData: unknown;
103
+ }
104
+
105
+ /**
106
+ * Creates a WebSocket connection handler
107
+ */
108
+ export async function handleWebSocketConnect(
109
+ req: Request | undefined,
110
+ runConfig: RunConfig,
111
+ actorDriver: ActorDriver,
112
+ actorId: string,
113
+ encoding: Encoding,
114
+ parameters: unknown,
115
+ authData: unknown,
116
+ ): Promise<UpgradeWebSocketArgs> {
117
+ const exposeInternalError = req ? getRequestExposeInternalError(req) : false;
118
+
119
+ // Setup promise for the init handlers since all other behavior depends on this
120
+ const {
121
+ promise: handlersPromise,
122
+ resolve: handlersResolve,
123
+ reject: handlersReject,
124
+ } = Promise.withResolvers<{
125
+ conn: AnyConn;
126
+ actor: AnyActorInstance;
127
+ connId: string;
128
+ }>();
129
+
130
+ // Pre-load the actor to catch errors early
131
+ let actor: AnyActorInstance;
132
+ try {
133
+ actor = await actorDriver.loadActor(actorId);
134
+ } catch (error) {
135
+ // Return handler that immediately closes with error
136
+ return {
137
+ onOpen: (_evt: any, ws: WSContext) => {
138
+ const { code } = deconstructError(
139
+ error,
140
+ actor.rLog,
141
+ {
142
+ wsEvent: "open",
143
+ },
144
+ exposeInternalError,
145
+ );
146
+ ws.close(1011, code);
147
+ },
148
+ onMessage: (_evt: { data: any }, ws: WSContext) => {
149
+ ws.close(1011, "Actor not loaded");
150
+ },
151
+ onClose: (_event: any, _ws: WSContext) => {},
152
+ onError: (_error: unknown) => {},
153
+ };
154
+ }
155
+
156
+ return {
157
+ onOpen: (_evt: any, ws: WSContext) => {
158
+ actor.rLog.debug("websocket open");
159
+
160
+ // Run async operations in background
161
+ (async () => {
162
+ 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);
171
+ actor.rLog.debug({
172
+ msg: "registered websocket for conn",
173
+ actorId,
174
+ totalCount: connGlobalState.websockets.size,
175
+ });
176
+
177
+ // Create connection
178
+ const conn = await actor.createConn(
179
+ connId,
180
+ connToken,
181
+ parameters,
182
+ connState,
183
+ CONNECTION_DRIVER_WEBSOCKET,
184
+ { encoding } satisfies GenericWebSocketDriverState,
185
+ authData,
186
+ );
187
+
188
+ // Unblock other handlers
189
+ handlersResolve({ conn, actor, connId });
190
+ } catch (error) {
191
+ handlersReject(error);
192
+
193
+ const { code } = deconstructError(
194
+ error,
195
+ actor.rLog,
196
+ {
197
+ wsEvent: "open",
198
+ },
199
+ exposeInternalError,
200
+ );
201
+ ws.close(1011, code);
202
+ }
203
+ })();
204
+ },
205
+ onMessage: (evt: { data: any }, ws: WSContext) => {
206
+ // Handle message asynchronously
207
+ handlersPromise
208
+ .then(({ conn, actor }) => {
209
+ actor.rLog.debug({ msg: "received message" });
210
+
211
+ const value = evt.data.valueOf() as InputData;
212
+ parseMessage(value, {
213
+ encoding: encoding,
214
+ maxIncomingMessageSize: runConfig.maxIncomingMessageSize,
215
+ })
216
+ .then((message) => {
217
+ actor.processMessage(message, conn).catch((error) => {
218
+ const { code } = deconstructError(
219
+ error,
220
+ actor.rLog,
221
+ {
222
+ wsEvent: "message",
223
+ },
224
+ exposeInternalError,
225
+ );
226
+ ws.close(1011, code);
227
+ });
228
+ })
229
+ .catch((error) => {
230
+ const { code } = deconstructError(
231
+ error,
232
+ actor.rLog,
233
+ {
234
+ wsEvent: "message",
235
+ },
236
+ exposeInternalError,
237
+ );
238
+ ws.close(1011, code);
239
+ });
240
+ })
241
+ .catch((error) => {
242
+ const { code } = deconstructError(
243
+ error,
244
+ actor.rLog,
245
+ {
246
+ wsEvent: "message",
247
+ },
248
+ exposeInternalError,
249
+ );
250
+ ws.close(1011, code);
251
+ });
252
+ },
253
+ onClose: (
254
+ event: {
255
+ wasClean: boolean;
256
+ code: number;
257
+ reason: string;
258
+ },
259
+ ws: WSContext,
260
+ ) => {
261
+ if (event.wasClean) {
262
+ actor.rLog.info({
263
+ msg: "websocket closed",
264
+ code: event.code,
265
+ reason: event.reason,
266
+ wasClean: event.wasClean,
267
+ });
268
+ } else {
269
+ actor.rLog.warn({
270
+ msg: "websocket closed",
271
+ code: event.code,
272
+ reason: event.reason,
273
+ wasClean: event.wasClean,
274
+ });
275
+ }
276
+
277
+ // HACK: Close socket in order to fix bug with Cloudflare leaving WS in closing state
278
+ // https://github.com/cloudflare/workerd/issues/2569
279
+ ws.close(1000, "hack_force_close");
280
+
281
+ // Handle cleanup asynchronously
282
+ 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);
301
+ })
302
+ .catch((error) => {
303
+ deconstructError(
304
+ error,
305
+ actor.rLog,
306
+ { wsEvent: "close" },
307
+ exposeInternalError,
308
+ );
309
+ });
310
+ },
311
+ onError: (_error: unknown) => {
312
+ try {
313
+ // Actors don't need to know about this, since it's abstracted away
314
+ actor.rLog.warn({ msg: "websocket error" });
315
+ } catch (error) {
316
+ deconstructError(
317
+ error,
318
+ actor.rLog,
319
+ { wsEvent: "error" },
320
+ exposeInternalError,
321
+ );
322
+ }
323
+ },
324
+ };
325
+ }
326
+
327
+ /**
328
+ * Creates an SSE connection handler
329
+ */
330
+ export async function handleSseConnect(
331
+ c: HonoContext,
332
+ _runConfig: RunConfig,
333
+ actorDriver: ActorDriver,
334
+ actorId: string,
335
+ authData: unknown,
336
+ ) {
337
+ const encoding = getRequestEncoding(c.req);
338
+ const parameters = getRequestConnParams(c.req);
339
+
340
+ // Return the main handler with all async work inside
341
+ return streamSSE(c, async (stream) => {
342
+ let actor: AnyActorInstance | undefined;
343
+ let connId: string | undefined;
344
+ let connToken: string | undefined;
345
+ let connState: unknown;
346
+ let conn: AnyConn | undefined;
347
+
348
+ try {
349
+ // Do all async work inside the handler
350
+ actor = await actorDriver.loadActor(actorId);
351
+ connId = generateConnId();
352
+ connToken = generateConnToken();
353
+ connState = await actor.prepareConn(parameters, c.req.raw);
354
+
355
+ actor.rLog.debug("sse open");
356
+
357
+ // Save stream
358
+ actorDriver
359
+ .getGenericConnGlobalState(actorId)
360
+ .sseStreams.set(connId, stream);
361
+
362
+ // Create connection
363
+ conn = await actor.createConn(
364
+ connId,
365
+ connToken,
366
+ parameters,
367
+ connState,
368
+ CONNECTION_DRIVER_SSE,
369
+ { encoding } satisfies GenericSseDriverState,
370
+ authData,
371
+ );
372
+
373
+ // Wait for close
374
+ const abortResolver = Promise.withResolvers();
375
+
376
+ // Handle stream abort (when client closes the connection)
377
+ stream.onAbort(async () => {
378
+ const rLog = actor?.rLog ?? loggerWithoutContext();
379
+ try {
380
+ rLog.debug("sse stream aborted");
381
+
382
+ // Cleanup
383
+ if (connId) {
384
+ actorDriver
385
+ .getGenericConnGlobalState(actorId)
386
+ .sseStreams.delete(connId);
387
+ }
388
+ if (conn && actor) {
389
+ actor.__removeConn(conn);
390
+ }
391
+
392
+ abortResolver.resolve(undefined);
393
+ } catch (error) {
394
+ rLog.error({ msg: "error closing sse connection", error });
395
+ abortResolver.resolve(undefined);
396
+ }
397
+ });
398
+
399
+ // HACK: Will throw if not configured
400
+ try {
401
+ c.executionCtx.waitUntil(abortResolver.promise);
402
+ } catch {}
403
+
404
+ // Wait until connection aborted
405
+ await abortResolver.promise;
406
+ } catch (error) {
407
+ loggerWithoutContext().error({ msg: "error in sse connection", error });
408
+
409
+ // Cleanup on error
410
+ if (connId !== undefined) {
411
+ actorDriver
412
+ .getGenericConnGlobalState(actorId)
413
+ .sseStreams.delete(connId);
414
+ }
415
+ if (conn && actor !== undefined) {
416
+ actor.__removeConn(conn);
417
+ }
418
+
419
+ // Close the stream on error
420
+ stream.close();
421
+ }
422
+ });
423
+ }
424
+
425
+ /**
426
+ * Creates an action handler
427
+ */
428
+ export async function handleAction(
429
+ c: HonoContext,
430
+ _runConfig: RunConfig,
431
+ actorDriver: ActorDriver,
432
+ actionName: string,
433
+ actorId: string,
434
+ authData: unknown,
435
+ ) {
436
+ const encoding = getRequestEncoding(c.req);
437
+ const parameters = getRequestConnParams(c.req);
438
+
439
+ // Validate incoming request
440
+ const arrayBuffer = await c.req.arrayBuffer();
441
+ const request = deserializeWithEncoding(
442
+ encoding,
443
+ new Uint8Array(arrayBuffer),
444
+ HTTP_ACTION_REQUEST_VERSIONED,
445
+ );
446
+ const actionArgs = cbor.decode(new Uint8Array(request.args));
447
+
448
+ // Invoke the action
449
+ let actor: AnyActorInstance | undefined;
450
+ let conn: AnyConn | undefined;
451
+ let output: unknown | undefined;
452
+ try {
453
+ actor = await actorDriver.loadActor(actorId);
454
+
455
+ actor.rLog.debug({ msg: "handling action", actionName, encoding });
456
+
457
+ // Create conn
458
+ const connState = await actor.prepareConn(parameters, c.req.raw);
459
+ conn = await actor.createConn(
460
+ generateConnId(),
461
+ generateConnToken(),
462
+ parameters,
463
+ connState,
464
+ CONNECTION_DRIVER_HTTP,
465
+ {} satisfies GenericHttpDriverState,
466
+ authData,
467
+ );
468
+
469
+ // Call action
470
+ const ctx = new ActionContext(actor.actorContext!, conn!);
471
+ output = await actor.executeAction(ctx, actionName, actionArgs);
472
+ } finally {
473
+ if (conn) {
474
+ actor?.__removeConn(conn);
475
+ }
476
+ }
477
+
478
+ // Send response
479
+ const responseData: protocol.HttpActionResponse = {
480
+ output: bufferToArrayBuffer(cbor.encode(output)),
481
+ };
482
+ const serialized = serializeWithEncoding(
483
+ encoding,
484
+ responseData,
485
+ HTTP_ACTION_RESPONSE_VERSIONED,
486
+ );
487
+ return c.body(serialized as Uint8Array, 200, {
488
+ "Content-Type": contentTypeForEncoding(encoding),
489
+ });
490
+ }
491
+
492
+ /**
493
+ * Create a connection message handler
494
+ */
495
+ export async function handleConnectionMessage(
496
+ c: HonoContext,
497
+ _runConfig: RunConfig,
498
+ actorDriver: ActorDriver,
499
+ connId: string,
500
+ connToken: string,
501
+ actorId: string,
502
+ ) {
503
+ const encoding = getRequestEncoding(c.req);
504
+
505
+ // Validate incoming request
506
+ const arrayBuffer = await c.req.arrayBuffer();
507
+ const message = deserializeWithEncoding(
508
+ encoding,
509
+ new Uint8Array(arrayBuffer),
510
+ TO_SERVER_VERSIONED,
511
+ );
512
+
513
+ const actor = await actorDriver.loadActor(actorId);
514
+
515
+ // Find connection
516
+ const conn = actor.conns.get(connId);
517
+ if (!conn) {
518
+ throw new errors.ConnNotFound(connId);
519
+ }
520
+
521
+ // Authenticate connection
522
+ if (conn._token !== connToken) {
523
+ throw new errors.IncorrectConnToken();
524
+ }
525
+
526
+ // Process message
527
+ await actor.processMessage(message, conn);
528
+
529
+ return c.json({});
530
+ }
531
+
532
+ export async function handleRawWebSocketHandler(
533
+ req: Request | undefined,
534
+ path: string,
535
+ actorDriver: ActorDriver,
536
+ actorId: string,
537
+ authData: unknown,
538
+ ): Promise<UpgradeWebSocketArgs> {
539
+ const actor = await actorDriver.loadActor(actorId);
540
+
541
+ // Return WebSocket event handlers
542
+ return {
543
+ onOpen: (_evt: any, ws: any) => {
544
+ // Wrap the Hono WebSocket in our adapter
545
+ const adapter = new HonoWebSocketAdapter(ws);
546
+
547
+ // Store adapter reference on the WebSocket for event handlers
548
+ (ws as any).__adapter = adapter;
549
+
550
+ // Extract the path after prefix and preserve query parameters
551
+ // Use URL API for cleaner parsing
552
+ const url = new URL(path, "http://actor");
553
+ const pathname = url.pathname.replace(/^\/raw\/websocket\/?/, "") || "/";
554
+ const normalizedPath =
555
+ (pathname.startsWith("/") ? pathname : "/" + pathname) + url.search;
556
+
557
+ let newRequest: Request;
558
+ if (req) {
559
+ newRequest = new Request(`http://actor${normalizedPath}`, req);
560
+ } else {
561
+ newRequest = new Request(`http://actor${normalizedPath}`, {
562
+ method: "GET",
563
+ });
564
+ }
565
+
566
+ actor.rLog.debug({
567
+ msg: "rewriting websocket url",
568
+ from: path,
569
+ to: newRequest.url,
570
+ pathname: url.pathname,
571
+ search: url.search,
572
+ normalizedPath,
573
+ });
574
+
575
+ // Call the actor's onWebSocket handler with the adapted WebSocket
576
+ actor.handleWebSocket(adapter, {
577
+ request: newRequest,
578
+ });
579
+ },
580
+ onMessage: (event: any, ws: any) => {
581
+ // Find the adapter for this WebSocket
582
+ const adapter = (ws as any).__adapter;
583
+ if (adapter) {
584
+ adapter._handleMessage(event);
585
+ }
586
+ },
587
+ onClose: (evt: any, ws: any) => {
588
+ // Find the adapter for this WebSocket
589
+ const adapter = (ws as any).__adapter;
590
+ if (adapter) {
591
+ adapter._handleClose(evt?.code || 1006, evt?.reason || "");
592
+ }
593
+ },
594
+ onError: (error: any, ws: any) => {
595
+ // Find the adapter for this WebSocket
596
+ const adapter = (ws as any).__adapter;
597
+ if (adapter) {
598
+ adapter._handleError(error);
599
+ }
600
+ },
601
+ };
602
+ }
603
+
604
+ // Helper to get the connection encoding from a request
605
+ export function getRequestEncoding(req: HonoRequest): Encoding {
606
+ const encodingParam = req.header(HEADER_ENCODING);
607
+ if (!encodingParam) {
608
+ throw new errors.InvalidEncoding("undefined");
609
+ }
610
+
611
+ const result = EncodingSchema.safeParse(encodingParam);
612
+ if (!result.success) {
613
+ throw new errors.InvalidEncoding(encodingParam as string);
614
+ }
615
+
616
+ return result.data;
617
+ }
618
+
619
+ export function getRequestExposeInternalError(_req: Request): boolean {
620
+ // Unipmlemented
621
+ return false;
622
+ }
623
+
624
+ export function getRequestQuery(c: HonoContext): unknown {
625
+ // Get query parameters for actor lookup
626
+ const queryParam = c.req.header(HEADER_ACTOR_QUERY);
627
+ if (!queryParam) {
628
+ loggerWithoutContext().error({ msg: "missing query parameter" });
629
+ throw new errors.InvalidRequest("missing query");
630
+ }
631
+
632
+ // Parse the query JSON and validate with schema
633
+ try {
634
+ const parsed = JSON.parse(queryParam);
635
+ return parsed;
636
+ } catch (error) {
637
+ loggerWithoutContext().error({ msg: "invalid query json", error });
638
+ throw new errors.InvalidQueryJSON(error);
639
+ }
640
+ }
641
+
642
+ export const HEADER_ACTOR_QUERY = "X-RivetKit-Query";
643
+
644
+ export const HEADER_ENCODING = "X-RivetKit-Encoding";
645
+
646
+ // 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.
647
+ export const HEADER_CONN_PARAMS = "X-RivetKit-Conn-Params";
648
+
649
+ // Internal header
650
+ export const HEADER_AUTH_DATA = "X-RivetKit-Auth-Data";
651
+
652
+ export const HEADER_ACTOR_ID = "X-RivetKit-Actor";
653
+
654
+ export const HEADER_CONN_ID = "X-RivetKit-Conn";
655
+
656
+ export const HEADER_CONN_TOKEN = "X-RivetKit-Conn-Token";
657
+
658
+ /**
659
+ * Headers that publics can send from public clients.
660
+ *
661
+ * Used for CORS.
662
+ **/
663
+ export const ALLOWED_PUBLIC_HEADERS = [
664
+ "Content-Type",
665
+ "User-Agent",
666
+ HEADER_ACTOR_QUERY,
667
+ HEADER_ENCODING,
668
+ HEADER_CONN_PARAMS,
669
+ HEADER_ACTOR_ID,
670
+ HEADER_CONN_ID,
671
+ HEADER_CONN_TOKEN,
672
+ ];
673
+
674
+ // Helper to get connection parameters for the request
675
+ export function getRequestConnParams(req: HonoRequest): unknown {
676
+ const paramsParam = req.header(HEADER_CONN_PARAMS);
677
+ if (!paramsParam) {
678
+ return null;
679
+ }
680
+
681
+ try {
682
+ return JSON.parse(paramsParam);
683
+ } catch (err) {
684
+ throw new errors.InvalidParams(
685
+ `Invalid params JSON: ${stringifyError(err)}`,
686
+ );
687
+ }
688
+ }