rivetkit 2.0.2 → 2.0.4-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (403) hide show
  1. package/README.md +3 -5
  2. package/dist/browser/client.d.ts +2485 -0
  3. package/dist/browser/client.js +5182 -0
  4. package/dist/browser/client.js.map +1 -0
  5. package/dist/browser/inspector/client.d.ts +130 -0
  6. package/dist/browser/inspector/client.js +2854 -0
  7. package/dist/browser/inspector/client.js.map +1 -0
  8. package/dist/browser/v3-DnYObHH3.d.ts +279 -0
  9. package/dist/inspector.tar.gz +0 -0
  10. package/dist/schemas/actor-inspector/v1.ts +784 -0
  11. package/dist/schemas/actor-inspector/v2.ts +796 -0
  12. package/dist/schemas/actor-inspector/v3.ts +899 -0
  13. package/dist/schemas/actor-persist/v1.ts +225 -0
  14. package/dist/schemas/actor-persist/v2.ts +268 -0
  15. package/dist/schemas/actor-persist/v3.ts +280 -0
  16. package/dist/schemas/actor-persist/v4.ts +406 -0
  17. package/dist/schemas/client-protocol/v1.ts +441 -0
  18. package/dist/schemas/client-protocol/v2.ts +438 -0
  19. package/dist/schemas/client-protocol/v3.ts +554 -0
  20. package/dist/schemas/file-system-driver/v1.ts +108 -0
  21. package/dist/schemas/file-system-driver/v2.ts +142 -0
  22. package/dist/schemas/file-system-driver/v3.ts +167 -0
  23. package/dist/schemas/persist/v1.ts +781 -0
  24. package/dist/schemas/transport/v1.ts +697 -0
  25. package/dist/tsup/actor/errors.cjs +106 -0
  26. package/dist/tsup/actor/errors.cjs.map +1 -0
  27. package/dist/tsup/actor/errors.d.cts +188 -0
  28. package/dist/tsup/actor/errors.d.ts +188 -0
  29. package/dist/tsup/actor/errors.js +106 -0
  30. package/dist/tsup/actor/errors.js.map +1 -0
  31. package/dist/tsup/actor-router-consts-D29T1Z-K.d.cts +24 -0
  32. package/dist/tsup/actor-router-consts-D29T1Z-K.d.ts +24 -0
  33. package/dist/tsup/chunk-325TLXJT.js +1060 -0
  34. package/dist/tsup/chunk-325TLXJT.js.map +1 -0
  35. package/dist/tsup/chunk-424PT5DM.js +23 -0
  36. package/dist/tsup/chunk-424PT5DM.js.map +1 -0
  37. package/dist/tsup/chunk-4JVIG3SS.cjs +6289 -0
  38. package/dist/tsup/chunk-4JVIG3SS.cjs.map +1 -0
  39. package/dist/tsup/chunk-6LJAZ5R4.cjs +96 -0
  40. package/dist/tsup/chunk-6LJAZ5R4.cjs.map +1 -0
  41. package/dist/tsup/chunk-6XU3FMCB.cjs +534 -0
  42. package/dist/tsup/chunk-6XU3FMCB.cjs.map +1 -0
  43. package/dist/tsup/chunk-7HTNH26M.js +509 -0
  44. package/dist/tsup/chunk-7HTNH26M.js.map +1 -0
  45. package/dist/tsup/chunk-AUVH72RE.cjs +5977 -0
  46. package/dist/tsup/chunk-AUVH72RE.cjs.map +1 -0
  47. package/dist/tsup/chunk-D4BYUPNQ.js +645 -0
  48. package/dist/tsup/chunk-D4BYUPNQ.js.map +1 -0
  49. package/dist/tsup/chunk-HDQ2JUQT.cjs +23 -0
  50. package/dist/tsup/chunk-HDQ2JUQT.cjs.map +1 -0
  51. package/dist/tsup/chunk-HHXX2VRM.js +6289 -0
  52. package/dist/tsup/chunk-HHXX2VRM.js.map +1 -0
  53. package/dist/tsup/chunk-JEAEA2PB.js +49 -0
  54. package/dist/tsup/chunk-JEAEA2PB.js.map +1 -0
  55. package/dist/tsup/chunk-JYSEG3VF.cjs +642 -0
  56. package/dist/tsup/chunk-JYSEG3VF.cjs.map +1 -0
  57. package/dist/tsup/chunk-K6DGYILQ.js +2657 -0
  58. package/dist/tsup/chunk-K6DGYILQ.js.map +1 -0
  59. package/dist/tsup/chunk-KJSYAUOM.js +96 -0
  60. package/dist/tsup/chunk-KJSYAUOM.js.map +1 -0
  61. package/dist/tsup/chunk-L47L3ZWJ.cjs +509 -0
  62. package/dist/tsup/chunk-L47L3ZWJ.cjs.map +1 -0
  63. package/dist/tsup/chunk-LXUQ667X.js +2006 -0
  64. package/dist/tsup/chunk-LXUQ667X.js.map +1 -0
  65. package/dist/tsup/chunk-MXNPAB5W.js +5977 -0
  66. package/dist/tsup/chunk-MXNPAB5W.js.map +1 -0
  67. package/dist/tsup/chunk-N4KRDJ56.js +72 -0
  68. package/dist/tsup/chunk-N4KRDJ56.js.map +1 -0
  69. package/dist/tsup/chunk-NIYZDWMW.cjs +2006 -0
  70. package/dist/tsup/chunk-NIYZDWMW.cjs.map +1 -0
  71. package/dist/tsup/chunk-PQZHDKRW.cjs +1060 -0
  72. package/dist/tsup/chunk-PQZHDKRW.cjs.map +1 -0
  73. package/dist/tsup/chunk-PVOE6BU7.cjs +1050 -0
  74. package/dist/tsup/chunk-PVOE6BU7.cjs.map +1 -0
  75. package/dist/tsup/chunk-Q4UD2GA4.cjs +1810 -0
  76. package/dist/tsup/chunk-Q4UD2GA4.cjs.map +1 -0
  77. package/dist/tsup/chunk-QUD664YZ.js +1810 -0
  78. package/dist/tsup/chunk-QUD664YZ.js.map +1 -0
  79. package/dist/tsup/chunk-RTOCTWME.js +1050 -0
  80. package/dist/tsup/chunk-RTOCTWME.js.map +1 -0
  81. package/dist/tsup/chunk-SAZZ4SB2.cjs +2657 -0
  82. package/dist/tsup/chunk-SAZZ4SB2.cjs.map +1 -0
  83. package/dist/tsup/chunk-SR3KQE7Q.cjs +72 -0
  84. package/dist/tsup/chunk-SR3KQE7Q.cjs.map +1 -0
  85. package/dist/tsup/chunk-V2GHLYC6.cjs +49 -0
  86. package/dist/tsup/chunk-V2GHLYC6.cjs.map +1 -0
  87. package/dist/tsup/chunk-V3WG7XTW.cjs +645 -0
  88. package/dist/tsup/chunk-V3WG7XTW.cjs.map +1 -0
  89. package/dist/tsup/chunk-VKVNIQRQ.js +257 -0
  90. package/dist/tsup/chunk-VKVNIQRQ.js.map +1 -0
  91. package/dist/tsup/chunk-WMPW7JYC.js +642 -0
  92. package/dist/tsup/chunk-WMPW7JYC.js.map +1 -0
  93. package/dist/tsup/chunk-Z7HNQ2WF.js +534 -0
  94. package/dist/tsup/chunk-Z7HNQ2WF.js.map +1 -0
  95. package/dist/tsup/chunk-ZFY5J2EP.cjs +257 -0
  96. package/dist/tsup/chunk-ZFY5J2EP.cjs.map +1 -0
  97. package/dist/tsup/client/mod.cjs +33 -0
  98. package/dist/tsup/client/mod.cjs.map +1 -0
  99. package/dist/tsup/client/mod.d.cts +64 -0
  100. package/dist/tsup/client/mod.d.ts +64 -0
  101. package/dist/tsup/client/mod.js +33 -0
  102. package/dist/tsup/client/mod.js.map +1 -0
  103. package/dist/tsup/common/log.cjs +21 -0
  104. package/dist/tsup/common/log.cjs.map +1 -0
  105. package/dist/tsup/common/log.d.cts +34 -0
  106. package/dist/tsup/common/log.d.ts +34 -0
  107. package/dist/tsup/common/log.js +21 -0
  108. package/dist/tsup/common/log.js.map +1 -0
  109. package/dist/tsup/common/websocket.cjs +10 -0
  110. package/dist/tsup/common/websocket.cjs.map +1 -0
  111. package/dist/tsup/common/websocket.d.cts +3 -0
  112. package/dist/tsup/common/websocket.d.ts +3 -0
  113. package/dist/tsup/common/websocket.js +10 -0
  114. package/dist/tsup/common/websocket.js.map +1 -0
  115. package/dist/tsup/config-BiNoIHRs.d.cts +80 -0
  116. package/dist/tsup/config-BiNoIHRs.d.ts +80 -0
  117. package/dist/tsup/config-P3XujgRr.d.ts +2594 -0
  118. package/dist/tsup/config-_gfywqqI.d.cts +2594 -0
  119. package/dist/tsup/context-Bxd8Cx4H.d.cts +75 -0
  120. package/dist/tsup/context-uNA4TRn3.d.ts +75 -0
  121. package/dist/tsup/db/drizzle/mod.cjs +49 -0
  122. package/dist/tsup/db/drizzle/mod.cjs.map +1 -0
  123. package/dist/tsup/db/drizzle/mod.d.cts +17 -0
  124. package/dist/tsup/db/drizzle/mod.d.ts +17 -0
  125. package/dist/tsup/db/drizzle/mod.js +49 -0
  126. package/dist/tsup/db/drizzle/mod.js.map +1 -0
  127. package/dist/tsup/db/mod.cjs +9 -0
  128. package/dist/tsup/db/mod.cjs.map +1 -0
  129. package/dist/tsup/db/mod.d.cts +9 -0
  130. package/dist/tsup/db/mod.d.ts +9 -0
  131. package/dist/tsup/db/mod.js +9 -0
  132. package/dist/tsup/db/mod.js.map +1 -0
  133. package/dist/tsup/driver-BcLvZcKl.d.cts +13 -0
  134. package/dist/tsup/driver-CPGHKXyh.d.ts +13 -0
  135. package/dist/tsup/driver-helpers/mod.cjs +53 -0
  136. package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
  137. package/dist/tsup/driver-helpers/mod.d.cts +47 -0
  138. package/dist/tsup/driver-helpers/mod.d.ts +47 -0
  139. package/dist/tsup/driver-helpers/mod.js +53 -0
  140. package/dist/tsup/driver-helpers/mod.js.map +1 -0
  141. package/dist/tsup/driver-test-suite/mod.cjs +4974 -0
  142. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
  143. package/dist/tsup/driver-test-suite/mod.d.cts +73 -0
  144. package/dist/tsup/driver-test-suite/mod.d.ts +73 -0
  145. package/dist/tsup/driver-test-suite/mod.js +4974 -0
  146. package/dist/tsup/driver-test-suite/mod.js.map +1 -0
  147. package/dist/tsup/inspector/mod.cjs +164 -0
  148. package/dist/tsup/inspector/mod.cjs.map +1 -0
  149. package/dist/tsup/inspector/mod.d.cts +130 -0
  150. package/dist/tsup/inspector/mod.d.ts +130 -0
  151. package/dist/tsup/inspector/mod.js +164 -0
  152. package/dist/tsup/inspector/mod.js.map +1 -0
  153. package/dist/tsup/keys-CydblqMh.d.cts +13 -0
  154. package/dist/tsup/keys-CydblqMh.d.ts +13 -0
  155. package/dist/tsup/mod.cjs +82 -0
  156. package/dist/tsup/mod.cjs.map +1 -0
  157. package/dist/tsup/mod.d.cts +126 -0
  158. package/dist/tsup/mod.d.ts +126 -0
  159. package/dist/tsup/mod.js +82 -0
  160. package/dist/tsup/mod.js.map +1 -0
  161. package/dist/tsup/serve-test-suite/mod.cjs +2601 -0
  162. package/dist/tsup/serve-test-suite/mod.cjs.map +1 -0
  163. package/dist/tsup/serve-test-suite/mod.d.cts +9 -0
  164. package/dist/tsup/serve-test-suite/mod.d.ts +9 -0
  165. package/dist/tsup/serve-test-suite/mod.js +2601 -0
  166. package/dist/tsup/serve-test-suite/mod.js.map +1 -0
  167. package/dist/tsup/test/mod.cjs +90 -0
  168. package/dist/tsup/test/mod.cjs.map +1 -0
  169. package/dist/tsup/test/mod.d.cts +26 -0
  170. package/dist/tsup/test/mod.d.ts +26 -0
  171. package/dist/tsup/test/mod.js +90 -0
  172. package/dist/tsup/test/mod.js.map +1 -0
  173. package/dist/tsup/utils-fwx3o3K9.d.cts +18 -0
  174. package/dist/tsup/utils-fwx3o3K9.d.ts +18 -0
  175. package/dist/tsup/utils.cjs +43 -0
  176. package/dist/tsup/utils.cjs.map +1 -0
  177. package/dist/tsup/utils.d.cts +148 -0
  178. package/dist/tsup/utils.d.ts +148 -0
  179. package/dist/tsup/utils.js +43 -0
  180. package/dist/tsup/utils.js.map +1 -0
  181. package/dist/tsup/v3-DnYObHH3.d.cts +279 -0
  182. package/dist/tsup/v3-DnYObHH3.d.ts +279 -0
  183. package/dist/tsup/workflow/mod.cjs +16 -0
  184. package/dist/tsup/workflow/mod.cjs.map +1 -0
  185. package/dist/tsup/workflow/mod.d.cts +25 -0
  186. package/dist/tsup/workflow/mod.d.ts +25 -0
  187. package/dist/tsup/workflow/mod.js +16 -0
  188. package/dist/tsup/workflow/mod.js.map +1 -0
  189. package/package.json +293 -5
  190. package/src/actor/config.ts +1221 -0
  191. package/src/actor/conn/driver.ts +61 -0
  192. package/src/actor/conn/drivers/http.ts +17 -0
  193. package/src/actor/conn/drivers/raw-request.ts +24 -0
  194. package/src/actor/conn/drivers/raw-websocket.ts +65 -0
  195. package/src/actor/conn/drivers/websocket.ts +144 -0
  196. package/src/actor/conn/mod.ts +288 -0
  197. package/src/actor/conn/persisted.ts +81 -0
  198. package/src/actor/conn/state-manager.ts +196 -0
  199. package/src/actor/contexts/action.ts +47 -0
  200. package/src/actor/contexts/base/actor.ts +347 -0
  201. package/src/actor/contexts/base/conn-init.ts +68 -0
  202. package/src/actor/contexts/base/conn.ts +73 -0
  203. package/src/actor/contexts/before-action-response.ts +42 -0
  204. package/src/actor/contexts/before-connect.ts +31 -0
  205. package/src/actor/contexts/connect.ts +42 -0
  206. package/src/actor/contexts/create-conn-state.ts +32 -0
  207. package/src/actor/contexts/create-vars.ts +39 -0
  208. package/src/actor/contexts/create.ts +39 -0
  209. package/src/actor/contexts/destroy.ts +42 -0
  210. package/src/actor/contexts/disconnect.ts +43 -0
  211. package/src/actor/contexts/index.ts +33 -0
  212. package/src/actor/contexts/request.ts +80 -0
  213. package/src/actor/contexts/run.ts +47 -0
  214. package/src/actor/contexts/sleep.ts +42 -0
  215. package/src/actor/contexts/state-change.ts +42 -0
  216. package/src/actor/contexts/wake.ts +42 -0
  217. package/src/actor/contexts/websocket.ts +80 -0
  218. package/src/actor/database.ts +13 -0
  219. package/src/actor/definition.ts +64 -0
  220. package/src/actor/driver.ts +114 -0
  221. package/src/actor/errors.ts +556 -0
  222. package/src/actor/instance/connection-manager.ts +574 -0
  223. package/src/actor/instance/event-manager.ts +314 -0
  224. package/src/actor/instance/keys.ts +146 -0
  225. package/src/actor/instance/kv.ts +241 -0
  226. package/src/actor/instance/mod.ts +1658 -0
  227. package/src/actor/instance/persisted.ts +67 -0
  228. package/src/actor/instance/queue-manager.ts +603 -0
  229. package/src/actor/instance/queue.ts +345 -0
  230. package/src/actor/instance/schedule-manager.ts +392 -0
  231. package/src/actor/instance/state-manager.ts +542 -0
  232. package/src/actor/instance/traces-driver.ts +128 -0
  233. package/src/actor/keys.test.ts +275 -0
  234. package/src/actor/keys.ts +89 -0
  235. package/src/actor/log.ts +6 -0
  236. package/src/actor/mod.ts +110 -0
  237. package/src/actor/protocol/old.ts +416 -0
  238. package/src/actor/protocol/serde.ts +222 -0
  239. package/src/actor/router-endpoints.ts +400 -0
  240. package/src/actor/router-websocket-endpoints.test.ts +54 -0
  241. package/src/actor/router-websocket-endpoints.ts +405 -0
  242. package/src/actor/router.ts +380 -0
  243. package/src/actor/schedule.ts +17 -0
  244. package/src/actor/schema.ts +291 -0
  245. package/src/actor/utils.test.ts +48 -0
  246. package/src/actor/utils.ts +158 -0
  247. package/src/client/actor-common.ts +32 -0
  248. package/src/client/actor-conn.ts +1262 -0
  249. package/src/client/actor-handle.ts +344 -0
  250. package/src/client/actor-query.ts +112 -0
  251. package/src/client/client.ts +558 -0
  252. package/src/client/config.ts +151 -0
  253. package/src/client/errors.ts +76 -0
  254. package/src/client/log.ts +5 -0
  255. package/src/client/mod.browser.ts +2 -0
  256. package/src/client/mod.ts +70 -0
  257. package/src/client/queue.ts +146 -0
  258. package/src/client/raw-utils.ts +149 -0
  259. package/src/client/test.ts +44 -0
  260. package/src/client/utils.ts +252 -0
  261. package/src/common/actor-router-consts.ts +59 -0
  262. package/src/common/cors.ts +57 -0
  263. package/src/common/eventsource-interface.ts +47 -0
  264. package/src/common/eventsource.ts +44 -0
  265. package/src/common/inline-websocket-adapter.ts +154 -0
  266. package/src/common/log-levels.ts +27 -0
  267. package/src/common/log.ts +229 -0
  268. package/src/common/logfmt.ts +221 -0
  269. package/src/common/network.ts +2 -0
  270. package/src/common/router.ts +174 -0
  271. package/src/common/utils.ts +339 -0
  272. package/src/common/websocket-interface.ts +7 -0
  273. package/src/common/websocket.ts +43 -0
  274. package/src/db/config.ts +100 -0
  275. package/src/db/drizzle/mod.ts +226 -0
  276. package/src/db/drizzle/sqlite-core.ts +22 -0
  277. package/src/db/mod.ts +125 -0
  278. package/src/db/shared.ts +92 -0
  279. package/src/db/sqlite-vfs.ts +12 -0
  280. package/src/devtools-loader/index.ts +33 -0
  281. package/src/devtools-loader/log.ts +5 -0
  282. package/src/driver-helpers/mod.ts +33 -0
  283. package/src/driver-helpers/utils.ts +54 -0
  284. package/src/driver-test-suite/log.ts +5 -0
  285. package/src/driver-test-suite/mod.ts +293 -0
  286. package/src/driver-test-suite/test-inline-client-driver.ts +307 -0
  287. package/src/driver-test-suite/tests/access-control.ts +218 -0
  288. package/src/driver-test-suite/tests/action-features.ts +203 -0
  289. package/src/driver-test-suite/tests/actor-conn-hibernation.ts +152 -0
  290. package/src/driver-test-suite/tests/actor-conn-state.ts +300 -0
  291. package/src/driver-test-suite/tests/actor-conn.ts +596 -0
  292. package/src/driver-test-suite/tests/actor-db-raw.ts +73 -0
  293. package/src/driver-test-suite/tests/actor-db.ts +477 -0
  294. package/src/driver-test-suite/tests/actor-destroy.ts +294 -0
  295. package/src/driver-test-suite/tests/actor-driver.ts +18 -0
  296. package/src/driver-test-suite/tests/actor-error-handling.ts +150 -0
  297. package/src/driver-test-suite/tests/actor-handle.ts +312 -0
  298. package/src/driver-test-suite/tests/actor-inline-client.ts +163 -0
  299. package/src/driver-test-suite/tests/actor-inspector.ts +264 -0
  300. package/src/driver-test-suite/tests/actor-kv.ts +65 -0
  301. package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
  302. package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
  303. package/src/driver-test-suite/tests/actor-queue.ts +325 -0
  304. package/src/driver-test-suite/tests/actor-run.ts +181 -0
  305. package/src/driver-test-suite/tests/actor-schedule.ts +97 -0
  306. package/src/driver-test-suite/tests/actor-sleep.ts +415 -0
  307. package/src/driver-test-suite/tests/actor-state.ts +54 -0
  308. package/src/driver-test-suite/tests/actor-stateless.ts +70 -0
  309. package/src/driver-test-suite/tests/actor-vars.ts +97 -0
  310. package/src/driver-test-suite/tests/actor-workflow.ts +118 -0
  311. package/src/driver-test-suite/tests/manager-driver.ts +388 -0
  312. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +227 -0
  313. package/src/driver-test-suite/tests/raw-http-request-properties.ts +454 -0
  314. package/src/driver-test-suite/tests/raw-http.ts +359 -0
  315. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +393 -0
  316. package/src/driver-test-suite/tests/raw-websocket.ts +513 -0
  317. package/src/driver-test-suite/tests/request-access.ts +240 -0
  318. package/src/driver-test-suite/utils.ts +80 -0
  319. package/src/drivers/default.ts +38 -0
  320. package/src/drivers/engine/actor-driver.ts +1027 -0
  321. package/src/drivers/engine/config.ts +43 -0
  322. package/src/drivers/engine/log.ts +5 -0
  323. package/src/drivers/engine/mod.ts +36 -0
  324. package/src/drivers/file-system/actor.ts +102 -0
  325. package/src/drivers/file-system/global-state.ts +1445 -0
  326. package/src/drivers/file-system/kv-limits.ts +70 -0
  327. package/src/drivers/file-system/log.ts +5 -0
  328. package/src/drivers/file-system/manager.ts +300 -0
  329. package/src/drivers/file-system/mod.ts +78 -0
  330. package/src/drivers/file-system/sqlite-runtime.ts +210 -0
  331. package/src/drivers/file-system/utils.ts +125 -0
  332. package/src/engine-process/constants.ts +2 -0
  333. package/src/engine-process/log.ts +5 -0
  334. package/src/engine-process/mod.ts +464 -0
  335. package/src/globals.d.ts +35 -0
  336. package/src/inspector/actor-inspector.ts +352 -0
  337. package/src/inspector/config.ts +49 -0
  338. package/src/inspector/handler.ts +273 -0
  339. package/src/inspector/log.ts +5 -0
  340. package/src/inspector/mod.browser.ts +8 -0
  341. package/src/inspector/mod.ts +4 -0
  342. package/src/inspector/serve-ui.ts +40 -0
  343. package/src/inspector/transport.ts +18 -0
  344. package/src/inspector/utils.ts +32 -0
  345. package/src/manager/driver.ts +106 -0
  346. package/src/manager/gateway.ts +668 -0
  347. package/src/manager/log.ts +5 -0
  348. package/src/manager/mod.ts +2 -0
  349. package/src/manager/protocol/mod.ts +22 -0
  350. package/src/manager/protocol/query.ts +85 -0
  351. package/src/manager/router-schema.ts +22 -0
  352. package/src/manager/router.ts +660 -0
  353. package/src/manager-api/actors.ts +83 -0
  354. package/src/manager-api/common.ts +4 -0
  355. package/src/mod.ts +24 -0
  356. package/src/registry/config/driver.ts +21 -0
  357. package/src/registry/config/index.ts +510 -0
  358. package/src/registry/config/legacy-runner.ts +157 -0
  359. package/src/registry/config/runner.ts +21 -0
  360. package/src/registry/config/serverless.ts +94 -0
  361. package/src/registry/index.ts +194 -0
  362. package/src/registry/log.ts +5 -0
  363. package/src/remote-manager-driver/actor-http-client.ts +84 -0
  364. package/src/remote-manager-driver/actor-websocket-client.ts +81 -0
  365. package/src/remote-manager-driver/api-endpoints.ts +159 -0
  366. package/src/remote-manager-driver/api-utils.ts +69 -0
  367. package/src/remote-manager-driver/log.ts +5 -0
  368. package/src/remote-manager-driver/metadata.ts +64 -0
  369. package/src/remote-manager-driver/mod.ts +414 -0
  370. package/src/remote-manager-driver/ws-proxy.ts +189 -0
  371. package/src/schemas/actor-inspector/mod.ts +1 -0
  372. package/src/schemas/actor-inspector/versioned.ts +233 -0
  373. package/src/schemas/actor-persist/mod.ts +1 -0
  374. package/src/schemas/actor-persist/versioned.ts +217 -0
  375. package/src/schemas/client-protocol/mod.ts +1 -0
  376. package/src/schemas/client-protocol/versioned.ts +330 -0
  377. package/src/schemas/client-protocol-zod/mod.ts +118 -0
  378. package/src/schemas/file-system-driver/mod.ts +1 -0
  379. package/src/schemas/file-system-driver/versioned.ts +135 -0
  380. package/src/schemas/persist/mod.ts +1 -0
  381. package/src/schemas/transport/mod.ts +1 -0
  382. package/src/serde.ts +138 -0
  383. package/src/serve-test-suite/mod.ts +148 -0
  384. package/src/serverless/configure.ts +82 -0
  385. package/src/serverless/log.ts +5 -0
  386. package/src/serverless/router.test.ts +299 -0
  387. package/src/serverless/router.ts +215 -0
  388. package/src/test/log.ts +5 -0
  389. package/src/test/mod.ts +99 -0
  390. package/src/utils/crypto.ts +24 -0
  391. package/src/utils/endpoint-parser.test.ts +202 -0
  392. package/src/utils/endpoint-parser.ts +124 -0
  393. package/src/utils/env-vars.ts +78 -0
  394. package/src/utils/node.ts +178 -0
  395. package/src/utils/router.ts +83 -0
  396. package/src/utils/serve.ts +212 -0
  397. package/src/utils.test.ts +34 -0
  398. package/src/utils.ts +437 -0
  399. package/src/workflow/constants.ts +2 -0
  400. package/src/workflow/context.ts +597 -0
  401. package/src/workflow/driver.ts +194 -0
  402. package/src/workflow/inspector.ts +268 -0
  403. package/src/workflow/mod.ts +128 -0
