rivetkit 2.0.24-rc.1 → 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-HHFKKVLR.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-ZTH3KYFH.cjs → chunk-5BZO5XPS.cjs} +3 -3
  17. package/dist/tsup/{chunk-ZTH3KYFH.cjs.map → chunk-5BZO5XPS.cjs.map} +1 -1
  18. package/dist/tsup/{chunk-PLUN2NQT.js → chunk-BAIGSF64.js} +189 -187
  19. package/dist/tsup/chunk-BAIGSF64.js.map +1 -0
  20. package/dist/tsup/{chunk-SHVX2QUR.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-7L65NNWP.cjs → chunk-DLK5YCTN.cjs} +187 -185
  27. package/dist/tsup/chunk-DLK5YCTN.cjs.map +1 -0
  28. package/dist/tsup/{chunk-YBG6R7LX.js → chunk-DUJQWGYD.js} +3 -7
  29. package/dist/tsup/chunk-DUJQWGYD.js.map +1 -0
  30. package/dist/tsup/{chunk-CD33GT6Z.js → chunk-EIPANQMF.js} +2 -2
  31. package/dist/tsup/{chunk-2JYPS5YM.cjs → chunk-ESMTDP7G.cjs} +6 -6
  32. package/dist/tsup/chunk-ESMTDP7G.cjs.map +1 -0
  33. package/dist/tsup/{chunk-VHGY7PU5.cjs → chunk-FVAKREFB.cjs} +1900 -1737
  34. package/dist/tsup/chunk-FVAKREFB.cjs.map +1 -0
  35. package/dist/tsup/{chunk-BLK27ES3.js → chunk-I3XT7WOF.js} +44 -56
  36. package/dist/tsup/chunk-I3XT7WOF.js.map +1 -0
  37. package/dist/tsup/{chunk-YBHYXIP6.js → chunk-IMDS5T42.js} +3 -3
  38. package/dist/tsup/chunk-IMDS5T42.js.map +1 -0
  39. package/dist/tsup/{chunk-INNFK746.cjs → chunk-J3HZJF2P.cjs} +10 -14
  40. package/dist/tsup/chunk-J3HZJF2P.cjs.map +1 -0
  41. package/dist/tsup/{chunk-BYMKMOBS.js → chunk-MBBJUHSP.js} +1844 -1681
  42. package/dist/tsup/chunk-MBBJUHSP.js.map +1 -0
  43. package/dist/tsup/{chunk-BOMZS2TJ.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-36JJ4IQB.cjs → chunk-YC5DUHPM.cjs} +4 -8
  50. package/dist/tsup/chunk-YC5DUHPM.cjs.map +1 -0
  51. package/dist/tsup/{chunk-FX7TWFQR.js → chunk-YC7YPM2T.js} +2 -6
  52. package/dist/tsup/chunk-YC7YPM2T.js.map +1 -0
  53. package/dist/tsup/{chunk-227FEWMB.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-227FEWMB.js.map +0 -1
  196. package/dist/tsup/chunk-2JYPS5YM.cjs.map +0 -1
  197. package/dist/tsup/chunk-36JJ4IQB.cjs.map +0 -1
  198. package/dist/tsup/chunk-7L65NNWP.cjs.map +0 -1
  199. package/dist/tsup/chunk-BLK27ES3.js.map +0 -1
  200. package/dist/tsup/chunk-BOMZS2TJ.js.map +0 -1
  201. package/dist/tsup/chunk-BYMKMOBS.js.map +0 -1
  202. package/dist/tsup/chunk-FX7TWFQR.js.map +0 -1
  203. package/dist/tsup/chunk-G64QUEDJ.js.map +0 -1
  204. package/dist/tsup/chunk-HHFKKVLR.cjs.map +0 -1
  205. package/dist/tsup/chunk-INNFK746.cjs.map +0 -1
  206. package/dist/tsup/chunk-KSRXX3Z4.cjs.map +0 -1
  207. package/dist/tsup/chunk-O44LFKSB.cjs +0 -4623
  208. package/dist/tsup/chunk-O44LFKSB.cjs.map +0 -1
  209. package/dist/tsup/chunk-PLUN2NQT.js.map +0 -1
  210. package/dist/tsup/chunk-S4UJG7ZE.js +0 -1119
  211. package/dist/tsup/chunk-S4UJG7ZE.js.map +0 -1
  212. package/dist/tsup/chunk-SHVX2QUR.cjs.map +0 -1
  213. package/dist/tsup/chunk-VFB23BYZ.cjs +0 -1119
  214. package/dist/tsup/chunk-VFB23BYZ.cjs.map +0 -1
  215. package/dist/tsup/chunk-VHGY7PU5.cjs.map +0 -1
  216. package/dist/tsup/chunk-YBG6R7LX.js.map +0 -1
  217. package/dist/tsup/chunk-YBHYXIP6.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-CD33GT6Z.js.map → chunk-EIPANQMF.js.map} +0 -0
@@ -4,64 +4,64 @@ import {
4
4
  inspectorLogger,
5
5
  isInspectorEnabled,
6
6
  secureInspector
7
- } from "./chunk-FX7TWFQR.js";
7
+ } from "./chunk-YC7YPM2T.js";
8
8
  import {
9
+ ActionContext,
9
10
  ActorDefinition,
10
- PERSIST_SYMBOL,
11
+ CONN_DRIVER_SYMBOL,
12
+ CONN_STATE_MANAGER_SYMBOL,
13
+ HTTP_ACTION_REQUEST_VERSIONED,
14
+ HTTP_ACTION_RESPONSE_VERSIONED,
15
+ HTTP_RESPONSE_ERROR_VERSIONED,
16
+ HttpActionRequestSchema,
17
+ HttpActionResponseSchema,
18
+ HttpResponseErrorSchema,
11
19
  RemoteManagerDriver,
12
20
  createActorInspectorRouter,
13
21
  createClientWithDriver,
22
+ createHttpDriver,
14
23
  deserializeActorKey,
15
- generateConnRequestId,
16
24
  getDatacenters,
17
25
  getEndpoint,
26
+ getValueLength,
18
27
  lookupInRegistry,
28
+ parseMessage,
19
29
  serializeActorKey,
20
30
  updateRunnerConfig
21
- } from "./chunk-227FEWMB.js";
31
+ } from "./chunk-ZSPU5R4C.js";
22
32
  import {
23
33
  CreateActorSchema
24
- } from "./chunk-YBG6R7LX.js";
34
+ } from "./chunk-DUJQWGYD.js";
25
35
  import {
26
- ActionContext,
27
36
  ClientConfigSchema,
28
- HTTP_ACTION_REQUEST_VERSIONED,
29
- HTTP_ACTION_RESPONSE_VERSIONED,
30
- HTTP_RESPONSE_ERROR_VERSIONED,
37
+ KEYS,
31
38
  RunnerConfigSchema,
32
- TO_SERVER_VERSIONED,
33
39
  createVersionedDataHandler,
34
- parseMessage,
35
- serializeEmptyPersistData
36
- } from "./chunk-S4UJG7ZE.js";
40
+ getInitialActorKvState
41
+ } from "./chunk-OFOTPKAH.js";
37
42
  import {
38
43
  EncodingSchema,
39
44
  HEADER_ACTOR_ID,
40
- HEADER_CONN_ID,
41
45
  HEADER_CONN_PARAMS,
42
- HEADER_CONN_TOKEN,
43
46
  HEADER_ENCODING,
44
47
  HEADER_RIVET_ACTOR,
45
48
  HEADER_RIVET_TARGET,
46
- PATH_CONNECT_WEBSOCKET,
47
- PATH_RAW_WEBSOCKET_PREFIX,
49
+ PATH_CONNECT,
50
+ PATH_INSPECTOR_CONNECT,
51
+ PATH_WEBSOCKET_BASE,
52
+ PATH_WEBSOCKET_PREFIX,
48
53
  WS_PROTOCOL_ACTOR,
49
- WS_PROTOCOL_CONN_ID,
50
54
  WS_PROTOCOL_CONN_PARAMS,
51
- WS_PROTOCOL_CONN_TOKEN,
52
55
  WS_PROTOCOL_ENCODING,
53
- WS_PROTOCOL_PATH,
54
56
  WS_PROTOCOL_TARGET,
55
- WS_PROTOCOL_TRANSPORT,
57
+ WS_TEST_PROTOCOL_PATH,
56
58
  contentTypeForEncoding,
57
59
  deserializeWithEncoding,
58
- encodingIsBinary,
59
60
  generateRandomString,
60
61
  loggerWithoutContext,
61
62
  serializeWithEncoding
62
- } from "./chunk-BLK27ES3.js";
63
+ } from "./chunk-I3XT7WOF.js";
63
64
  import {
64
- EXTRA_ERROR_LOG,
65
65
  VERSION,
66
66
  arrayBuffersEqual,
67
67
  assertUnreachable,
@@ -71,18 +71,15 @@ import {
71
71
  deconstructError,
72
72
  getEnvUniversal,
73
73
  getLogger,
74
- idToStr,
75
74
  noopNext,
76
75
  package_default,
77
76
  promiseWithResolvers,
78
77
  setLongTimeout,
79
78
  stringifyError
80
- } from "./chunk-PLUN2NQT.js";
79
+ } from "./chunk-BAIGSF64.js";
81
80
  import {
82
- ActorAlreadyExists,
83
- ConnNotFound,
84
- IncorrectConnToken,
85
- InternalError,
81
+ ActorDuplicateKey,
82
+ ActorStopping,
86
83
  InvalidEncoding,
87
84
  InvalidParams,
88
85
  InvalidRequest,
@@ -90,20 +87,21 @@ import {
90
87
  Unsupported,
91
88
  UserError,
92
89
  WebSocketsNotEnabled
93
- } from "./chunk-G64QUEDJ.js";
90
+ } from "./chunk-W6RDS6NW.js";
94
91
 
95
92
  // src/actor/config.ts
96
93
  import { z } from "zod";
