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
@@ -0,0 +1,408 @@
1
+ import type { WSContext } from "hono/ws";
2
+ import invariant from "invariant";
3
+ import type { AnyConn } from "@/actor/conn/mod";
4
+ import type { AnyActorInstance } from "@/actor/instance/mod";
5
+ import type { InputData } from "@/actor/protocol/serde";
6
+ import { type Encoding, EncodingSchema } from "@/actor/protocol/serde";
7
+ import {
8
+ PATH_CONNECT,
9
+ PATH_INSPECTOR_CONNECT,
10
+ PATH_WEBSOCKET_BASE,
11
+ PATH_WEBSOCKET_PREFIX,
12
+ WS_PROTOCOL_CONN_PARAMS,
13
+ WS_PROTOCOL_ENCODING,
14
+ } from "@/common/actor-router-consts";
15
+ import { deconstructError } from "@/common/utils";
16
+ import type {
17
+ RivetMessageEvent,
18
+ UniversalWebSocket,
19
+ } from "@/common/websocket-interface";
20
+ import type { RunnerConfig } from "@/registry/run-config";
21
+ import { promiseWithResolvers } from "@/utils";
22
+ import type { ConnDriver } from "./conn/driver";
23
+ import { createRawWebSocketDriver } from "./conn/drivers/raw-websocket";
24
+ import { createWebSocketDriver } from "./conn/drivers/websocket";
25
+ import type { ActorDriver } from "./driver";
26
+ import { loggerWithoutContext } from "./log";
27
+ import { parseMessage } from "./protocol/old";
28
+ import { getRequestExposeInternalError } from "./router-endpoints";
29
+
30
+ // TODO: Merge with ConnectWebSocketOutput interface
31
+ export interface UpgradeWebSocketArgs {
32
+ conn?: AnyConn;
33
+ actor?: AnyActorInstance;
34
+ onRestore?: (ws: WSContext) => void;
35
+ onOpen: (event: any, ws: WSContext) => void;
36
+ onMessage: (event: any, ws: WSContext) => void;
37
+ onClose: (event: any, ws: WSContext) => void;
38
+ onError: (error: any, ws: WSContext) => void;
39
+ }
40
+
41
+ interface WebSocketHandlerOpts {
42
+ runConfig: RunnerConfig;
43
+ request: Request | undefined;
44
+ encoding: Encoding;
45
+ actor: AnyActorInstance;
46
+ closePromiseResolvers: ReturnType<typeof promiseWithResolvers<void>>;
47
+ conn: AnyConn;
48
+ exposeInternalError: boolean;
49
+ }
50
+
51
+ /** Handler for a specific WebSocket route. Used in routeWebSocket. */
52
+ type WebSocketHandler = (
53
+ opts: WebSocketHandlerOpts,
54
+ ) => Promise<UpgradeWebSocketArgs>;
55
+
56
+ export async function routeWebSocket(
57
+ request: Request | undefined,
58
+ requestPath: string,
59
+ requestHeaders: Record<string, string>,
60
+ runConfig: RunnerConfig,
61
+ actorDriver: ActorDriver,
62
+ actorId: string,
63
+ encoding: Encoding,
64
+ parameters: unknown,
65
+ gatewayId: ArrayBuffer | undefined,
66
+ requestId: ArrayBuffer | undefined,
67
+ isHibernatable: boolean,
68
+ isRestoringHibernatable: boolean,
69
+ ): Promise<UpgradeWebSocketArgs> {
70
+ const exposeInternalError = request
71
+ ? getRequestExposeInternalError(request)
72
+ : false;
73
+
74
+ let createdConn: AnyConn | undefined;
75
+ try {
76
+ const actor = await actorDriver.loadActor(actorId);
77
+
78
+ actor.rLog.debug({
79
+ msg: "new websocket connection",
80
+ actorId,
81
+ requestPath,
82
+ isHibernatable,
83
+ });
84
+
85
+ // Promise used to wait for the websocket close in `disconnect`
86
+ const closePromiseResolvers = promiseWithResolvers<void>();
87
+
88
+ // Route WebSocket & create driver
89
+ let handler: WebSocketHandler;
90
+ let connDriver: ConnDriver;
91
+ if (requestPath === PATH_CONNECT) {
92
+ const { driver, setWebSocket } = createWebSocketDriver(
93
+ isHibernatable
94
+ ? { gatewayId: gatewayId!, requestId: requestId! }
95
+ : undefined,
96
+ encoding,
97
+ closePromiseResolvers.promise,
98
+ );
99
+ handler = handleWebSocketConnect.bind(undefined, setWebSocket);
100
+ connDriver = driver;
101
+ } else if (
102
+ requestPath === PATH_WEBSOCKET_BASE ||
103
+ requestPath.startsWith(PATH_WEBSOCKET_PREFIX)
104
+ ) {
105
+ const { driver, setWebSocket } = createRawWebSocketDriver(
106
+ isHibernatable
107
+ ? { gatewayId: gatewayId!, requestId: requestId! }
108
+ : undefined,
109
+ closePromiseResolvers.promise,
110
+ );
111
+ handler = handleRawWebSocket.bind(undefined, setWebSocket);
112
+ connDriver = driver;
113
+ } else if (requestPath === PATH_INSPECTOR_CONNECT) {
114
+ // This returns raw UpgradeWebSocketArgs instead of accepting a
115
+ // Conn since this does not need a Conn
116
+ return await handleWebSocketInspectorConnect();
117
+ } else {
118
+ throw `WebSocket Path Not Found: ${requestPath}`;
119
+ }
120
+
121
+ // Prepare connection
122
+ const conn = await actor.connectionManager.prepareConn(
123
+ connDriver,
124
+ parameters,
125
+ request,
126
+ requestPath,
127
+ requestHeaders,
128
+ isHibernatable,
129
+ isRestoringHibernatable,
130
+ );
131
+ createdConn = conn;
132
+
133
+ // Create handler
134
+ //
135
+ // This must call actor.connectionManager.connectConn in onOpen.
136
+ return await handler({
137
+ runConfig,
138
+ request,
139
+ encoding,
140
+ actor,
141
+ closePromiseResolvers,
142
+ conn,
143
+ exposeInternalError,
144
+ });
145
+ } catch (error) {
146
+ const { group, code } = deconstructError(
147
+ error,
148
+ loggerWithoutContext(),
149
+ {},
150
+ exposeInternalError,
151
+ );
152
+
153
+ // Clean up connection
154
+ if (createdConn) {
155
+ createdConn.disconnect(`${group}.${code}`);
156
+ }
157
+
158
+ // Return handler that immediately closes with error
159
+ // Note: createdConn should always exist here, but we use a type assertion for safety
160
+ return {
161
+ conn: createdConn!,
162
+ onOpen: (_evt: any, ws: WSContext) => {
163
+ ws.close(1011, code);
164
+ },
165
+ onMessage: (_evt: { data: any }, ws: WSContext) => {
166
+ ws.close(1011, "actor.not_loaded");
167
+ },
168
+ onClose: (_event: any, _ws: WSContext) => {},
169
+ onError: (_error: unknown) => {},
170
+ };
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Creates a WebSocket connection handler
176
+ */
177
+ export async function handleWebSocketConnect(
178
+ setWebSocket: (ws: WSContext) => void,
179
+ {
180
+ runConfig,
181
+ encoding,
182
+ actor,
183
+ closePromiseResolvers,
184
+ conn,
185
+ exposeInternalError,
186
+ }: WebSocketHandlerOpts,
187
+ ): Promise<UpgradeWebSocketArgs> {
188
+ return {
189
+ conn,
190
+ actor,
191
+ onRestore: (ws: WSContext) => {
192
+ setWebSocket(ws);
193
+ },
194
+ // NOTE: onOpen cannot be async since this messes up the open event listener order
195
+ onOpen: (_evt: any, ws: WSContext) => {
196
+ actor.rLog.debug("actor websocket open");
197
+
198
+ setWebSocket(ws);
199
+
200
+ // This will not be called by restoring hibernatable
201
+ // connections. All restoration is done in prepareConn.
202
+ actor.connectionManager.connectConn(conn);
203
+ },
204
+ onMessage: (evt: RivetMessageEvent, ws: WSContext) => {
205
+ // Handle message asynchronously
206
+ actor.rLog.debug({ msg: "received message" });
207
+
208
+ const value = evt.data.valueOf() as InputData;
209
+ parseMessage(value, {
210
+ encoding: encoding,
211
+ maxIncomingMessageSize: runConfig.maxIncomingMessageSize,
212
+ })
213
+ .then((message) => {
214
+ actor.processMessage(message, conn).catch((error) => {
215
+ const { code } = deconstructError(
216
+ error,
217
+ actor.rLog,
218
+ {
219
+ wsEvent: "message",
220
+ },
221
+ exposeInternalError,
222
+ );
223
+ ws.close(1011, code);
224
+ });
225
+ })
226
+ .catch((error) => {
227
+ const { code } = deconstructError(
228
+ error,
229
+ actor.rLog,
230
+ {
231
+ wsEvent: "message",
232
+ },
233
+ exposeInternalError,
234
+ );
235
+ ws.close(1011, code);
236
+ });
237
+ },
238
+ onClose: (
239
+ event: {
240
+ wasClean: boolean;
241
+ code: number;
242
+ reason: string;
243
+ },
244
+ ws: WSContext,
245
+ ) => {
246
+ closePromiseResolvers.resolve();
247
+
248
+ if (event.wasClean) {
249
+ actor.rLog.info({
250
+ msg: "websocket closed",
251
+ code: event.code,
252
+ reason: event.reason,
253
+ wasClean: event.wasClean,
254
+ });
255
+ } else {
256
+ actor.rLog.warn({
257
+ msg: "websocket closed",
258
+ code: event.code,
259
+ reason: event.reason,
260
+ wasClean: event.wasClean,
261
+ });
262
+ }
263
+
264
+ // HACK: Close socket in order to fix bug with Cloudflare leaving WS in closing state
265
+ // https://github.com/cloudflare/workerd/issues/2569
266
+ ws.close(1000, "hack_force_close");
267
+
268
+ // Wait for actor.createConn to finish before removing the connection
269
+ conn.disconnect(event?.reason);
270
+ },
271
+ onError: (_error: unknown) => {
272
+ try {
273
+ // Actors don't need to know about this, since it's abstracted away
274
+ actor.rLog.warn({ msg: "websocket error" });
275
+ } catch (error) {
276
+ deconstructError(
277
+ error,
278
+ actor.rLog,
279
+ { wsEvent: "error" },
280
+ exposeInternalError,
281
+ );
282
+ }
283
+ },
284
+ };
285
+ }
286
+
287
+ export async function handleRawWebSocket(
288
+ setWebSocket: (ws: UniversalWebSocket) => void,
289
+ { request, actor, closePromiseResolvers, conn }: WebSocketHandlerOpts,
290
+ ): Promise<UpgradeWebSocketArgs> {
291
+ return {
292
+ conn,
293
+ actor,
294
+ onRestore: (wsContext: WSContext) => {
295
+ const ws = wsContext.raw as UniversalWebSocket;
296
+ invariant(ws, "missing wsContext.raw");
297
+
298
+ setWebSocket(ws);
299
+ },
300
+ // NOTE: onOpen cannot be async since this will cause the client's open
301
+ // event to be called before this completes. Do all async work in
302
+ // handleRawWebSocket root.
303
+ onOpen: (_evt: any, wsContext: WSContext) => {
304
+ const ws = wsContext.raw as UniversalWebSocket;
305
+ invariant(ws, "missing wsContext.raw");
306
+
307
+ setWebSocket(ws);
308
+
309
+ // This will not be called by restoring hibernatable
310
+ // connections. All restoration is done in prepareConn.
311
+ actor.connectionManager.connectConn(conn);
312
+
313
+ // Call the actor's onWebSocket handler with the adapted WebSocket
314
+ //
315
+ // NOTE: onWebSocket is called inside this function. Make sure
316
+ // this is called synchronously within onOpen.
317
+ actor.handleRawWebSocket(conn, ws, request);
318
+ },
319
+ onMessage: (event: any, ws: any) => {
320
+ // Find the adapter for this WebSocket
321
+ const adapter = (ws as any).__adapter;
322
+ if (adapter) {
323
+ adapter._handleMessage(event);
324
+ }
325
+ },
326
+ onClose: (evt: any, ws: any) => {
327
+ // Resolve the close promise
328
+ closePromiseResolvers.resolve();
329
+
330
+ // Clean up the connection
331
+ conn.disconnect(evt?.reason);
332
+ },
333
+ onError: (error: any, ws: any) => {},
334
+ };
335
+ }
336
+
337
+ export async function handleWebSocketInspectorConnect(): Promise<UpgradeWebSocketArgs> {
338
+ return {
339
+ // NOTE: onOpen cannot be async since this messes up the open event listener order
340
+ onOpen: (_evt: any, ws: WSContext) => {
341
+ ws.send("Hello world");
342
+ },
343
+ onMessage: (evt: RivetMessageEvent, ws: WSContext) => {
344
+ ws.send("Pong");
345
+ },
346
+ onClose: (
347
+ event: {
348
+ wasClean: boolean;
349
+ code: number;
350
+ reason: string;
351
+ },
352
+ ws: WSContext,
353
+ ) => {
354
+ // TODO:
355
+ },
356
+ onError: (_error: unknown) => {
357
+ // TODO:
358
+ },
359
+ };
360
+ }
361
+
362
+ /**
363
+ * Parse encoding and connection parameters from WebSocket Sec-WebSocket-Protocol header
364
+ */
365
+ export function parseWebSocketProtocols(protocols: string | null | undefined): {
366
+ encoding: Encoding;
367
+ connParams: unknown;
368
+ } {
369
+ let encodingRaw: string | undefined;
370
+ let connParamsRaw: string | undefined;
371
+
372
+ if (protocols) {
373
+ const protocolList = protocols.split(",").map((p) => p.trim());
374
+ for (const protocol of protocolList) {
375
+ if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
376
+ encodingRaw = protocol.substring(WS_PROTOCOL_ENCODING.length);
377
+ } else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
378
+ connParamsRaw = decodeURIComponent(
379
+ protocol.substring(WS_PROTOCOL_CONN_PARAMS.length),
380
+ );
381
+ }
382
+ }
383
+ }
384
+
385
+ const encoding = EncodingSchema.parse(encodingRaw);
386
+ const connParams = connParamsRaw ? JSON.parse(connParamsRaw) : undefined;
387
+
388
+ return { encoding, connParams };
389
+ }
390
+
391
+ /**
392
+ * Truncase the PATH_WEBSOCKET_PREFIX path prefix in order to pass a clean
393
+ * path to the onWebSocket handler.
394
+ *
395
+ * Example:
396
+ * - `/websocket/foo` -> `/foo`
397
+ * - `/websocket` -> `/`
398
+ */
399
+ export function truncateRawWebSocketPathPrefix(path: string): string {
400
+ // Extract the path after prefix and preserve query parameters
401
+ // Use URL API for cleaner parsing
402
+ const url = new URL(path, "http://actor");
403
+ const pathname = url.pathname.replace(/^\/websocket\/?/, "") || "/";
404
+ const normalizedPath =
405
+ (pathname.startsWith("/") ? pathname : `/${pathname}`) + url.search;
406
+
407
+ return normalizedPath;
408
+ }