@@ -0,0 +1,1658 @@
1
+ import type { OtlpExportTraceServiceRequestJson } from "@rivetkit/traces";
2
+ import {
3
+ createNoopTraces,
4
+ createTraces,
5
+ type SpanHandle,
6
+ type SpanStatusInput,
7
+ type Traces,
8
+ } from "@rivetkit/traces";
9
+ import type { SqliteVfs } from "@rivetkit/sqlite-vfs";
10
+ import invariant from "invariant";
11
+ import type { ActorKey } from "@/actor/mod";
12
+ import type { Client } from "@/client/client";
13
+ import { getBaseLogger, getIncludeTarget, type Logger } from "@/common/log";
14
+ import { stringifyError } from "@/common/utils";
15
+ import type { UniversalWebSocket } from "@/common/websocket-interface";
16
+ import { ActorInspector } from "@/inspector/actor-inspector";
17
+ import type { Registry } from "@/mod";
18
+ import {
19
+ ACTOR_VERSIONED,
20
+ CONN_VERSIONED,
21
+ } from "@/schemas/actor-persist/versioned";
22
+ import { EXTRA_ERROR_LOG } from "@/utils";
23
+ import { getRivetExperimentalOtel } from "@/utils/env-vars";
24
+ import {
25
+ type ActorConfig,
26
+ getRunFunction,
27
+ } from "../config";
28
+ import type { ConnDriver } from "../conn/driver";
29
+ import { createHttpDriver } from "../conn/drivers/http";
30
+ import {
31
+ CONN_DRIVER_SYMBOL,
32
+ CONN_STATE_MANAGER_SYMBOL,
33
+ type Conn,
34
+ type ConnId,
35
+ } from "../conn/mod";
36
+ import {
37
+ convertConnFromBarePersistedConn,
38
+ type PersistedConn,
39
+ } from "../conn/persisted";
40
+ import {
41
+ ActionContext,
42
+ ActorContext,
43
+ RequestContext,
44
+ WebSocketContext,
45
+ } from "../contexts";
46
+
47
+ import type { AnyDatabaseProvider, InferDatabaseClient } from "../database";
48
+ import type { ActorDriver } from "../driver";
49
+ import * as errors from "../errors";
50
+ import { serializeActorKey } from "../keys";
51
+ import { processMessage } from "../protocol/old";
52
+ import { Schedule } from "../schedule";
53
+ import {
54
+ type EventSchemaConfig,
55
+ getEventCanSubscribe,
56
+ getQueueCanPublish,
57
+ type QueueSchemaConfig,
58
+ } from "../schema";
59
+ import {
60
+ assertUnreachable,
61
+ DeadlineError,
62
+ deadline,
63
+ generateSecureToken,
64
+ } from "../utils";
65
+ import { ConnectionManager } from "./connection-manager";
66
+ import { EventManager } from "./event-manager";
67
+ import { KEYS } from "./keys";
68
+ import {
69
+ convertActorFromBarePersisted,
70
+ type PersistedActor,
71
+ } from "./persisted";
72
+ import { QueueManager } from "./queue-manager";
73
+ import { ScheduleManager } from "./schedule-manager";
74
+ import { type SaveStateOptions, StateManager } from "./state-manager";
75
+ import { ActorTracesDriver } from "./traces-driver";
76
+
77
+ export type { SaveStateOptions };
78
+
79
+ enum CanSleep {
80
+ Yes,
81
+ NotReady,
82
+ NotStarted,
83
+ ActiveConns,
84
+ ActiveDisconnectCallbacks,
85
+ ActiveHonoHttpRequests,
86
+ ActiveKeepAwake,
87
+ ActiveRun,
88
+ }
89
+
90
+ /** Actor type alias with all `any` types. Used for `extends` in classes referencing this actor. */
91
+ export type AnyActorInstance = ActorInstance<
92
+ any,
93
+ any,
94
+ any,
95
+ any,
96
+ any,
97
+ any,
98
+ any,
99
+ any
100
+ >;
101
+
102
+ export type ExtractActorState<A extends AnyActorInstance> =
103
+ A extends ActorInstance<infer State, any, any, any, any, any, any, any>
104
+ ? State
105
+ : never;
106
+
107
+ export type ExtractActorConnParams<A extends AnyActorInstance> =
108
+ A extends ActorInstance<any, infer ConnParams, any, any, any, any, any, any>
109
+ ? ConnParams
110
+ : never;
111
+
112
+ export type ExtractActorConnState<A extends AnyActorInstance> =
113
+ A extends ActorInstance<any, any, infer ConnState, any, any, any, any, any>
114
+ ? ConnState
115
+ : never;
116
+
117
+ // MARK: - Main ActorInstance Class
118
+ export class ActorInstance<
119
+ S,
120
+ CP,
121
+ CS,
122
+ V,
123
+ I,
124
+ DB extends AnyDatabaseProvider,
125
+ E extends EventSchemaConfig = Record<never, never>,
126
+ Q extends QueueSchemaConfig = Record<never, never>,
127
+ > {
128
+ // MARK: - Core Properties
129
+ actorContext: ActorContext<S, CP, CS, V, I, DB, E, Q>;
130
+ #config: ActorConfig<S, CP, CS, V, I, DB, E, Q>;
131
+ driver!: ActorDriver;
132
+ #inlineClient!: Client<Registry<any>>;
133
+ #actorId!: string;
134
+ #name!: string;
135
+ #key!: ActorKey;
136
+ #actorKeyString!: string;
137
+ #region!: string;
138
+
139
+ // MARK: - Managers
140
+ connectionManager!: ConnectionManager<S, CP, CS, V, I, DB, E, Q>;
141
+
142
+ stateManager!: StateManager<S, CP, CS, I, E, Q>;
143
+
144
+ eventManager!: EventManager<S, CP, CS, V, I, DB, E, Q>;
145
+
146
+ #scheduleManager!: ScheduleManager<S, CP, CS, V, I, DB, E, Q>;
147
+
148
+ queueManager!: QueueManager<S, CP, CS, V, I, DB, E, Q>;
149
+
150
+ // MARK: - Logging
151
+ #log!: Logger;
152
+ #rLog!: Logger;
153
+
154
+ // MARK: - Lifecycle State
155
+ /**
156
+ * If the core actor initiation has set up.
157
+ *
158
+ * Almost all actions on this actor will throw an error if false.
159
+ **/
160
+ #ready = false;
161
+ /**
162
+ * If the actor has fully started.
163
+ *
164
+ * The only purpose of this is to prevent sleeping until started.
165
+ */
166
+ #started = false;
167
+ #sleepCalled = false;
168
+ #destroyCalled = false;
169
+ #stopCalled = false;
170
+ #sleepTimeout?: NodeJS.Timeout;
171
+ #abortController = new AbortController();
172
+
173
+ // MARK: - Variables & Database
174
+ #vars?: V;
175
+ #db?: InferDatabaseClient<DB>;
176
+ #sqliteVfs?: SqliteVfs;
177
+
178
+ // MARK: - Background Tasks
179
+ #backgroundPromises: Promise<void>[] = [];
180
+ #runPromise?: Promise<void>;
181
+ #runHandlerActive = false;
182
+ #activeQueueWaitCount = 0;
183
+
184
+ // MARK: - HTTP/WebSocket Tracking
185
+ #activeHonoHttpRequests = 0;
186
+ #activeKeepAwakeCount = 0;
187
+
188
+ // MARK: - Deprecated (kept for compatibility)
189
+ #schedule!: Schedule;
190
+
191
+ // MARK: - Inspector
192
+ #inspectorToken?: string;
193
+ #inspector: ActorInspector;
194
+
195
+ // MARK: - Tracing
196
+ #traces!: Traces<OtlpExportTraceServiceRequestJson>;
197
+
198
+ // MARK: - Constructor
199
+ constructor(config: ActorConfig<S, CP, CS, V, I, DB, E, Q>) {
200
+ this.#config = config;
201
+ this.actorContext = new ActorContext(this);
202
+ this.#inspector = new ActorInspector(this);
203
+ }
204
+
205
+ // MARK: - Public Getters
206
+ get log(): Logger {
207
+ invariant(this.#log, "log not configured");
208
+ return this.#log;
209
+ }
210
+
211
+ get rLog(): Logger {
212
+ invariant(this.#rLog, "log not configured");
213
+ return this.#rLog;
214
+ }
215
+
216
+ get isStopping(): boolean {
217
+ return this.#stopCalled;
218
+ }
219
+
220
+ get id(): string {
221
+ return this.#actorId;
222
+ }
223
+
224
+ get name(): string {
225
+ return this.#name;
226
+ }
227
+
228
+ get key(): ActorKey {
229
+ return this.#key;
230
+ }
231
+
232
+ get region(): string {
233
+ return this.#region;
234
+ }
235
+
236
+ get inlineClient(): Client<Registry<any>> {
237
+ return this.#inlineClient;
238
+ }
239
+
240
+ get inspector(): ActorInspector {
241
+ return this.#inspector;
242
+ }
243
+
244
+ get traces(): Traces<OtlpExportTraceServiceRequestJson> {
245
+ return this.#traces;
246
+ }
247
+
248
+ get inspectorToken(): string | undefined {
249
+ return this.#inspectorToken;
250
+ }
251
+
252
+ // MARK: - Tracing
253
+ getCurrentTraceSpan(): SpanHandle | null {
254
+ return this.#traces.getCurrentSpan();
255
+ }
256
+
257
+ startTraceSpan(
258
+ name: string,
259
+ attributes?: Record<string, unknown>,
260
+ ): SpanHandle {
261
+ return this.#traces.startSpan(name, {
262
+ parent: this.#traces.getCurrentSpan() ?? undefined,
263
+ attributes: this.#traceAttributes(attributes),
264
+ });
265
+ }
266
+
267
+ endTraceSpan(handle: SpanHandle, status?: SpanStatusInput): void {
268
+ this.#traces.endSpan(handle, status ? { status } : undefined);
269
+ }
270
+
271
+ async runInTraceSpan<T>(
272
+ name: string,
273
+ attributes: Record<string, unknown> | undefined,
274
+ fn: () => T | Promise<T>,
275
+ ): Promise<T> {
276
+ const span = this.startTraceSpan(name, attributes);
277
+ try {
278
+ const result = this.#traces.withSpan(span, fn);
279
+ const resolved = result instanceof Promise ? await result : result;
280
+ this.#traces.endSpan(span, {
281
+ status: { code: "OK" },
282
+ });
283
+ return resolved;
284
+ } catch (error) {
285
+ this.#traces.endSpan(span, {
286
+ status: {
287
+ code: "ERROR",
288
+ message: stringifyError(error),
289
+ },
290
+ });
291
+ throw error;
292
+ }
293
+ }
294
+
295
+ emitTraceEvent(
296
+ name: string,
297
+ attributes?: Record<string, unknown>,
298
+ handle?: SpanHandle,
299
+ ): void {
300
+ const span = handle ?? this.#traces.getCurrentSpan();
301
+ if (!span) {
302
+ return;
303
+ }
304
+ this.#traces.emitEvent(span, name, {
305
+ attributes: this.#traceAttributes(attributes),
306
+ timeUnixMs: Date.now(),
307
+ });
308
+ }
309
+
310
+ get conns(): Map<ConnId, Conn<S, CP, CS, V, I, DB, E, Q>> {
311
+ return this.connectionManager.connections;
312
+ }
313
+
314
+ get schedule(): Schedule {
315
+ return this.#schedule;
316
+ }
317
+
318
+ get abortSignal(): AbortSignal {
319
+ return this.#abortController.signal;
320
+ }
321
+
322
+ get actions(): string[] {
323
+ return Object.keys(this.#config.actions ?? {});
324
+ }
325
+
326
+ get config(): ActorConfig<S, CP, CS, V, I, DB, E, Q> {
327
+ return this.#config;
328
+ }
329
+
330
+ // MARK: - State Access
331
+ get persist(): PersistedActor<S, I> {
332
+ return this.stateManager.persist;
333
+ }
334
+
335
+ get state(): S {
336
+ return this.stateManager.state;
337
+ }
338
+
339
+ set state(value: S) {
340
+ this.stateManager.state = value;
341
+ }
342
+
343
+ get stateEnabled(): boolean {
344
+ return this.stateManager.stateEnabled;
345
+ }
346
+
347
+ get connStateEnabled(): boolean {
348
+ return "createConnState" in this.#config || "connState" in this.#config;
349
+ }
350
+
351
+ // MARK: - Variables & Database
352
+ get vars(): V {
353
+ this.#validateVarsEnabled();
354
+ invariant(this.#vars !== undefined, "vars not enabled");
355
+ return this.#vars;
356
+ }
357
+
358
+ get db(): InferDatabaseClient<DB> {
359
+ if (!this.#db) {
360
+ throw new errors.DatabaseNotEnabled();
361
+ }
362
+ return this.#db;
363
+ }
364
+
365
+ // MARK: - Initialization
366
+ async start(
367
+ actorDriver: ActorDriver,
368
+ inlineClient: Client<Registry<any>>,
369
+ actorId: string,
370
+ name: string,
371
+ key: ActorKey,
372
+ region: string,
373
+ ) {
374
+ // Initialize properties
375
+ this.driver = actorDriver;
376
+ this.#inlineClient = inlineClient;
377
+ this.#actorId = actorId;
378
+ this.#name = name;
379
+ this.#key = key;
380
+ this.#actorKeyString = serializeActorKey(this.#key);
381
+ this.#region = region;
382
+
383
+ // Initialize tracing
384
+ this.#initializeTraces();
385
+
386
+ // Initialize logging
387
+ this.#initializeLogging();
388
+
389
+ // Initialize managers
390
+ this.connectionManager = new ConnectionManager(this);
391
+ this.stateManager = new StateManager(this, actorDriver, this.#config);
392
+ this.eventManager = new EventManager(this);
393
+ this.queueManager = new QueueManager(this, actorDriver);
394
+ this.#scheduleManager = new ScheduleManager(
395
+ this,
396
+ actorDriver,
397
+ this.#config,
398
+ );
399
+
400
+ // Legacy schedule object (for compatibility)
401
+ this.#schedule = new Schedule(this);
402
+
403
+ // Load state
404
+ await this.#loadState();
405
+
406
+ await this.queueManager.initialize();
407
+
408
+ // Generate or load inspector token
409
+ await this.#initializeInspectorToken();
410
+
411
+ // Initialize variables
412
+ if (this.#varsEnabled) {
413
+ await this.#initializeVars();
414
+ }
415
+
416
+ // Call onStart lifecycle
417
+ await this.#callOnStart();
418
+
419
+ // Setup database
420
+ await this.#setupDatabase();
421
+
422
+ // Initialize alarms
423
+ await this.#scheduleManager.initializeAlarms();
424
+
425
+ // Mark as ready
426
+ this.#ready = true;
427
+
428
+ // Finish up any remaining initiation
429
+ //
430
+ // Do this after #ready = true since this can call any actor callbacks
431
+ // (which require #assertReady)
432
+ await this.driver.onBeforeActorStart?.(this);
433
+
434
+ // Mark as started
435
+ //
436
+ // We do this after onBeforeActorStart to prevent the actor from going
437
+ // to sleep before finishing setup
438
+ this.#started = true;
439
+ this.#rLog.info({ msg: "actor started" });
440
+
441
+ // Start sleep timer after setting #started since this affects the
442
+ // timer
443
+ this.resetSleepTimer();
444
+
445
+ // Start run handler in background (does not block startup)
446
+ this.#startRunHandler();
447
+
448
+ // Trigger any pending alarms
449
+ await this.onAlarm();
450
+ }
451
+
452
+ // MARK: - Ready Check
453
+ isReady(): boolean {
454
+ return this.#ready;
455
+ }
456
+
457
+ assertReady(allowStoppingState: boolean = false) {
458
+ if (!this.#ready) throw new errors.InternalError("Actor not ready");
459
+ if (!allowStoppingState && this.#stopCalled)
460
+ throw new errors.InternalError("Actor is stopping");
461
+ }
462
+
463
+ async cleanupPersistedConnections(reason?: string): Promise<number> {
464
+ this.assertReady(true);
465
+ return await this.connectionManager.cleanupPersistedHibernatableConnections(
466
+ reason,
467
+ );
468
+ }
469
+
470
+ // MARK: - Stop
471
+ async onStop(mode: "sleep" | "destroy") {
472
+ if (this.#stopCalled) {
473
+ this.#rLog.warn({ msg: "already stopping actor" });
474
+ return;
475
+ }
476
+ this.#stopCalled = true;
477
+ this.#rLog.info({
478
+ msg: "setting stopCalled=true",
479
+ mode,
480
+ });
481
+
482
+ try {
483
+ // Clear sleep timeout
484
+ if (this.#sleepTimeout) {
485
+ clearTimeout(this.#sleepTimeout);
486
+ this.#sleepTimeout = undefined;
487
+ }
488
+
489
+ // Abort listeners in the canonical stop path.
490
+ // This must run for all stop modes, including sleep and remote stop.
491
+ // Destroy may have already triggered an early abort, but repeating abort
492
+ // is intentional and safe.
493
+ try {
494
+ this.#abortController.abort();
495
+ } catch { }
496
+
497
+ // Wait for run handler to complete
498
+ await this.#waitForRunHandler(this.#config.options.runStopTimeout);
499
+
500
+ // Call onStop lifecycle
501
+ if (mode === "sleep") {
502
+ await this.#callOnSleep();
503
+ } else if (mode === "destroy") {
504
+ await this.#callOnDestroy();
505
+ } else {
506
+ assertUnreachable(mode);
507
+ }
508
+
509
+ // Disconnect non-hibernatable connections
510
+ await this.#disconnectConnections();
511
+
512
+ // Wait for background tasks
513
+ await this.#waitBackgroundPromises(
514
+ this.#config.options.waitUntilTimeout,
515
+ );
516
+
517
+ // Clear timeouts and save state
518
+ this.#rLog.info({ msg: "clearing pending save timeouts" });
519
+ this.stateManager.clearPendingSaveTimeout();
520
+ this.#rLog.info({ msg: "saving state immediately" });
521
+ await this.stateManager.saveState({
522
+ immediate: true,
523
+ allowStoppingState: true,
524
+ });
525
+
526
+ // Wait for write queues
527
+ await this.stateManager.waitForPendingWrites();
528
+ await this.#scheduleManager.waitForPendingAlarmWrites();
529
+ } finally {
530
+ await this.#cleanupDatabase();
531
+ }
532
+ }
533
+
534
+ // MARK: - Sleep
535
+ startSleep() {
536
+ if (this.#stopCalled || this.#destroyCalled) {
537
+ this.#rLog.debug({
538
+ msg: "cannot call startSleep if actor already stopping",
539
+ });
540
+ return;
541
+ }
542
+
543
+ if (this.#sleepCalled) {
544
+ this.#rLog.warn({
545
+ msg: "cannot call startSleep twice, actor already sleeping",
546
+ });
547
+ return;
548
+ }
549
+ this.#sleepCalled = true;
550
+
551
+ const sleep = this.driver.startSleep?.bind(this.driver, this.#actorId);
552
+ invariant(this.#sleepingSupported, "sleeping not supported");
553
+ invariant(sleep, "no sleep on driver");
554
+
555
+ this.#rLog.info({ msg: "actor sleeping" });
556
+
557
+ // Start sleep on next tick so call site of startSleep can exit
558
+ setImmediate(() => {
559
+ sleep();
560
+ });
561
+ }
562
+
563
+ // MARK: - Destroy
564
+ startDestroy() {
565
+ if (this.#stopCalled || this.#sleepCalled) {
566
+ this.#rLog.debug({
567
+ msg: "cannot call startDestroy if actor already stopping or sleeping",
568
+ });
569
+ return;
570
+ }
571
+
572
+ if (this.#destroyCalled) {
573
+ this.#rLog.warn({
574
+ msg: "cannot call startDestroy twice, actor already destroying",
575
+ });
576
+ return;
577
+ }
578
+ this.#destroyCalled = true;
579
+
580
+ // Abort immediately so in flight waits can exit before the driver stop
581
+ // handshake completes.
582
+ // The onStop path will call abort again as a safety net for all stop
583
+ // modes.
584
+ try {
585
+ this.#abortController.abort();
586
+ } catch {}
587
+
588
+ const destroy = this.driver.startDestroy.bind(
589
+ this.driver,
590
+ this.#actorId,
591
+ );
592
+
593
+ this.#rLog.info({ msg: "actor destroying" });
594
+
595
+ // Start destroy on next tick so call site of startDestroy can exit
596
+ setImmediate(() => {
597
+ destroy();
598
+ });
599
+ }
600
+
601
+ // MARK: - HTTP Request Tracking
602
+ beginHonoHttpRequest() {
603
+ this.#activeHonoHttpRequests++;
604
+ this.resetSleepTimer();
605
+ }
606
+
607
+ endHonoHttpRequest() {
608
+ this.#activeHonoHttpRequests--;
609
+ if (this.#activeHonoHttpRequests < 0) {
610
+ this.#activeHonoHttpRequests = 0;
611
+ this.#rLog.warn({
612
+ msg: "active hono requests went below 0, this is a RivetKit bug",
613
+ ...EXTRA_ERROR_LOG,
614
+ });
615
+ }
616
+ this.resetSleepTimer();
617
+ }
618
+
619
+ // MARK: - Message Processing
620
+ async processMessage(
621
+ message: {
622
+ body:
623
+ | {
624
+ tag: "ActionRequest";
625
+ val: { id: bigint; name: string; args: unknown };
626
+ }
627
+ | {
628
+ tag: "SubscriptionRequest";
629
+ val: { eventName: string; subscribe: boolean };
630
+ };
631
+ },
632
+ conn: Conn<S, CP, CS, V, I, DB, E, Q>,
633
+ ) {
634
+ await processMessage(message, this, conn, {
635
+ onExecuteAction: async (ctx, name, args) => {
636
+ return await this.executeAction(ctx, name, args);
637
+ },
638
+ onSubscribe: async (eventName, conn) => {
639
+ this.eventManager.addSubscription(eventName, conn, false);
640
+ },
641
+ onUnsubscribe: async (eventName, conn) => {
642
+ this.eventManager.removeSubscription(eventName, conn, false);
643
+ },
644
+ });
645
+ }
646
+
647
+ async assertCanSubscribe(
648
+ ctx: ActionContext<S, CP, CS, V, I, DB, E, Q>,
649
+ eventName: string,
650
+ ): Promise<void> {
651
+ const canSubscribe = getEventCanSubscribe(this.#config.events, eventName);
652
+ if (!canSubscribe) {
653
+ return;
654
+ }
655
+
656
+ const result = await canSubscribe(ctx);
657
+ if (typeof result !== "boolean") {
658
+ throw new errors.InvalidCanSubscribeResponse();
659
+ }
660
+ if (!result) {
661
+ throw new errors.Forbidden();
662
+ }
663
+ }
664
+
665
+ async assertCanPublish(
666
+ ctx: ActionContext<S, CP, CS, V, I, DB, E, Q>,
667
+ queueName: string,
668
+ ): Promise<void> {
669
+ const canPublish = getQueueCanPublish<
670
+ ActionContext<S, CP, CS, V, I, DB, E, Q>
671
+ >(this.#config.queues, queueName);
672
+ if (!canPublish) {
673
+ return;
674
+ }
675
+
676
+ const result = await canPublish(ctx);
677
+ if (typeof result !== "boolean") {
678
+ throw new errors.InvalidCanPublishResponse();
679
+ }
680
+ if (!result) {
681
+ throw new errors.Forbidden();
682
+ }
683
+ }
684
+
685
+ // MARK: - Action Execution
686
+ async executeAction(
687
+ ctx: ActionContext<S, CP, CS, V, I, DB, E, Q>,
688
+ actionName: string,
689
+ args: unknown[],
690
+ ): Promise<unknown> {
691
+ this.assertReady();
692
+
693
+ const actions = this.#config.actions ?? {};
694
+ if (!(actionName in actions)) {
695
+ this.#rLog.warn({ msg: "action does not exist", actionName });
696
+ throw new errors.ActionNotFound(actionName);
697
+ }
698
+
699
+ const actionFunction = actions[actionName];
700
+ if (typeof actionFunction !== "function") {
701
+ this.#rLog.warn({
702
+ msg: "action is not a function",
703
+ actionName,
704
+ type: typeof actionFunction,
705
+ });
706
+ throw new errors.ActionNotFound(actionName);
707
+ }
708
+
709
+ this.#activeKeepAwakeCount++;
710
+ this.resetSleepTimer();
711
+ const actionSpan = this.startTraceSpan(`actor.action.${actionName}`, {
712
+ "rivet.action.name": actionName,
713
+ });
714
+ let spanEnded = false;
715
+
716
+ try {
717
+ return await this.#traces.withSpan(actionSpan, async () => {
718
+ this.#rLog.debug({
719
+ msg: "executing action",
720
+ actionName,
721
+ args,
722
+ });
723
+
724
+ const outputOrPromise = actionFunction.call(
725
+ undefined,
726
+ ctx,
727
+ ...args,
728
+ );
729
+
730
+ let output: unknown;
731
+ const maybeThenable = outputOrPromise as {
732
+ then?: (
733
+ onfulfilled?: unknown,
734
+ onrejected?: unknown,
735
+ ) => unknown;
736
+ };
737
+ if (maybeThenable && typeof maybeThenable.then === "function") {
738
+ output = await deadline(
739
+ Promise.resolve(outputOrPromise),
740
+ this.#config.options.actionTimeout,
741
+ );
742
+ } else {
743
+ output = outputOrPromise;
744
+ }
745
+
746
+ // Process through onBeforeActionResponse if configured
747
+ if (this.#config.onBeforeActionResponse) {
748
+ try {
749
+ output = await this.runInTraceSpan(
750
+ "actor.onBeforeActionResponse",
751
+ { "rivet.action.name": actionName },
752
+ () =>
753
+ this.#config.onBeforeActionResponse!(
754
+ this.actorContext,
755
+ actionName,
756
+ args,
757
+ output,
758
+ ),
759
+ );
760
+ } catch (error) {
761
+ this.#rLog.error({
762
+ msg: "error in `onBeforeActionResponse`",
763
+ error: stringifyError(error),
764
+ });
765
+ }
766
+ }
767
+
768
+ return output;
769
+ });
770
+ } catch (error) {
771
+ const isTimeout = error instanceof DeadlineError;
772
+ const message = isTimeout
773
+ ? "ActionTimedOut"
774
+ : stringifyError(error);
775
+ this.#traces.setAttributes(actionSpan, {
776
+ "error.message": message,
777
+ "error.type":
778
+ error instanceof Error ? error.name : typeof error,
779
+ });
780
+ this.#traces.endSpan(actionSpan, {
781
+ status: { code: "ERROR", message },
782
+ });
783
+ spanEnded = true;
784
+ if (isTimeout) {
785
+ throw new errors.ActionTimedOut();
786
+ }
787
+ this.#rLog.error({
788
+ msg: "action error",
789
+ actionName,
790
+ error: stringifyError(error),
791
+ });
792
+ throw error;
793
+ } finally {
794
+ if (!spanEnded && actionSpan.isActive()) {
795
+ this.#traces.endSpan(actionSpan, {
796
+ status: { code: "OK" },
797
+ });
798
+ }
799
+ this.#activeKeepAwakeCount--;
800
+ if (this.#activeKeepAwakeCount < 0) {
801
+ this.#activeKeepAwakeCount = 0;
802
+ this.#rLog.warn({
803
+ msg: "active keep awake count went below 0, this is a RivetKit bug",
804
+ ...EXTRA_ERROR_LOG,
805
+ });
806
+ }
807
+ this.resetSleepTimer();
808
+ this.stateManager.savePersistThrottled();
809
+ }
810
+ }
811
+
812
+ // MARK: - HTTP/WebSocket Handlers
813
+ async handleRawRequest(
814
+ conn: Conn<S, CP, CS, V, I, DB, E, Q>,
815
+ request: Request,
816
+ ): Promise<Response> {
817
+ this.assertReady();
818
+
819
+ if (!this.#config.onRequest) {
820
+ throw new errors.RequestHandlerNotDefined();
821
+ }
822
+ const onRequest = this.#config.onRequest;
823
+
824
+ return await this.runInTraceSpan(
825
+ "actor.onRequest",
826
+ {
827
+ "http.method": request.method,
828
+ "http.url": request.url,
829
+ "rivet.conn.id": conn.id,
830
+ },
831
+ async () => {
832
+ const ctx = new RequestContext(this, conn, request);
833
+ try {
834
+ const response = await onRequest(ctx, request);
835
+ if (!response) {
836
+ throw new errors.InvalidRequestHandlerResponse();
837
+ }
838
+ return response;
839
+ } catch (error) {
840
+ this.#rLog.error({
841
+ msg: "onRequest error",
842
+ error: stringifyError(error),
843
+ });
844
+ throw error;
845
+ } finally {
846
+ this.stateManager.savePersistThrottled();
847
+ }
848
+ },
849
+ );
850
+ }
851
+
852
+ handleRawWebSocket(
853
+ conn: Conn<S, CP, CS, V, I, DB, E, Q>,
854
+ websocket: UniversalWebSocket,
855
+ request?: Request,
856
+ ) {
857
+ // NOTE: All code before `onWebSocket` must be synchronous in order to ensure the order of `open` events happen in the correct order.
858
+
859
+ this.assertReady();
860
+
861
+ if (!this.#config.onWebSocket) {
862
+ throw new errors.InternalError("onWebSocket handler not defined");
863
+ }
864
+
865
+ const span = this.startTraceSpan("actor.onWebSocket", {
866
+ "http.url": request?.url,
867
+ "rivet.conn.id": conn.id,
868
+ });
869
+ let spanEnded = false;
870
+
871
+ try {
872
+ // Reset sleep timer when handling WebSocket
873
+ this.resetSleepTimer();
874
+
875
+ // Handle WebSocket
876
+ const ctx = new WebSocketContext(this, conn, request);
877
+
878
+ // NOTE: This is async and will run in the background
879
+ const voidOrPromise = this.#traces.withSpan(span, () =>
880
+ this.#config.onWebSocket!(ctx, websocket),
881
+ );
882
+
883
+ // Save changes from the WebSocket open
884
+ if (voidOrPromise instanceof Promise) {
885
+ voidOrPromise
886
+ .then(() => {
887
+ if (!spanEnded) {
888
+ this.endTraceSpan(span, { code: "OK" });
889
+ spanEnded = true;
890
+ }
891
+ })
892
+ .catch((error) => {
893
+ if (!spanEnded) {
894
+ this.endTraceSpan(span, {
895
+ code: "ERROR",
896
+ message: stringifyError(error),
897
+ });
898
+ spanEnded = true;
899
+ }
900
+ this.#rLog.error({
901
+ msg: "onWebSocket error",
902
+ error: stringifyError(error),
903
+ });
904
+ })
905
+ .finally(() => {
906
+ this.stateManager.savePersistThrottled();
907
+ });
908
+ } else {
909
+ if (!spanEnded) {
910
+ this.endTraceSpan(span, { code: "OK" });
911
+ spanEnded = true;
912
+ }
913
+ this.stateManager.savePersistThrottled();
914
+ }
915
+ } catch (error) {
916
+ if (!spanEnded) {
917
+ this.endTraceSpan(span, {
918
+ code: "ERROR",
919
+ message: stringifyError(error),
920
+ });
921
+ spanEnded = true;
922
+ }
923
+ this.#rLog.error({
924
+ msg: "onWebSocket error",
925
+ error: stringifyError(error),
926
+ });
927
+ throw error;
928
+ }
929
+ }
930
+
931
+ // MARK: - Scheduling
932
+ async scheduleEvent(
933
+ timestamp: number,
934
+ action: string,
935
+ args: unknown[],
936
+ ): Promise<void> {
937
+ await this.#scheduleManager.scheduleEvent(timestamp, action, args);
938
+ }
939
+
940
+ async onAlarm() {
941
+ this.resetSleepTimer();
942
+ await this.#scheduleManager.onAlarm();
943
+ }
944
+
945
+ // MARK: - Background Tasks
946
+ waitUntil(promise: Promise<void>) {
947
+ this.assertReady();
948
+
949
+ const nonfailablePromise = promise
950
+ .then(() => {
951
+ this.#rLog.debug({ msg: "wait until promise complete" });
952
+ })
953
+ .catch((error) => {
954
+ this.#rLog.error({
955
+ msg: "wait until promise failed",
956
+ error: stringifyError(error),
957
+ });
958
+ });
959
+ this.#backgroundPromises.push(nonfailablePromise);
960
+ }
961
+
962
+ /**
963
+ * Prevents the actor from sleeping while the given promise is running.
964
+ *
965
+ * Use this when performing async operations in the `run` handler or other
966
+ * background contexts where you need to ensure the actor stays awake.
967
+ *
968
+ * Returns the resolved value and resets the sleep timer on completion.
969
+ * Errors are propagated to the caller.
970
+ */
971
+ async keepAwake<T>(promise: Promise<T>): Promise<T> {
972
+ this.assertReady(true);
973
+
974
+ this.#activeKeepAwakeCount++;
975
+ this.resetSleepTimer();
976
+
977
+ try {
978
+ return await promise;
979
+ } finally {
980
+ this.#activeKeepAwakeCount--;
981
+ if (this.#activeKeepAwakeCount < 0) {
982
+ this.#activeKeepAwakeCount = 0;
983
+ this.#rLog.warn({
984
+ msg: "active keep awake count went below 0, this is a RivetKit bug",
985
+ ...EXTRA_ERROR_LOG,
986
+ });
987
+ }
988
+ this.resetSleepTimer();
989
+ }
990
+ }
991
+
992
+ beginQueueWait() {
993
+ this.assertReady(true);
994
+ this.#activeQueueWaitCount++;
995
+ this.resetSleepTimer();
996
+ }
997
+
998
+ endQueueWait() {
999
+ this.#activeQueueWaitCount--;
1000
+ if (this.#activeQueueWaitCount < 0) {
1001
+ this.#activeQueueWaitCount = 0;
1002
+ this.#rLog.warn({
1003
+ msg: "active queue wait count went below 0, this is a RivetKit bug",
1004
+ ...EXTRA_ERROR_LOG,
1005
+ });
1006
+ }
1007
+ this.resetSleepTimer();
1008
+ }
1009
+
1010
+ // MARK: - Private Helper Methods
1011
+ #initializeTraces() {
1012
+ if (getRivetExperimentalOtel()) {
1013
+ // Experimental mode persists trace data to actor storage so inspector
1014
+ // queries can return OTel payloads.
1015
+ this.#traces = createTraces({
1016
+ driver: new ActorTracesDriver(this.driver, this.#actorId),
1017
+ });
1018
+ } else {
1019
+ // Keep the tracing API calls active while disabling trace persistence
1020
+ // until the experimental flag is enabled.
1021
+ this.#traces = createNoopTraces();
1022
+ }
1023
+ }
1024
+
1025
+ #traceAttributes(
1026
+ attributes?: Record<string, unknown>,
1027
+ ): Record<string, unknown> {
1028
+ return {
1029
+ "rivet.actor.id": this.#actorId,
1030
+ "rivet.actor.name": this.#name,
1031
+ "rivet.actor.key": this.#actorKeyString,
1032
+ "rivet.actor.region": this.#region,
1033
+ ...(attributes ?? {}),
1034
+ };
1035
+ }
1036
+
1037
+ #patchLoggerForTraces(logger: Logger) {
1038
+ const levels: Array<
1039
+ "trace" | "debug" | "info" | "warn" | "error" | "fatal"
1040
+ > = ["trace", "debug", "info", "warn", "error", "fatal"];
1041
+ for (const level of levels) {
1042
+ const original = logger[level].bind(logger) as (
1043
+ ...args: any[]
1044
+ ) => unknown;
1045
+ logger[level] = ((...args: unknown[]) => {
1046
+ this.#emitLogEvent(level, args);
1047
+ return original(...(args as any[]));
1048
+ }) as Logger[typeof level];
1049
+ }
1050
+ }
1051
+
1052
+ #emitLogEvent(level: string, args: unknown[]) {
1053
+ const span = this.#traces.getCurrentSpan();
1054
+ if (!span || !span.isActive()) {
1055
+ return;
1056
+ }
1057
+
1058
+ let message: string | undefined;
1059
+ if (args.length >= 2) {
1060
+ message = String(args[1]);
1061
+ } else if (args.length === 1) {
1062
+ const [value] = args;
1063
+ if (typeof value === "string") {
1064
+ message = value;
1065
+ } else if (
1066
+ typeof value === "number" ||
1067
+ typeof value === "boolean"
1068
+ ) {
1069
+ message = String(value);
1070
+ } else if (value && typeof value === "object") {
1071
+ const maybeMsg = (value as { msg?: unknown }).msg;
1072
+ if (maybeMsg !== undefined) {
1073
+ message = String(maybeMsg);
1074
+ }
1075
+ }
1076
+ }
1077
+
1078
+ this.#traces.emitEvent(span, "log", {
1079
+ attributes: this.#traceAttributes({
1080
+ "log.level": level,
1081
+ ...(message ? { "log.message": message } : {}),
1082
+ }),
1083
+ timeUnixMs: Date.now(),
1084
+ });
1085
+ }
1086
+
1087
+ #initializeLogging() {
1088
+ const logParams = {
1089
+ actor: this.#name,
1090
+ key: this.#actorKeyString,
1091
+ actorId: this.#actorId,
1092
+ };
1093
+
1094
+ const extraLogParams = this.driver.getExtraActorLogParams?.();
1095
+ if (extraLogParams) Object.assign(logParams, extraLogParams);
1096
+
1097
+ this.#log = getBaseLogger().child(
1098
+ Object.assign(
1099
+ getIncludeTarget() ? { target: "actor" } : {},
1100
+ logParams,
1101
+ ),
1102
+ );
1103
+ this.#rLog = getBaseLogger().child(
1104
+ Object.assign(
1105
+ getIncludeTarget() ? { target: "actor-runtime" } : {},
1106
+ logParams,
1107
+ ),
1108
+ );
1109
+
1110
+ this.#patchLoggerForTraces(this.#log);
1111
+ this.#patchLoggerForTraces(this.#rLog);
1112
+ }
1113
+
1114
+ async #loadState() {
1115
+ // Read initial state from KV
1116
+ const [persistDataBuffer] = await this.driver.kvBatchGet(
1117
+ this.#actorId,
1118
+ [KEYS.PERSIST_DATA],
1119
+ );
1120
+ invariant(
1121
+ persistDataBuffer !== null,
1122
+ "persist data has not been set, it should be set when initialized",
1123
+ );
1124
+
1125
+ const bareData =
1126
+ ACTOR_VERSIONED.deserializeWithEmbeddedVersion(persistDataBuffer);
1127
+ const persistData = convertActorFromBarePersisted<S, I>(bareData);
1128
+
1129
+ if (persistData.hasInitialized) {
1130
+ // Restore existing actor
1131
+ await this.#restoreExistingActor(persistData);
1132
+ } else {
1133
+ // Create new actor
1134
+ await this.#createNewActor(persistData);
1135
+ }
1136
+
1137
+ // Pass persist reference to schedule manager
1138
+ this.#scheduleManager.setPersist(this.stateManager.persist);
1139
+ }
1140
+
1141
+ async #createNewActor(persistData: PersistedActor<S, I>) {
1142
+ this.#rLog.info({ msg: "actor creating" });
1143
+
1144
+ // Initialize state
1145
+ await this.stateManager.initializeState(persistData);
1146
+
1147
+ // Call onCreate lifecycle
1148
+ if (this.#config.onCreate) {
1149
+ const onCreate = this.#config.onCreate;
1150
+ await this.runInTraceSpan("actor.onCreate", undefined, () =>
1151
+ onCreate(this.actorContext as any, persistData.input!),
1152
+ );
1153
+ }
1154
+ }
1155
+
1156
+ async #restoreExistingActor(persistData: PersistedActor<S, I>) {
1157
+ // List all connection keys
1158
+ const connEntries = await this.driver.kvListPrefix(
1159
+ this.#actorId,
1160
+ KEYS.CONN_PREFIX,
1161
+ );
1162
+
1163
+ // Decode connections
1164
+ const connections: PersistedConn<CP, CS>[] = [];
1165
+ for (const [_key, value] of connEntries) {
1166
+ try {
1167
+ const bareData = CONN_VERSIONED.deserializeWithEmbeddedVersion(
1168
+ new Uint8Array(value),
1169
+ );
1170
+ const conn = convertConnFromBarePersistedConn<CP, CS>(bareData);
1171
+ connections.push(conn);
1172
+ } catch (error) {
1173
+ this.#rLog.error({
1174
+ msg: "failed to decode connection",
1175
+ error: stringifyError(error),
1176
+ });
1177
+ }
1178
+ }
1179
+
1180
+ this.#rLog.info({
1181
+ msg: "actor restoring",
1182
+ connections: connections.length,
1183
+ });
1184
+
1185
+ // Initialize state
1186
+ this.stateManager.initPersistProxy(persistData);
1187
+
1188
+ // Restore connections
1189
+ this.connectionManager.restoreConnections(connections);
1190
+ }
1191
+
1192
+ async #initializeInspectorToken() {
1193
+ // Try to load existing token
1194
+ const [tokenBuffer] = await this.driver.kvBatchGet(this.#actorId, [
1195
+ KEYS.INSPECTOR_TOKEN,
1196
+ ]);
1197
+
1198
+ if (tokenBuffer !== null) {
1199
+ // Token exists, decode it
1200
+ const decoder = new TextDecoder();
1201
+ this.#inspectorToken = decoder.decode(tokenBuffer);
1202
+ this.#rLog.debug({ msg: "loaded existing inspector token" });
1203
+ } else {
1204
+ // Generate new token
1205
+ this.#inspectorToken = generateSecureToken();
1206
+ const tokenBytes = new TextEncoder().encode(this.#inspectorToken);
1207
+ await this.driver.kvBatchPut(this.#actorId, [
1208
+ [KEYS.INSPECTOR_TOKEN, tokenBytes],
1209
+ ]);
1210
+ this.#rLog.debug({ msg: "generated new inspector token" });
1211
+ }
1212
+ }
1213
+
1214
+ async #initializeVars() {
1215
+ let vars: V | undefined;
1216
+ if ("createVars" in this.#config) {
1217
+ const createVars = this.#config.createVars;
1218
+ vars = await this.runInTraceSpan(
1219
+ "actor.createVars",
1220
+ undefined,
1221
+ () => {
1222
+ const dataOrPromise = createVars!(
1223
+ this.actorContext as any,
1224
+ this.driver.getContext(this.#actorId),
1225
+ );
1226
+ if (dataOrPromise instanceof Promise) {
1227
+ return deadline(
1228
+ dataOrPromise,
1229
+ this.#config.options.createVarsTimeout,
1230
+ );
1231
+ }
1232
+ return dataOrPromise;
1233
+ },
1234
+ );
1235
+ } else if ("vars" in this.#config) {
1236
+ vars = structuredClone(this.#config.vars);
1237
+ } else {
1238
+ throw new Error(
1239
+ "Could not create variables from 'createVars' or 'vars'",
1240
+ );
1241
+ }
1242
+ this.#vars = vars;
1243
+ }
1244
+
1245
+ async #callOnStart() {
1246
+ this.#rLog.info({ msg: "actor starting" });
1247
+ if (this.#config.onWake) {
1248
+ const onWake = this.#config.onWake;
1249
+ await this.runInTraceSpan("actor.onWake", undefined, () =>
1250
+ onWake(this.actorContext),
1251
+ );
1252
+ }
1253
+ }
1254
+
1255
+ async #callOnSleep() {
1256
+ if (this.#config.onSleep) {
1257
+ const onSleep = this.#config.onSleep;
1258
+ try {
1259
+ this.#rLog.debug({ msg: "calling onSleep" });
1260
+ await this.runInTraceSpan(
1261
+ "actor.onSleep",
1262
+ undefined,
1263
+ async () => {
1264
+ const result = onSleep(this.actorContext);
1265
+ if (result instanceof Promise) {
1266
+ await deadline(
1267
+ result,
1268
+ this.#config.options.onSleepTimeout,
1269
+ );
1270
+ }
1271
+ },
1272
+ );
1273
+ this.#rLog.debug({ msg: "onSleep completed" });
1274
+ } catch (error) {
1275
+ if (error instanceof DeadlineError) {
1276
+ this.#rLog.error({ msg: "onSleep timed out" });
1277
+ } else {
1278
+ this.#rLog.error({
1279
+ msg: "error in onSleep",
1280
+ error: stringifyError(error),
1281
+ });
1282
+ }
1283
+ }
1284
+ }
1285
+ }
1286
+
1287
+ async #callOnDestroy() {
1288
+ if (this.#config.onDestroy) {
1289
+ const onDestroy = this.#config.onDestroy;
1290
+ try {
1291
+ this.#rLog.debug({ msg: "calling onDestroy" });
1292
+ await this.runInTraceSpan(
1293
+ "actor.onDestroy",
1294
+ undefined,
1295
+ async () => {
1296
+ const result = onDestroy(this.actorContext);
1297
+ if (result instanceof Promise) {
1298
+ await deadline(
1299
+ result,
1300
+ this.#config.options.onDestroyTimeout,
1301
+ );
1302
+ }
1303
+ },
1304
+ );
1305
+ this.#rLog.debug({ msg: "onDestroy completed" });
1306
+ } catch (error) {
1307
+ if (error instanceof DeadlineError) {
1308
+ this.#rLog.error({ msg: "onDestroy timed out" });
1309
+ } else {
1310
+ this.#rLog.error({
1311
+ msg: "error in onDestroy",
1312
+ error: stringifyError(error),
1313
+ });
1314
+ }
1315
+ }
1316
+ }
1317
+ }
1318
+
1319
+ #startRunHandler() {
1320
+ const runFn = getRunFunction(this.#config.run);
1321
+ if (!runFn) return;
1322
+
1323
+ this.#rLog.debug({ msg: "starting run handler" });
1324
+ this.#runHandlerActive = true;
1325
+ this.resetSleepTimer();
1326
+
1327
+ const runSpan = this.startTraceSpan("actor.run");
1328
+ const runResult = this.#traces.withSpan(runSpan, () =>
1329
+ runFn(this.actorContext),
1330
+ );
1331
+
1332
+ if (runResult instanceof Promise) {
1333
+ this.#runPromise = runResult
1334
+ .then(() => {
1335
+ if (this.#stopCalled) {
1336
+ if (runSpan.isActive()) {
1337
+ this.endTraceSpan(runSpan, { code: "OK" });
1338
+ }
1339
+ this.#rLog.debug({
1340
+ msg: "run handler exited during actor stop",
1341
+ });
1342
+ return;
1343
+ }
1344
+
1345
+ // Run handler exited normally - this should crash the actor
1346
+ this.emitTraceEvent(
1347
+ "actor.crash",
1348
+ { "rivet.actor.reason": "run_exited" },
1349
+ runSpan,
1350
+ );
1351
+ this.endTraceSpan(runSpan, {
1352
+ code: "ERROR",
1353
+ message: "run exited unexpectedly",
1354
+ });
1355
+ this.#rLog.warn({
1356
+ msg: "run handler exited unexpectedly, crashing actor to reschedule",
1357
+ });
1358
+ this.startDestroy();
1359
+ })
1360
+ .catch((error) => {
1361
+ if (this.#stopCalled) {
1362
+ if (runSpan.isActive()) {
1363
+ this.endTraceSpan(runSpan, { code: "OK" });
1364
+ }
1365
+ this.#rLog.debug({
1366
+ msg: "run handler threw during actor stop",
1367
+ error: stringifyError(error),
1368
+ });
1369
+ return;
1370
+ }
1371
+
1372
+ // Run handler threw an error - crash the actor
1373
+ this.emitTraceEvent(
1374
+ "actor.crash",
1375
+ {
1376
+ "rivet.actor.reason": "run_error",
1377
+ "error.message": stringifyError(error),
1378
+ },
1379
+ runSpan,
1380
+ );
1381
+ this.endTraceSpan(runSpan, {
1382
+ code: "ERROR",
1383
+ message: stringifyError(error),
1384
+ });
1385
+ this.#rLog.error({
1386
+ msg: "run handler threw error, crashing actor to reschedule",
1387
+ error: stringifyError(error),
1388
+ });
1389
+ this.startDestroy();
1390
+ })
1391
+ .finally(() => {
1392
+ this.#runHandlerActive = false;
1393
+ this.resetSleepTimer();
1394
+ });
1395
+ } else if (runSpan.isActive()) {
1396
+ this.endTraceSpan(runSpan, { code: "OK" });
1397
+ this.#runHandlerActive = false;
1398
+ this.resetSleepTimer();
1399
+ }
1400
+ }
1401
+
1402
+ async #waitForRunHandler(timeoutMs: number) {
1403
+ if (!this.#runPromise) {
1404
+ return;
1405
+ }
1406
+
1407
+ this.#rLog.debug({ msg: "waiting for run handler to complete" });
1408
+
1409
+ const timedOut = await Promise.race([
1410
+ this.#runPromise.then(() => false).catch(() => false),
1411
+ new Promise<true>((resolve) =>
1412
+ setTimeout(() => resolve(true), timeoutMs),
1413
+ ),
1414
+ ]);
1415
+
1416
+ if (timedOut) {
1417
+ this.#rLog.warn({
1418
+ msg: "run handler did not complete in time, it may have leaked - ensure you use c.aborted (or the abort signal c.abortSignal) to exit gracefully",
1419
+ timeoutMs,
1420
+ });
1421
+ } else {
1422
+ this.#rLog.debug({ msg: "run handler completed" });
1423
+ }
1424
+ }
1425
+
1426
+ async #setupDatabase() {
1427
+ if (!("db" in this.#config) || !this.#config.db) {
1428
+ return;
1429
+ }
1430
+
1431
+ let client: InferDatabaseClient<DB> | undefined;
1432
+ try {
1433
+ // Every actor gets its own SqliteVfs/@rivetkit/sqlite instance. The async
1434
+ // @rivetkit/sqlite build is not re-entrant, and sharing one instance across
1435
+ // actors can cause cross-actor contention and runtime corruption.
1436
+ if (!this.#sqliteVfs && this.driver.createSqliteVfs) {
1437
+ this.#sqliteVfs = await this.driver.createSqliteVfs();
1438
+ }
1439
+
1440
+ client = await this.#config.db.createClient({
1441
+ actorId: this.#actorId,
1442
+ overrideRawDatabaseClient: this.driver.overrideRawDatabaseClient
1443
+ ? () => this.driver.overrideRawDatabaseClient!(this.#actorId)
1444
+ : undefined,
1445
+ overrideDrizzleDatabaseClient: this.driver.overrideDrizzleDatabaseClient
1446
+ ? () => this.driver.overrideDrizzleDatabaseClient!(this.#actorId)
1447
+ : undefined,
1448
+ kv: {
1449
+ batchPut: (entries) => this.driver.kvBatchPut(this.#actorId, entries),
1450
+ batchGet: (keys) => this.driver.kvBatchGet(this.#actorId, keys),
1451
+ batchDelete: (keys) => this.driver.kvBatchDelete(this.#actorId, keys),
1452
+ },
1453
+ sqliteVfs: this.#sqliteVfs,
1454
+ });
1455
+ this.#rLog.info({ msg: "database migration starting" });
1456
+ await this.#config.db.onMigrate?.(client);
1457
+ this.#rLog.info({ msg: "database migration complete" });
1458
+ this.#db = client;
1459
+ } catch (error) {
1460
+ if (client) {
1461
+ try {
1462
+ await this.#config.db.onDestroy?.(client);
1463
+ } catch (cleanupError) {
1464
+ this.#rLog.error({
1465
+ msg: "database setup cleanup failed",
1466
+ error: stringifyError(cleanupError),
1467
+ });
1468
+ }
1469
+ }
1470
+ if (this.#sqliteVfs) {
1471
+ try {
1472
+ await this.#sqliteVfs.destroy();
1473
+ } catch (cleanupError) {
1474
+ this.#rLog.error({
1475
+ msg: "sqlite vfs teardown after setup failure failed",
1476
+ error: stringifyError(cleanupError),
1477
+ });
1478
+ }
1479
+ }
1480
+ this.#sqliteVfs = undefined;
1481
+ if (error instanceof Error) {
1482
+ this.#rLog.error({
1483
+ msg: "database setup failed",
1484
+ error: stringifyError(error),
1485
+ });
1486
+ throw error;
1487
+ }
1488
+ const wrappedError = new Error(`Database setup failed: ${String(error)}`);
1489
+ this.#rLog.error({
1490
+ msg: "database setup failed with non-Error object",
1491
+ error: String(error),
1492
+ errorType: typeof error,
1493
+ });
1494
+ throw wrappedError;
1495
+ }
1496
+ }
1497
+
1498
+ async #cleanupDatabase() {
1499
+ const client = this.#db;
1500
+ const sqliteVfs = this.#sqliteVfs;
1501
+ const dbConfig = "db" in this.#config ? this.#config.db : undefined;
1502
+ this.#db = undefined;
1503
+ this.#sqliteVfs = undefined;
1504
+
1505
+ if (client && dbConfig) {
1506
+ try {
1507
+ await dbConfig.onDestroy?.(client);
1508
+ } catch (error) {
1509
+ this.#rLog.error({
1510
+ msg: "database cleanup failed",
1511
+ error: stringifyError(error),
1512
+ });
1513
+ }
1514
+ }
1515
+
1516
+ if (sqliteVfs) {
1517
+ try {
1518
+ await sqliteVfs.destroy();
1519
+ } catch (error) {
1520
+ this.#rLog.error({
1521
+ msg: "sqlite vfs cleanup failed",
1522
+ error: stringifyError(error),
1523
+ });
1524
+ }
1525
+ }
1526
+ }
1527
+
1528
+ async #disconnectConnections() {
1529
+ const promises: Promise<unknown>[] = [];
1530
+ this.#rLog.debug({
1531
+ msg: "disconnecting connections on actor stop",
1532
+ totalConns: this.connectionManager.connections.size,
1533
+ });
1534
+ for (const connection of this.connectionManager.connections.values()) {
1535
+ this.#rLog.debug({
1536
+ msg: "checking connection for disconnect",
1537
+ connId: connection.id,
1538
+ isHibernatable: connection.isHibernatable,
1539
+ });
1540
+ if (!connection.isHibernatable) {
1541
+ this.#rLog.debug({
1542
+ msg: "disconnecting non-hibernatable connection on actor stop",
1543
+ connId: connection.id,
1544
+ });
1545
+ promises.push(connection.disconnect());
1546
+ } else {
1547
+ this.#rLog.debug({
1548
+ msg: "preserving hibernatable connection on actor stop",
1549
+ connId: connection.id,
1550
+ });
1551
+ }
1552
+ }
1553
+
1554
+ // Wait with timeout
1555
+ const res = await Promise.race([
1556
+ Promise.all(promises).then(() => false),
1557
+ new Promise<boolean>((res) =>
1558
+ globalThis.setTimeout(() => res(true), 1500),
1559
+ ),
1560
+ ]);
1561
+
1562
+ if (res) {
1563
+ this.#rLog.warn({
1564
+ msg: "timed out waiting for connections to close, shutting down anyway",
1565
+ });
1566
+ }
1567
+ }
1568
+
1569
+ async #waitBackgroundPromises(timeoutMs: number) {
1570
+ const pending = this.#backgroundPromises;
1571
+ if (pending.length === 0) {
1572
+ this.#rLog.debug({ msg: "no background promises" });
1573
+ return;
1574
+ }
1575
+
1576
+ const timedOut = await Promise.race([
1577
+ Promise.allSettled(pending).then(() => false),
1578
+ new Promise<true>((resolve) =>
1579
+ setTimeout(() => resolve(true), timeoutMs),
1580
+ ),
1581
+ ]);
1582
+
1583
+ if (timedOut) {
1584
+ this.#rLog.error({
1585
+ msg: "timed out waiting for background tasks",
1586
+ count: pending.length,
1587
+ timeoutMs,
1588
+ });
1589
+ } else {
1590
+ this.#rLog.debug({ msg: "background promises finished" });
1591
+ }
1592
+ }
1593
+
1594
+ resetSleepTimer() {
1595
+ if (this.#config.options.noSleep || !this.#sleepingSupported) return;
1596
+ if (this.#stopCalled) return;
1597
+
1598
+ const canSleep = this.#canSleep();
1599
+
1600
+ this.#rLog.debug({
1601
+ msg: "resetting sleep timer",
1602
+ canSleep: CanSleep[canSleep],
1603
+ existingTimeout: !!this.#sleepTimeout,
1604
+ timeout: this.#config.options.sleepTimeout,
1605
+ });
1606
+
1607
+ if (this.#sleepTimeout) {
1608
+ clearTimeout(this.#sleepTimeout);
1609
+ this.#sleepTimeout = undefined;
1610
+ }
1611
+
1612
+ if (this.#sleepCalled) return;
1613
+
1614
+ if (canSleep === CanSleep.Yes) {
1615
+ this.#sleepTimeout = setTimeout(() => {
1616
+ this.startSleep();
1617
+ }, this.#config.options.sleepTimeout);
1618
+ }
1619
+ }
1620
+
1621
+ #canSleep(): CanSleep {
1622
+ if (!this.#ready) return CanSleep.NotReady;
1623
+ if (!this.#started) return CanSleep.NotReady;
1624
+ if (this.#activeHonoHttpRequests > 0)
1625
+ return CanSleep.ActiveHonoHttpRequests;
1626
+ if (this.#activeKeepAwakeCount > 0) return CanSleep.ActiveKeepAwake;
1627
+ if (this.#runHandlerActive && this.#activeQueueWaitCount === 0) {
1628
+ return CanSleep.ActiveRun;
1629
+ }
1630
+
1631
+ for (const _conn of this.connectionManager.connections.values()) {
1632
+ // TODO: Add back
1633
+ // if (!_conn.isHibernatable) {
1634
+ return CanSleep.ActiveConns;
1635
+ // }
1636
+ }
1637
+
1638
+ if (this.connectionManager.pendingDisconnectCount > 0) {
1639
+ return CanSleep.ActiveDisconnectCallbacks;
1640
+ }
1641
+
1642
+ return CanSleep.Yes;
1643
+ }
1644
+
1645
+ get #sleepingSupported(): boolean {
1646
+ return this.driver.startSleep !== undefined;
1647
+ }
1648
+
1649
+ get #varsEnabled(): boolean {
1650
+ return "createVars" in this.#config || "vars" in this.#config;
1651
+ }
1652
+
1653
+ #validateVarsEnabled() {
1654
+ if (!this.#varsEnabled) {
1655
+ throw new errors.VarsNotEnabled();
1656
+ }
1657
+ }
1658
+ }