97
94
  var ActorConfigSchema = z.object({
98
95
  onCreate: z.function().optional(),
99
- onStart: z.function().optional(),
100
- onStop: z.function().optional(),
96
+ onDestroy: z.function().optional(),
97
+ onWake: z.function().optional(),
98
+ onSleep: z.function().optional(),
101
99
  onStateChange: z.function().optional(),
102
100
  onBeforeConnect: z.function().optional(),
103
101
  onConnect: z.function().optional(),
104
102
  onDisconnect: z.function().optional(),
105
103
  onBeforeActionResponse: z.function().optional(),
106
- onFetch: z.function().optional(),
104
+ onRequest: z.function().optional(),
107
105
  onWebSocket: z.function().optional(),
108
106
  actions: z.record(z.function()).default({}),
109
107
  state: z.any().optional(),
@@ -118,7 +116,8 @@ var ActorConfigSchema = z.object({
118
116
  createConnStateTimeout: z.number().positive().default(5e3),
119
117
  onConnectTimeout: z.number().positive().default(5e3),
120
118
  // This must be less than ACTOR_STOP_THRESHOLD_MS
121
- onStopTimeout: z.number().positive().default(5e3),
119
+ onSleepTimeout: z.number().positive().default(5e3),
120
+ onDestroyTimeout: z.number().positive().default(5e3),
122
121
  stateSaveInterval: z.number().positive().default(1e4),
123
122
  actionTimeout: z.number().positive().default(6e4),
124
123
  // Max time to wait for waitUntil background promises during shutdown
@@ -127,8 +126,14 @@ var ActorConfigSchema = z.object({
127
126
  connectionLivenessInterval: z.number().positive().default(5e3),
128
127
  noSleep: z.boolean().default(false),
129
128
  sleepTimeout: z.number().positive().default(3e4),
130
- /** @experimental */
131
- canHibernatWebSocket: z.union([
129
+ /**
130
+ * Can hibernate WebSockets for onWebSocket.
131
+ *
132
+ * WebSockets using actions/events are hibernatable by default.
133
+ *
134
+ * @experimental
135
+ **/
136
+ canHibernateWebSocket: z.union([
132
137
  z.boolean(),
133
138
  z.function().args(z.custom()).returns(z.boolean())
134
139
  ]).default(false)
@@ -159,359 +164,434 @@ import invariant2 from "invariant";
159
164
 
160
165
  // src/actor/router-endpoints.ts
161
166
  import * as cbor from "cbor-x";
162
- import { streamSSE } from "hono/streaming";
163
- import invariant from "invariant";
164
167
 
165
- // src/manager/log.ts
166
- function logger() {
167
- return getLogger("actor-manager");
168
+ // src/actor/conn/drivers/raw-request.ts
169
+ function createRawRequestDriver() {
170
+ return {
171
+ type: "raw-request",
172
+ disconnect: async () => {
173
+ },
174
+ getConnectionReadyState: () => {
175
+ return 1 /* OPEN */;
176
+ }
177
+ };
168
178
  }
169
179
 
170
- // src/manager/hono-websocket-adapter.ts
171
- var HonoWebSocketAdapter = class {
172
- // WebSocket readyState values
173
- CONNECTING = 0;
174
- OPEN = 1;
175
- CLOSING = 2;
176
- CLOSED = 3;
177
- #ws;
178
- #readyState = 1;
179
- // Start as OPEN since WSContext is already connected
180
- #eventListeners = /* @__PURE__ */ new Map();
181
- #closeCode;
182
- #closeReason;
183
- rivetRequestId;
184
- isHibernatable;
185
- constructor(ws, rivetRequestId, isHibernatable) {
186
- this.#ws = ws;
187
- this.rivetRequestId = rivetRequestId;
188
- this.isHibernatable = isHibernatable;
189
- this.#readyState = this.OPEN;
190
- setTimeout(() => {
191
- this.#fireEvent("open", {
192
- type: "open",
193
- target: this,
194
- rivetRequestId: this.rivetRequestId
195
- });
196
- }, 0);
197
- }
198
- get readyState() {
199
- return this.#readyState;
180
+ // src/actor/router-endpoints.ts
181
+ async function handleAction(c, _runConfig, actorDriver, actionName, actorId) {
182
+ const encoding = getRequestEncoding(c.req);
183
+ const parameters = getRequestConnParams(c.req);
184
+ const arrayBuffer = await c.req.arrayBuffer();
185
+ const request = deserializeWithEncoding(
186
+ encoding,
187
+ new Uint8Array(arrayBuffer),
188
+ HTTP_ACTION_REQUEST_VERSIONED,
189
+ HttpActionRequestSchema,
190
+ // JSON: args is already the decoded value (raw object/array)
191
+ (json) => json.args,
192
+ // BARE/CBOR: args is ArrayBuffer that needs CBOR-decoding
193
+ (bare2) => cbor.decode(new Uint8Array(bare2.args))
194
+ );
195
+ const actionArgs = request;
196
+ let actor2;
197
+ let conn;
198
+ let output;
199
+ try {
200
+ actor2 = await actorDriver.loadActor(actorId);
201
+ actor2.rLog.debug({ msg: "handling action", actionName, encoding });
202
+ conn = await actor2.connectionManager.prepareAndConnectConn(
203
+ createHttpDriver(),
204
+ parameters,
205
+ c.req.raw,
206
+ c.req.path,
207
+ c.req.header()
208
+ );
209
+ const ctx = new ActionContext(actor2, conn);
210
+ output = await actor2.executeAction(ctx, actionName, actionArgs);
211
+ } finally {
212
+ if (conn) {
213
+ conn.disconnect();
214
+ }
200
215
  }
201
- get binaryType() {
202
- return "arraybuffer";
216
+ const serialized = serializeWithEncoding(
217
+ encoding,
218
+ output,
219
+ HTTP_ACTION_RESPONSE_VERSIONED,
220
+ HttpActionResponseSchema,
221
+ // JSON: output is the raw value (will be serialized by jsonStringifyCompat)
222
+ (value) => ({ output: value }),
223
+ // BARE/CBOR: output needs to be CBOR-encoded to ArrayBuffer
224
+ (value) => ({
225
+ output: bufferToArrayBuffer(cbor.encode(value))
226
+ })
227
+ );
228
+ return c.body(serialized, 200, {
229
+ "Content-Type": contentTypeForEncoding(encoding)
230
+ });
231
+ }
232
+ async function handleRawRequest(c, req, actorDriver, actorId) {
233
+ const actor2 = await actorDriver.loadActor(actorId);
234
+ const parameters = getRequestConnParams(c.req);
235
+ let createdConn;
236
+ try {
237
+ const conn = await actor2.connectionManager.prepareAndConnectConn(
238
+ createRawRequestDriver(),
239
+ parameters,
240
+ req,
241
+ c.req.path,
242
+ c.req.header()
243
+ );
244
+ createdConn = conn;
245
+ return await actor2.handleRawRequest(conn, req);
246
+ } finally {
247
+ if (createdConn) {
248
+ createdConn.disconnect();
249
+ }
203
250
  }
204
- set binaryType(value) {
251
+ }
252
+ function getRequestEncoding(req) {
253
+ const encodingParam = req.header(HEADER_ENCODING);
254
+ if (!encodingParam) {
255
+ return "json";
205
256
  }
206
- get bufferedAmount() {
207
- return 0;
257
+ const result = EncodingSchema.safeParse(encodingParam);
258
+ if (!result.success) {
259
+ throw new InvalidEncoding(encodingParam);
208
260
  }
209
- get extensions() {
210
- return "";
261
+ return result.data;
262
+ }
263
+ function getRequestExposeInternalError(_req) {
264
+ return false;
265
+ }
266
+ function getRequestConnParams(req) {
267
+ const paramsParam = req.header(HEADER_CONN_PARAMS);
268
+ if (!paramsParam) {
269
+ return null;
211
270
  }
212
- get protocol() {
213
- return "";
271
+ try {
272
+ return JSON.parse(paramsParam);
273
+ } catch (err) {
274
+ throw new InvalidParams(
275
+ `Invalid params JSON: ${stringifyError(err)}`
276
+ );
214
277
  }
215
- get url() {
216
- return "";
278
+ }
279
+
280
+ // src/common/router.ts
281
+ import * as cbor2 from "cbor-x";
282
+
283
+ // src/registry/config.ts
284
+ import { z as z2 } from "zod";
285
+ var ActorsSchema = z2.record(
286
+ z2.string(),
287
+ z2.custom()
288
+ );
289
+ var TestConfigSchema = z2.object({ enabled: z2.boolean() });
290
+ var RegistryConfigSchema = z2.object({
291
+ use: z2.record(z2.string(), z2.custom()),
292
+ // TODO: Find a better way of passing around the test config
293
+ /**
294
+ * Test configuration.
295
+ *
296
+ * DO NOT MANUALLY ENABLE. THIS IS USED INTERNALLY.
297
+ * @internal
298
+ **/
299
+ test: TestConfigSchema.optional().default({ enabled: false })
300
+ });
301
+ function buildActorNames(registryConfig) {
302
+ return Object.fromEntries(
303
+ Object.keys(registryConfig.use).map((name) => [name, { metadata: {} }])
304
+ );
305
+ }
306
+
307
+ // src/common/router.ts
308
+ function logger() {
309
+ return getLogger("router");
310
+ }
311
+ function loggerMiddleware(logger8) {
312
+ return async (c, next) => {
313
+ const method = c.req.method;
314
+ const path = c.req.path;
315
+ const startTime = Date.now();
316
+ await next();
317
+ const duration = Date.now() - startTime;
318
+ logger8.debug({
319
+ msg: "http request",
320
+ method,
321
+ path,
322
+ status: c.res.status,
323
+ dt: `${duration}ms`,
324
+ reqSize: c.req.header("content-length"),
325
+ resSize: c.res.headers.get("content-length"),
326
+ userAgent: c.req.header("user-agent"),
327
+ ...getEnvUniversal("_RIVET_LOG_HEADERS") ? { allHeaders: JSON.stringify(c.req.header()) } : {}
328
+ });
329
+ };
330
+ }
331
+ function handleRouteNotFound(c) {
332
+ return c.text("Not Found (RivetKit)", 404);
333
+ }
334
+ function handleRouteError(error, c) {
335
+ const exposeInternalError = getRequestExposeInternalError(c.req.raw);
336
+ const { statusCode, group, code, message, metadata } = deconstructError(
337
+ error,
338
+ logger(),
339
+ {
340
+ method: c.req.method,
341
+ path: c.req.path
342
+ },
343
+ exposeInternalError
344
+ );
345
+ let encoding;
346
+ try {
347
+ encoding = getRequestEncoding(c.req);
348
+ } catch (_) {
349
+ encoding = "json";
217
350
  }
218
- send(data) {
219
- if (this.readyState !== this.OPEN) {
220
- throw new Error("WebSocket is not open");
221
- }
222
- try {
223
- logger().debug({
224
- msg: "bridge sending data",
225
- dataType: typeof data,
226
- isString: typeof data === "string",
227
- isArrayBuffer: data instanceof ArrayBuffer,
228
- dataStr: typeof data === "string" ? data.substring(0, 100) : "<non-string>"
229
- });
230
- if (typeof data === "string") {
231
- this.#ws.send(data);
232
- } else if (data instanceof ArrayBuffer) {
233
- this.#ws.send(data);
234
- } else if (ArrayBuffer.isView(data)) {
235
- const buffer = data.buffer.slice(
236
- data.byteOffset,
237
- data.byteOffset + data.byteLength
351
+ const errorData = { group, code, message, metadata };
352
+ const output = serializeWithEncoding(
353
+ encoding,
354
+ errorData,
355
+ HTTP_RESPONSE_ERROR_VERSIONED,
356
+ HttpResponseErrorSchema,
357
+ // JSON: metadata is the raw value (will be serialized by jsonStringifyCompat)
358
+ (value) => ({
359
+ group: value.group,
360
+ code: value.code,
361
+ message: value.message,
362
+ metadata: value.metadata
363
+ }),
364
+ // BARE/CBOR: metadata needs to be CBOR-encoded to ArrayBuffer
365
+ (value) => ({
366
+ group: value.group,
367
+ code: value.code,
368
+ message: value.message,
369
+ metadata: value.metadata ? bufferToArrayBuffer(cbor2.encode(value.metadata)) : null
370
+ })
371
+ );
372
+ return c.body(output, { status: statusCode });
373
+ }
374
+ function handleMetadataRequest(c, registryConfig, runConfig) {
375
+ const response = {
376
+ runtime: "rivetkit",
377
+ version: VERSION,
378
+ runner: {
379
+ kind: runConfig.runnerKind === "serverless" ? { serverless: {} } : { normal: {} }
380
+ },
381
+ actorNames: buildActorNames(registryConfig),
382
+ // If server address is changed, return a different client endpoint.
383
+ // Otherwise, return null indicating the client should use the current
384
+ // endpoint it's already configured with.
385
+ clientEndpoint: runConfig.overrideServerAddress
386
+ };
387
+ return c.json(response);
388
+ }
389
+ function handleHealthRequest(c) {
390
+ return c.json({
391
+ status: "ok",
392
+ runtime: "rivetkit",
393
+ version: VERSION
394
+ });
395
+ }
396
+
397
+ // src/actor/router-websocket-endpoints.ts
398
+ import invariant from "invariant";
399
+
400
+ // src/actor/conn/drivers/raw-websocket.ts
401
+ function createRawWebSocketDriver(hibernatable, closePromise) {
402
+ let websocket;
403
+ const driver = {
404
+ type: "raw-websocket",
405
+ hibernatable,
406
+ // No sendMessage implementation since this is a raw WebSocket that doesn't
407
+ // handle messages from the RivetKit protocol
408
+ disconnect: async (_actor, _conn, reason) => {
409
+ if (!websocket) {
410
+ loggerWithoutContext().warn(
411
+ "disconnecting raw ws without websocket"
238
412
  );
239
- if (buffer instanceof SharedArrayBuffer) {
240
- const arrayBuffer = new ArrayBuffer(buffer.byteLength);
241
- new Uint8Array(arrayBuffer).set(new Uint8Array(buffer));
242
- this.#ws.send(arrayBuffer);
243
- } else {
244
- this.#ws.send(buffer);
245
- }
246
- } else if (data instanceof Blob) {
247
- data.arrayBuffer().then((buffer) => {
248
- this.#ws.send(buffer);
249
- }).catch((error) => {
250
- logger().error({
251
- msg: "failed to convert blob to arraybuffer",
252
- error
413
+ return;
414
+ }
415
+ websocket.close(1e3, reason);
416
+ await closePromise;
417
+ },
418
+ terminate: () => {
419
+ var _a;
420
+ (_a = websocket == null ? void 0 : websocket.terminate) == null ? void 0 : _a.call(websocket);
421
+ },
422
+ getConnectionReadyState: (_actor, _conn) => {
423
+ return (websocket == null ? void 0 : websocket.readyState) ?? 0 /* CONNECTING */;
424
+ }
425
+ };
426
+ return {
427
+ driver,
428
+ setWebSocket(ws) {
429
+ websocket = ws;
430
+ }
431
+ };
432
+ }
433
+
434
+ // src/actor/conn/drivers/websocket.ts
435
+ function createWebSocketDriver(hibernatable, encoding, closePromise) {
436
+ loggerWithoutContext().debug({
437
+ msg: "createWebSocketDriver creating driver",
438
+ hibernatable
439
+ });
440
+ let websocket;
441
+ const driver = {
442
+ type: "websocket",
443
+ hibernatable,
444
+ rivetKitProtocol: {
445
+ sendMessage: (actor2, conn, message) => {
446
+ if (!websocket) {
447
+ actor2.rLog.warn({
448
+ msg: "websocket not open",
449
+ connId: conn.id
253
450
  });
254
- this.#fireEvent("error", {
255
- type: "error",
256
- target: this,
257
- error
451
+ return;
452
+ }
453
+ if (websocket.readyState !== 1 /* OPEN */) {
454
+ actor2.rLog.warn({
455
+ msg: "attempting to send message to closed websocket, this is likely a bug in RivetKit",
456
+ connId: conn.id,
457
+ wsReadyState: websocket.readyState
258
458
  });
459
+ return;
460
+ }
461
+ const serialized = message.serialize(encoding);
462
+ actor2.rLog.debug({
463
+ msg: "sending websocket message",
464
+ encoding,
465
+ dataType: typeof serialized,
466
+ isUint8Array: serialized instanceof Uint8Array,
467
+ isArrayBuffer: serialized instanceof ArrayBuffer,
468
+ dataLength: serialized.byteLength || serialized.length
259
469
  });
260
- } else {
261
- logger().warn({
262
- msg: "unsupported data type, converting to string",
263
- dataType: typeof data,
264
- data
265
- });
266
- this.#ws.send(String(data));
470
+ if (serialized instanceof Uint8Array) {
471
+ const buffer = serialized.buffer.slice(
472
+ serialized.byteOffset,
473
+ serialized.byteOffset + serialized.byteLength
474
+ );
475
+ if (buffer instanceof SharedArrayBuffer) {
476
+ const arrayBuffer = new ArrayBuffer(buffer.byteLength);
477
+ new Uint8Array(arrayBuffer).set(new Uint8Array(buffer));
478
+ actor2.rLog.debug({
479
+ msg: "converted SharedArrayBuffer to ArrayBuffer",
480
+ byteLength: arrayBuffer.byteLength
481
+ });
482
+ websocket.send(arrayBuffer);
483
+ } else {
484
+ actor2.rLog.debug({
485
+ msg: "sending ArrayBuffer",
486
+ byteLength: buffer.byteLength
487
+ });
488
+ websocket.send(buffer);
489
+ }
490
+ } else {
491
+ actor2.rLog.debug({
492
+ msg: "sending string data",
493
+ length: serialized.length
494
+ });
495
+ websocket.send(serialized);
496
+ }
267
497
  }
268
- } catch (error) {
269
- logger().error({ msg: "error sending websocket data", error });
270
- this.#fireEvent("error", { type: "error", target: this, error });
271
- throw error;
498
+ },
499
+ disconnect: async (_actor, _conn, reason) => {
500
+ if (!websocket) {
501
+ loggerWithoutContext().warn(
502
+ "disconnecting ws without websocket"
503
+ );
504
+ return;
505
+ }
506
+ websocket.close(1e3, reason);
507
+ await closePromise;
508
+ },
509
+ terminate: () => {
510
+ websocket.terminate();
511
+ },
512
+ getConnectionReadyState: (_actor, _conn) => {
513
+ return (websocket == null ? void 0 : websocket.readyState) ?? 0 /* CONNECTING */;
272
514
  }
273
- }
274
- close(code = 1e3, reason = "") {
275
- if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {
276
- return;
515
+ };
516
+ return {
517
+ driver,
518
+ setWebSocket(ws) {
519
+ websocket = ws;
277
520
  }
278
- this.#readyState = this.CLOSING;
279
- this.#closeCode = code;
280
- this.#closeReason = reason;
281
- try {
282
- this.#ws.close(code, reason);
283
- this.#readyState = this.CLOSED;
284
- this.#fireEvent("close", {
285
- type: "close",
286
- target: this,
287
- code,
288
- reason,
289
- wasClean: code === 1e3,
290
- rivetRequestId: this.rivetRequestId
291
- });
292
- } catch (error) {
293
- logger().error({ msg: "error closing websocket", error });
294
- this.#readyState = this.CLOSED;
295
- this.#fireEvent("close", {
296
- type: "close",
297
- target: this,
298
- code: 1006,
299
- reason: "Abnormal closure",
300
- wasClean: false,
301
- rivetRequestId: this.rivetRequestId
302
- });
303
- }
304
- }
305
- addEventListener(type, listener) {
306
- if (!this.#eventListeners.has(type)) {
307
- this.#eventListeners.set(type, /* @__PURE__ */ new Set());
308
- }
309
- this.#eventListeners.get(type).add(listener);
310
- }
311
- removeEventListener(type, listener) {
312
- const listeners = this.#eventListeners.get(type);
313
- if (listeners) {
314
- listeners.delete(listener);
315
- }
316
- }
317
- dispatchEvent(event) {
318
- const listeners = this.#eventListeners.get(event.type);
319
- if (listeners) {
320
- for (const listener of listeners) {
321
- try {
322
- listener(event);
323
- } catch (error) {
324
- logger().error({
325
- msg: `error in ${event.type} event listener`,
326
- error
327
- });
328
- }
329
- }
330
- }
331
- return true;
332
- }
333
- // Internal method to handle incoming messages from WSContext
334
- _handleMessage(data) {
335
- let messageData;
336
- let rivetRequestId;
337
- let rivetMessageIndex;
338
- if (typeof data === "string") {
339
- messageData = data;
340
- } else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
341
- messageData = data;
342
- } else if (data && typeof data === "object" && "data" in data) {
343
- messageData = data.data;
344
- if ("rivetRequestId" in data) {
345
- rivetRequestId = data.rivetRequestId;
346
- }
347
- if ("rivetMessageIndex" in data) {
348
- rivetMessageIndex = data.rivetMessageIndex;
349
- }
350
- } else {
351
- messageData = String(data);
352
- }
353
- logger().debug({
354
- msg: "bridge handling message",
355
- dataType: typeof messageData,
356
- isArrayBuffer: messageData instanceof ArrayBuffer,
357
- dataStr: typeof messageData === "string" ? messageData : "<binary>",
358
- rivetMessageIndex
359
- });
360
- this.#fireEvent("message", {
361
- type: "message",
362
- target: this,
363
- data: messageData,
364
- rivetRequestId,
365
- rivetMessageIndex
366
- });
367
- }
368
- // Internal method to handle close from WSContext
369
- _handleClose(code, reason) {
370
- this.#ws.close(1e3, "hack_force_close");
371
- if (this.readyState === this.CLOSED) return;
372
- this.#readyState = this.CLOSED;
373
- this.#closeCode = code;
374
- this.#closeReason = reason;
375
- this.#fireEvent("close", {
376
- type: "close",
377
- target: this,
378
- code,
379
- reason,
380
- wasClean: code === 1e3,
381
- rivetRequestId: this.rivetRequestId
382
- });
383
- }
384
- // Internal method to handle errors from WSContext
385
- _handleError(error) {
386
- this.#fireEvent("error", {
387
- type: "error",
388
- target: this,
389
- error
390
- });
391
- }
392
- #fireEvent(type, event) {
393
- const listeners = this.#eventListeners.get(type);
394
- if (listeners) {
395
- for (const listener of listeners) {
396
- try {
397
- listener(event);
398
- } catch (error) {
399
- logger().error({
400
- msg: `error in ${type} event listener`,
401
- error
402
- });
403
- }
404
- }
405
- }
406
- switch (type) {
407
- case "open":
408
- if (this.#onopen) {
409
- try {
410
- this.#onopen(event);
411
- } catch (error) {
412
- logger().error({
413
- msg: "error in onopen handler",
414
- error
415
- });
416
- }
417
- }
418
- break;
419
- case "close":
420
- if (this.#onclose) {
421
- try {
422
- this.#onclose(event);
423
- } catch (error) {
424
- logger().error({
425
- msg: "error in onclose handler",
426
- error
427
- });
428
- }
429
- }
430
- break;
431
- case "error":
432
- if (this.#onerror) {
433
- try {
434
- this.#onerror(event);
435
- } catch (error) {
436
- logger().error({
437
- msg: "error in onerror handler",
438
- error
439
- });
440
- }
441
- }
442
- break;
443
- case "message":
444
- if (this.#onmessage) {
445
- try {
446
- this.#onmessage(event);
447
- } catch (error) {
448
- logger().error({
449
- msg: "error in onmessage handler",
450
- error
451
- });
452
- }
453
- }
454
- break;
455
- }
456
- }
457
- // Event handler properties with getters/setters
458
- #onopen = null;
459
- #onclose = null;
460
- #onerror = null;
461
- #onmessage = null;
462
- get onopen() {
463
- return this.#onopen;
464
- }
465
- set onopen(handler) {
466
- this.#onopen = handler;
467
- }
468
- get onclose() {
469
- return this.#onclose;
470
- }
471
- set onclose(handler) {
472
- this.#onclose = handler;
473
- }
474
- get onerror() {
475
- return this.#onerror;
476
- }
477
- set onerror(handler) {
478
- this.#onerror = handler;
479
- }
480
- get onmessage() {
481
- return this.#onmessage;
482
- }
483
- set onmessage(handler) {
484
- this.#onmessage = handler;
485
- }
486
- };
521
+ };
522
+ }
487
523
 
488
- // src/actor/router-endpoints.ts
489
- var SSE_PING_INTERVAL = 1e3;
490
- async function handleWebSocketConnect(req, runConfig, actorDriver, actorId, encoding, parameters, requestId, requestIdBuf, connId, connToken) {
491
- const exposeInternalError = req ? getRequestExposeInternalError(req) : false;
492
- const {
493
- promise: handlersPromise,
494
- resolve: handlersResolve,
495
- reject: handlersReject
496
- } = promiseWithResolvers();
497
- let actor2;
524
+ // src/actor/router-websocket-endpoints.ts
525
+ async function routeWebSocket(request, requestPath, requestHeaders, runConfig, actorDriver, actorId, encoding, parameters, gatewayId, requestId, isHibernatable, isRestoringHibernatable) {
526
+ const exposeInternalError = request ? getRequestExposeInternalError(request) : false;
527
+ let createdConn;
498
528
  try {
499
- actor2 = await actorDriver.loadActor(actorId);
529
+ const actor2 = await actorDriver.loadActor(actorId);
530
+ actor2.rLog.debug({
531
+ msg: "new websocket connection",
532
+ actorId,
533
+ requestPath,
534
+ isHibernatable
535
+ });
536
+ const closePromiseResolvers = promiseWithResolvers();
537
+ let handler;
538
+ let connDriver;
539
+ if (requestPath === PATH_CONNECT) {
540
+ const { driver, setWebSocket } = createWebSocketDriver(
541
+ isHibernatable ? { gatewayId, requestId } : void 0,
542
+ encoding,
543
+ closePromiseResolvers.promise
544
+ );
545
+ handler = handleWebSocketConnect.bind(void 0, setWebSocket);
546
+ connDriver = driver;
547
+ } else if (requestPath === PATH_WEBSOCKET_BASE || requestPath.startsWith(PATH_WEBSOCKET_PREFIX)) {
548
+ const { driver, setWebSocket } = createRawWebSocketDriver(
549
+ isHibernatable ? { gatewayId, requestId } : void 0,
550
+ closePromiseResolvers.promise
551
+ );
552
+ handler = handleRawWebSocket.bind(void 0, setWebSocket);
553
+ connDriver = driver;
554
+ } else if (requestPath === PATH_INSPECTOR_CONNECT) {
555
+ return await handleWebSocketInspectorConnect();
556
+ } else {
557
+ throw `WebSocket Path Not Found: ${requestPath}`;
558
+ }
559
+ const conn = await actor2.connectionManager.prepareConn(
560
+ connDriver,
561
+ parameters,
562
+ request,
563
+ requestPath,
564
+ requestHeaders,
565
+ isHibernatable,
566
+ isRestoringHibernatable
567
+ );
568
+ createdConn = conn;
569
+ return await handler({
570
+ runConfig,
571
+ request,
572
+ encoding,
573
+ actor: actor2,
574
+ closePromiseResolvers,
575
+ conn,
576
+ exposeInternalError
577
+ });
500
578
  } catch (error) {
579
+ const { group, code } = deconstructError(
580
+ error,
581
+ loggerWithoutContext(),
582
+ {},
583
+ exposeInternalError
584
+ );
585
+ if (createdConn) {
586
+ createdConn.disconnect(`${group}.${code}`);
587
+ }
501
588
  return {
589
+ conn: createdConn,
502
590
  onOpen: (_evt, ws) => {
503
- const { code } = deconstructError(
504
- error,
505
- actor2.rLog,
506
- {
507
- wsEvent: "open"
508
- },
509
- exposeInternalError
510
- );
511
591
  ws.close(1011, code);
512
592
  },
513
593
  onMessage: (_evt, ws) => {
514
- ws.close(1011, "Actor not loaded");
594
+ ws.close(1011, "actor.not_loaded");
515
595
  },
516
596
  onClose: (_event, _ws) => {
517
597
  },
@@ -519,79 +599,38 @@ async function handleWebSocketConnect(req, runConfig, actorDriver, actorId, enco
519
599
  }
520
600
  };
521
601
  }
522
- const closePromise = promiseWithResolvers();
523
- let createdConn;
602
+ }
603
+ async function handleWebSocketConnect(setWebSocket, {
604
+ runConfig,
605
+ encoding,
606
+ actor: actor2,
607
+ closePromiseResolvers,
608
+ conn,
609
+ exposeInternalError
610
+ }) {
524
611
  return {
612
+ conn,
613
+ actor: actor2,
614
+ onRestore: (ws) => {
615
+ setWebSocket(ws);
616
+ },
617
+ // NOTE: onOpen cannot be async since this messes up the open event listener order
525
618
  onOpen: (_evt, ws) => {
526
619
  actor2.rLog.debug("actor websocket open");
527
- (async () => {
528
- try {
529
- let conn;
530
- actor2.rLog.debug({
531
- msg: connId ? "websocket reconnection attempt" : "new websocket connection",
532
- connId,
533
- actorId
534
- });
535
- const isHibernatable = !!requestIdBuf && actor2[PERSIST_SYMBOL].hibernatableWebSocket.findIndex(
536
- (ws2) => arrayBuffersEqual(ws2.requestId, requestIdBuf)
537
- ) !== -1;
538
- conn = await actor2.createConn(
539
- {
540
- requestId,
541
- requestIdBuf,
542
- hibernatable: isHibernatable,
543
- driverState: {
544
- [0 /* WEBSOCKET */]: {
545
- encoding,
546
- websocket: ws,
547
- closePromise
548
- }
549
- }
550
- },
551
- parameters,
552
- req,
553
- connId,
554
- connToken
555
- );
556
- createdConn = conn;
557
- handlersResolve({ conn, actor: actor2, connId: conn.id });
558
- } catch (error) {
559
- handlersReject(error);
560
- const { code } = deconstructError(
561
- error,
562
- actor2.rLog,
563
- {
564
- wsEvent: "open"
565
- },
566
- exposeInternalError
567
- );
568
- ws.close(1011, code);
569
- }
570
- })();
620
+ setWebSocket(ws);
621
+ actor2.connectionManager.connectConn(conn);
571
622
  },
572
623
  onMessage: (evt, ws) => {
573
- handlersPromise.then(({ conn, actor: actor3 }) => {
574
- actor3.rLog.debug({ msg: "received message" });
575
- const value = evt.data.valueOf();
576
- parseMessage(value, {
577
- encoding,
578
- maxIncomingMessageSize: runConfig.maxIncomingMessageSize
579
- }).then((message) => {
580
- actor3.processMessage(message, conn).catch((error) => {
581
- const { code } = deconstructError(
582
- error,
583
- actor3.rLog,
584
- {
585
- wsEvent: "message"
586
- },
587
- exposeInternalError
588
- );
589
- ws.close(1011, code);
590
- });
591
- }).catch((error) => {
624
+ actor2.rLog.debug({ msg: "received message" });
625
+ const value = evt.data.valueOf();
626
+ parseMessage(value, {
627
+ encoding,
628
+ maxIncomingMessageSize: runConfig.maxIncomingMessageSize
629
+ }).then((message) => {
630
+ actor2.processMessage(message, conn).catch((error) => {
592
631
  const { code } = deconstructError(
593
632
  error,
594
- actor3.rLog,
633
+ actor2.rLog,
595
634
  {
596
635
  wsEvent: "message"
597
636
  },
@@ -612,8 +651,7 @@ async function handleWebSocketConnect(req, runConfig, actorDriver, actorId, enco
612
651
  });
613
652
  },
614
653
  onClose: (event, ws) => {
615
- handlersReject(`WebSocket closed (${event.code}): ${event.reason}`);
616
- closePromise.resolve();
654
+ closePromiseResolvers.resolve();
617
655
  if (event.wasClean) {
618
656
  actor2.rLog.info({
619
657
  msg: "websocket closed",
@@ -630,12 +668,7 @@ async function handleWebSocketConnect(req, runConfig, actorDriver, actorId, enco
630
668
  });
631
669
  }
632
670
  ws.close(1e3, "hack_force_close");
633
- handlersPromise.finally(() => {
634
- if (createdConn) {
635
- const wasClean = event.wasClean || event.code === 1e3;
636
- actor2.__connDisconnected(createdConn, wasClean, requestId);
637
- }
638
- });
671
+ conn.disconnect(event == null ? void 0 : event.reason);
639
672
  },
640
673
  onError: (_error) => {
641
674
  try {
@@ -651,192 +684,24 @@ async function handleWebSocketConnect(req, runConfig, actorDriver, actorId, enco
651
684
  }
652
685
  };
653
686
  }
654
- async function handleSseConnect(c, _runConfig, actorDriver, actorId) {
655
- c.header("Content-Encoding", "Identity");
656
- const encoding = getRequestEncoding(c.req);
657
- const parameters = getRequestConnParams(c.req);
658
- const requestId = generateConnRequestId();
659
- const connId = c.req.header(HEADER_CONN_ID);
660
- const connToken = c.req.header(HEADER_CONN_TOKEN);
661
- return streamSSE(c, async (stream) => {
662
- let actor2;
663
- let conn;
664
- try {
665
- actor2 = await actorDriver.loadActor(actorId);
666
- actor2.rLog.debug({
667
- msg: connId ? "sse reconnection attempt" : "sse open",
668
- connId
669
- });
670
- conn = await actor2.createConn(
671
- {
672
- requestId,
673
- hibernatable: false,
674
- driverState: {
675
- [1 /* SSE */]: {
676
- encoding,
677
- stream
678
- }
679
- }
680
- },
681
- parameters,
682
- c.req.raw,
683
- connId,
684
- connToken
685
- );
686
- const abortResolver = promiseWithResolvers();
687
- stream.onAbort(() => {
688
- });
689
- c.req.raw.signal.addEventListener("abort", async () => {
690
- invariant(actor2, "actor should exist");
691
- const rLog = actor2.rLog ?? loggerWithoutContext();
692
- try {
693
- rLog.debug("sse stream aborted");
694
- if (conn) {
695
- actor2.__connDisconnected(conn, false, requestId);
696
- }
697
- abortResolver.resolve(void 0);
698
- } catch (error) {
699
- rLog.error({ msg: "error closing sse connection", error });
700
- abortResolver.resolve(void 0);
701
- }
702
- });
703
- while (true) {
704
- if (stream.closed || stream.aborted) {
705
- actor2 == null ? void 0 : actor2.rLog.debug({
706
- msg: "sse stream closed",
707
- closed: stream.closed,
708
- aborted: stream.aborted
709
- });
710
- break;
711
- }
712
- await stream.writeSSE({ event: "ping", data: "" });
713
- await stream.sleep(SSE_PING_INTERVAL);
714
- }
715
- } catch (error) {
716
- loggerWithoutContext().error({
717
- msg: "error in sse connection",
718
- error
719
- });
720
- if (conn && actor2 !== void 0) {
721
- actor2.__connDisconnected(conn, false, requestId);
722
- }
723
- stream.close();
724
- }
725
- });
726
- }
727
- async function handleAction(c, _runConfig, actorDriver, actionName, actorId) {
728
- const encoding = getRequestEncoding(c.req);
729
- const parameters = getRequestConnParams(c.req);
730
- const arrayBuffer = await c.req.arrayBuffer();
731
- const request = deserializeWithEncoding(
732
- encoding,
733
- new Uint8Array(arrayBuffer),
734
- HTTP_ACTION_REQUEST_VERSIONED
735
- );
736
- const actionArgs = cbor.decode(new Uint8Array(request.args));
737
- const requestId = generateConnRequestId();
738
- let actor2;
739
- let conn;
740
- let output;
741
- try {
742
- actor2 = await actorDriver.loadActor(actorId);
743
- actor2.rLog.debug({ msg: "handling action", actionName, encoding });
744
- conn = await actor2.createConn(
745
- {
746
- requestId,
747
- hibernatable: false,
748
- driverState: { [2 /* HTTP */]: {} }
749
- },
750
- parameters,
751
- c.req.raw
752
- );
753
- const ctx = new ActionContext(actor2.actorContext, conn);
754
- output = await actor2.executeAction(ctx, actionName, actionArgs);
755
- } finally {
756
- if (conn) {
757
- actor2 == null ? void 0 : actor2.__connDisconnected(conn, true, requestId);
758
- }
759
- }
760
- const responseData = {
761
- output: bufferToArrayBuffer(cbor.encode(output))
762
- };
763
- const serialized = serializeWithEncoding(
764
- encoding,
765
- responseData,
766
- HTTP_ACTION_RESPONSE_VERSIONED
767
- );
768
- return c.body(serialized, 200, {
769
- "Content-Type": contentTypeForEncoding(encoding)
770
- });
771
- }
772
- async function handleConnectionMessage(c, _runConfig, actorDriver, connId, connToken, actorId) {
773
- const encoding = getRequestEncoding(c.req);
774
- const arrayBuffer = await c.req.arrayBuffer();
775
- const message = deserializeWithEncoding(
776
- encoding,
777
- new Uint8Array(arrayBuffer),
778
- TO_SERVER_VERSIONED
779
- );
780
- const actor2 = await actorDriver.loadActor(actorId);
781
- const conn = actor2.conns.get(connId);
782
- if (!conn) {
783
- throw new ConnNotFound(connId);
784
- }
785
- if (conn._token !== connToken) {
786
- throw new IncorrectConnToken();
787
- }
788
- await actor2.processMessage(message, conn);
789
- return c.json({});
790
- }
791
- async function handleConnectionClose(c, _runConfig, actorDriver, connId, connToken, actorId) {
792
- var _a;
793
- const actor2 = await actorDriver.loadActor(actorId);
794
- const conn = actor2.conns.get(connId);
795
- if (!conn) {
796
- throw new ConnNotFound(connId);
797
- }
798
- if (conn._token !== connToken) {
799
- throw new IncorrectConnToken();
800
- }
801
- if (!((_a = conn.__socket) == null ? void 0 : _a.driverState) || !(1 /* SSE */ in conn.__socket.driverState)) {
802
- throw new UserError(
803
- "Connection close is only supported for SSE connections"
804
- );
805
- }
806
- await conn.disconnect("Connection closed by client request");
807
- return c.json({});
808
- }
809
- async function handleRawWebSocketHandler(req, path4, actorDriver, actorId, requestIdBuf) {
810
- const actor2 = await actorDriver.loadActor(actorId);
687
+ async function handleRawWebSocket(setWebSocket, { request, actor: actor2, closePromiseResolvers, conn }) {
811
688
  return {
812
- onOpen: (evt, ws) => {
813
- const rivetRequestId = evt == null ? void 0 : evt.rivetRequestId;
814
- const isHibernatable = actor2[PERSIST_SYMBOL].hibernatableWebSocket.findIndex(
815
- (ws2) => arrayBuffersEqual(ws2.requestId, rivetRequestId)
816
- ) !== -1;
817
- const adapter = new HonoWebSocketAdapter(
818
- ws,
819
- rivetRequestId,
820
- isHibernatable
821
- );
822
- ws.__adapter = adapter;
823
- const newPath = truncateRawWebSocketPathPrefix(path4);
824
- let newRequest;
825
- if (req) {
826
- newRequest = new Request(`http://actor${newPath}`, req);
827
- } else {
828
- newRequest = new Request(`http://actor${newPath}`, {
829
- method: "GET"
830
- });
831
- }
832
- actor2.rLog.debug({
833
- msg: "rewriting websocket url",
834
- fromPath: path4,
835
- toUrl: newRequest.url
836
- });
837
- actor2.handleWebSocket(adapter, {
838
- request: newRequest
839
- });
689
+ conn,
690
+ actor: actor2,
691
+ onRestore: (wsContext) => {
692
+ const ws = wsContext.raw;
693
+ invariant(ws, "missing wsContext.raw");
694
+ setWebSocket(ws);
695
+ },
696
+ // NOTE: onOpen cannot be async since this will cause the client's open
697
+ // event to be called before this completes. Do all async work in
698
+ // handleRawWebSocket root.
699
+ onOpen: (_evt, wsContext) => {
700
+ const ws = wsContext.raw;
701
+ invariant(ws, "missing wsContext.raw");
702
+ setWebSocket(ws);
703
+ actor2.connectionManager.connectConn(conn);
704
+ actor2.handleRawWebSocket(conn, ws, request);
840
705
  },
841
706
  onMessage: (event, ws) => {
842
707
  const adapter = ws.__adapter;
@@ -844,157 +709,53 @@ async function handleRawWebSocketHandler(req, path4, actorDriver, actorId, reque
844
709
  adapter._handleMessage(event);
845
710
  }
846
711
  },
847
- onClose: (evt, ws) => {
848
- const adapter = ws.__adapter;
849
- if (adapter) {
850
- adapter._handleClose((evt == null ? void 0 : evt.code) || 1006, (evt == null ? void 0 : evt.reason) || "");
851
- }
852
- },
853
- onError: (error, ws) => {
854
- const adapter = ws.__adapter;
855
- if (adapter) {
856
- adapter._handleError(error);
857
- }
858
- }
859
- };
860
- }
861
- function getRequestEncoding(req) {
862
- const encodingParam = req.header(HEADER_ENCODING);
863
- if (!encodingParam) {
864
- throw new InvalidEncoding("undefined");
865
- }
866
- const result = EncodingSchema.safeParse(encodingParam);
867
- if (!result.success) {
868
- throw new InvalidEncoding(encodingParam);
869
- }
870
- return result.data;
871
- }
872
- function getRequestExposeInternalError(_req) {
873
- return false;
874
- }
875
- function getRequestConnParams(req) {
876
- const paramsParam = req.header(HEADER_CONN_PARAMS);
877
- if (!paramsParam) {
878
- return null;
879
- }
880
- try {
881
- return JSON.parse(paramsParam);
882
- } catch (err) {
883
- throw new InvalidParams(
884
- `Invalid params JSON: ${stringifyError(err)}`
885
- );
886
- }
887
- }
888
- function truncateRawWebSocketPathPrefix(path4) {
889
- const url = new URL(path4, "http://actor");
890
- const pathname = url.pathname.replace(/^\/raw\/websocket\/?/, "") || "/";
891
- const normalizedPath = (pathname.startsWith("/") ? pathname : "/" + pathname) + url.search;
892
- return normalizedPath;
893
- }
894
-
895
- // src/common/router.ts
896
- import * as cbor2 from "cbor-x";
897
-
898
- // src/registry/config.ts
899
- import { z as z2 } from "zod";
900
- var ActorsSchema = z2.record(
901
- z2.string(),
902
- z2.custom()
903
- );
904
- var TestConfigSchema = z2.object({ enabled: z2.boolean() });
905
- var RegistryConfigSchema = z2.object({
906
- use: z2.record(z2.string(), z2.custom()),
907
- // TODO: Find a better way of passing around the test config
908
- /**
909
- * Test configuration.
910
- *
911
- * DO NOT MANUALLY ENABLE. THIS IS USED INTERNALLY.
912
- * @internal
913
- **/
914
- test: TestConfigSchema.optional().default({ enabled: false })
915
- });
916
- function buildActorNames(registryConfig) {
917
- return Object.fromEntries(
918
- Object.keys(registryConfig.use).map((name) => [name, { metadata: {} }])
919
- );
920
- }
921
-
922
- // src/common/router.ts
923
- function logger2() {
924
- return getLogger("router");
925
- }
926
- function loggerMiddleware(logger8) {
927
- return async (c, next) => {
928
- const method = c.req.method;
929
- const path4 = c.req.path;
930
- const startTime = Date.now();
931
- await next();
932
- const duration = Date.now() - startTime;
933
- logger8.debug({
934
- msg: "http request",
935
- method,
936
- path: path4,
937
- status: c.res.status,
938
- dt: `${duration}ms`,
939
- reqSize: c.req.header("content-length"),
940
- resSize: c.res.headers.get("content-length"),
941
- userAgent: c.req.header("user-agent"),
942
- ...getEnvUniversal("_RIVET_LOG_HEADERS") ? { allHeaders: JSON.stringify(c.req.header()) } : {}
943
- });
712
+ onClose: (evt, ws) => {
713
+ closePromiseResolvers.resolve();
714
+ conn.disconnect(evt == null ? void 0 : evt.reason);
715
+ },
716
+ onError: (error, ws) => {
717
+ }
944
718
  };
945
719
  }
946
- function handleRouteNotFound(c) {
947
- return c.text("Not Found (RivetKit)", 404);
948
- }
949
- function handleRouteError(error, c) {
950
- const exposeInternalError = getRequestExposeInternalError(c.req.raw);
951
- const { statusCode, group, code, message, metadata } = deconstructError(
952
- error,
953
- logger2(),
954
- {
955
- method: c.req.method,
956
- path: c.req.path
720
+ async function handleWebSocketInspectorConnect() {
721
+ return {
722
+ // NOTE: onOpen cannot be async since this messes up the open event listener order
723
+ onOpen: (_evt, ws) => {
724
+ ws.send("Hello world");
957
725
  },
958
- exposeInternalError
959
- );
960
- let encoding;
961
- try {
962
- encoding = getRequestEncoding(c.req);
963
- } catch (_) {
964
- encoding = "json";
965
- }
966
- const output = serializeWithEncoding(
967
- encoding,
968
- {
969
- group,
970
- code,
971
- message,
972
- // TODO: Cannot serialize non-binary meta since it requires ArrayBuffer atm
973
- metadata: encodingIsBinary(encoding) ? bufferToArrayBuffer(cbor2.encode(metadata)) : null
726
+ onMessage: (evt, ws) => {
727
+ ws.send("Pong");
974
728
  },
975
- HTTP_RESPONSE_ERROR_VERSIONED
976
- );
977
- return c.body(output, { status: statusCode });
978
- }
979
- function handleMetadataRequest(c, registryConfig, runConfig) {
980
- const response = {
981
- runtime: "rivetkit",
982
- version: VERSION,
983
- runner: {
984
- kind: runConfig.runnerKind === "serverless" ? { serverless: {} } : { normal: {} }
729
+ onClose: (event, ws) => {
985
730
  },
986
- actorNames: buildActorNames(registryConfig),
987
- // Do not return client endpoint if default server disabled
988
- clientEndpoint: runConfig.overrideServerAddress ?? (runConfig.disableDefaultServer ? void 0 : getEndpoint(runConfig))
731
+ onError: (_error) => {
732
+ }
989
733
  };
990
- return c.json(response);
991
734
  }
992
- function handleHealthRequest(c) {
993
- return c.json({
994
- status: "ok",
995
- runtime: "rivetkit",
996
- version: VERSION
997
- });
735
+ function parseWebSocketProtocols(protocols) {
736
+ let encodingRaw;
737
+ let connParamsRaw;
738
+ if (protocols) {
739
+ const protocolList = protocols.split(",").map((p) => p.trim());
740
+ for (const protocol of protocolList) {
741
+ if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
742
+ encodingRaw = protocol.substring(WS_PROTOCOL_ENCODING.length);
743
+ } else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
744
+ connParamsRaw = decodeURIComponent(
745
+ protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
746
+ );
747
+ }
748
+ }
749
+ }
750
+ const encoding = EncodingSchema.parse(encodingRaw);
751
+ const connParams = connParamsRaw ? JSON.parse(connParamsRaw) : void 0;
752
+ return { encoding, connParams };
753
+ }
754
+ function truncateRawWebSocketPathPrefix(path) {
755
+ const url = new URL(path, "http://actor");
756
+ const pathname = url.pathname.replace(/^\/websocket\/?/, "") || "/";
757
+ const normalizedPath = (pathname.startsWith("/") ? pathname : `/${pathname}`) + url.search;
758
+ return normalizedPath;
998
759
  }
999
760
 
1000
761
  // src/actor/router.ts
@@ -1005,11 +766,11 @@ function createActorRouter(runConfig, actorDriver, isTest) {
1005
766
  router.use("*", loggerMiddleware(loggerWithoutContext()));
1006
767
  router.use("*", async (c, next) => {
1007
768
  const actor2 = await actorDriver.loadActor(c.env.actorId);
1008
- actor2.__beginHonoHttpRequest();
769
+ actor2.beginHonoHttpRequest();
1009
770
  try {
1010
771
  await next();
1011
772
  } finally {
1012
- actor2.__endHonoHttpRequest();
773
+ actor2.endHonoHttpRequest();
1013
774
  }
1014
775
  });
1015
776
  router.get("/", (c) => {
@@ -1022,85 +783,55 @@ function createActorRouter(runConfig, actorDriver, isTest) {
1022
783
  });
1023
784
  if (isTest) {
1024
785
  router.post("/.test/force-disconnect", async (c) => {
786
+ var _a;
1025
787
  const connId = c.req.query("conn");
1026
788
  if (!connId) {
1027
789
  return c.text("Missing conn query parameter", 400);
1028
790
  }
1029
791
  const actor2 = await actorDriver.loadActor(c.env.actorId);
1030
- const conn = actor2.__getConnForId(connId);
792
+ const conn = actor2.connectionManager.getConnForId(connId);
1031
793
  if (!conn) {
1032
794
  return c.text(`Connection not found: ${connId}`, 404);
1033
795
  }
1034
- const driverState = conn.__driverState;
1035
- if (driverState && 0 /* WEBSOCKET */ in driverState) {
1036
- const ws = driverState[0 /* WEBSOCKET */].websocket;
1037
- ws.raw.terminate();
1038
- } else if (driverState && 1 /* SSE */ in driverState) {
1039
- const stream = driverState[1 /* SSE */].stream;
1040
- stream.abort();
796
+ if ((_a = conn[CONN_DRIVER_SYMBOL]) == null ? void 0 : _a.terminate) {
797
+ conn[CONN_DRIVER_SYMBOL].terminate(actor2, conn);
1041
798
  }
1042
799
  return c.json({ success: true });
1043
800
  });
1044
801
  }
1045
- router.get(PATH_CONNECT_WEBSOCKET, async (c) => {
1046
- var _a;
1047
- const upgradeWebSocket = (_a = runConfig.getUpgradeWebSocket) == null ? void 0 : _a.call(runConfig);
1048
- if (upgradeWebSocket) {
1049
- return upgradeWebSocket(async (c2) => {
1050
- const protocols = c2.req.header("sec-websocket-protocol");
1051
- let encodingRaw;
1052
- let connParamsRaw;
1053
- let connIdRaw;
1054
- let connTokenRaw;
1055
- if (protocols) {
1056
- const protocolList = protocols.split(",").map((p) => p.trim());
1057
- for (const protocol of protocolList) {
1058
- if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
1059
- encodingRaw = protocol.substring(
1060
- WS_PROTOCOL_ENCODING.length
1061
- );
1062
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
1063
- connParamsRaw = decodeURIComponent(
1064
- protocol.substring(
1065
- WS_PROTOCOL_CONN_PARAMS.length
1066
- )
1067
- );
1068
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_ID)) {
1069
- connIdRaw = protocol.substring(
1070
- WS_PROTOCOL_CONN_ID.length
1071
- );
1072
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_TOKEN)) {
1073
- connTokenRaw = protocol.substring(
1074
- WS_PROTOCOL_CONN_TOKEN.length
1075
- );
1076
- }
1077
- }
1078
- }
1079
- const encoding = EncodingSchema.parse(encodingRaw);
1080
- const connParams = connParamsRaw ? JSON.parse(connParamsRaw) : void 0;
1081
- return await handleWebSocketConnect(
1082
- c2.req.raw,
1083
- runConfig,
1084
- actorDriver,
1085
- c2.env.actorId,
1086
- encoding,
1087
- connParams,
1088
- generateConnRequestId(),
1089
- void 0,
1090
- connIdRaw,
1091
- connTokenRaw
802
+ router.on(
803
+ "GET",
804
+ [PATH_CONNECT, `${PATH_WEBSOCKET_PREFIX}*`, PATH_INSPECTOR_CONNECT],
805
+ async (c) => {
806
+ var _a;
807
+ const upgradeWebSocket = (_a = runConfig.getUpgradeWebSocket) == null ? void 0 : _a.call(runConfig);
808
+ if (upgradeWebSocket) {
809
+ return upgradeWebSocket(async (c2) => {
810
+ const protocols = c2.req.header("sec-websocket-protocol");
811
+ const { encoding, connParams } = parseWebSocketProtocols(protocols);
812
+ return await routeWebSocket(
813
+ c2.req.raw,
814
+ c2.req.path,
815
+ c2.req.header(),
816
+ runConfig,
817
+ actorDriver,
818
+ c2.env.actorId,
819
+ encoding,
820
+ connParams,
821
+ void 0,
822
+ void 0,
823
+ false,
824
+ false
825
+ );
826
+ })(c, noopNext());
827
+ } else {
828
+ return c.text(
829
+ "WebSockets are not enabled for this driver.",
830
+ 400
1092
831
  );
1093
- })(c, noopNext());
1094
- } else {
1095
- return c.text(
1096
- "WebSockets are not enabled for this driver. Use SSE instead.",
1097
- 400
1098
- );
832
+ }
1099
833
  }
1100
- });
1101
- router.get("/connect/sse", async (c) => {
1102
- return handleSseConnect(c, runConfig, actorDriver, c.env.actorId);
1103
- });
834
+ );
1104
835
  router.post("/action/:action", async (c) => {
1105
836
  const actionName = c.req.param("action");
1106
837
  return handleAction(
@@ -1111,40 +842,9 @@ function createActorRouter(runConfig, actorDriver, isTest) {
1111
842
  c.env.actorId
1112
843
  );
1113
844
  });
1114
- router.post("/connections/message", async (c) => {
1115
- const connId = c.req.header(HEADER_CONN_ID);
1116
- const connToken = c.req.header(HEADER_CONN_TOKEN);
1117
- if (!connId || !connToken) {
1118
- throw new Error("Missing required parameters");
1119
- }
1120
- return handleConnectionMessage(
1121
- c,
1122
- runConfig,
1123
- actorDriver,
1124
- connId,
1125
- connToken,
1126
- c.env.actorId
1127
- );
1128
- });
1129
- router.post("/connections/close", async (c) => {
1130
- const connId = c.req.header(HEADER_CONN_ID);
1131
- const connToken = c.req.header(HEADER_CONN_TOKEN);
1132
- if (!connId || !connToken) {
1133
- throw new Error("Missing required parameters");
1134
- }
1135
- return handleConnectionClose(
1136
- c,
1137
- runConfig,
1138
- actorDriver,
1139
- connId,
1140
- connToken,
1141
- c.env.actorId
1142
- );
1143
- });
1144
- router.all("/raw/http/*", async (c) => {
1145
- const actor2 = await actorDriver.loadActor(c.env.actorId);
845
+ router.all("/request/*", async (c) => {
1146
846
  const url = new URL(c.req.url);
1147
- const originalPath = url.pathname.replace(/^\/raw\/http/, "") || "/";
847
+ const originalPath = url.pathname.replace(/^\/request/, "") || "/";
1148
848
  const correctedUrl = new URL(originalPath + url.search, url.origin);
1149
849
  const correctedRequest = new Request(correctedUrl, {
1150
850
  method: c.req.method,
@@ -1157,40 +857,12 @@ function createActorRouter(runConfig, actorDriver, isTest) {
1157
857
  from: c.req.url,
1158
858
  to: correctedRequest.url
1159
859
  });
1160
- const response = await actor2.handleFetch(correctedRequest, {});
1161
- if (!response) {
1162
- throw new InternalError("handleFetch returned void unexpectedly");
1163
- }
1164
- return response;
1165
- });
1166
- router.get(`${PATH_RAW_WEBSOCKET_PREFIX}*`, async (c) => {
1167
- var _a;
1168
- const upgradeWebSocket = (_a = runConfig.getUpgradeWebSocket) == null ? void 0 : _a.call(runConfig);
1169
- if (upgradeWebSocket) {
1170
- return upgradeWebSocket(async (c2) => {
1171
- const url = new URL(c2.req.url);
1172
- const pathWithQuery = c2.req.path + url.search;
1173
- loggerWithoutContext().debug({
1174
- msg: "actor router raw websocket",
1175
- path: c2.req.path,
1176
- url: c2.req.url,
1177
- search: url.search,
1178
- pathWithQuery
1179
- });
1180
- return await handleRawWebSocketHandler(
1181
- c2.req.raw,
1182
- pathWithQuery,
1183
- actorDriver,
1184
- c2.env.actorId,
1185
- void 0
1186
- );
1187
- })(c, noopNext());
1188
- } else {
1189
- return c.text(
1190
- "WebSockets are not enabled for this driver. Use SSE instead.",
1191
- 400
1192
- );
1193
- }
860
+ return await handleRawRequest(
861
+ c,
862
+ correctedRequest,
863
+ actorDriver,
864
+ c.env.actorId
865
+ );
1194
866
  });
1195
867
  if (isInspectorEnabled(runConfig, "actor")) {
1196
868
  router.route(
@@ -1217,12 +889,12 @@ function actor(input) {
1217
889
  return new ActorDefinition(config2);
1218
890
  }
1219
891
 
1220
- // src/common/inline-websocket-adapter2.ts
892
+ // src/common/inline-websocket-adapter.ts
1221
893
  import { WSContext } from "hono/ws";
1222
- function logger3() {
894
+ function logger2() {
1223
895
  return getLogger("fake-event-source2");
1224
896
  }
1225
- var InlineWebSocketAdapter2 = class {
897
+ var InlineWebSocketAdapter = class {
1226
898
  // WebSocket readyState values
1227
899
  CONNECTING = 0;
1228
900
  OPEN = 1;
@@ -1234,27 +906,26 @@ var InlineWebSocketAdapter2 = class {
1234
906
  #readyState = 0;
1235
907
  // Start in CONNECTING state
1236
908
  #queuedMessages = [];
1237
- // Event buffering is needed since events can be fired
1238
- // before JavaScript has a chance to add event listeners (e.g. within the same tick)
1239
- #bufferedEvents = [];
1240
- // Event listeners with buffering
909
+ // Event listeners
1241
910
  #eventListeners = /* @__PURE__ */ new Map();
1242
911
  constructor(handler) {
1243
912
  this.#handler = handler;
1244
913
  this.#wsContext = new WSContext({
1245
914
  raw: this,
1246
915
  send: (data) => {
1247
- logger3().debug({ msg: "WSContext.send called" });
916
+ logger2().debug({ msg: "WSContext.send called" });
1248
917
  this.#handleMessage(data);
1249
918
  },
1250
919
  close: (code, reason) => {
1251
- logger3().debug({ msg: "WSContext.close called", code, reason });
920
+ logger2().debug({ msg: "WSContext.close called", code, reason });
1252
921
  this.#handleClose(code || 1e3, reason || "");
1253
922
  },
1254
923
  // Set readyState to 1 (OPEN) since handlers expect an open connection
1255
924
  readyState: 1
1256
925
  });
1257
- this.#initialize();
926
+ setTimeout(() => {
927
+ this.#initialize();
928
+ }, 0);
1258
929
  }
1259
930
  get readyState() {
1260
931
  return this.#readyState;
@@ -1277,17 +948,18 @@ var InlineWebSocketAdapter2 = class {
1277
948
  return "";
1278
949
  }
1279
950
  send(data) {
1280
- logger3().debug({ msg: "send called", readyState: this.readyState });
1281
- if (this.readyState !== this.OPEN) {
1282
- const error = new Error("WebSocket is not open");
1283
- logger3().warn({
1284
- msg: "cannot send message, websocket not open",
1285
- readyState: this.readyState,
1286
- dataType: typeof data,
1287
- dataLength: typeof data === "string" ? data.length : "binary",
1288
- error
951
+ logger2().debug({ msg: "send called", readyState: this.readyState });
952
+ if (this.readyState === this.CONNECTING) {
953
+ throw new DOMException(
954
+ "WebSocket is still in CONNECTING state",
955
+ "InvalidStateError"
956
+ );
957
+ }
958
+ if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {
959
+ logger2().debug({
960
+ msg: "ignoring send, websocket is closing or closed",
961
+ readyState: this.readyState
1289
962
  });
1290
- this.#fireError(error);
1291
963
  return;
1292
964
  }
1293
965
  this.#handler.onMessage({ data }, this.#wsContext);
@@ -1299,7 +971,7 @@ var InlineWebSocketAdapter2 = class {
1299
971
  if (this.readyState === this.CLOSED || this.readyState === this.CLOSING) {
1300
972
  return;
1301
973
  }
1302
- logger3().debug({ msg: "closing fake websocket", code, reason });
974
+ logger2().debug({ msg: "closing fake websocket", code, reason });
1303
975
  this.#readyState = this.CLOSING;
1304
976
  try {
1305
977
  this.#handler.onClose(
@@ -1307,7 +979,7 @@ var InlineWebSocketAdapter2 = class {
1307
979
  this.#wsContext
1308
980
  );
1309
981
  } catch (err) {
1310
- logger3().error({ msg: "error closing websocket", error: err });
982
+ logger2().error({ msg: "error closing websocket", error: err });
1311
983
  } finally {
1312
984
  this.#readyState = this.CLOSED;
1313
985
  const closeEvent = {
@@ -1326,31 +998,31 @@ var InlineWebSocketAdapter2 = class {
1326
998
  */
1327
999
  async #initialize() {
1328
1000
  try {
1329
- logger3().debug({ msg: "fake websocket initializing" });
1330
- logger3().debug({ msg: "calling handler.onOpen with WSContext" });
1001
+ logger2().debug({ msg: "fake websocket initializing" });
1002
+ logger2().debug({ msg: "calling handler.onOpen with WSContext" });
1331
1003
  this.#handler.onOpen(void 0, this.#wsContext);
1332
1004
  this.#readyState = this.OPEN;
1333
- logger3().debug({ msg: "fake websocket initialized and now OPEN" });
1005
+ logger2().debug({ msg: "fake websocket initialized and now OPEN" });
1334
1006
  this.#fireOpen();
1335
1007
  if (this.#queuedMessages.length > 0) {
1336
1008
  if (this.readyState !== this.OPEN) {
1337
- logger3().warn({
1009
+ logger2().warn({
1338
1010
  msg: "socket no longer open, dropping queued messages"
1339
1011
  });
1340
1012
  return;
1341
1013
  }
1342
- logger3().debug({
1014
+ logger2().debug({
1343
1015
  msg: `now processing ${this.#queuedMessages.length} queued messages`
1344
1016
  });
1345
1017
  const messagesToProcess = [...this.#queuedMessages];
1346
1018
  this.#queuedMessages = [];
1347
1019
  for (const message of messagesToProcess) {
1348
- logger3().debug({ msg: "processing queued message" });
1020
+ logger2().debug({ msg: "processing queued message" });
1349
1021
  this.#handleMessage(message);
1350
1022
  }
1351
1023
  }
1352
1024
  } catch (err) {
1353
- logger3().error({
1025
+ logger2().error({
1354
1026
  msg: "error opening fake websocket",
1355
1027
  error: err,
1356
1028
  errorMessage: err instanceof Error ? err.message : String(err),
@@ -1365,7 +1037,7 @@ var InlineWebSocketAdapter2 = class {
1365
1037
  */
1366
1038
  #handleMessage(data) {
1367
1039
  if (this.readyState !== this.OPEN) {
1368
- logger3().debug({
1040
+ logger2().debug({
1369
1041
  msg: "message received before socket is OPEN, queuing",
1370
1042
  readyState: this.readyState,
1371
1043
  dataType: typeof data,
@@ -1374,7 +1046,7 @@ var InlineWebSocketAdapter2 = class {
1374
1046
  this.#queuedMessages.push(data);
1375
1047
  return;
1376
1048
  }
1377
- logger3().debug({
1049
+ logger2().debug({
1378
1050
  msg: "fake websocket received message from server",
1379
1051
  dataType: typeof data,
1380
1052
  dataLength: typeof data === "string" ? data.length : data instanceof ArrayBuffer ? data.byteLength : data instanceof Uint8Array ? data.byteLength : "unknown"
@@ -1405,7 +1077,6 @@ var InlineWebSocketAdapter2 = class {
1405
1077
  this.#eventListeners.set(type, []);
1406
1078
  }
1407
1079
  this.#eventListeners.get(type).push(listener);
1408
- this.#flushBufferedEvents(type);
1409
1080
  }
1410
1081
  removeEventListener(type, listener) {
1411
1082
  const listeners = this.#eventListeners.get(type);
@@ -1419,24 +1090,19 @@ var InlineWebSocketAdapter2 = class {
1419
1090
  #dispatchEvent(type, event) {
1420
1091
  const listeners = this.#eventListeners.get(type);
1421
1092
  if (listeners && listeners.length > 0) {
1422
- logger3().debug(
1093
+ logger2().debug(
1423
1094
  `dispatching ${type} event to ${listeners.length} listeners`
1424
1095
  );
1425
1096
  for (const listener of listeners) {
1426
1097
  try {
1427
1098
  listener(event);
1428
1099
  } catch (err) {
1429
- logger3().error({
1100
+ logger2().error({
1430
1101
  msg: `error in ${type} event listener`,
1431
1102
  error: err
1432
1103
  });
1433
1104
  }
1434
1105
  }
1435
- } else {
1436
- logger3().debug({
1437
- msg: `no ${type} listeners registered, buffering event`
1438
- });
1439
- this.#bufferedEvents.push({ type, event });
1440
1106
  }
1441
1107
  switch (type) {
1442
1108
  case "open":
@@ -1444,7 +1110,7 @@ var InlineWebSocketAdapter2 = class {
1444
1110
  try {
1445
1111
  this.#onopen(event);
1446
1112
  } catch (error) {
1447
- logger3().error({
1113
+ logger2().error({
1448
1114
  msg: "error in onopen handler",
1449
1115
  error
1450
1116
  });
@@ -1456,7 +1122,7 @@ var InlineWebSocketAdapter2 = class {
1456
1122
  try {
1457
1123
  this.#onclose(event);
1458
1124
  } catch (error) {
1459
- logger3().error({
1125
+ logger2().error({
1460
1126
  msg: "error in onclose handler",
1461
1127
  error
1462
1128
  });
@@ -1468,7 +1134,7 @@ var InlineWebSocketAdapter2 = class {
1468
1134
  try {
1469
1135
  this.#onerror(event);
1470
1136
  } catch (error) {
1471
- logger3().error({
1137
+ logger2().error({
1472
1138
  msg: "error in onerror handler",
1473
1139
  error
1474
1140
  });
@@ -1480,7 +1146,7 @@ var InlineWebSocketAdapter2 = class {
1480
1146
  try {
1481
1147
  this.#onmessage(event);
1482
1148
  } catch (error) {
1483
- logger3().error({
1149
+ logger2().error({
1484
1150
  msg: "error in onmessage handler",
1485
1151
  error
1486
1152
  });
@@ -1493,17 +1159,6 @@ var InlineWebSocketAdapter2 = class {
1493
1159
  this.#dispatchEvent(event.type, event);
1494
1160
  return true;
1495
1161
  }
1496
- #flushBufferedEvents(type) {
1497
- const eventsToFlush = this.#bufferedEvents.filter(
1498
- (buffered) => buffered.type === type
1499
- );
1500
- this.#bufferedEvents = this.#bufferedEvents.filter(
1501
- (buffered) => buffered.type !== type
1502
- );
1503
- for (const { event } of eventsToFlush) {
1504
- this.#dispatchEvent(type, event);
1505
- }
1506
- }
1507
1162
  #fireOpen() {
1508
1163
  try {
1509
1164
  const event = {
@@ -1513,14 +1168,14 @@ var InlineWebSocketAdapter2 = class {
1513
1168
  };
1514
1169
  this.#dispatchEvent("open", event);
1515
1170
  } catch (err) {
1516
- logger3().error({ msg: "error in open event", error: err });
1171
+ logger2().error({ msg: "error in open event", error: err });
1517
1172
  }
1518
1173
  }
1519
1174
  #fireClose(event) {
1520
1175
  try {
1521
1176
  this.#dispatchEvent("close", event);
1522
1177
  } catch (err) {
1523
- logger3().error({ msg: "error in close event", error: err });
1178
+ logger2().error({ msg: "error in close event", error: err });
1524
1179
  }
1525
1180
  }
1526
1181
  #fireError(error) {
@@ -1534,9 +1189,9 @@ var InlineWebSocketAdapter2 = class {
1534
1189
  };
1535
1190
  this.#dispatchEvent("error", event);
1536
1191
  } catch (err) {
1537
- logger3().error({ msg: "error in error event", error: err });
1192
+ logger2().error({ msg: "error in error event", error: err });
1538
1193
  }
1539
- logger3().error({ msg: "websocket error", error });
1194
+ logger2().error({ msg: "websocket error", error });
1540
1195
  }
1541
1196
  // Event handler properties with getters/setters
1542
1197
  #onopen = null;
@@ -1570,24 +1225,21 @@ var InlineWebSocketAdapter2 = class {
1570
1225
  };
1571
1226
 
1572
1227
  // src/drivers/engine/actor-driver.ts
1573
- import { Runner } from "@rivetkit/engine-runner";
1228
+ import { idToStr, Runner } from "@rivetkit/engine-runner";
1574
1229
  import * as cbor3 from "cbor-x";
1575
- import { streamSSE as streamSSE2 } from "hono/streaming";
1230
+ import { streamSSE } from "hono/streaming";
1576
1231
  import { WSContext as WSContext2 } from "hono/ws";
1577
1232
  import invariant3 from "invariant";
1578
1233
 
1579
- // src/drivers/engine/kv.ts
1580
- var KEYS = {
1581
- PERSIST_DATA: Uint8Array.from([1])
1582
- };
1583
-
1584
1234
  // src/drivers/engine/log.ts
1585
- function logger4() {
1235
+ function logger3() {
1586
1236
  return getLogger("driver-engine");
1587
1237
  }
1588
1238
 
1589
1239
  // src/drivers/engine/actor-driver.ts
1590
1240
  var RUNNER_SSE_PING_INTERVAL = 1e3;
1241
+ var CONN_MESSAGE_ACK_DEADLINE = 5e3;
1242
+ var CONN_BUFFERED_MESSAGE_SIZE_THRESHOLD = 5e5;
1591
1243
  var EngineActorDriver = class {
1592
1244
  #registryConfig;
1593
1245
  #runConfig;
@@ -1602,9 +1254,23 @@ var EngineActorDriver = class {
1602
1254
  #runnerStarted = promiseWithResolvers();
1603
1255
  #runnerStopped = promiseWithResolvers();
1604
1256
  #isRunnerStopped = false;
1605
- // WebSocket message acknowledgment debouncing
1606
- #wsAckQueue = /* @__PURE__ */ new Map();
1607
- #wsAckFlushInterval;
1257
+ // HACK: Track actor stop intent locally since the runner protocol doesn't
1258
+ // pass the stop reason to onActorStop. This will be fixed when the runner
1259
+ // protocol is updated to send the intent directly (see RVT-5284)
1260
+ #actorStopIntent = /* @__PURE__ */ new Map();
1261
+ // Map of conn IDs to message index waiting to be persisted before sending
1262
+ // an ack
1263
+ //
1264
+ // serverMessageIndex is updated and pendingAck is flagged in needed in
1265
+ // onBeforePersistConnect, then the HWS ack message is sent in
1266
+ // onAfterPersistConn. This allows us to track what's about to be written
1267
+ // to storage to prevent race conditions with the serverMessageIndex being
1268
+ // updated while writing the existing state.
1269
+ //
1270
+ // bufferedMessageSize tracks the total bytes received since last persist
1271
+ // to force a saveState when threshold is reached. This is the amount of
1272
+ // data currently buffered on the gateway.
1273
+ #hwsMessageIndex = /* @__PURE__ */ new Map();
1608
1274
  constructor(registryConfig, runConfig, managerDriver, inlineClient) {
1609
1275
  this.#registryConfig = registryConfig;
1610
1276
  this.#runConfig = runConfig;
@@ -1642,147 +1308,24 @@ var EngineActorDriver = class {
1642
1308
  },
1643
1309
  fetch: this.#runnerFetch.bind(this),
1644
1310
  websocket: this.#runnerWebSocket.bind(this),
1311
+ hibernatableWebSocket: {
1312
+ canHibernate: this.#hwsCanHibernate.bind(this)
1313
+ },
1645
1314
  onActorStart: this.#runnerOnActorStart.bind(this),
1646
1315
  onActorStop: this.#runnerOnActorStop.bind(this),
1647
- logger: getLogger("engine-runner"),
1648
- getActorHibernationConfig: (actorId, requestId, request) => {
1649
- var _a;
1650
- const url = new URL(request.url);
1651
- const path4 = url.pathname;
1652
- const actorInstance = this.#runner.getActor(actorId);
1653
- if (!actorInstance) {
1654
- logger4().warn({
1655
- msg: "actor not found in getActorHibernationConfig",
1656
- actorId
1657
- });
1658
- return { enabled: false, lastMsgIndex: void 0 };
1659
- }
1660
- const handler = this.#actors.get(actorId);
1661
- if (!handler) {
1662
- logger4().warn({
1663
- msg: "actor handler not found in getActorHibernationConfig",
1664
- actorId
1665
- });
1666
- return { enabled: false, lastMsgIndex: void 0 };
1667
- }
1668
- if (!handler.actor) {
1669
- logger4().warn({
1670
- msg: "actor not found in getActorHibernationConfig",
1671
- actorId
1672
- });
1673
- return { enabled: false, lastMsgIndex: void 0 };
1674
- }
1675
- const hibernatableArray = handler.actor[PERSIST_SYMBOL].hibernatableWebSocket;
1676
- logger4().debug({
1677
- msg: "checking hibernatable websockets",
1678
- requestId: idToStr(requestId),
1679
- existingHibernatableWebSockets: hibernatableArray.length
1680
- });
1681
- const existingWs = hibernatableArray.find(
1682
- (ws) => arrayBuffersEqual(ws.requestId, requestId)
1683
- );
1684
- let hibernationConfig;
1685
- if (existingWs) {
1686
- logger4().debug({
1687
- msg: "found existing hibernatable websocket",
1688
- requestId: idToStr(requestId),
1689
- lastMsgIndex: existingWs.msgIndex
1690
- });
1691
- hibernationConfig = {
1692
- enabled: true,
1693
- lastMsgIndex: Number(existingWs.msgIndex)
1694
- };
1695
- } else {
1696
- logger4().debug({
1697
- msg: "no existing hibernatable websocket found",
1698
- requestId: idToStr(requestId)
1699
- });
1700
- if (path4 === PATH_CONNECT_WEBSOCKET) {
1701
- hibernationConfig = {
1702
- enabled: true,
1703
- lastMsgIndex: void 0
1704
- };
1705
- } else if (path4.startsWith(PATH_RAW_WEBSOCKET_PREFIX)) {
1706
- const definition = lookupInRegistry(
1707
- this.#registryConfig,
1708
- actorInstance.config.name
1709
- );
1710
- const canHibernatWebSocket = (_a = definition.config.options) == null ? void 0 : _a.canHibernatWebSocket;
1711
- if (canHibernatWebSocket === true) {
1712
- hibernationConfig = {
1713
- enabled: true,
1714
- lastMsgIndex: void 0
1715
- };
1716
- } else if (typeof canHibernatWebSocket === "function") {
1717
- try {
1718
- const newPath = truncateRawWebSocketPathPrefix(
1719
- url.pathname
1720
- );
1721
- const truncatedRequest = new Request(
1722
- `http://actor${newPath}`,
1723
- request
1724
- );
1725
- const canHibernate = canHibernatWebSocket(truncatedRequest);
1726
- hibernationConfig = {
1727
- enabled: canHibernate,
1728
- lastMsgIndex: void 0
1729
- };
1730
- } catch (error) {
1731
- logger4().error({
1732
- msg: "error calling canHibernatWebSocket",
1733
- error
1734
- });
1735
- hibernationConfig = {
1736
- enabled: false,
1737
- lastMsgIndex: void 0
1738
- };
1739
- }
1740
- } else {
1741
- hibernationConfig = {
1742
- enabled: false,
1743
- lastMsgIndex: void 0
1744
- };
1745
- }
1746
- } else {
1747
- logger4().warn({
1748
- msg: "unexpected path for getActorHibernationConfig",
1749
- path: path4
1750
- });
1751
- hibernationConfig = {
1752
- enabled: false,
1753
- lastMsgIndex: void 0
1754
- };
1755
- }
1756
- }
1757
- if (existingWs) {
1758
- logger4().debug({
1759
- msg: "updated existing hibernatable websocket timestamp",
1760
- requestId: idToStr(requestId)
1761
- });
1762
- existingWs.lastSeenTimestamp = BigInt(Date.now());
1763
- } else {
1764
- logger4().debug({
1765
- msg: "created new hibernatable websocket entry",
1766
- requestId: idToStr(requestId)
1767
- });
1768
- handler.actor[PERSIST_SYMBOL].hibernatableWebSocket.push({
1769
- requestId,
1770
- lastSeenTimestamp: BigInt(Date.now()),
1771
- msgIndex: -1n
1772
- });
1773
- }
1774
- return hibernationConfig;
1775
- }
1316
+ logger: getLogger("engine-runner")
1776
1317
  };
1777
1318
  this.#runner = new Runner(engineRunnerConfig);
1778
1319
  this.#runner.start();
1779
- logger4().debug({
1320
+ logger3().debug({
1780
1321
  msg: "engine runner started",
1781
1322
  endpoint: runConfig.endpoint,
1782
1323
  namespace: runConfig.namespace,
1783
1324
  runnerName: runConfig.runnerName
1784
1325
  });
1785
- this.#wsAckFlushInterval = setInterval(() => this.#flushWsAcks(), 1e3);
1326
+ }
1327
+ getExtraActorLogParams() {
1328
+ return { runnerId: this.#runner.runnerId ?? "-" };
1786
1329
  }
1787
1330
  async #loadActorHandler(actorId) {
1788
1331
  const handler = this.#actors.get(actorId);
@@ -1792,40 +1335,9 @@ var EngineActorDriver = class {
1792
1335
  if (!handler.actor) throw new Error("Actor should be loaded");
1793
1336
  return handler;
1794
1337
  }
1795
- async loadActor(actorId) {
1796
- const handler = await this.#loadActorHandler(actorId);
1797
- if (!handler.actor) throw new Error(`Actor ${actorId} failed to load`);
1798
- return handler.actor;
1799
- }
1800
- #flushWsAcks() {
1801
- if (this.#wsAckQueue.size === 0) return;
1802
- for (const {
1803
- requestIdBuf: requestId,
1804
- messageIndex: index
1805
- } of this.#wsAckQueue.values()) {
1806
- this.#runner.sendWebsocketMessageAck(requestId, index);
1807
- }
1808
- this.#wsAckQueue.clear();
1809
- }
1810
1338
  getContext(actorId) {
1811
1339
  return {};
1812
1340
  }
1813
- async readPersistedData(actorId) {
1814
- const handler = this.#actors.get(actorId);
1815
- if (!handler) throw new Error(`Actor ${actorId} not loaded`);
1816
- return handler.persistedData;
1817
- }
1818
- async writePersistedData(actorId, data) {
1819
- const handler = this.#actors.get(actorId);
1820
- if (!handler) throw new Error(`Actor ${actorId} not loaded`);
1821
- handler.persistedData = data;
1822
- logger4().debug({
1823
- msg: "writing persisted data for actor",
1824
- actorId,
1825
- dataSize: data.byteLength
1826
- });
1827
- await this.#runner.kvPut(actorId, [[KEYS.PERSIST_DATA, data]]);
1828
- }
1829
1341
  async setAlarm(actor2, timestamp) {
1830
1342
  if (this.#alarmTimeout) {
1831
1343
  this.#alarmTimeout.abort();
@@ -1833,7 +1345,7 @@ var EngineActorDriver = class {
1833
1345
  }
1834
1346
  const delay = Math.max(0, timestamp - Date.now());
1835
1347
  this.#alarmTimeout = setLongTimeout(() => {
1836
- actor2._onAlarm();
1348
+ actor2.onAlarm();
1837
1349
  this.#alarmTimeout = void 0;
1838
1350
  }, delay);
1839
1351
  this.#runner.setAlarm(actor2.id, timestamp);
@@ -1841,10 +1353,114 @@ var EngineActorDriver = class {
1841
1353
  async getDatabase(_actorId) {
1842
1354
  return void 0;
1843
1355
  }
1844
- // Runner lifecycle callbacks
1356
+ // MARK: - Batch KV operations
1357
+ async kvBatchPut(actorId, entries) {
1358
+ await this.#runner.kvPut(actorId, entries);
1359
+ }
1360
+ async kvBatchGet(actorId, keys) {
1361
+ return await this.#runner.kvGet(actorId, keys);
1362
+ }
1363
+ async kvBatchDelete(actorId, keys) {
1364
+ await this.#runner.kvDelete(actorId, keys);
1365
+ }
1366
+ async kvList(actorId) {
1367
+ const entries = await this.#runner.kvListPrefix(
1368
+ actorId,
1369
+ new Uint8Array()
1370
+ );
1371
+ const keys = entries.map(([key]) => key);
1372
+ logger3().info({
1373
+ msg: "kvList called",
1374
+ actorId,
1375
+ keysCount: keys.length,
1376
+ keys: keys.map((k) => new TextDecoder().decode(k))
1377
+ });
1378
+ return keys;
1379
+ }
1380
+ async kvListPrefix(actorId, prefix) {
1381
+ const result = await this.#runner.kvListPrefix(actorId, prefix);
1382
+ logger3().info({
1383
+ msg: "kvListPrefix called",
1384
+ actorId,
1385
+ prefixStr: new TextDecoder().decode(prefix),
1386
+ entriesCount: result.length,
1387
+ keys: result.map(([key]) => new TextDecoder().decode(key))
1388
+ });
1389
+ return result;
1390
+ }
1391
+ // MARK: - Actor Lifecycle
1392
+ async loadActor(actorId) {
1393
+ const handler = await this.#loadActorHandler(actorId);
1394
+ if (!handler.actor) throw new Error(`Actor ${actorId} failed to load`);
1395
+ return handler.actor;
1396
+ }
1397
+ startSleep(actorId) {
1398
+ this.#actorStopIntent.set(actorId, "sleep");
1399
+ this.#runner.sleepActor(actorId);
1400
+ }
1401
+ startDestroy(actorId) {
1402
+ this.#actorStopIntent.set(actorId, "destroy");
1403
+ this.#runner.stopActor(actorId);
1404
+ }
1405
+ async shutdownRunner(immediate) {
1406
+ logger3().info({ msg: "stopping engine actor driver", immediate });
1407
+ logger3().debug({
1408
+ msg: "stopping all actors before shutdown",
1409
+ actorCount: this.#actors.size
1410
+ });
1411
+ const stopPromises = [];
1412
+ for (const [_actorId, handler] of this.#actors.entries()) {
1413
+ if (handler.actor) {
1414
+ stopPromises.push(
1415
+ handler.actor.onStop("sleep").catch((err) => {
1416
+ var _a;
1417
+ (_a = handler.actor) == null ? void 0 : _a.rLog.error({
1418
+ msg: "onStop errored",
1419
+ error: stringifyError(err)
1420
+ });
1421
+ })
1422
+ );
1423
+ }
1424
+ }
1425
+ await Promise.all(stopPromises);
1426
+ logger3().debug({ msg: "all actors stopped" });
1427
+ await this.#runner.shutdown(immediate);
1428
+ }
1429
+ async serverlessHandleStart(c) {
1430
+ return streamSSE(c, async (stream) => {
1431
+ stream.onAbort(() => {
1432
+ });
1433
+ c.req.raw.signal.addEventListener("abort", () => {
1434
+ logger3().debug("SSE aborted, shutting down runner");
1435
+ this.shutdownRunner(false);
1436
+ });
1437
+ await this.#runnerStarted.promise;
1438
+ const payload = this.#runner.getServerlessInitPacket();
1439
+ invariant3(payload, "runnerId not set");
1440
+ await stream.writeSSE({ data: payload });
1441
+ while (true) {
1442
+ if (this.#isRunnerStopped) {
1443
+ logger3().debug({
1444
+ msg: "runner is stopped"
1445
+ });
1446
+ break;
1447
+ }
1448
+ if (stream.closed || stream.aborted) {
1449
+ logger3().debug({
1450
+ msg: "runner sse stream closed",
1451
+ closed: stream.closed,
1452
+ aborted: stream.aborted
1453
+ });
1454
+ break;
1455
+ }
1456
+ await stream.writeSSE({ event: "ping", data: "" });
1457
+ await stream.sleep(RUNNER_SSE_PING_INTERVAL);
1458
+ }
1459
+ await this.#runnerStopped.promise;
1460
+ });
1461
+ }
1845
1462
  async #runnerOnActorStart(actorId, generation, actorConfig) {
1846
- var _a, _b;
1847
- logger4().debug({
1463
+ logger3().debug({
1848
1464
  msg: "runner actor starting",
1849
1465
  actorId,
1850
1466
  name: actorConfig.name,
@@ -1858,24 +1474,30 @@ var EngineActorDriver = class {
1858
1474
  let handler = this.#actors.get(actorId);
1859
1475
  if (!handler) {
1860
1476
  handler = {
1861
- actorStartPromise: promiseWithResolvers(),
1862
- persistedData: void 0
1477
+ actorStartPromise: promiseWithResolvers()
1863
1478
  };
1864
1479
  this.#actors.set(actorId, handler);
1865
- const [persistedValue] = await this.#runner.kvGet(actorId, [
1866
- KEYS.PERSIST_DATA
1867
- ]);
1868
- handler.persistedData = persistedValue !== null ? persistedValue : serializeEmptyPersistData(input);
1869
- logger4().debug({
1870
- msg: "loaded persisted data for actor",
1871
- actorId,
1872
- dataSize: (_a = handler.persistedData) == null ? void 0 : _a.byteLength,
1873
- wasInStorage: persistedValue !== null
1874
- });
1875
1480
  }
1876
1481
  const name = actorConfig.name;
1877
1482
  invariant3(actorConfig.key, "actor should have a key");
1878
1483
  const key = deserializeActorKey(actorConfig.key);
1484
+ const [persistDataBuffer] = await this.#runner.kvGet(actorId, [
1485
+ KEYS.PERSIST_DATA
1486
+ ]);
1487
+ if (persistDataBuffer === null) {
1488
+ const initialKvState = getInitialActorKvState(input);
1489
+ await this.#runner.kvPut(actorId, initialKvState);
1490
+ logger3().debug({
1491
+ msg: "initialized persist data for new actor",
1492
+ actorId
1493
+ });
1494
+ } else {
1495
+ logger3().debug({
1496
+ msg: "found existing persist data for actor",
1497
+ actorId,
1498
+ dataSize: persistDataBuffer.byteLength
1499
+ });
1500
+ }
1879
1501
  const definition = lookupInRegistry(
1880
1502
  this.#registryConfig,
1881
1503
  actorConfig.name
@@ -1890,28 +1512,29 @@ var EngineActorDriver = class {
1890
1512
  "unknown"
1891
1513
  // TODO: Add regions
1892
1514
  );
1893
- (_b = handler.actorStartPromise) == null ? void 0 : _b.resolve();
1894
- handler.actorStartPromise = void 0;
1895
- logger4().debug({ msg: "runner actor started", actorId, name, key });
1515
+ logger3().debug({ msg: "runner actor started", actorId, name, key });
1896
1516
  }
1897
1517
  async #runnerOnActorStop(actorId, generation) {
1898
- logger4().debug({ msg: "runner actor stopping", actorId, generation });
1518
+ logger3().debug({ msg: "runner actor stopping", actorId, generation });
1519
+ const reason = this.#actorStopIntent.get(actorId) ?? "sleep";
1520
+ this.#actorStopIntent.delete(actorId);
1899
1521
  const handler = this.#actors.get(actorId);
1900
1522
  if (handler == null ? void 0 : handler.actor) {
1901
1523
  try {
1902
- await handler.actor._onStop();
1524
+ await handler.actor.onStop(reason);
1903
1525
  } catch (err) {
1904
- logger4().error({
1905
- msg: "error in _onStop, proceeding with removing actor",
1526
+ logger3().error({
1527
+ msg: "error in onStop, proceeding with removing actor",
1906
1528
  err: stringifyError(err)
1907
1529
  });
1908
1530
  }
1909
1531
  this.#actors.delete(actorId);
1910
1532
  }
1911
- logger4().debug({ msg: "runner actor stopped", actorId });
1533
+ logger3().debug({ msg: "runner actor stopped", actorId, reason });
1912
1534
  }
1913
- async #runnerFetch(_runner, actorId, _requestIdBuf, request) {
1914
- logger4().debug({
1535
+ // MARK: - Runner Networking
1536
+ async #runnerFetch(_runner, actorId, _gatewayIdBuf, _requestIdBuf, request) {
1537
+ logger3().debug({
1915
1538
  msg: "runner fetch",
1916
1539
  actorId,
1917
1540
  url: request.url,
@@ -1919,183 +1542,302 @@ var EngineActorDriver = class {
1919
1542
  });
1920
1543
  return await this.#actorRouter.fetch(request, { actorId });
1921
1544
  }
1922
- async #runnerWebSocket(_runner, actorId, websocketRaw, requestIdBuf, request) {
1545
+ async #runnerWebSocket(_runner, actorId, websocketRaw, gatewayIdBuf, requestIdBuf, request, requestPath, requestHeaders, isHibernatable, isRestoringHibernatable) {
1546
+ var _a, _b, _c, _d;
1923
1547
  const websocket = websocketRaw;
1924
- const requestId = idToStr(requestIdBuf);
1925
- logger4().debug({ msg: "runner websocket", actorId, url: request.url });
1926
- const url = new URL(request.url);
1548
+ const wsUniqueId = `ws_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1549
+ websocket.__rivet_ws_id = wsUniqueId;
1550
+ logger3().debug({
1551
+ msg: "runner websocket",
1552
+ actorId,
1553
+ url: request.url,
1554
+ isRestoringHibernatable,
1555
+ websocketObjectId: websocketRaw ? Object.prototype.toString.call(websocketRaw) : "null",
1556
+ websocketType: (_a = websocketRaw == null ? void 0 : websocketRaw.constructor) == null ? void 0 : _a.name,
1557
+ wsUniqueId,
1558
+ websocketProps: websocketRaw ? Object.keys(websocketRaw).join(", ") : "null"
1559
+ });
1927
1560
  const protocols = request.headers.get("sec-websocket-protocol");
1928
- let encodingRaw;
1929
- let connParamsRaw;
1930
- if (protocols) {
1931
- const protocolList = protocols.split(",").map((p) => p.trim());
1932
- for (const protocol of protocolList) {
1933
- if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
1934
- encodingRaw = protocol.substring(
1935
- WS_PROTOCOL_ENCODING.length
1936
- );
1937
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
1938
- connParamsRaw = decodeURIComponent(
1939
- protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
1940
- );
1941
- }
1942
- }
1943
- }
1944
- const encoding = EncodingSchema.parse(encodingRaw);
1945
- const connParams = connParamsRaw ? JSON.parse(connParamsRaw) : void 0;
1946
- let wsHandlerPromise;
1947
- if (url.pathname === PATH_CONNECT_WEBSOCKET) {
1948
- wsHandlerPromise = handleWebSocketConnect(
1561
+ const { encoding, connParams } = parseWebSocketProtocols(protocols);
1562
+ let wsHandler;
1563
+ try {
1564
+ wsHandler = await routeWebSocket(
1949
1565
  request,
1566
+ requestPath,
1567
+ requestHeaders,
1950
1568
  this.#runConfig,
1951
1569
  this,
1952
1570
  actorId,
1953
1571
  encoding,
1954
1572
  connParams,
1955
- requestId,
1573
+ gatewayIdBuf,
1956
1574
  requestIdBuf,
1957
- // Extract connId and connToken from protocols if needed
1958
- void 0,
1959
- void 0
1575
+ isHibernatable,
1576
+ isRestoringHibernatable
1960
1577
  );
1961
- } else if (url.pathname.startsWith(PATH_RAW_WEBSOCKET_PREFIX)) {
1962
- wsHandlerPromise = handleRawWebSocketHandler(
1963
- request,
1964
- url.pathname + url.search,
1965
- this,
1966
- actorId,
1967
- requestIdBuf
1968
- );
1969
- } else {
1970
- throw new Error(`Unreachable path: ${url.pathname}`);
1578
+ } catch (err) {
1579
+ logger3().error({ msg: "building websocket handlers errored", err });
1580
+ websocketRaw.close(1011, "ws.route_error");
1581
+ return;
1971
1582
  }
1583
+ websocket.raw = websocket;
1972
1584
  const wsContext = new WSContext2(websocket);
1973
- wsHandlerPromise.catch((err) => {
1974
- logger4().error({ msg: "building websocket handlers errored", err });
1975
- wsContext.close(1011, `${err}`);
1585
+ const conn = wsHandler.conn;
1586
+ const actor2 = wsHandler.actor;
1587
+ const connStateManager = conn == null ? void 0 : conn[CONN_STATE_MANAGER_SYMBOL];
1588
+ logger3().debug({
1589
+ msg: "attaching websocket event listeners",
1590
+ actorId,
1591
+ connId: conn == null ? void 0 : conn.id,
1592
+ wsUniqueId: websocket.__rivet_ws_id,
1593
+ isRestoringHibernatable,
1594
+ websocketType: (_b = websocket == null ? void 0 : websocket.constructor) == null ? void 0 : _b.name
1976
1595
  });
1977
- if (websocket.readyState === 1) {
1978
- wsHandlerPromise.then(
1979
- (x) => {
1980
- var _a;
1981
- return (_a = x.onOpen) == null ? void 0 : _a.call(x, new Event("open"), wsContext);
1982
- }
1983
- );
1984
- } else {
1985
- websocket.addEventListener("open", (event) => {
1986
- wsHandlerPromise.then((x) => {
1987
- var _a;
1988
- return (_a = x.onOpen) == null ? void 0 : _a.call(x, event, wsContext);
1989
- });
1990
- });
1596
+ if (isRestoringHibernatable) {
1597
+ (_c = wsHandler.onRestore) == null ? void 0 : _c.call(wsHandler, wsContext);
1991
1598
  }
1599
+ websocket.addEventListener("open", (event) => {
1600
+ wsHandler.onOpen(event, wsContext);
1601
+ });
1992
1602
  websocket.addEventListener("message", (event) => {
1993
- wsHandlerPromise.then((x) => {
1994
- var _a;
1995
- return (_a = x.onMessage) == null ? void 0 : _a.call(x, event, wsContext);
1603
+ var _a2, _b2;
1604
+ logger3().debug({
1605
+ msg: "websocket message event listener triggered",
1606
+ connId: conn == null ? void 0 : conn.id,
1607
+ actorId: actor2 == null ? void 0 : actor2.id,
1608
+ messageIndex: event.rivetMessageIndex,
1609
+ hasWsHandler: !!wsHandler,
1610
+ hasOnMessage: !!(wsHandler == null ? void 0 : wsHandler.onMessage),
1611
+ actorIsStopping: actor2 == null ? void 0 : actor2.isStopping,
1612
+ websocketType: (_a2 = websocket == null ? void 0 : websocket.constructor) == null ? void 0 : _a2.name,
1613
+ wsUniqueId: websocket.__rivet_ws_id,
1614
+ eventTargetWsId: (_b2 = event.target) == null ? void 0 : _b2.__rivet_ws_id
1996
1615
  });
1997
- invariant3(event.rivetRequestId, "missing rivetRequestId");
1998
- invariant3(event.rivetMessageIndex, "missing rivetMessageIndex");
1999
- const currentEntry = this.#wsAckQueue.get(requestId);
2000
- if (currentEntry) {
2001
- if (event.rivetMessageIndex > currentEntry.messageIndex) {
2002
- currentEntry.messageIndex = event.rivetMessageIndex;
1616
+ if (actor2 == null ? void 0 : actor2.isStopping) {
1617
+ logger3().debug({
1618
+ msg: "ignoring ws message, actor is stopping",
1619
+ connId: conn == null ? void 0 : conn.id,
1620
+ actorId: actor2 == null ? void 0 : actor2.id,
1621
+ messageIndex: event.rivetMessageIndex
1622
+ });
1623
+ return;
1624
+ }
1625
+ logger3().debug({
1626
+ msg: "calling wsHandler.onMessage",
1627
+ connId: conn == null ? void 0 : conn.id,
1628
+ messageIndex: event.rivetMessageIndex
1629
+ });
1630
+ wsHandler.onMessage(event, wsContext);
1631
+ const hibernate = connStateManager == null ? void 0 : connStateManager.hibernatableData;
1632
+ if (hibernate && conn && actor2) {
1633
+ invariant3(
1634
+ typeof event.rivetMessageIndex === "number",
1635
+ "missing event.rivetMessageIndex"
1636
+ );
1637
+ const previousMsgIndex = hibernate.serverMessageIndex;
1638
+ hibernate.serverMessageIndex = event.rivetMessageIndex;
1639
+ logger3().info({
1640
+ msg: "persisting message index",
1641
+ connId: conn.id,
1642
+ previousMsgIndex,
1643
+ newMsgIndex: event.rivetMessageIndex
1644
+ });
1645
+ const entry = this.#hwsMessageIndex.get(conn.id);
1646
+ if (entry) {
1647
+ const messageLength = getValueLength(event.data);
1648
+ entry.bufferedMessageSize += messageLength;
1649
+ if (entry.bufferedMessageSize >= CONN_BUFFERED_MESSAGE_SIZE_THRESHOLD) {
1650
+ entry.bufferedMessageSize = 0;
1651
+ entry.pendingAckFromBufferSize = true;
1652
+ actor2.stateManager.saveState({
1653
+ immediate: true
1654
+ });
1655
+ } else {
1656
+ actor2.stateManager.saveState({
1657
+ maxWait: CONN_MESSAGE_ACK_DEADLINE
1658
+ });
1659
+ }
2003
1660
  } else {
2004
- logger4().warn({
2005
- msg: "received lower index than ack queue for message",
2006
- requestId,
2007
- queuedMessageIndex: currentEntry,
2008
- eventMessageIndex: event.rivetMessageIndex
1661
+ actor2.stateManager.saveState({
1662
+ maxWait: CONN_MESSAGE_ACK_DEADLINE
2009
1663
  });
2010
1664
  }
2011
- } else {
2012
- this.#wsAckQueue.set(requestId, {
2013
- requestIdBuf,
2014
- messageIndex: event.rivetMessageIndex
2015
- });
2016
1665
  }
2017
1666
  });
2018
1667
  websocket.addEventListener("close", (event) => {
2019
- this.#flushWsAcks();
2020
- wsHandlerPromise.then((x) => {
2021
- var _a;
2022
- return (_a = x.onClose) == null ? void 0 : _a.call(x, event, wsContext);
2023
- });
1668
+ wsHandler.onClose(event, wsContext);
2024
1669
  });
2025
1670
  websocket.addEventListener("error", (event) => {
2026
- wsHandlerPromise.then((x) => {
2027
- var _a;
2028
- return (_a = x.onError) == null ? void 0 : _a.call(x, event, wsContext);
2029
- });
2030
- });
2031
- }
2032
- startSleep(actorId) {
2033
- this.#runner.sleepActor(actorId);
2034
- }
2035
- async shutdownRunner(immediate) {
2036
- logger4().info({ msg: "stopping engine actor driver", immediate });
2037
- logger4().debug({
2038
- msg: "stopping all actors before shutdown",
2039
- actorCount: this.#actors.size
1671
+ wsHandler.onError(event, wsContext);
2040
1672
  });
2041
- const stopPromises = [];
2042
- for (const [_actorId, handler] of this.#actors.entries()) {
2043
- if (handler.actor) {
2044
- stopPromises.push(
2045
- handler.actor._onStop().catch((err) => {
2046
- var _a;
2047
- (_a = handler.actor) == null ? void 0 : _a.rLog.error({
2048
- msg: "_onStop errored",
2049
- error: stringifyError(err)
2050
- });
2051
- })
2052
- );
2053
- }
2054
- }
2055
- await Promise.all(stopPromises);
2056
- logger4().debug({ msg: "all actors stopped" });
2057
- if (this.#wsAckFlushInterval) {
2058
- clearInterval(this.#wsAckFlushInterval);
2059
- this.#wsAckFlushInterval = void 0;
1673
+ if (isRestoringHibernatable) {
1674
+ logger3().info({
1675
+ msg: "event listeners attached to restored websocket",
1676
+ actorId,
1677
+ connId: conn == null ? void 0 : conn.id,
1678
+ gatewayId: idToStr(gatewayIdBuf),
1679
+ requestId: idToStr(requestIdBuf),
1680
+ websocketType: (_d = websocket == null ? void 0 : websocket.constructor) == null ? void 0 : _d.name,
1681
+ hasMessageListener: !!websocket.addEventListener
1682
+ });
2060
1683
  }
2061
- this.#flushWsAcks();
2062
- await this.#runner.shutdown(immediate);
2063
1684
  }
2064
- async serverlessHandleStart(c) {
2065
- return streamSSE2(c, async (stream) => {
2066
- stream.onAbort(() => {
1685
+ // MARK: - Hibernating WebSockets
1686
+ #hwsCanHibernate(actorId, gatewayId, requestId, request) {
1687
+ var _a;
1688
+ const url = new URL(request.url);
1689
+ const path = url.pathname;
1690
+ const actorInstance = this.#runner.getActor(actorId);
1691
+ if (!actorInstance) {
1692
+ logger3().warn({
1693
+ msg: "actor not found in #hwsCanHibernate",
1694
+ actorId
2067
1695
  });
2068
- c.req.raw.signal.addEventListener("abort", () => {
2069
- logger4().debug("SSE aborted, shutting down runner");
2070
- this.shutdownRunner(false);
1696
+ return false;
1697
+ }
1698
+ const handler = this.#actors.get(actorId);
1699
+ if (!handler) {
1700
+ logger3().warn({
1701
+ msg: "actor handler not found in #hwsCanHibernate",
1702
+ actorId
2071
1703
  });
2072
- await this.#runnerStarted.promise;
2073
- const payload = this.#runner.getServerlessInitPacket();
2074
- invariant3(payload, "runnerId not set");
2075
- await stream.writeSSE({ data: payload });
2076
- while (true) {
2077
- if (this.#isRunnerStopped) {
2078
- logger4().debug({
2079
- msg: "runner is stopped"
2080
- });
2081
- break;
2082
- }
2083
- if (stream.closed || stream.aborted) {
2084
- logger4().debug({
2085
- msg: "runner sse stream closed",
2086
- closed: stream.closed,
2087
- aborted: stream.aborted
1704
+ return false;
1705
+ }
1706
+ if (!handler.actor) {
1707
+ logger3().warn({
1708
+ msg: "actor not found in #hwsCanHibernate",
1709
+ actorId
1710
+ });
1711
+ return false;
1712
+ }
1713
+ logger3().debug({
1714
+ msg: "no existing hibernatable websocket found",
1715
+ gatewayId: idToStr(gatewayId),
1716
+ requestId: idToStr(requestId)
1717
+ });
1718
+ if (path === PATH_CONNECT) {
1719
+ return true;
1720
+ } else if (path === PATH_WEBSOCKET_BASE || path.startsWith(PATH_WEBSOCKET_PREFIX)) {
1721
+ const definition = lookupInRegistry(
1722
+ this.#registryConfig,
1723
+ actorInstance.config.name
1724
+ );
1725
+ const canHibernateWebSocket = (_a = definition.config.options) == null ? void 0 : _a.canHibernateWebSocket;
1726
+ if (canHibernateWebSocket === true) {
1727
+ return true;
1728
+ } else if (typeof canHibernateWebSocket === "function") {
1729
+ try {
1730
+ const newPath = truncateRawWebSocketPathPrefix(
1731
+ url.pathname
1732
+ );
1733
+ const truncatedRequest = new Request(
1734
+ `http://actor${newPath}`,
1735
+ request
1736
+ );
1737
+ const canHibernate = canHibernateWebSocket(truncatedRequest);
1738
+ return canHibernate;
1739
+ } catch (error) {
1740
+ logger3().error({
1741
+ msg: "error calling canHibernateWebSocket",
1742
+ error
2088
1743
  });
2089
- break;
1744
+ return false;
2090
1745
  }
2091
- await stream.writeSSE({ event: "ping", data: "" });
2092
- await stream.sleep(RUNNER_SSE_PING_INTERVAL);
1746
+ } else {
1747
+ return false;
2093
1748
  }
2094
- await this.#runnerStopped.promise;
1749
+ } else if (path === PATH_INSPECTOR_CONNECT) {
1750
+ return false;
1751
+ } else {
1752
+ logger3().warn({
1753
+ msg: "unexpected path for getActorHibernationConfig",
1754
+ path
1755
+ });
1756
+ return false;
1757
+ }
1758
+ }
1759
+ async #hwsLoadAll(actorId) {
1760
+ const actor2 = await this.loadActor(actorId);
1761
+ return actor2.conns.values().map((conn) => {
1762
+ const connStateManager = conn[CONN_STATE_MANAGER_SYMBOL];
1763
+ const hibernatable = connStateManager.hibernatableData;
1764
+ if (!hibernatable) return void 0;
1765
+ return {
1766
+ gatewayId: hibernatable.gatewayId,
1767
+ requestId: hibernatable.requestId,
1768
+ serverMessageIndex: hibernatable.serverMessageIndex,
1769
+ clientMessageIndex: hibernatable.clientMessageIndex,
1770
+ path: hibernatable.requestPath,
1771
+ headers: hibernatable.requestHeaders
1772
+ };
1773
+ }).filter((x) => x !== void 0).toArray();
1774
+ }
1775
+ async onBeforeActorStart(actor2) {
1776
+ var _a;
1777
+ const handler = this.#actors.get(actor2.id);
1778
+ invariant3(handler, "missing actor handler in onBeforeActorReady");
1779
+ (_a = handler.actorStartPromise) == null ? void 0 : _a.resolve();
1780
+ handler.actorStartPromise = void 0;
1781
+ const metaEntries = await this.#hwsLoadAll(actor2.id);
1782
+ await this.#runner.restoreHibernatingRequests(actor2.id, metaEntries);
1783
+ }
1784
+ onCreateConn(conn) {
1785
+ const hibernatable = conn[CONN_STATE_MANAGER_SYMBOL].hibernatableData;
1786
+ if (!hibernatable) return;
1787
+ this.#hwsMessageIndex.set(conn.id, {
1788
+ serverMessageIndex: hibernatable.serverMessageIndex,
1789
+ bufferedMessageSize: 0,
1790
+ pendingAckFromMessageIndex: false,
1791
+ pendingAckFromBufferSize: false
1792
+ });
1793
+ logger3().debug({
1794
+ msg: "created #hwsMessageIndex entry",
1795
+ connId: conn.id,
1796
+ serverMessageIndex: hibernatable.serverMessageIndex
2095
1797
  });
2096
1798
  }
2097
- getExtraActorLogParams() {
2098
- return { runnerId: this.#runner.runnerId ?? "-" };
1799
+ onDestroyConn(conn) {
1800
+ this.#hwsMessageIndex.delete(conn.id);
1801
+ logger3().debug({
1802
+ msg: "removed #hwsMessageIndex entry",
1803
+ connId: conn.id
1804
+ });
1805
+ }
1806
+ onBeforePersistConn(conn) {
1807
+ const stateManager = conn[CONN_STATE_MANAGER_SYMBOL];
1808
+ const hibernatable = stateManager.hibernatableDataOrError();
1809
+ const entry = this.#hwsMessageIndex.get(conn.id);
1810
+ if (!entry) {
1811
+ logger3().warn({
1812
+ msg: "missing EngineActorDriver.#hwsMessageIndex entry for conn",
1813
+ connId: conn.id
1814
+ });
1815
+ return;
1816
+ }
1817
+ entry.pendingAckFromMessageIndex = hibernatable.serverMessageIndex > entry.serverMessageIndex;
1818
+ entry.serverMessageIndex = hibernatable.serverMessageIndex;
1819
+ }
1820
+ onAfterPersistConn(conn) {
1821
+ const stateManager = conn[CONN_STATE_MANAGER_SYMBOL];
1822
+ const hibernatable = stateManager.hibernatableDataOrError();
1823
+ const entry = this.#hwsMessageIndex.get(conn.id);
1824
+ if (!entry) {
1825
+ logger3().warn({
1826
+ msg: "missing EngineActorDriver.#hwsMessageIndex entry for conn",
1827
+ connId: conn.id
1828
+ });
1829
+ return;
1830
+ }
1831
+ if (entry.pendingAckFromMessageIndex || entry.pendingAckFromBufferSize) {
1832
+ this.#runner.sendHibernatableWebSocketMessageAck(
1833
+ hibernatable.gatewayId,
1834
+ hibernatable.requestId,
1835
+ entry.serverMessageIndex
1836
+ );
1837
+ entry.pendingAckFromMessageIndex = false;
1838
+ entry.pendingAckFromBufferSize = false;
1839
+ entry.bufferedMessageSize = 0;
1840
+ }
2099
1841
  }
2100
1842
  };
2101
1843
 
@@ -2117,6 +1859,117 @@ function createEngineDriver() {
2117
1859
  };
2118
1860
  }
2119
1861
 
1862
+ // src/utils/node.ts
1863
+ import { createRequire } from "module";
1864
+ var nodeCrypto;
1865
+ var nodeFsSync;
1866
+ var nodeFs;
1867
+ var nodePath;
1868
+ var nodeOs;
1869
+ var nodeChildProcess;
1870
+ var nodeStream;
1871
+ var hasImportedDependencies = false;
1872
+ function getRequireFn() {
1873
+ return createRequire(import.meta.url);
1874
+ }
1875
+ function importNodeDependencies() {
1876
+ if (hasImportedDependencies) return;
1877
+ try {
1878
+ const requireFn = getRequireFn();
1879
+ nodeCrypto = requireFn(
1880
+ /* webpackIgnore: true */
1881
+ "node:crypto"
1882
+ );
1883
+ nodeFsSync = requireFn(
1884
+ /* webpackIgnore: true */
1885
+ "node:fs"
1886
+ );
1887
+ nodeFs = requireFn(
1888
+ /* webpackIgnore: true */
1889
+ "node:fs/promises"
1890
+ );
1891
+ nodePath = requireFn(
1892
+ /* webpackIgnore: true */
1893
+ "node:path"
1894
+ );
1895
+ nodeOs = requireFn(
1896
+ /* webpackIgnore: true */
1897
+ "node:os"
1898
+ );
1899
+ nodeChildProcess = requireFn(
1900
+ /* webpackIgnore: true */
1901
+ "node:child_process"
1902
+ );
1903
+ nodeStream = requireFn(
1904
+ /* webpackIgnore: true */
1905
+ "node:stream/promises"
1906
+ );
1907
+ hasImportedDependencies = true;
1908
+ } catch (err) {
1909
+ console.warn(
1910
+ "Node.js modules not available, file system driver will not work",
1911
+ err
1912
+ );
1913
+ throw err;
1914
+ }
1915
+ }
1916
+ function getNodeCrypto() {
1917
+ if (!nodeCrypto) {
1918
+ throw new Error(
1919
+ "Node crypto module not loaded. Ensure importNodeDependencies() has been called."
1920
+ );
1921
+ }
1922
+ return nodeCrypto;
1923
+ }
1924
+ function getNodeFsSync() {
1925
+ if (!nodeFsSync) {
1926
+ throw new Error(
1927
+ "Node fs module not loaded. Ensure importNodeDependencies() has been called."
1928
+ );
1929
+ }
1930
+ return nodeFsSync;
1931
+ }
1932
+ function getNodeFs() {
1933
+ if (!nodeFs) {
1934
+ throw new Error(
1935
+ "Node fs/promises module not loaded. Ensure importNodeDependencies() has been called."
1936
+ );
1937
+ }
1938
+ return nodeFs;
1939
+ }
1940
+ function getNodePath() {
1941
+ if (!nodePath) {
1942
+ throw new Error(
1943
+ "Node path module not loaded. Ensure importNodeDependencies() has been called."
1944
+ );
1945
+ }
1946
+ return nodePath;
1947
+ }
1948
+ function getNodeOs() {
1949
+ if (!nodeOs) {
1950
+ throw new Error(
1951
+ "Node os module not loaded. Ensure importNodeDependencies() has been called."
1952
+ );
1953
+ }
1954
+ return nodeOs;
1955
+ }
1956
+ function getNodeChildProcess() {
1957
+ if (!nodeChildProcess) {
1958
+ throw new Error(
1959
+ "Node child_process module not loaded. Ensure importNodeDependencies() has been called."
1960
+ );
1961
+ }
1962
+ return nodeChildProcess;
1963
+ }
1964
+ function getNodeStream() {
1965
+ if (!nodeStream) {
1966
+ throw new Error(
1967
+ "Node stream/promises module not loaded. Ensure importNodeDependencies() has been called."
1968
+ );
1969
+ }
1970
+ return nodeStream;
1971
+ }
1972
+
2120
1973
  // src/drivers/file-system/actor.ts
2121
1974
  var FileSystemActorDriver = class {
2122
1975
  #registryConfig;
@@ -2149,17 +2002,17 @@ var FileSystemActorDriver = class {
2149
2002
  getContext(_actorId) {
2150
2003
  return {};
2151
2004
  }
2152
- async readPersistedData(actorId) {
2153
- return new Uint8Array(
2154
- (await this.#state.loadActorStateOrError(actorId)).persistedData
2155
- );
2005
+ async kvBatchPut(actorId, entries) {
2006
+ await this.#state.kvBatchPut(actorId, entries);
2156
2007
  }
2157
- async writePersistedData(actorId, data) {
2158
- const state = await this.#state.loadActorStateOrError(actorId);
2159
- await this.#state.writeActor(actorId, {
2160
- ...state,
2161
- persistedData: bufferToArrayBuffer(data)
2162
- });
2008
+ async kvBatchGet(actorId, keys) {
2009
+ return await this.#state.kvBatchGet(actorId, keys);
2010
+ }
2011
+ async kvBatchDelete(actorId, keys) {
2012
+ await this.#state.kvBatchDelete(actorId, keys);
2013
+ }
2014
+ async kvListPrefix(actorId, prefix) {
2015
+ return await this.#state.kvListPrefix(actorId, prefix);
2163
2016
  }
2164
2017
  async setAlarm(actor2, timestamp) {
2165
2018
  await this.#state.setActorAlarm(actor2.id, timestamp);
@@ -2170,18 +2023,27 @@ var FileSystemActorDriver = class {
2170
2023
  startSleep(actorId) {
2171
2024
  this.#state.sleepActor(actorId);
2172
2025
  }
2026
+ async startDestroy(actorId) {
2027
+ await this.#state.destroyActor(actorId);
2028
+ }
2173
2029
  };
2174
2030
 
2175
2031
  // src/drivers/file-system/global-state.ts
2176
- import * as crypto3 from "crypto";
2177
- import * as fsSync2 from "fs";
2178
- import * as fs2 from "fs/promises";
2179
- import * as path2 from "path";
2180
2032
  import invariant4 from "invariant";
2181
2033
 
2182
- // dist/schemas/file-system-driver/v1.ts
2034
+ // dist/schemas/file-system-driver/v2.ts
2183
2035
  import * as bare from "@bare-ts/lib";
2184
2036
  var config = /* @__PURE__ */ bare.Config({});
2037
+ function readActorKvEntry(bc) {
2038
+ return {
2039
+ key: bare.readData(bc),
2040
+ value: bare.readData(bc)
2041
+ };
2042
+ }
2043
+ function writeActorKvEntry(bc, x) {
2044
+ bare.writeData(bc, x.key);
2045
+ bare.writeData(bc, x.value);
2046
+ }
2185
2047
  function read0(bc) {
2186
2048
  const len = bare.readUintSafe(bc);
2187
2049
  if (len === 0) {
@@ -2199,12 +2061,29 @@ function write0(bc, x) {
2199
2061
  bare.writeString(bc, x[i]);
2200
2062
  }
2201
2063
  }
2064
+ function read1(bc) {
2065
+ const len = bare.readUintSafe(bc);
2066
+ if (len === 0) {
2067
+ return [];
2068
+ }
2069
+ const result = [readActorKvEntry(bc)];
2070
+ for (let i = 1; i < len; i++) {
2071
+ result[i] = readActorKvEntry(bc);
2072
+ }
2073
+ return result;
2074
+ }
2075
+ function write1(bc, x) {
2076
+ bare.writeUintSafe(bc, x.length);
2077
+ for (let i = 0; i < x.length; i++) {
2078
+ writeActorKvEntry(bc, x[i]);
2079
+ }
2080
+ }
2202
2081
  function readActorState(bc) {
2203
2082
  return {
2204
2083
  actorId: bare.readString(bc),
2205
2084
  name: bare.readString(bc),
2206
2085
  key: read0(bc),
2207
- persistedData: bare.readData(bc),
2086
+ kvStorage: read1(bc),
2208
2087
  createdAt: bare.readU64(bc)
2209
2088
  };
2210
2089
  }
@@ -2212,7 +2091,7 @@ function writeActorState(bc, x) {
2212
2091
  bare.writeString(bc, x.actorId);
2213
2092
  bare.writeString(bc, x.name);
2214
2093
  write0(bc, x.key);
2215
- bare.writeData(bc, x.persistedData);
2094
+ write1(bc, x.kvStorage);
2216
2095
  bare.writeU64(bc, x.createdAt);
2217
2096
  }
2218
2097
  function encodeActorState(x) {
@@ -2259,8 +2138,29 @@ function decodeActorAlarm(bytes) {
2259
2138
  }
2260
2139
 
2261
2140
  // src/schemas/file-system-driver/versioned.ts
2262
- var CURRENT_VERSION = 1;
2263
- var migrations = /* @__PURE__ */ new Map();
2141
+ var CURRENT_VERSION = 2;
2142
+ var migrations = /* @__PURE__ */ new Map([
2143
+ [
2144
+ 2,
2145
+ (v1State) => {
2146
+ const kvStorage = [];
2147
+ if (v1State.persistedData) {
2148
+ const key = new Uint8Array([1]);
2149
+ kvStorage.push({
2150
+ key: bufferToArrayBuffer(key),
2151
+ value: v1State.persistedData
2152
+ });
2153
+ }
2154
+ return {
2155
+ actorId: v1State.actorId,
2156
+ name: v1State.name,
2157
+ key: v1State.key,
2158
+ kvStorage,
2159
+ createdAt: v1State.createdAt
2160
+ };
2161
+ }
2162
+ ]
2163
+ ]);
2264
2164
  var ACTOR_STATE_VERSIONED = createVersionedDataHandler({
2265
2165
  currentVersion: CURRENT_VERSION,
2266
2166
  migrations,
@@ -2275,36 +2175,35 @@ var ACTOR_ALARM_VERSIONED = createVersionedDataHandler({
2275
2175
  });
2276
2176
 
2277
2177
  // src/drivers/file-system/log.ts
2278
- function logger5() {
2178
+ function logger4() {
2279
2179
  return getLogger("driver-fs");
2280
2180
  }
2281
2181
 
2282
2182
  // src/drivers/file-system/utils.ts
2283
- import * as crypto2 from "crypto";
2284
- import * as fsSync from "fs";
2285
- import * as fs from "fs/promises";
2286
- import * as os from "os";
2287
- import * as path from "path";
2288
2183
  function generateActorId(name, key) {
2289
2184
  const jsonString = JSON.stringify([name, key]);
2185
+ const crypto2 = getNodeCrypto();
2290
2186
  const hash = crypto2.createHash("sha256").update(jsonString).digest("hex").substring(0, 16);
2291
2187
  return hash;
2292
2188
  }
2293
2189
  function createHashForPath(dirPath) {
2190
+ const path = getNodePath();
2294
2191
  const normalizedPath = path.normalize(dirPath);
2295
2192
  const lastComponent = path.basename(normalizedPath);
2193
+ const crypto2 = getNodeCrypto();
2296
2194
  const hash = crypto2.createHash("sha256").update(normalizedPath).digest("hex").substring(0, 8);
2297
2195
  return `${lastComponent}-${hash}`;
2298
2196
  }
2299
- function getStoragePath(customPath) {
2197
+ function getStoragePath() {
2300
2198
  const dataPath = getDataPath("rivetkit");
2301
- const pathToHash = customPath || process.cwd();
2302
- const dirHash = createHashForPath(pathToHash);
2199
+ const dirHash = createHashForPath(process.cwd());
2200
+ const path = getNodePath();
2303
2201
  return path.join(dataPath, dirHash);
2304
2202
  }
2305
- async function pathExists(path4) {
2203
+ async function pathExists(path) {
2306
2204
  try {
2307
- await fs.access(path4);
2205
+ const fs = getNodeFs();
2206
+ await fs.access(path);
2308
2207
  return true;
2309
2208
  } catch {
2310
2209
  return false;
@@ -2312,17 +2211,21 @@ async function pathExists(path4) {
2312
2211
  }
2313
2212
  async function ensureDirectoryExists(directoryPath) {
2314
2213
  if (!await pathExists(directoryPath)) {
2214
+ const fs = getNodeFs();
2315
2215
  await fs.mkdir(directoryPath, { recursive: true });
2316
2216
  }
2317
2217
  }
2318
2218
  function ensureDirectoryExistsSync(directoryPath) {
2219
+ const fsSync = getNodeFsSync();
2319
2220
  if (!fsSync.existsSync(directoryPath)) {
2320
2221
  fsSync.mkdirSync(directoryPath, { recursive: true });
2321
2222
  }
2322
2223
  }
2323
2224
  function getDataPath(appName) {
2324
2225
  const platform = process.platform;
2226
+ const os = getNodeOs();
2325
2227
  const homeDir = os.homedir();
2228
+ const path = getNodePath();
2326
2229
  switch (platform) {
2327
2230
  case "win32":
2328
2231
  return path.join(
@@ -2351,6 +2254,9 @@ var FileSystemGlobalState = class {
2351
2254
  #dbsDir;
2352
2255
  #alarmsDir;
2353
2256
  #persist;
2257
+ // IMPORTANT: Never delete from this map. Doing so will result in race
2258
+ // conditions since the actor generation will cease to be tracked
2259
+ // correctly. Always increment generation if a new actor is created.
2354
2260
  #actors = /* @__PURE__ */ new Map();
2355
2261
  #actorCountOnStartup = 0;
2356
2262
  #runnerParams;
@@ -2365,21 +2271,23 @@ var FileSystemGlobalState = class {
2365
2271
  }
2366
2272
  constructor(persist = true, customPath) {
2367
2273
  this.#persist = persist;
2368
- this.#storagePath = persist ? getStoragePath(customPath) : "/tmp";
2369
- this.#stateDir = path2.join(this.#storagePath, "state");
2370
- this.#dbsDir = path2.join(this.#storagePath, "databases");
2371
- this.#alarmsDir = path2.join(this.#storagePath, "alarms");
2274
+ this.#storagePath = persist ? customPath ?? getStoragePath() : "/tmp";
2275
+ const path = getNodePath();
2276
+ this.#stateDir = path.join(this.#storagePath, "state");
2277
+ this.#dbsDir = path.join(this.#storagePath, "databases");
2278
+ this.#alarmsDir = path.join(this.#storagePath, "alarms");
2372
2279
  if (this.#persist) {
2373
2280
  ensureDirectoryExistsSync(this.#stateDir);
2374
2281
  ensureDirectoryExistsSync(this.#dbsDir);
2375
2282
  ensureDirectoryExistsSync(this.#alarmsDir);
2376
2283
  try {
2377
- const actorIds = fsSync2.readdirSync(this.#stateDir);
2284
+ const fsSync = getNodeFsSync();
2285
+ const actorIds = fsSync.readdirSync(this.#stateDir);
2378
2286
  this.#actorCountOnStartup = actorIds.length;
2379
2287
  } catch (error) {
2380
- logger5().error({ msg: "failed to count actors", error });
2288
+ logger4().error({ msg: "failed to count actors", error });
2381
2289
  }
2382
- logger5().debug({
2290
+ logger4().debug({
2383
2291
  msg: "file system driver ready",
2384
2292
  dir: this.#storagePath,
2385
2293
  actorCount: this.#actorCountOnStartup
@@ -2387,28 +2295,29 @@ var FileSystemGlobalState = class {
2387
2295
  try {
2388
2296
  this.#cleanupTempFilesSync();
2389
2297
  } catch (err) {
2390
- logger5().error({
2298
+ logger4().error({
2391
2299
  msg: "failed to cleanup temp files",
2392
2300
  error: err
2393
2301
  });
2394
2302
  }
2395
2303
  } else {
2396
- logger5().debug({ msg: "memory driver ready" });
2304
+ logger4().debug({ msg: "memory driver ready" });
2397
2305
  }
2398
2306
  }
2399
2307
  getActorStatePath(actorId) {
2400
- return path2.join(this.#stateDir, actorId);
2308
+ return getNodePath().join(this.#stateDir, actorId);
2401
2309
  }
2402
2310
  getActorDbPath(actorId) {
2403
- return path2.join(this.#dbsDir, `${actorId}.db`);
2311
+ return getNodePath().join(this.#dbsDir, `${actorId}.db`);
2404
2312
  }
2405
2313
  getActorAlarmPath(actorId) {
2406
- return path2.join(this.#alarmsDir, actorId);
2314
+ return getNodePath().join(this.#alarmsDir, actorId);
2407
2315
  }
2408
2316
  async *getActorsIterator(params) {
2409
2317
  let actorIds = Array.from(this.#actors.keys()).sort();
2410
- if (fsSync2.existsSync(this.#stateDir)) {
2411
- actorIds = fsSync2.readdirSync(this.#stateDir).filter((id) => !id.includes(".tmp")).sort();
2318
+ const fsSync = getNodeFsSync();
2319
+ if (fsSync.existsSync(this.#stateDir)) {
2320
+ actorIds = fsSync.readdirSync(this.#stateDir).filter((id) => !id.includes(".tmp")).sort();
2412
2321
  }
2413
2322
  const startIndex = params.cursor ? actorIds.indexOf(params.cursor) + 1 : 0;
2414
2323
  for (let i = startIndex; i < actorIds.length; i++) {
@@ -2420,7 +2329,7 @@ var FileSystemGlobalState = class {
2420
2329
  const state = await this.loadActorStateOrError(actorId);
2421
2330
  yield state;
2422
2331
  } catch (error) {
2423
- logger5().error({
2332
+ logger4().error({
2424
2333
  msg: "failed to load actor state",
2425
2334
  actorId,
2426
2335
  error
@@ -2440,7 +2349,8 @@ var FileSystemGlobalState = class {
2440
2349
  }
2441
2350
  entry = {
2442
2351
  id: actorId,
2443
- removed: false
2352
+ lifecycleState: 0 /* NONEXISTENT */,
2353
+ generation: crypto.randomUUID()
2444
2354
  };
2445
2355
  this.#actors.set(actorId, entry);
2446
2356
  return entry;
@@ -2449,20 +2359,34 @@ var FileSystemGlobalState = class {
2449
2359
  * Creates a new actor and writes to file system.
2450
2360
  */
2451
2361
  async createActor(actorId, name, key, input) {
2452
- if (this.#actors.has(actorId)) {
2453
- throw new ActorAlreadyExists(name, key);
2454
- }
2455
2362
  const entry = this.#upsertEntry(actorId);
2363
+ if (entry.state) {
2364
+ throw new ActorDuplicateKey(name, key);
2365
+ }
2366
+ if (this.isActorStopping(actorId)) {
2367
+ throw new Error(`Actor ${actorId} is stopping`);
2368
+ }
2369
+ if (entry.lifecycleState === 4 /* DESTROYED */) {
2370
+ entry.lifecycleState = 0 /* NONEXISTENT */;
2371
+ entry.generation = crypto.randomUUID();
2372
+ }
2373
+ const kvStorage = [];
2374
+ const initialKvState = getInitialActorKvState(input);
2375
+ for (const [key2, value] of initialKvState) {
2376
+ kvStorage.push({
2377
+ key: bufferToArrayBuffer(key2),
2378
+ value: bufferToArrayBuffer(value)
2379
+ });
2380
+ }
2456
2381
  entry.state = {
2457
2382
  actorId,
2458
2383
  name,
2459
2384
  key,
2460
2385
  createdAt: BigInt(Date.now()),
2461
- persistedData: bufferToArrayBuffer(
2462
- serializeEmptyPersistData(input)
2463
- )
2386
+ kvStorage
2464
2387
  };
2465
- await this.writeActor(actorId, entry.state);
2388
+ entry.lifecycleState = 1 /* AWAKE */;
2389
+ await this.writeActor(actorId, entry.generation, entry.state);
2466
2390
  return entry;
2467
2391
  }
2468
2392
  /**
@@ -2470,6 +2394,9 @@ var FileSystemGlobalState = class {
2470
2394
  */
2471
2395
  async loadActor(actorId) {
2472
2396
  const entry = this.#upsertEntry(actorId);
2397
+ if (entry.lifecycleState === 4 /* DESTROYED */) {
2398
+ return entry;
2399
+ }
2473
2400
  if (entry.state) {
2474
2401
  return entry;
2475
2402
  }
@@ -2486,7 +2413,8 @@ var FileSystemGlobalState = class {
2486
2413
  async loadActorState(entry) {
2487
2414
  const stateFilePath = this.getActorStatePath(entry.id);
2488
2415
  try {
2489
- const stateData = await fs2.readFile(stateFilePath);
2416
+ const fs = getNodeFs();
2417
+ const stateData = await fs.readFile(stateFilePath);
2490
2418
  entry.state = ACTOR_STATE_VERSIONED.deserializeWithEmbeddedVersion(
2491
2419
  new Uint8Array(stateData)
2492
2420
  );
@@ -2505,16 +2433,29 @@ var FileSystemGlobalState = class {
2505
2433
  async loadOrCreateActor(actorId, name, key, input) {
2506
2434
  const entry = await this.loadActor(actorId);
2507
2435
  if (!entry.state) {
2436
+ if (this.isActorStopping(actorId)) {
2437
+ throw new Error(`Actor ${actorId} stopping`);
2438
+ }
2439
+ if (entry.lifecycleState === 4 /* DESTROYED */) {
2440
+ entry.lifecycleState = 0 /* NONEXISTENT */;
2441
+ entry.generation = crypto.randomUUID();
2442
+ }
2443
+ const kvStorage = [];
2444
+ const initialKvState = getInitialActorKvState(input);
2445
+ for (const [key2, value] of initialKvState) {
2446
+ kvStorage.push({
2447
+ key: bufferToArrayBuffer(key2),
2448
+ value: bufferToArrayBuffer(value)
2449
+ });
2450
+ }
2508
2451
  entry.state = {
2509
2452
  actorId,
2510
2453
  name,
2511
2454
  key,
2512
2455
  createdAt: BigInt(Date.now()),
2513
- persistedData: bufferToArrayBuffer(
2514
- serializeEmptyPersistData(input)
2515
- )
2456
+ kvStorage
2516
2457
  };
2517
- await this.writeActor(actorId, entry.state);
2458
+ await this.writeActor(actorId, entry.generation, entry.state);
2518
2459
  }
2519
2460
  return entry;
2520
2461
  }
@@ -2524,35 +2465,127 @@ var FileSystemGlobalState = class {
2524
2465
  this.#persist,
2525
2466
  "cannot sleep actor with memory driver, must use file system driver"
2526
2467
  );
2527
- const actor2 = this.#actors.get(actorId);
2468
+ const actor2 = this.#upsertEntry(actorId);
2528
2469
  invariant4(actor2, `tried to sleep ${actorId}, does not exist`);
2470
+ if (this.isActorStopping(actorId)) {
2471
+ return;
2472
+ }
2473
+ actor2.lifecycleState = 2 /* STARTING_SLEEP */;
2529
2474
  if (actor2.loadPromise) await actor2.loadPromise.catch();
2530
2475
  if ((_a = actor2.startPromise) == null ? void 0 : _a.promise)
2531
2476
  await actor2.startPromise.promise.catch();
2532
- actor2.removed = true;
2533
2477
  invariant4(actor2.actor, "actor should be loaded");
2534
- await actor2.actor._onStop();
2478
+ await actor2.actor.onStop("sleep");
2535
2479
  this.#actors.delete(actorId);
2536
2480
  }
2481
+ async destroyActor(actorId) {
2482
+ var _a;
2483
+ const actor2 = this.#upsertEntry(actorId);
2484
+ if (this.isActorStopping(actorId)) {
2485
+ return;
2486
+ }
2487
+ actor2.lifecycleState = 3 /* STARTING_DESTROY */;
2488
+ if (actor2.loadPromise) await actor2.loadPromise.catch();
2489
+ if ((_a = actor2.startPromise) == null ? void 0 : _a.promise)
2490
+ await actor2.startPromise.promise.catch();
2491
+ if (actor2.actor) {
2492
+ await actor2.actor.onStop("destroy");
2493
+ }
2494
+ if (actor2.alarmTimeout) {
2495
+ actor2.alarmTimeout.abort();
2496
+ }
2497
+ if (this.#persist) {
2498
+ const fs = getNodeFs();
2499
+ await Promise.all([
2500
+ // Delete actor state file
2501
+ (async () => {
2502
+ try {
2503
+ await fs.unlink(this.getActorStatePath(actorId));
2504
+ } catch (err) {
2505
+ if ((err == null ? void 0 : err.code) !== "ENOENT") {
2506
+ logger4().error({
2507
+ msg: "failed to delete actor state file",
2508
+ actorId,
2509
+ error: stringifyError(err)
2510
+ });
2511
+ }
2512
+ }
2513
+ })(),
2514
+ // Delete actor database file
2515
+ (async () => {
2516
+ try {
2517
+ await fs.unlink(this.getActorDbPath(actorId));
2518
+ } catch (err) {
2519
+ if ((err == null ? void 0 : err.code) !== "ENOENT") {
2520
+ logger4().error({
2521
+ msg: "failed to delete actor database file",
2522
+ actorId,
2523
+ error: stringifyError(err)
2524
+ });
2525
+ }
2526
+ }
2527
+ })(),
2528
+ // Delete actor alarm file
2529
+ (async () => {
2530
+ try {
2531
+ await fs.unlink(this.getActorAlarmPath(actorId));
2532
+ } catch (err) {
2533
+ if ((err == null ? void 0 : err.code) !== "ENOENT") {
2534
+ logger4().error({
2535
+ msg: "failed to delete actor alarm file",
2536
+ actorId,
2537
+ error: stringifyError(err)
2538
+ });
2539
+ }
2540
+ }
2541
+ })()
2542
+ ]);
2543
+ }
2544
+ actor2.state = void 0;
2545
+ actor2.loadPromise = void 0;
2546
+ actor2.actor = void 0;
2547
+ actor2.startPromise = void 0;
2548
+ actor2.alarmTimeout = void 0;
2549
+ actor2.alarmTimeout = void 0;
2550
+ actor2.pendingWriteResolver = void 0;
2551
+ actor2.lifecycleState = 4 /* DESTROYED */;
2552
+ }
2537
2553
  /**
2538
2554
  * Save actor state to disk.
2539
2555
  */
2540
- async writeActor(actorId, state) {
2556
+ async writeActor(actorId, generation, state) {
2541
2557
  if (!this.#persist) {
2542
2558
  return;
2543
2559
  }
2544
2560
  const entry = this.#actors.get(actorId);
2545
2561
  invariant4(entry, "actor entry does not exist");
2546
- await this.#performWrite(actorId, state);
2562
+ await this.#performWrite(actorId, generation, state);
2563
+ }
2564
+ isGenerationCurrentAndNotDestroyed(actorId, generation) {
2565
+ const entry = this.#upsertEntry(actorId);
2566
+ if (!entry) return false;
2567
+ return entry.generation === generation && entry.lifecycleState !== 3 /* STARTING_DESTROY */;
2568
+ }
2569
+ isActorStopping(actorId) {
2570
+ const entry = this.#upsertEntry(actorId);
2571
+ if (!entry) return false;
2572
+ return entry.lifecycleState === 2 /* STARTING_SLEEP */ || entry.lifecycleState === 3 /* STARTING_DESTROY */;
2547
2573
  }
2548
2574
  async setActorAlarm(actorId, timestamp) {
2549
2575
  const entry = this.#actors.get(actorId);
2550
2576
  invariant4(entry, "actor entry does not exist");
2577
+ const writeGeneration = entry.generation;
2578
+ if (this.isActorStopping(actorId)) {
2579
+ logger4().info("skipping set alarm since actor stopping");
2580
+ return;
2581
+ }
2551
2582
  if (this.#persist) {
2552
2583
  const alarmPath = this.getActorAlarmPath(actorId);
2553
- const tempPath = `${alarmPath}.tmp.${crypto3.randomUUID()}`;
2584
+ const crypto2 = getNodeCrypto();
2585
+ const tempPath = `${alarmPath}.tmp.${crypto2.randomUUID()}`;
2554
2586
  try {
2555
- await ensureDirectoryExists(path2.dirname(alarmPath));
2587
+ const path = getNodePath();
2588
+ await ensureDirectoryExists(path.dirname(alarmPath));
2556
2589
  const alarmData = {
2557
2590
  actorId,
2558
2591
  timestamp: BigInt(timestamp)
@@ -2560,14 +2593,25 @@ var FileSystemGlobalState = class {
2560
2593
  const data = ACTOR_ALARM_VERSIONED.serializeWithEmbeddedVersion(
2561
2594
  alarmData
2562
2595
  );
2563
- await fs2.writeFile(tempPath, data);
2564
- await fs2.rename(tempPath, alarmPath);
2596
+ const fs = getNodeFs();
2597
+ await fs.writeFile(tempPath, data);
2598
+ if (!this.isGenerationCurrentAndNotDestroyed(
2599
+ actorId,
2600
+ writeGeneration
2601
+ )) {
2602
+ logger4().debug(
2603
+ "skipping writing alarm since actor destroying or new generation"
2604
+ );
2605
+ return;
2606
+ }
2607
+ await fs.rename(tempPath, alarmPath);
2565
2608
  } catch (error) {
2566
2609
  try {
2567
- await fs2.unlink(tempPath);
2610
+ const fs = getNodeFs();
2611
+ await fs.unlink(tempPath);
2568
2612
  } catch {
2569
2613
  }
2570
- logger5().error({
2614
+ logger4().error({
2571
2615
  msg: "failed to write alarm",
2572
2616
  actorId,
2573
2617
  error
@@ -2580,27 +2624,37 @@ var FileSystemGlobalState = class {
2580
2624
  /**
2581
2625
  * Perform the actual write operation with atomic writes
2582
2626
  */
2583
- async #performWrite(actorId, state) {
2627
+ async #performWrite(actorId, generation, state) {
2584
2628
  const dataPath = this.getActorStatePath(actorId);
2585
- const tempPath = `${dataPath}.tmp.${crypto3.randomUUID()}`;
2629
+ const crypto2 = getNodeCrypto();
2630
+ const tempPath = `${dataPath}.tmp.${crypto2.randomUUID()}`;
2586
2631
  try {
2587
- await ensureDirectoryExists(path2.dirname(dataPath));
2632
+ const path = getNodePath();
2633
+ await ensureDirectoryExists(path.dirname(dataPath));
2588
2634
  const bareState = {
2589
2635
  actorId: state.actorId,
2590
2636
  name: state.name,
2591
2637
  key: state.key,
2592
2638
  createdAt: state.createdAt,
2593
- persistedData: state.persistedData
2639
+ kvStorage: state.kvStorage
2594
2640
  };
2595
2641
  const serializedState = ACTOR_STATE_VERSIONED.serializeWithEmbeddedVersion(bareState);
2596
- await fs2.writeFile(tempPath, serializedState);
2597
- await fs2.rename(tempPath, dataPath);
2642
+ const fs = getNodeFs();
2643
+ await fs.writeFile(tempPath, serializedState);
2644
+ if (!this.isGenerationCurrentAndNotDestroyed(actorId, generation)) {
2645
+ logger4().debug(
2646
+ "skipping writing alarm since actor destroying or new generation"
2647
+ );
2648
+ return;
2649
+ }
2650
+ await fs.rename(tempPath, dataPath);
2598
2651
  } catch (error) {
2599
2652
  try {
2600
- await fs2.unlink(tempPath);
2653
+ const fs = getNodeFs();
2654
+ await fs.unlink(tempPath);
2601
2655
  } catch {
2602
2656
  }
2603
- logger5().error({
2657
+ logger4().error({
2604
2658
  msg: "failed to save actor state",
2605
2659
  actorId,
2606
2660
  error
@@ -2628,7 +2682,7 @@ var FileSystemGlobalState = class {
2628
2682
  try {
2629
2683
  this.#loadAlarmsSync();
2630
2684
  } catch (err) {
2631
- logger5().error({
2685
+ logger4().error({
2632
2686
  msg: "failed to load alarms on startup",
2633
2687
  error: err
2634
2688
  });
@@ -2696,12 +2750,14 @@ var FileSystemGlobalState = class {
2696
2750
  */
2697
2751
  #loadAlarmsSync() {
2698
2752
  try {
2699
- const files = fsSync2.existsSync(this.#alarmsDir) ? fsSync2.readdirSync(this.#alarmsDir) : [];
2753
+ const fsSync = getNodeFsSync();
2754
+ const files = fsSync.existsSync(this.#alarmsDir) ? fsSync.readdirSync(this.#alarmsDir) : [];
2700
2755
  for (const file of files) {
2701
2756
  if (file.includes(".tmp.")) continue;
2702
- const fullPath = path2.join(this.#alarmsDir, file);
2757
+ const path = getNodePath();
2758
+ const fullPath = path.join(this.#alarmsDir, file);
2703
2759
  try {
2704
- const buf = fsSync2.readFileSync(fullPath);
2760
+ const buf = fsSync.readFileSync(fullPath);
2705
2761
  const alarmData = ACTOR_ALARM_VERSIONED.deserializeWithEmbeddedVersion(
2706
2762
  new Uint8Array(buf)
2707
2763
  );
@@ -2712,13 +2768,13 @@ var FileSystemGlobalState = class {
2712
2768
  timestamp
2713
2769
  );
2714
2770
  } else {
2715
- logger5().debug({
2771
+ logger4().debug({
2716
2772
  msg: "invalid alarm file contents",
2717
2773
  file
2718
2774
  });
2719
2775
  }
2720
2776
  } catch (err) {
2721
- logger5().error({
2777
+ logger4().error({
2722
2778
  msg: "failed to read alarm file",
2723
2779
  file,
2724
2780
  error: stringifyError(err)
@@ -2726,7 +2782,7 @@ var FileSystemGlobalState = class {
2726
2782
  }
2727
2783
  }
2728
2784
  } catch (err) {
2729
- logger5().error({
2785
+ logger4().error({
2730
2786
  msg: "failed to list alarms directory",
2731
2787
  error: err
2732
2788
  });
@@ -2739,7 +2795,7 @@ var FileSystemGlobalState = class {
2739
2795
  var _a;
2740
2796
  const entry = this.#upsertEntry(actorId);
2741
2797
  if (entry.alarmTimestamp !== void 0 && timestamp >= entry.alarmTimestamp) {
2742
- logger5().debug({
2798
+ logger4().debug({
2743
2799
  msg: "skipping alarm schedule (later than existing)",
2744
2800
  actorId,
2745
2801
  timestamp,
@@ -2747,7 +2803,7 @@ var FileSystemGlobalState = class {
2747
2803
  });
2748
2804
  return;
2749
2805
  }
2750
- logger5().debug({ msg: "scheduling alarm", actorId, timestamp });
2806
+ logger4().debug({ msg: "scheduling alarm", actorId, timestamp });
2751
2807
  (_a = entry.alarmTimeout) == null ? void 0 : _a.abort();
2752
2808
  entry.alarmTimestamp = timestamp;
2753
2809
  const delay = Math.max(0, timestamp - Date.now());
@@ -2755,10 +2811,11 @@ var FileSystemGlobalState = class {
2755
2811
  entry.alarmTimestamp = void 0;
2756
2812
  if (this.#persist) {
2757
2813
  try {
2758
- await fs2.unlink(this.getActorAlarmPath(actorId));
2814
+ const fs = getNodeFs();
2815
+ await fs.unlink(this.getActorAlarmPath(actorId));
2759
2816
  } catch (err) {
2760
2817
  if ((err == null ? void 0 : err.code) !== "ENOENT") {
2761
- logger5().debug({
2818
+ logger4().debug({
2762
2819
  msg: "failed to remove alarm file",
2763
2820
  actorId,
2764
2821
  error: stringifyError(err)
@@ -2767,7 +2824,7 @@ var FileSystemGlobalState = class {
2767
2824
  }
2768
2825
  }
2769
2826
  try {
2770
- logger5().debug({ msg: "triggering alarm", actorId, timestamp });
2827
+ logger4().debug({ msg: "triggering alarm", actorId, timestamp });
2771
2828
  const loaded = await this.loadActor(actorId);
2772
2829
  if (!loaded.state)
2773
2830
  throw new Error(`Actor does not exist: ${actorId}`);
@@ -2783,9 +2840,9 @@ var FileSystemGlobalState = class {
2783
2840
  );
2784
2841
  }
2785
2842
  invariant4(loaded.actor, "actor should be loaded after wake");
2786
- await loaded.actor._onAlarm();
2843
+ await loaded.actor.onAlarm();
2787
2844
  } catch (err) {
2788
- logger5().error({
2845
+ logger4().error({
2789
2846
  msg: "failed to handle alarm",
2790
2847
  actorId,
2791
2848
  error: stringifyError(err)
@@ -2794,12 +2851,14 @@ var FileSystemGlobalState = class {
2794
2851
  }, delay);
2795
2852
  }
2796
2853
  getOrCreateInspectorAccessToken() {
2797
- const tokenPath = path2.join(this.#storagePath, "inspector-token");
2798
- if (fsSync2.existsSync(tokenPath)) {
2799
- return fsSync2.readFileSync(tokenPath, "utf-8");
2854
+ const path = getNodePath();
2855
+ const fsSync = getNodeFsSync();
2856
+ const tokenPath = path.join(this.#storagePath, "inspector-token");
2857
+ if (fsSync.existsSync(tokenPath)) {
2858
+ return fsSync.readFileSync(tokenPath, "utf-8");
2800
2859
  }
2801
2860
  const newToken = generateRandomString();
2802
- fsSync2.writeFileSync(tokenPath, newToken);
2861
+ fsSync.writeFileSync(tokenPath, newToken);
2803
2862
  return newToken;
2804
2863
  }
2805
2864
  /**
@@ -2807,22 +2866,24 @@ var FileSystemGlobalState = class {
2807
2866
  */
2808
2867
  #cleanupTempFilesSync() {
2809
2868
  try {
2810
- const files = fsSync2.readdirSync(this.#stateDir);
2869
+ const fsSync = getNodeFsSync();
2870
+ const files = fsSync.readdirSync(this.#stateDir);
2811
2871
  const tempFiles = files.filter((f) => f.includes(".tmp."));
2812
2872
  const oneHourAgo = Date.now() - 36e5;
2813
2873
  for (const tempFile of tempFiles) {
2814
2874
  try {
2815
- const fullPath = path2.join(this.#stateDir, tempFile);
2816
- const stat2 = fsSync2.statSync(fullPath);
2817
- if (stat2.mtimeMs < oneHourAgo) {
2818
- fsSync2.unlinkSync(fullPath);
2819
- logger5().info({
2875
+ const path = getNodePath();
2876
+ const fullPath = path.join(this.#stateDir, tempFile);
2877
+ const stat = fsSync.statSync(fullPath);
2878
+ if (stat.mtimeMs < oneHourAgo) {
2879
+ fsSync.unlinkSync(fullPath);
2880
+ logger4().info({
2820
2881
  msg: "cleaned up stale temp file",
2821
2882
  file: tempFile
2822
2883
  });
2823
2884
  }
2824
2885
  } catch (err) {
2825
- logger5().debug({
2886
+ logger4().debug({
2826
2887
  msg: "failed to cleanup temp file",
2827
2888
  file: tempFile,
2828
2889
  error: err
@@ -2830,12 +2891,129 @@ var FileSystemGlobalState = class {
2830
2891
  }
2831
2892
  }
2832
2893
  } catch (err) {
2833
- logger5().error({
2894
+ logger4().error({
2834
2895
  msg: "failed to read actors directory for cleanup",
2835
2896
  error: err
2836
2897
  });
2837
2898
  }
2838
2899
  }
2900
+ /**
2901
+ * Batch put KV entries for an actor.
2902
+ */
2903
+ async kvBatchPut(actorId, entries) {
2904
+ const entry = await this.loadActor(actorId);
2905
+ if (!entry.state) {
2906
+ if (this.isActorStopping(actorId)) {
2907
+ return;
2908
+ } else {
2909
+ throw new Error(`Actor ${actorId} state not loaded`);
2910
+ }
2911
+ }
2912
+ const newKvStorage = [...entry.state.kvStorage];
2913
+ for (const [key, value] of entries) {
2914
+ const existingIndex = newKvStorage.findIndex(
2915
+ (e) => arrayBuffersEqual(e.key, bufferToArrayBuffer(key))
2916
+ );
2917
+ if (existingIndex >= 0) {
2918
+ newKvStorage[existingIndex] = {
2919
+ key: bufferToArrayBuffer(key),
2920
+ value: bufferToArrayBuffer(value)
2921
+ };
2922
+ } else {
2923
+ newKvStorage.push({
2924
+ key: bufferToArrayBuffer(key),
2925
+ value: bufferToArrayBuffer(value)
2926
+ });
2927
+ }
2928
+ }
2929
+ entry.state = {
2930
+ ...entry.state,
2931
+ kvStorage: newKvStorage
2932
+ };
2933
+ await this.writeActor(actorId, entry.generation, entry.state);
2934
+ }
2935
+ /**
2936
+ * Batch get KV entries for an actor.
2937
+ */
2938
+ async kvBatchGet(actorId, keys) {
2939
+ const entry = await this.loadActor(actorId);
2940
+ if (!entry.state) {
2941
+ if (this.isActorStopping(actorId)) {
2942
+ throw new Error(`Actor ${actorId} is stopping`);
2943
+ } else {
2944
+ throw new Error(`Actor ${actorId} state not loaded`);
2945
+ }
2946
+ }
2947
+ const results = [];
2948
+ for (const key of keys) {
2949
+ const foundEntry = entry.state.kvStorage.find(
2950
+ (e) => arrayBuffersEqual(e.key, bufferToArrayBuffer(key))
2951
+ );
2952
+ if (foundEntry) {
2953
+ results.push(new Uint8Array(foundEntry.value));
2954
+ } else {
2955
+ results.push(null);
2956
+ }
2957
+ }
2958
+ return results;
2959
+ }
2960
+ /**
2961
+ * Batch delete KV entries for an actor.
2962
+ */
2963
+ async kvBatchDelete(actorId, keys) {
2964
+ const entry = await this.loadActor(actorId);
2965
+ if (!entry.state) {
2966
+ if (this.isActorStopping(actorId)) {
2967
+ return;
2968
+ } else {
2969
+ throw new Error(`Actor ${actorId} state not loaded`);
2970
+ }
2971
+ }
2972
+ const newKvStorage = [...entry.state.kvStorage];
2973
+ for (const key of keys) {
2974
+ const indexToDelete = newKvStorage.findIndex(
2975
+ (e) => arrayBuffersEqual(e.key, bufferToArrayBuffer(key))
2976
+ );
2977
+ if (indexToDelete >= 0) {
2978
+ newKvStorage.splice(indexToDelete, 1);
2979
+ }
2980
+ }
2981
+ entry.state = {
2982
+ ...entry.state,
2983
+ kvStorage: newKvStorage
2984
+ };
2985
+ await this.writeActor(actorId, entry.generation, entry.state);
2986
+ }
2987
+ /**
2988
+ * List KV entries with a given prefix for an actor.
2989
+ */
2990
+ async kvListPrefix(actorId, prefix) {
2991
+ const entry = await this.loadActor(actorId);
2992
+ if (!entry.state) {
2993
+ if (this.isActorStopping(actorId)) {
2994
+ throw new Error(`Actor ${actorId} is destroying`);
2995
+ } else {
2996
+ throw new Error(`Actor ${actorId} state not loaded`);
2997
+ }
2998
+ }
2999
+ const results = [];
3000
+ for (const kvEntry of entry.state.kvStorage) {
3001
+ const keyBytes = new Uint8Array(kvEntry.key);
3002
+ if (keyBytes.length >= prefix.length) {
3003
+ let hasPrefix = true;
3004
+ for (let i = 0; i < prefix.length; i++) {
3005
+ if (keyBytes[i] !== prefix[i]) {
3006
+ hasPrefix = false;
3007
+ break;
3008
+ }
3009
+ }
3010
+ if (hasPrefix) {
3011
+ results.push([keyBytes, new Uint8Array(kvEntry.value)]);
3012
+ }
3013
+ }
3014
+ }
3015
+ return results;
3016
+ }
2839
3017
  };
2840
3018
 
2841
3019
  // src/drivers/file-system/manager.ts
@@ -2994,73 +3172,53 @@ var FileSystemManagerDriver = class {
2994
3172
  actorId
2995
3173
  });
2996
3174
  }
2997
- async openWebSocket(path4, actorId, encoding, params, connId, connToken) {
2998
- const pathOnly = path4.split("?")[0];
3175
+ async openWebSocket(path, actorId, encoding, params) {
3176
+ const pathOnly = path.split("?")[0];
2999
3177
  const normalizedPath = pathOnly.startsWith("/") ? pathOnly : `/${pathOnly}`;
3000
- if (normalizedPath === PATH_CONNECT_WEBSOCKET) {
3001
- const wsHandler = await handleWebSocketConnect(
3002
- void 0,
3003
- this.#runConfig,
3004
- this.#actorDriver,
3005
- actorId,
3006
- encoding,
3007
- params,
3008
- generateConnRequestId(),
3009
- void 0,
3010
- connId,
3011
- connToken
3012
- );
3013
- return new InlineWebSocketAdapter2(wsHandler);
3014
- } else if (normalizedPath.startsWith(PATH_RAW_WEBSOCKET_PREFIX) || normalizedPath === "/raw/websocket") {
3015
- const wsHandler = await handleRawWebSocketHandler(
3016
- void 0,
3017
- path4,
3018
- this.#actorDriver,
3019
- actorId,
3020
- void 0
3021
- );
3022
- return new InlineWebSocketAdapter2(wsHandler);
3023
- } else {
3024
- throw new Error(`Unreachable path: ${path4}`);
3025
- }
3178
+ const wsHandler = await routeWebSocket(
3179
+ // TODO: Create fake request
3180
+ void 0,
3181
+ normalizedPath,
3182
+ {},
3183
+ this.#runConfig,
3184
+ this.#actorDriver,
3185
+ actorId,
3186
+ encoding,
3187
+ params,
3188
+ void 0,
3189
+ void 0,
3190
+ false,
3191
+ false
3192
+ );
3193
+ return new InlineWebSocketAdapter(wsHandler);
3026
3194
  }
3027
3195
  async proxyRequest(c, actorRequest, actorId) {
3028
3196
  return await this.#actorRouter.fetch(actorRequest, {
3029
3197
  actorId
3030
3198
  });
3031
3199
  }
3032
- async proxyWebSocket(c, path4, actorId, encoding, connParams, connId, connToken) {
3200
+ async proxyWebSocket(c, path, actorId, encoding, params) {
3033
3201
  var _a, _b;
3034
3202
  const upgradeWebSocket = (_b = (_a = this.#runConfig).getUpgradeWebSocket) == null ? void 0 : _b.call(_a);
3035
3203
  invariant5(upgradeWebSocket, "missing getUpgradeWebSocket");
3036
- const pathOnly = path4.split("?")[0];
3204
+ const pathOnly = path.split("?")[0];
3037
3205
  const normalizedPath = pathOnly.startsWith("/") ? pathOnly : `/${pathOnly}`;
3038
- if (normalizedPath === PATH_CONNECT_WEBSOCKET) {
3039
- const wsHandler = await handleWebSocketConnect(
3040
- c.req.raw,
3041
- this.#runConfig,
3042
- this.#actorDriver,
3043
- actorId,
3044
- encoding,
3045
- connParams,
3046
- generateConnRequestId(),
3047
- void 0,
3048
- connId,
3049
- connToken
3050
- );
3051
- return upgradeWebSocket(() => wsHandler)(c, noopNext());
3052
- } else if (normalizedPath.startsWith(PATH_RAW_WEBSOCKET_PREFIX) || normalizedPath === "/raw/websocket") {
3053
- const wsHandler = await handleRawWebSocketHandler(
3054
- c.req.raw,
3055
- path4,
3056
- this.#actorDriver,
3057
- actorId,
3058
- void 0
3059
- );
3060
- return upgradeWebSocket(() => wsHandler)(c, noopNext());
3061
- } else {
3062
- throw new Error(`Unreachable path: ${path4}`);
3063
- }
3206
+ const wsHandler = await routeWebSocket(
3207
+ // TODO: Create new request with new path
3208
+ c.req.raw,
3209
+ normalizedPath,
3210
+ c.req.header(),
3211
+ this.#runConfig,
3212
+ this.#actorDriver,
3213
+ actorId,
3214
+ encoding,
3215
+ params,
3216
+ void 0,
3217
+ void 0,
3218
+ false,
3219
+ false
3220
+ );
3221
+ return upgradeWebSocket(() => wsHandler)(c, noopNext());
3064
3222
  }
3065
3223
  async getForId({
3066
3224
  actorId
@@ -3069,6 +3227,9 @@ var FileSystemManagerDriver = class {
3069
3227
  if (!actor2.state) {
3070
3228
  return void 0;
3071
3229
  }
3230
+ if (this.#state.isActorStopping(actorId)) {
3231
+ throw new ActorStopping(actorId);
3232
+ }
3072
3233
  try {
3073
3234
  return {
3074
3235
  actorId,
@@ -3076,7 +3237,7 @@ var FileSystemManagerDriver = class {
3076
3237
  key: actor2.state.key
3077
3238
  };
3078
3239
  } catch (error) {
3079
- logger5().error({
3240
+ logger4().error({
3080
3241
  msg: "failed to read actor state",
3081
3242
  actorId,
3082
3243
  error
@@ -3123,6 +3284,26 @@ var FileSystemManagerDriver = class {
3123
3284
  key
3124
3285
  };
3125
3286
  }
3287
+ async listActors({ name }) {
3288
+ const actors = [];
3289
+ const itr = this.#state.getActorsIterator({});
3290
+ for await (const actor2 of itr) {
3291
+ if (actor2.name === name) {
3292
+ actors.push({
3293
+ actorId: actor2.actorId,
3294
+ name: actor2.name,
3295
+ key: actor2.key,
3296
+ createTs: Number(actor2.createdAt)
3297
+ });
3298
+ }
3299
+ }
3300
+ actors.sort((a, b) => {
3301
+ const aTs = a.createTs ?? 0;
3302
+ const bTs = b.createTs ?? 0;
3303
+ return bTs - aTs;
3304
+ });
3305
+ return actors;
3306
+ }
3126
3307
  displayInformation() {
3127
3308
  return {
3128
3309
  name: this.#state.persist ? "File System" : "Memory",
@@ -3145,6 +3326,7 @@ var FileSystemManagerDriver = class {
3145
3326
 
3146
3327
  // src/drivers/file-system/mod.ts
3147
3328
  function createFileSystemOrMemoryDriver(persist = true, customPath) {
3329
+ importNodeDependencies();
3148
3330
  const state = new FileSystemGlobalState(persist, customPath);
3149
3331
  const driverConfig = {
3150
3332
  name: persist ? "file-system" : "memory",
@@ -3204,16 +3386,8 @@ function chooseDefaultDriver(runConfig) {
3204
3386
  return createFileSystemOrMemoryDriver(true);
3205
3387
  }
3206
3388
 
3207
- // src/engine-process/mod.ts
3208
- import { spawn } from "child_process";
3209
- import { randomUUID as randomUUID2 } from "crypto";
3210
- import { createWriteStream } from "fs";
3211
- import * as fs3 from "fs/promises";
3212
- import * as path3 from "path";
3213
- import { pipeline } from "stream/promises";
3214
-
3215
3389
  // src/engine-process/log.ts
3216
- function logger6() {
3390
+ function logger5() {
3217
3391
  return getLogger("engine-process");
3218
3392
  }
3219
3393
 
@@ -3223,30 +3397,32 @@ var ENGINE_ENDPOINT = `http://localhost:${ENGINE_PORT}`;
3223
3397
  var ENGINE_BASE_URL = "https://releases.rivet.gg/engine";
3224
3398
  var ENGINE_BINARY_NAME = "rivet-engine";
3225
3399
  async function ensureEngineProcess(options) {
3226
- logger6().debug({
3400
+ importNodeDependencies();
3401
+ logger5().debug({
3227
3402
  msg: "ensuring engine process",
3228
3403
  version: options.version
3229
3404
  });
3405
+ const path = getNodePath();
3230
3406
  const storageRoot = getStoragePath();
3231
- const binDir = path3.join(storageRoot, "bin");
3232
- const varDir = path3.join(storageRoot, "var");
3233
- const logsDir = path3.join(varDir, "logs", "rivet-engine");
3407
+ const binDir = path.join(storageRoot, "bin");
3408
+ const varDir = path.join(storageRoot, "var");
3409
+ const logsDir = path.join(varDir, "logs", "rivet-engine");
3234
3410
  await ensureDirectoryExists(binDir);
3235
3411
  await ensureDirectoryExists(varDir);
3236
3412
  await ensureDirectoryExists(logsDir);
3237
3413
  const executableName = process.platform === "win32" ? `${ENGINE_BINARY_NAME}-${options.version}.exe` : `${ENGINE_BINARY_NAME}-${options.version}`;
3238
- const binaryPath = path3.join(binDir, executableName);
3414
+ const binaryPath = path.join(binDir, executableName);
3239
3415
  await downloadEngineBinaryIfNeeded(binaryPath, options.version, varDir);
3240
3416
  if (await isEngineRunning()) {
3241
3417
  try {
3242
3418
  await waitForEngineHealth();
3243
- logger6().debug({
3419
+ logger5().debug({
3244
3420
  msg: "engine already running and healthy",
3245
3421
  version: options.version
3246
3422
  });
3247
3423
  return;
3248
3424
  } catch (error) {
3249
- logger6().warn({
3425
+ logger5().warn({
3250
3426
  msg: "existing engine process not healthy, cannot restart automatically",
3251
3427
  error
3252
3428
  });
@@ -3256,39 +3432,26 @@ async function ensureEngineProcess(options) {
3256
3432
  }
3257
3433
  }
3258
3434
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-").replace(/\./g, "-");
3259
- const stdoutLogPath = path3.join(logsDir, `engine-${timestamp}-stdout.log`);
3260
- const stderrLogPath = path3.join(logsDir, `engine-${timestamp}-stderr.log`);
3261
- const stdoutStream = createWriteStream(stdoutLogPath, { flags: "a" });
3262
- const stderrStream = createWriteStream(stderrLogPath, { flags: "a" });
3263
- logger6().debug({
3435
+ const stdoutLogPath = path.join(logsDir, `engine-${timestamp}-stdout.log`);
3436
+ const stderrLogPath = path.join(logsDir, `engine-${timestamp}-stderr.log`);
3437
+ const fsSync = getNodeFsSync();
3438
+ const stdoutStream = fsSync.createWriteStream(stdoutLogPath, {
3439
+ flags: "a"
3440
+ });
3441
+ const stderrStream = fsSync.createWriteStream(stderrLogPath, {
3442
+ flags: "a"
3443
+ });
3444
+ logger5().debug({
3264
3445
  msg: "creating engine log files",
3265
3446
  stdout: stdoutLogPath,
3266
3447
  stderr: stderrLogPath
3267
3448
  });
3268
- const child = spawn(binaryPath, ["start"], {
3269
- cwd: path3.dirname(binaryPath),
3449
+ const childProcess = getNodeChildProcess();
3450
+ const child = childProcess.spawn(binaryPath, ["start"], {
3451
+ cwd: path.dirname(binaryPath),
3270
3452
  stdio: ["inherit", "pipe", "pipe"],
3271
3453
  env: {
3272
- ...process.env,
3273
- // In development, runners can be terminated without a graceful
3274
- // shutdown (i.e. SIGKILL instead of SIGTERM). This is treated as a
3275
- // crash by Rivet Engine in production and implements a backoff for
3276
- // rescheduling actors in case of a crash loop.
3277
- //
3278
- // This is problematic in development since this will cause actors
3279
- // to become unresponsive if frequently killing your dev server.
3280
- //
3281
- // We reduce the timeouts for resetting a runner as healthy in
3282
- // order to account for this.
3283
- RIVET__PEGBOARD__RETRY_RESET_DURATION: "100",
3284
- RIVET__PEGBOARD__BASE_RETRY_TIMEOUT: "100",
3285
- // Set max exponent to 1 to have a maximum of base_retry_timeout
3286
- RIVET__PEGBOARD__RESCHEDULE_BACKOFF_MAX_EXPONENT: "1",
3287
- // Reduce thresholds for faster development iteration
3288
- //
3289
- // Default ping interval is 3s, this gives a 2s & 4s grace
3290
- RIVET__PEGBOARD__RUNNER_ELIGIBLE_THRESHOLD: "5000",
3291
- RIVET__PEGBOARD__RUNNER_LOST_THRESHOLD: "7000"
3454
+ ...process.env
3292
3455
  }
3293
3456
  });
3294
3457
  if (!child.pid) {
@@ -3300,23 +3463,24 @@ async function ensureEngineProcess(options) {
3300
3463
  if (child.stderr) {
3301
3464
  child.stderr.pipe(stderrStream);
3302
3465
  }
3303
- logger6().debug({
3466
+ logger5().debug({
3304
3467
  msg: "spawned engine process",
3305
3468
  pid: child.pid,
3306
- cwd: path3.dirname(binaryPath)
3469
+ cwd: path.dirname(binaryPath)
3307
3470
  });
3308
3471
  child.once("exit", (code, signal) => {
3309
- logger6().warn({
3472
+ logger5().warn({
3310
3473
  msg: "engine process exited, please report this error",
3311
3474
  code,
3312
3475
  signal,
3313
- ...EXTRA_ERROR_LOG
3476
+ issues: "https://github.com/rivet-dev/rivetkit/issues",
3477
+ support: "https://rivet.dev/discord"
3314
3478
  });
3315
3479
  stdoutStream.end();
3316
3480
  stderrStream.end();
3317
3481
  });
3318
3482
  child.once("error", (error) => {
3319
- logger6().error({
3483
+ logger5().error({
3320
3484
  msg: "engine process failed",
3321
3485
  error
3322
3486
  });
@@ -3324,7 +3488,7 @@ async function ensureEngineProcess(options) {
3324
3488
  stderrStream.end();
3325
3489
  });
3326
3490
  await waitForEngineHealth();
3327
- logger6().info({
3491
+ logger5().info({
3328
3492
  msg: "engine process started",
3329
3493
  pid: child.pid,
3330
3494
  version: options.version,
@@ -3337,7 +3501,7 @@ async function ensureEngineProcess(options) {
3337
3501
  async function downloadEngineBinaryIfNeeded(binaryPath, version, varDir) {
3338
3502
  const binaryExists = await fileExists(binaryPath);
3339
3503
  if (binaryExists) {
3340
- logger6().debug({
3504
+ logger5().debug({
3341
3505
  msg: "engine binary already cached",
3342
3506
  version,
3343
3507
  path: binaryPath
@@ -3347,7 +3511,7 @@ async function downloadEngineBinaryIfNeeded(binaryPath, version, varDir) {
3347
3511
  const { targetTriplet, extension } = resolveTargetTriplet();
3348
3512
  const remoteFile = `${ENGINE_BINARY_NAME}-${targetTriplet}${extension}`;
3349
3513
  const downloadUrl = `${ENGINE_BASE_URL}/${version}/${remoteFile}`;
3350
- logger6().info({
3514
+ logger5().info({
3351
3515
  msg: "downloading engine binary",
3352
3516
  url: downloadUrl,
3353
3517
  path: binaryPath,
@@ -3359,50 +3523,59 @@ async function downloadEngineBinaryIfNeeded(binaryPath, version, varDir) {
3359
3523
  `failed to download rivet engine binary from ${downloadUrl}: ${response.status} ${response.statusText}`
3360
3524
  );
3361
3525
  }
3362
- const tempPath = `${binaryPath}.${randomUUID2()}.tmp`;
3526
+ const crypto2 = getNodeCrypto();
3527
+ const tempPath = `${binaryPath}.${crypto2.randomUUID()}.tmp`;
3363
3528
  const startTime = Date.now();
3364
- logger6().debug({
3529
+ logger5().debug({
3365
3530
  msg: "starting binary download",
3366
3531
  tempPath,
3367
3532
  contentLength: response.headers.get("content-length")
3368
3533
  });
3369
3534
  const slowDownloadWarning = setTimeout(() => {
3370
- logger6().warn({
3535
+ logger5().warn({
3371
3536
  msg: "engine binary download is taking longer than expected, please be patient",
3372
3537
  version
3373
3538
  });
3374
3539
  }, 5e3);
3375
3540
  try {
3376
- await pipeline(response.body, createWriteStream(tempPath));
3541
+ const stream = getNodeStream();
3542
+ const fsSync = getNodeFsSync();
3543
+ await stream.pipeline(
3544
+ response.body,
3545
+ fsSync.createWriteStream(tempPath)
3546
+ );
3377
3547
  clearTimeout(slowDownloadWarning);
3378
- const stats = await fs3.stat(tempPath);
3548
+ const fs = getNodeFs();
3549
+ const stats = await fs.stat(tempPath);
3379
3550
  const downloadDuration = Date.now() - startTime;
3380
3551
  if (process.platform !== "win32") {
3381
- await fs3.chmod(tempPath, 493);
3552
+ await fs.chmod(tempPath, 493);
3382
3553
  }
3383
- await fs3.rename(tempPath, binaryPath);
3384
- logger6().debug({
3554
+ await fs.rename(tempPath, binaryPath);
3555
+ logger5().debug({
3385
3556
  msg: "engine binary download complete",
3386
3557
  version,
3387
3558
  path: binaryPath,
3388
3559
  size: stats.size,
3389
3560
  durationMs: downloadDuration
3390
3561
  });
3391
- logger6().info({
3562
+ logger5().info({
3392
3563
  msg: "engine binary downloaded",
3393
3564
  version,
3394
3565
  path: binaryPath
3395
3566
  });
3396
3567
  } catch (error) {
3397
3568
  clearTimeout(slowDownloadWarning);
3398
- logger6().warn({
3569
+ logger5().warn({
3399
3570
  msg: "engine download failed, please report this error",
3400
3571
  tempPath,
3401
3572
  error,
3402
- ...EXTRA_ERROR_LOG
3573
+ issues: "https://github.com/rivet-dev/rivetkit/issues",
3574
+ support: "https://rivet.dev/discord"
3403
3575
  });
3404
3576
  try {
3405
- await fs3.unlink(tempPath);
3577
+ const fs = getNodeFs();
3578
+ await fs.unlink(tempPath);
3406
3579
  } catch (unlinkError) {
3407
3580
  }
3408
3581
  throw error;
@@ -3455,13 +3628,13 @@ async function checkIfEngineAlreadyRunningOnPort(port) {
3455
3628
  if (response.ok) {
3456
3629
  const health = await response.json();
3457
3630
  if (health.runtime === "engine") {
3458
- logger6().debug({
3631
+ logger5().debug({
3459
3632
  msg: "rivet engine already running on port",
3460
3633
  port
3461
3634
  });
3462
3635
  return true;
3463
3636
  } else if (health.runtime === "rivetkit") {
3464
- logger6().error({
3637
+ logger5().error({
3465
3638
  msg: "another rivetkit process is already running on port",
3466
3639
  port
3467
3640
  });
@@ -3478,7 +3651,8 @@ async function checkIfEngineAlreadyRunningOnPort(port) {
3478
3651
  }
3479
3652
  async function fileExists(filePath) {
3480
3653
  try {
3481
- await fs3.access(filePath);
3654
+ const fs = getNodeFs();
3655
+ await fs.access(filePath);
3482
3656
  return true;
3483
3657
  } catch {
3484
3658
  return false;
@@ -3488,12 +3662,12 @@ var HEALTH_MAX_WAIT = 1e4;
3488
3662
  var HEALTH_INTERVAL = 100;
3489
3663
  async function waitForEngineHealth() {
3490
3664
  const maxRetries = Math.ceil(HEALTH_MAX_WAIT / HEALTH_INTERVAL);
3491
- logger6().debug({ msg: "waiting for engine health check" });
3665
+ logger5().debug({ msg: "waiting for engine health check" });
3492
3666
  for (let i = 0; i < maxRetries; i++) {
3493
3667
  try {
3494
3668
  const response = await fetch(`${ENGINE_ENDPOINT}/health`);
3495
3669
  if (response.ok) {
3496
- logger6().debug({ msg: "engine health check passed" });
3670
+ logger5().debug({ msg: "engine health check passed" });
3497
3671
  return;
3498
3672
  }
3499
3673
  } catch (error) {
@@ -3504,7 +3678,7 @@ async function waitForEngineHealth() {
3504
3678
  }
3505
3679
  }
3506
3680
  if (i < maxRetries - 1) {
3507
- logger6().trace({
3681
+ logger5().trace({
3508
3682
  msg: "engine not ready, retrying",
3509
3683
  attempt: i + 1,
3510
3684
  maxRetries
@@ -3579,6 +3753,9 @@ var ActorSchema = z4.object({
3579
3753
  sleep_ts: z4.number().nullable().optional(),
3580
3754
  start_ts: z4.number().nullable().optional()
3581
3755
  });
3756
+ var ActorNameSchema = z4.object({
3757
+ metadata: z4.record(z4.string(), z4.unknown())
3758
+ });
3582
3759
  var ActorsListResponseSchema = z4.object({
3583
3760
  actors: z4.array(ActorSchema)
3584
3761
  });
@@ -3606,6 +3783,14 @@ var ActorsGetOrCreateResponseSchema = z4.object({
3606
3783
  created: z4.boolean()
3607
3784
  });
3608
3785
  var ActorsDeleteResponseSchema = z4.object({});
3786
+ var ActorsListNamesResponseSchema = z4.object({
3787
+ names: z4.record(z4.string(), ActorNameSchema)
3788
+ });
3789
+
3790
+ // src/manager/log.ts
3791
+ function logger6() {
3792
+ return getLogger("actor-manager");
3793
+ }
3609
3794
 
3610
3795
  // src/manager/gateway.ts
3611
3796
  async function handleWebSocketGatewayPathBased(runConfig, managerDriver, c, actorPathInfo) {
@@ -3617,8 +3802,6 @@ async function handleWebSocketGatewayPathBased(runConfig, managerDriver, c, acto
3617
3802
  const protocols = c.req.header("sec-websocket-protocol");
3618
3803
  let encodingRaw;
3619
3804
  let connParamsRaw;
3620
- let connIdRaw;
3621
- let connTokenRaw;
3622
3805
  if (protocols) {
3623
3806
  const protocolList = protocols.split(",").map((p) => p.trim());
3624
3807
  for (const protocol of protocolList) {
@@ -3628,16 +3811,10 @@ async function handleWebSocketGatewayPathBased(runConfig, managerDriver, c, acto
3628
3811
  connParamsRaw = decodeURIComponent(
3629
3812
  protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
3630
3813
  );
3631
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_ID)) {
3632
- connIdRaw = protocol.substring(WS_PROTOCOL_CONN_ID.length);
3633
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_TOKEN)) {
3634
- connTokenRaw = protocol.substring(
3635
- WS_PROTOCOL_CONN_TOKEN.length
3636
- );
3637
3814
  }
3638
3815
  }
3639
3816
  }
3640
- logger().debug({
3817
+ logger6().debug({
3641
3818
  msg: "proxying websocket to actor via path-based routing",
3642
3819
  actorId: actorPathInfo.actorId,
3643
3820
  path: actorPathInfo.remainingPath,
@@ -3651,13 +3828,11 @@ async function handleWebSocketGatewayPathBased(runConfig, managerDriver, c, acto
3651
3828
  actorPathInfo.actorId,
3652
3829
  encoding,
3653
3830
  // Will be validated by driver
3654
- connParams,
3655
- connIdRaw,
3656
- connTokenRaw
3831
+ connParams
3657
3832
  );
3658
3833
  }
3659
3834
  async function handleHttpGatewayPathBased(managerDriver, c, actorPathInfo) {
3660
- logger().debug({
3835
+ logger6().debug({
3661
3836
  msg: "proxying request to actor via path-based routing",
3662
3837
  actorId: actorPathInfo.actorId,
3663
3838
  path: actorPathInfo.remainingPath,
@@ -3692,7 +3867,7 @@ async function actorGateway(runConfig, managerDriver, c, next) {
3692
3867
  const pathWithQuery = c.req.url.includes("?") ? strippedPath + c.req.url.substring(c.req.url.indexOf("?")) : strippedPath;
3693
3868
  const actorPathInfo = parseActorPath(pathWithQuery);
3694
3869
  if (actorPathInfo) {
3695
- logger().debug({
3870
+ logger6().debug({
3696
3871
  msg: "routing using path-based actor routing",
3697
3872
  actorPathInfo
3698
3873
  });
@@ -3732,27 +3907,19 @@ async function handleWebSocketGateway(runConfig, managerDriver, c, strippedPath)
3732
3907
  let actorId;
3733
3908
  let encodingRaw;
3734
3909
  let connParamsRaw;
3735
- let connIdRaw;
3736
- let connTokenRaw;
3737
3910
  if (protocols) {
3738
3911
  const protocolList = protocols.split(",").map((p) => p.trim());
3739
3912
  for (const protocol of protocolList) {
3740
3913
  if (protocol.startsWith(WS_PROTOCOL_TARGET)) {
3741
3914
  target = protocol.substring(WS_PROTOCOL_TARGET.length);
3742
3915
  } else if (protocol.startsWith(WS_PROTOCOL_ACTOR)) {
3743
- actorId = protocol.substring(WS_PROTOCOL_ACTOR.length);
3916
+ actorId = decodeURIComponent(protocol.substring(WS_PROTOCOL_ACTOR.length));
3744
3917
  } else if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
3745
3918
  encodingRaw = protocol.substring(WS_PROTOCOL_ENCODING.length);
3746
3919
  } else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
3747
3920
  connParamsRaw = decodeURIComponent(
3748
3921
  protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
3749
3922
  );
3750
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_ID)) {
3751
- connIdRaw = protocol.substring(WS_PROTOCOL_CONN_ID.length);
3752
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_TOKEN)) {
3753
- connTokenRaw = protocol.substring(
3754
- WS_PROTOCOL_CONN_TOKEN.length
3755
- );
3756
3923
  }
3757
3924
  }
3758
3925
  }
@@ -3762,7 +3929,7 @@ async function handleWebSocketGateway(runConfig, managerDriver, c, strippedPath)
3762
3929
  if (!actorId) {
3763
3930
  throw new MissingActorHeader();
3764
3931
  }
3765
- logger().debug({
3932
+ logger6().debug({
3766
3933
  msg: "proxying websocket to actor",
3767
3934
  actorId,
3768
3935
  path: strippedPath,
@@ -3777,9 +3944,7 @@ async function handleWebSocketGateway(runConfig, managerDriver, c, strippedPath)
3777
3944
  actorId,
3778
3945
  encoding,
3779
3946
  // Will be validated by driver
3780
- connParams,
3781
- connIdRaw,
3782
- connTokenRaw
3947
+ connParams
3783
3948
  );
3784
3949
  }
3785
3950
  async function handleHttpGateway(managerDriver, c, next, strippedPath) {
@@ -3791,7 +3956,7 @@ async function handleHttpGateway(managerDriver, c, next, strippedPath) {
3791
3956
  if (!actorId) {
3792
3957
  throw new MissingActorHeader();
3793
3958
  }
3794
- logger().debug({
3959
+ logger6().debug({
3795
3960
  msg: "proxying request to actor",
3796
3961
  actorId,
3797
3962
  path: strippedPath,
@@ -3811,22 +3976,22 @@ async function handleHttpGateway(managerDriver, c, next, strippedPath) {
3811
3976
  });
3812
3977
  return await managerDriver.proxyRequest(c, proxyRequest, actorId);
3813
3978
  }
3814
- function parseActorPath(path4) {
3815
- const queryPos = path4.indexOf("?");
3816
- const fragmentPos = path4.indexOf("#");
3979
+ function parseActorPath(path) {
3980
+ const queryPos = path.indexOf("?");
3981
+ const fragmentPos = path.indexOf("#");
3817
3982
  let queryString = "";
3818
3983
  if (queryPos !== -1) {
3819
3984
  if (fragmentPos !== -1 && queryPos < fragmentPos) {
3820
- queryString = path4.slice(queryPos, fragmentPos);
3985
+ queryString = path.slice(queryPos, fragmentPos);
3821
3986
  } else {
3822
- queryString = path4.slice(queryPos);
3987
+ queryString = path.slice(queryPos);
3823
3988
  }
3824
3989
  }
3825
- let basePath = path4;
3990
+ let basePath = path;
3826
3991
  if (queryPos !== -1) {
3827
- basePath = path4.slice(0, queryPos);
3992
+ basePath = path.slice(0, queryPos);
3828
3993
  } else if (fragmentPos !== -1) {
3829
- basePath = path4.slice(0, fragmentPos);
3994
+ basePath = path.slice(0, fragmentPos);
3830
3995
  }
3831
3996
  if (basePath.includes("//")) {
3832
3997
  return null;
@@ -3895,22 +4060,22 @@ async function createTestWebSocketProxy(clientWsPromise) {
3895
4060
  reject: serverWsReject
3896
4061
  } = promiseWithResolvers();
3897
4062
  try {
3898
- logger().debug({ msg: "awaiting client websocket promise" });
4063
+ logger6().debug({ msg: "awaiting client websocket promise" });
3899
4064
  const ws = await clientWsPromise;
3900
4065
  clientWs = ws;
3901
- logger().debug({
4066
+ logger6().debug({
3902
4067
  msg: "client websocket promise resolved",
3903
4068
  constructor: ws == null ? void 0 : ws.constructor.name
3904
4069
  });
3905
4070
  await new Promise((resolve, reject) => {
3906
4071
  const onOpen = () => {
3907
- logger().debug({
4072
+ logger6().debug({
3908
4073
  msg: "test websocket connection to actor opened"
3909
4074
  });
3910
4075
  resolve();
3911
4076
  };
3912
4077
  const onError = (error) => {
3913
- logger().error({
4078
+ logger6().error({
3914
4079
  msg: "test websocket connection failed",
3915
4080
  error
3916
4081
  });
@@ -3926,7 +4091,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
3926
4091
  ws.addEventListener("message", async (clientEvt) => {
3927
4092
  var _a, _b;
3928
4093
  const serverWs = await serverWsPromise;
3929
- logger().debug({
4094
+ logger6().debug({
3930
4095
  msg: `test websocket connection message from client`,
3931
4096
  dataType: typeof clientEvt.data,
3932
4097
  isBlob: clientEvt.data instanceof Blob,
@@ -3937,19 +4102,19 @@ async function createTestWebSocketProxy(clientWsPromise) {
3937
4102
  if (serverWs.readyState === 1) {
3938
4103
  if (clientEvt.data instanceof Blob) {
3939
4104
  clientEvt.data.arrayBuffer().then((buffer) => {
3940
- logger().debug({
4105
+ logger6().debug({
3941
4106
  msg: "converted client blob to arraybuffer, sending to server",
3942
4107
  bufferSize: buffer.byteLength
3943
4108
  });
3944
4109
  serverWs.send(buffer);
3945
4110
  }).catch((error) => {
3946
- logger().error({
4111
+ logger6().error({
3947
4112
  msg: "failed to convert blob to arraybuffer",
3948
4113
  error
3949
4114
  });
3950
4115
  });
3951
4116
  } else {
3952
- logger().debug({
4117
+ logger6().debug({
3953
4118
  msg: "sending client data directly to server",
3954
4119
  dataType: typeof clientEvt.data,
3955
4120
  dataLength: typeof clientEvt.data === "string" ? clientEvt.data.length : void 0
@@ -3960,7 +4125,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
3960
4125
  });
3961
4126
  ws.addEventListener("close", async (clientEvt) => {
3962
4127
  const serverWs = await serverWsPromise;
3963
- logger().debug({
4128
+ logger6().debug({
3964
4129
  msg: `test websocket connection closed`
3965
4130
  });
3966
4131
  if (serverWs.readyState !== 3) {
@@ -3969,7 +4134,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
3969
4134
  });
3970
4135
  ws.addEventListener("error", async () => {
3971
4136
  const serverWs = await serverWsPromise;
3972
- logger().debug({
4137
+ logger6().debug({
3973
4138
  msg: `test websocket connection error`
3974
4139
  });
3975
4140
  if (serverWs.readyState !== 3) {
@@ -3978,7 +4143,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
3978
4143
  });
3979
4144
  });
3980
4145
  } catch (error) {
3981
- logger().error({
4146
+ logger6().error({
3982
4147
  msg: `failed to establish client websocket connection`,
3983
4148
  error
3984
4149
  });
@@ -3996,10 +4161,10 @@ async function createTestWebSocketProxy(clientWsPromise) {
3996
4161
  }
3997
4162
  return {
3998
4163
  onOpen: (_evt, serverWs) => {
3999
- logger().debug({
4164
+ logger6().debug({
4000
4165
  msg: `test websocket connection from client opened`
4001
4166
  });
4002
- logger().debug({
4167
+ logger6().debug({
4003
4168
  msg: "clientWs info",
4004
4169
  constructor: clientWs.constructor.name,
4005
4170
  hasAddEventListener: typeof clientWs.addEventListener === "function",
@@ -4009,7 +4174,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
4009
4174
  },
4010
4175
  onMessage: (evt) => {
4011
4176
  var _a, _b;
4012
- logger().debug({
4177
+ logger6().debug({
4013
4178
  msg: "received message from server",
4014
4179
  dataType: typeof evt.data,
4015
4180
  isBlob: evt.data instanceof Blob,
@@ -4020,19 +4185,19 @@ async function createTestWebSocketProxy(clientWsPromise) {
4020
4185
  if (clientWs.readyState === 1) {
4021
4186
  if (evt.data instanceof Blob) {
4022
4187
  evt.data.arrayBuffer().then((buffer) => {
4023
- logger().debug({
4188
+ logger6().debug({
4024
4189
  msg: "converted blob to arraybuffer, sending",
4025
4190
  bufferSize: buffer.byteLength
4026
4191
  });
4027
4192
  clientWs.send(buffer);
4028
4193
  }).catch((error) => {
4029
- logger().error({
4194
+ logger6().error({
4030
4195
  msg: "failed to convert blob to arraybuffer",
4031
4196
  error
4032
4197
  });
4033
4198
  });
4034
4199
  } else {
4035
- logger().debug({
4200
+ logger6().debug({
4036
4201
  msg: "sending data directly",
4037
4202
  dataType: typeof evt.data,
4038
4203
  dataLength: typeof evt.data === "string" ? evt.data.length : void 0
@@ -4042,7 +4207,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
4042
4207
  }
4043
4208
  },
4044
4209
  onClose: (event, serverWs) => {
4045
- logger().debug({
4210
+ logger6().debug({
4046
4211
  msg: `server websocket closed`,
4047
4212
  wasClean: event.wasClean,
4048
4213
  code: event.code,
@@ -4054,7 +4219,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
4054
4219
  }
4055
4220
  },
4056
4221
  onError: (error) => {
4057
- logger().error({
4222
+ logger6().error({
4058
4223
  msg: `error in server websocket`,
4059
4224
  error
4060
4225
  });
@@ -4103,11 +4268,21 @@ function buildOpenApiResponses(schema) {
4103
4268
  }
4104
4269
  };
4105
4270
  }
4271
+ function buildOpenApiRequestBody(schema) {
4272
+ return {
4273
+ required: true,
4274
+ content: {
4275
+ "application/json": {
4276
+ schema
4277
+ }
4278
+ }
4279
+ };
4280
+ }
4106
4281
  function createManagerRouter(registryConfig, runConfig, managerDriver, driverConfig, client) {
4107
4282
  const router = new OpenAPIHono({ strict: false }).basePath(
4108
4283
  runConfig.basePath
4109
4284
  );
4110
- router.use("*", loggerMiddleware(logger()), cors());
4285
+ router.use("*", loggerMiddleware(logger6()), cors());
4111
4286
  router.use(
4112
4287
  "*",
4113
4288
  createMiddleware(async (c, next) => {
@@ -4159,7 +4334,7 @@ function addServerlessRoutes(driverConfig, registryConfig, runConfig, managerDri
4159
4334
  );
4160
4335
  }
4161
4336
  const { endpoint, token, totalSlots, runnerName, namespace } = parseResult.data;
4162
- logger().debug({
4337
+ logger6().debug({
4163
4338
  msg: "received serverless runner start request",
4164
4339
  endpoint,
4165
4340
  totalSlots,
@@ -4173,7 +4348,7 @@ function addServerlessRoutes(driverConfig, registryConfig, runConfig, managerDri
4173
4348
  newRunConfig.runnerName = runnerName;
4174
4349
  newRunConfig.namespace = namespace;
4175
4350
  if (newRunConfig.runnerKey) {
4176
- logger().warn({
4351
+ logger6().warn({
4177
4352
  msg: "runner keys are not supported by serverless runners, this will be overwritten with a random runner key",
4178
4353
  oldRunnerKey: newRunConfig.runnerKey
4179
4354
  });
@@ -4245,15 +4420,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4245
4420
  if (key && !name) {
4246
4421
  return c.json(
4247
4422
  {
4248
- error: "When providing 'key', 'name' must also be provided."
4249
- },
4250
- 400
4251
- );
4252
- }
4253
- if (!actorIdsParsed && !key) {
4254
- return c.json(
4255
- {
4256
- error: "Must provide either 'actor_ids' or both 'name' and 'key'."
4423
+ error: "Name is required when key is provided."
4257
4424
  },
4258
4425
  400
4259
4426
  );
@@ -4298,7 +4465,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4298
4465
  }
4299
4466
  }
4300
4467
  }
4301
- } else if (key) {
4468
+ } else if (key && name) {
4302
4469
  const actorOutput = await managerDriver.getWithKey({
4303
4470
  c,
4304
4471
  name,
@@ -4308,6 +4475,22 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4308
4475
  if (actorOutput) {
4309
4476
  actors.push(actorOutput);
4310
4477
  }
4478
+ } else {
4479
+ if (!name) {
4480
+ return c.json(
4481
+ {
4482
+ error: "Name is required when not using actor_ids."
4483
+ },
4484
+ 400
4485
+ );
4486
+ }
4487
+ const actorOutputs = await managerDriver.listActors({
4488
+ c,
4489
+ name,
4490
+ key,
4491
+ includeDestroyed: false
4492
+ });
4493
+ actors.push(...actorOutputs);
4311
4494
  }
4312
4495
  return c.json({
4313
4496
  actors: actors.map(
@@ -4316,18 +4499,30 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4316
4499
  });
4317
4500
  });
4318
4501
  }
4502
+ {
4503
+ const route = createRoute({
4504
+ method: "get",
4505
+ path: "/actors/names",
4506
+ request: {
4507
+ query: z6.object({
4508
+ namespace: z6.string()
4509
+ })
4510
+ },
4511
+ responses: buildOpenApiResponses(ActorsListNamesResponseSchema)
4512
+ });
4513
+ router.openapi(route, async (c) => {
4514
+ const names = buildActorNames(registryConfig);
4515
+ return c.json({
4516
+ names
4517
+ });
4518
+ });
4519
+ }
4319
4520
  {
4320
4521
  const route = createRoute({
4321
4522
  method: "put",
4322
4523
  path: "/actors",
4323
4524
  request: {
4324
- body: {
4325
- content: {
4326
- "application/json": {
4327
- schema: ActorsGetOrCreateRequestSchema
4328
- }
4329
- }
4330
- }
4525
+ body: buildOpenApiRequestBody(ActorsGetOrCreateRequestSchema)
4331
4526
  },
4332
4527
  responses: buildOpenApiResponses(ActorsGetOrCreateResponseSchema)
4333
4528
  });
@@ -4365,13 +4560,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4365
4560
  method: "post",
4366
4561
  path: "/actors",
4367
4562
  request: {
4368
- body: {
4369
- content: {
4370
- "application/json": {
4371
- schema: ActorsCreateRequestSchema
4372
- }
4373
- }
4374
- }
4563
+ body: buildOpenApiRequestBody(ActorsCreateRequestSchema)
4375
4564
  },
4376
4565
  responses: buildOpenApiResponses(ActorsCreateResponseSchema)
4377
4566
  });
@@ -4393,18 +4582,10 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4393
4582
  if (registryConfig.test.enabled) {
4394
4583
  router.post(".test/inline-driver/call", async (c) => {
4395
4584
  const buffer = await c.req.arrayBuffer();
4396
- const {
4397
- encoding,
4398
- transport,
4399
- method,
4400
- args
4401
- } = cbor4.decode(
4402
- new Uint8Array(buffer)
4403
- );
4404
- logger().debug({
4585
+ const { encoding, method, args } = cbor4.decode(new Uint8Array(buffer));
4586
+ logger6().debug({
4405
4587
  msg: "received inline request",
4406
4588
  encoding,
4407
- transport,
4408
4589
  method,
4409
4590
  args
4410
4591
  });
@@ -4415,7 +4596,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4415
4596
  );
4416
4597
  response = { ok: output };
4417
4598
  } catch (rawErr) {
4418
- const err = deconstructError(rawErr, logger(), {}, true);
4599
+ const err = deconstructError(rawErr, logger6(), {}, true);
4419
4600
  response = { err };
4420
4601
  }
4421
4602
  return c.body(cbor4.encode(response));
@@ -4432,54 +4613,38 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4432
4613
  const protocols = protocolHeader.split(/,\s*/);
4433
4614
  let actorId = "";
4434
4615
  let encoding = "bare";
4435
- let transport = "websocket";
4436
- let path4 = "";
4616
+ let path = "";
4437
4617
  let params;
4438
- let connId;
4439
- let connToken;
4440
4618
  for (const protocol of protocols) {
4441
4619
  if (protocol.startsWith(WS_PROTOCOL_ACTOR)) {
4442
- actorId = protocol.substring(WS_PROTOCOL_ACTOR.length);
4620
+ actorId = decodeURIComponent(protocol.substring(WS_PROTOCOL_ACTOR.length));
4443
4621
  } else if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
4444
4622
  encoding = protocol.substring(
4445
4623
  WS_PROTOCOL_ENCODING.length
4446
4624
  );
4447
- } else if (protocol.startsWith(WS_PROTOCOL_TRANSPORT)) {
4448
- transport = protocol.substring(
4449
- WS_PROTOCOL_TRANSPORT.length
4450
- );
4451
- } else if (protocol.startsWith(WS_PROTOCOL_PATH)) {
4452
- path4 = decodeURIComponent(
4453
- protocol.substring(WS_PROTOCOL_PATH.length)
4625
+ } else if (protocol.startsWith(WS_TEST_PROTOCOL_PATH)) {
4626
+ path = decodeURIComponent(
4627
+ protocol.substring(WS_TEST_PROTOCOL_PATH.length)
4454
4628
  );
4455
4629
  } else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
4456
4630
  const paramsRaw = decodeURIComponent(
4457
4631
  protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
4458
4632
  );
4459
4633
  params = JSON.parse(paramsRaw);
4460
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_ID)) {
4461
- connId = protocol.substring(WS_PROTOCOL_CONN_ID.length);
4462
- } else if (protocol.startsWith(WS_PROTOCOL_CONN_TOKEN)) {
4463
- connToken = protocol.substring(
4464
- WS_PROTOCOL_CONN_TOKEN.length
4465
- );
4466
4634
  }
4467
4635
  }
4468
- logger().debug({
4636
+ logger6().debug({
4469
4637
  msg: "received test inline driver websocket",
4470
4638
  actorId,
4471
4639
  params,
4472
4640
  encodingKind: encoding,
4473
- transport,
4474
- path: path4
4641
+ path
4475
4642
  });
4476
4643
  const clientWsPromise = managerDriver.openWebSocket(
4477
- path4,
4644
+ path,
4478
4645
  actorId,
4479
4646
  encoding,
4480
- params,
4481
- connId,
4482
- connToken
4647
+ params
4483
4648
  );
4484
4649
  return await createTestWebSocketProxy(clientWsPromise);
4485
4650
  })(c, noopNext());
@@ -4492,7 +4657,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4492
4657
  const pathOnly = c.req.path.split("/.test/inline-driver/send-request/")[1] || "";
4493
4658
  const url = new URL(c.req.url);
4494
4659
  const pathWithQuery = pathOnly + url.search;
4495
- logger().debug({
4660
+ logger6().debug({
4496
4661
  msg: "received test inline driver raw http",
4497
4662
  actorId,
4498
4663
  path: pathWithQuery,
@@ -4510,11 +4675,11 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4510
4675
  );
4511
4676
  return response;
4512
4677
  } catch (error) {
4513
- logger().error({
4678
+ logger6().error({
4514
4679
  msg: "error in test inline raw http",
4515
4680
  error: stringifyError(error)
4516
4681
  });
4517
- const err = deconstructError(error, logger(), {}, true);
4682
+ const err = deconstructError(error, logger6(), {}, true);
4518
4683
  return c.json(
4519
4684
  {
4520
4685
  error: {
@@ -4533,7 +4698,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4533
4698
  if (!actorId || !connId) {
4534
4699
  return c.text("Missing actor or conn query parameters", 400);
4535
4700
  }
4536
- logger().debug({
4701
+ logger6().debug({
4537
4702
  msg: "forcing unclean disconnect",
4538
4703
  actorId,
4539
4704
  connId
@@ -4557,7 +4722,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
4557
4722
  }
4558
4723
  return c.json({ success: true });
4559
4724
  } catch (error) {
4560
- logger().error({
4725
+ logger6().error({
4561
4726
  msg: "error forcing disconnect",
4562
4727
  error: stringifyError(error)
4563
4728
  });
@@ -4584,7 +4749,7 @@ function createApiActor(actor2, runnerName = "default") {
4584
4749
  namespace_id: "default",
4585
4750
  // Assert default namespace
4586
4751
  runner_name_selector: runnerName,
4587
- create_ts: Date.now(),
4752
+ create_ts: actor2.createTs ?? Date.now(),
4588
4753
  connectable_ts: null,
4589
4754
  destroy_ts: null,
4590
4755
  sleep_ts: null,
@@ -4598,14 +4763,13 @@ function logger7() {
4598
4763
  }
4599
4764
 
4600
4765
  // src/registry/serve.ts
4601
- import { Hono as Hono4 } from "hono";
4602
- async function crossPlatformServe(runConfig, rivetKitRouter, userRouter) {
4603
- const app = userRouter ?? new Hono4();
4766
+ async function crossPlatformServe(runConfig, app) {
4767
+ const nodeServerModule = "@hono/node-server";
4604
4768
  let serve;
4605
4769
  try {
4606
4770
  const dep = await import(
4607
4771
  /* webpackIgnore: true */
4608
- "@hono/node-server"
4772
+ nodeServerModule
4609
4773
  );
4610
4774
  serve = dep.serve;
4611
4775
  } catch (err) {
@@ -4614,12 +4778,12 @@ async function crossPlatformServe(runConfig, rivetKitRouter, userRouter) {
4614
4778
  );
4615
4779
  process.exit(1);
4616
4780
  }
4617
- app.route("/", rivetKitRouter);
4781
+ const nodeWsModule = "@hono/node-ws";
4618
4782
  let createNodeWebSocket;
4619
4783
  try {
4620
4784
  const dep = await import(
4621
4785
  /* webpackIgnore: true */
4622
- "@hono/node-ws"
4786
+ nodeWsModule
4623
4787
  );
4624
4788
  createNodeWebSocket = dep.createNodeWebSocket;
4625
4789
  } catch (err) {
@@ -4663,7 +4827,7 @@ var Registry = class {
4663
4827
  const readyPromises = [];
4664
4828
  if (config2.runnerKind === "serverless") {
4665
4829
  logger7().debug("disabling health check since using serverless");
4666
- config2.disableHealthCheck = true;
4830
+ config2.disableMetadataLookup = true;
4667
4831
  }
4668
4832
  if (process.env.NODE_ENV !== "production" && config2.runnerKind === "serverless") {
4669
4833
  if ((inputConfig == null ? void 0 : inputConfig.runEngine) === void 0) config2.runEngine = true;
@@ -4753,17 +4917,6 @@ var Registry = class {
4753
4917
  }
4754
4918
  console.log();
4755
4919
  }
4756
- if (!config2.disableActorDriver) {
4757
- Promise.all(readyPromises).then(async () => {
4758
- logger7().debug("starting actor driver");
4759
- driver.actor(this.#config, config2, managerDriver, client);
4760
- });
4761
- }
4762
- if (config2.runnerKind === "serverless" && config2.autoConfigureServerless) {
4763
- Promise.all(readyPromises).then(async () => {
4764
- await configureServerlessRunner(config2);
4765
- });
4766
- }
4767
4920
  const { router: hono } = createManagerRouter(
4768
4921
  this.#config,
4769
4922
  config2,
@@ -4772,10 +4925,22 @@ var Registry = class {
4772
4925
  client
4773
4926
  );
4774
4927
  if (!config2.disableDefaultServer) {
4775
- (async () => {
4776
- const out = await crossPlatformServe(config2, hono, void 0);
4928
+ const serverPromise = (async () => {
4929
+ const out = await crossPlatformServe(config2, hono);
4777
4930
  upgradeWebSocket = out.upgradeWebSocket;
4778
4931
  })();
4932
+ readyPromises.push(serverPromise);
4933
+ }
4934
+ if (!config2.disableActorDriver) {
4935
+ Promise.all(readyPromises).then(async () => {
4936
+ logger7().debug("starting actor driver");
4937
+ driver.actor(this.#config, config2, managerDriver, client);
4938
+ });
4939
+ }
4940
+ if (config2.runnerKind === "serverless" && config2.autoConfigureServerless) {
4941
+ Promise.all(readyPromises).then(async () => {
4942
+ await configureServerlessRunner(config2);
4943
+ });
4779
4944
  }
4780
4945
  return {
4781
4946
  client,
@@ -4808,10 +4973,9 @@ async function configureServerlessRunner(config2) {
4808
4973
  namespace: config2.namespace,
4809
4974
  runnerName: config2.runnerName,
4810
4975
  encoding: config2.encoding,
4811
- transport: config2.transport,
4812
4976
  headers: config2.headers,
4813
4977
  getUpgradeWebSocket: config2.getUpgradeWebSocket,
4814
- disableHealthCheck: true
4978
+ disableMetadataLookup: true
4815
4979
  // We don't need health check for this operation
4816
4980
  };
4817
4981
  logger7().debug({
@@ -4859,12 +5023,11 @@ function setup(input) {
4859
5023
  }
4860
5024
 
4861
5025
  export {
4862
- handleWebSocketConnect,
4863
- handleRawWebSocketHandler,
4864
5026
  RegistryConfigSchema,
5027
+ routeWebSocket,
4865
5028
  createActorRouter,
4866
5029
  actor,
4867
- InlineWebSocketAdapter2,
5030
+ InlineWebSocketAdapter,
4868
5031
  createEngineDriver,
4869
5032
  createFileSystemOrMemoryDriver,
4870
5033
  createFileSystemDriver,
@@ -4874,4 +5037,4 @@ export {
4874
5037
  setup
4875
5038
  };
4876
5039
  //! These configs configs hold anything that's not platform-specific about running actors.
4877
- //# sourceMappingURL=chunk-BYMKMOBS.js.map
5040
+ //# sourceMappingURL=chunk-MBBJUHSP.js.map