rivetkit 2.0.42 → 2.1.0-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 (322) hide show
  1. package/dist/{tsup/config-CLnylLYY.d.ts → browser/client.d.ts} +2127 -1910
  2. package/dist/browser/client.js +5182 -0
  3. package/dist/browser/client.js.map +1 -0
  4. package/dist/browser/inspector/client.d.ts +130 -0
  5. package/dist/browser/inspector/client.js +2854 -0
  6. package/dist/browser/inspector/client.js.map +1 -0
  7. package/dist/browser/v3-DnYObHH3.d.ts +279 -0
  8. package/dist/schemas/actor-inspector/v2.ts +796 -0
  9. package/dist/schemas/actor-inspector/v3.ts +899 -0
  10. package/dist/schemas/actor-persist/v4.ts +406 -0
  11. package/dist/schemas/client-protocol/v3.ts +554 -0
  12. package/dist/schemas/persist/v1.ts +781 -0
  13. package/dist/schemas/transport/v1.ts +697 -0
  14. package/dist/tsup/actor/errors.cjs +27 -3
  15. package/dist/tsup/actor/errors.cjs.map +1 -1
  16. package/dist/tsup/actor/errors.d.cts +37 -1
  17. package/dist/tsup/actor/errors.d.ts +37 -1
  18. package/dist/tsup/actor/errors.js +26 -1
  19. package/dist/tsup/{actor-router-consts-DzI2szci.d.cts → actor-router-consts-D29T1Z-K.d.cts} +1 -1
  20. package/dist/tsup/{actor-router-consts-DzI2szci.d.ts → actor-router-consts-D29T1Z-K.d.ts} +1 -1
  21. package/dist/tsup/chunk-424PT5DM.js +23 -0
  22. package/dist/tsup/chunk-424PT5DM.js.map +1 -0
  23. package/dist/tsup/{chunk-JDAD2YFA.js → chunk-5ESWDTHJ.js} +148 -273
  24. package/dist/tsup/chunk-5ESWDTHJ.js.map +1 -0
  25. package/dist/tsup/{chunk-FJ3KTN4V.js → chunk-6LIBPELE.js} +119 -11
  26. package/dist/tsup/chunk-6LIBPELE.js.map +1 -0
  27. package/dist/tsup/chunk-6LJAZ5R4.cjs +96 -0
  28. package/dist/tsup/chunk-6LJAZ5R4.cjs.map +1 -0
  29. package/dist/tsup/{chunk-LFVF5SCU.js → chunk-7HTNH26M.js} +126 -1
  30. package/dist/tsup/chunk-7HTNH26M.js.map +1 -0
  31. package/dist/tsup/chunk-7K4CYDGD.js +630 -0
  32. package/dist/tsup/chunk-7K4CYDGD.js.map +1 -0
  33. package/dist/tsup/{chunk-XXGJCOL6.js → chunk-A6YIZWTK.js} +2 -2
  34. package/dist/tsup/chunk-AIYEYMX5.cjs +630 -0
  35. package/dist/tsup/chunk-AIYEYMX5.cjs.map +1 -0
  36. package/dist/tsup/{chunk-Q6W7RJJP.js → chunk-DIGBC2VI.js} +211 -2316
  37. package/dist/tsup/chunk-DIGBC2VI.js.map +1 -0
  38. package/dist/tsup/{chunk-RZW2DNND.cjs → chunk-F6JYU5IK.cjs} +1957 -1039
  39. package/dist/tsup/chunk-F6JYU5IK.cjs.map +1 -0
  40. package/dist/tsup/chunk-HAZL2EPK.cjs +534 -0
  41. package/dist/tsup/chunk-HAZL2EPK.cjs.map +1 -0
  42. package/dist/tsup/chunk-HDQ2JUQT.cjs +23 -0
  43. package/dist/tsup/chunk-HDQ2JUQT.cjs.map +1 -0
  44. package/dist/tsup/chunk-HIDX4C5Y.cjs +1036 -0
  45. package/dist/tsup/chunk-HIDX4C5Y.cjs.map +1 -0
  46. package/dist/tsup/chunk-IVG73YCW.js +534 -0
  47. package/dist/tsup/chunk-IVG73YCW.js.map +1 -0
  48. package/dist/tsup/chunk-KJSYAUOM.js +96 -0
  49. package/dist/tsup/chunk-KJSYAUOM.js.map +1 -0
  50. package/dist/tsup/{chunk-2XQS746M.cjs → chunk-L47L3ZWJ.cjs} +127 -2
  51. package/dist/tsup/chunk-L47L3ZWJ.cjs.map +1 -0
  52. package/dist/tsup/{chunk-H4TB4X25.cjs → chunk-LW6KLR7A.cjs} +126 -18
  53. package/dist/tsup/chunk-LW6KLR7A.cjs.map +1 -0
  54. package/dist/tsup/chunk-LXUQ667X.js +2006 -0
  55. package/dist/tsup/chunk-LXUQ667X.js.map +1 -0
  56. package/dist/tsup/{chunk-GMAVRZSF.js → chunk-M2T62AZQ.js} +1790 -872
  57. package/dist/tsup/chunk-M2T62AZQ.js.map +1 -0
  58. package/dist/tsup/chunk-MZ37VV3P.js +5974 -0
  59. package/dist/tsup/chunk-MZ37VV3P.js.map +1 -0
  60. package/dist/tsup/chunk-N4KRDJ56.js +72 -0
  61. package/dist/tsup/chunk-N4KRDJ56.js.map +1 -0
  62. package/dist/tsup/chunk-NIYZDWMW.cjs +2006 -0
  63. package/dist/tsup/chunk-NIYZDWMW.cjs.map +1 -0
  64. package/dist/tsup/chunk-OMEPCQK2.js +649 -0
  65. package/dist/tsup/chunk-OMEPCQK2.js.map +1 -0
  66. package/dist/tsup/chunk-SR3KQE7Q.cjs +72 -0
  67. package/dist/tsup/chunk-SR3KQE7Q.cjs.map +1 -0
  68. package/dist/tsup/chunk-SSEP6DHP.cjs +2657 -0
  69. package/dist/tsup/chunk-SSEP6DHP.cjs.map +1 -0
  70. package/dist/tsup/chunk-T5YCUGVS.js +1036 -0
  71. package/dist/tsup/chunk-T5YCUGVS.js.map +1 -0
  72. package/dist/tsup/{chunk-EJVBH5VF.cjs → chunk-TPGXWFQT.cjs} +3 -3
  73. package/dist/tsup/{chunk-EJVBH5VF.cjs.map → chunk-TPGXWFQT.cjs.map} +1 -1
  74. package/dist/tsup/{chunk-X35U3YNX.cjs → chunk-TYLXNCA5.cjs} +214 -339
  75. package/dist/tsup/chunk-TYLXNCA5.cjs.map +1 -0
  76. package/dist/tsup/chunk-VKVNIQRQ.js +257 -0
  77. package/dist/tsup/chunk-VKVNIQRQ.js.map +1 -0
  78. package/dist/tsup/chunk-XWBAQO5H.cjs +649 -0
  79. package/dist/tsup/chunk-XWBAQO5H.cjs.map +1 -0
  80. package/dist/tsup/chunk-YQ4LDVD6.cjs +5974 -0
  81. package/dist/tsup/chunk-YQ4LDVD6.cjs.map +1 -0
  82. package/dist/tsup/chunk-ZFY5J2EP.cjs +257 -0
  83. package/dist/tsup/chunk-ZFY5J2EP.cjs.map +1 -0
  84. package/dist/tsup/client/mod.cjs +9 -10
  85. package/dist/tsup/client/mod.cjs.map +1 -1
  86. package/dist/tsup/client/mod.d.cts +11 -5
  87. package/dist/tsup/client/mod.d.ts +11 -5
  88. package/dist/tsup/client/mod.js +8 -8
  89. package/dist/tsup/common/log.cjs +4 -4
  90. package/dist/tsup/common/log.d.cts +2 -2
  91. package/dist/tsup/common/log.d.ts +2 -2
  92. package/dist/tsup/common/log.js +3 -2
  93. package/dist/tsup/common/websocket.cjs +5 -5
  94. package/dist/tsup/common/websocket.js +4 -3
  95. package/dist/tsup/config-BFqid9Gr.d.ts +2574 -0
  96. package/dist/tsup/config-BiNoIHRs.d.cts +80 -0
  97. package/dist/tsup/config-BiNoIHRs.d.ts +80 -0
  98. package/dist/tsup/{config-CZB2-W8x.d.cts → config-CAZphOS1.d.cts} +681 -355
  99. package/dist/tsup/db/drizzle/mod.cjs +49 -0
  100. package/dist/tsup/db/drizzle/mod.cjs.map +1 -0
  101. package/dist/tsup/db/drizzle/mod.d.cts +17 -0
  102. package/dist/tsup/db/drizzle/mod.d.ts +17 -0
  103. package/dist/tsup/db/drizzle/mod.js +49 -0
  104. package/dist/tsup/db/drizzle/mod.js.map +1 -0
  105. package/dist/tsup/db/mod.cjs +9 -0
  106. package/dist/tsup/db/mod.cjs.map +1 -0
  107. package/dist/tsup/db/mod.d.cts +9 -0
  108. package/dist/tsup/db/mod.d.ts +9 -0
  109. package/dist/tsup/db/mod.js +9 -0
  110. package/dist/tsup/db/mod.js.map +1 -0
  111. package/dist/tsup/{driver-D0QX9M11.d.ts → driver-Bxv62E2p.d.ts} +2 -2
  112. package/dist/tsup/{driver-q-zqG7fc.d.cts → driver-DYXwJR5D.d.cts} +2 -2
  113. package/dist/tsup/driver-helpers/mod.cjs +12 -6
  114. package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
  115. package/dist/tsup/driver-helpers/mod.d.cts +12 -5
  116. package/dist/tsup/driver-helpers/mod.d.ts +12 -5
  117. package/dist/tsup/driver-helpers/mod.js +12 -5
  118. package/dist/tsup/driver-test-suite/mod.cjs +1370 -116
  119. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  120. package/dist/tsup/driver-test-suite/mod.d.cts +10 -4
  121. package/dist/tsup/driver-test-suite/mod.d.ts +10 -4
  122. package/dist/tsup/driver-test-suite/mod.js +2093 -838
  123. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  124. package/dist/tsup/inspector/mod.cjs +29 -3
  125. package/dist/tsup/inspector/mod.cjs.map +1 -1
  126. package/dist/tsup/inspector/mod.d.cts +124 -3
  127. package/dist/tsup/inspector/mod.d.ts +124 -3
  128. package/dist/tsup/inspector/mod.js +72 -45
  129. package/dist/tsup/keys-CydblqMh.d.cts +13 -0
  130. package/dist/tsup/keys-CydblqMh.d.ts +13 -0
  131. package/dist/tsup/mod.cjs +16 -10
  132. package/dist/tsup/mod.cjs.map +1 -1
  133. package/dist/tsup/mod.d.cts +26 -14
  134. package/dist/tsup/mod.d.ts +26 -14
  135. package/dist/tsup/mod.js +20 -13
  136. package/dist/tsup/serve-test-suite/mod.cjs +1165 -83
  137. package/dist/tsup/serve-test-suite/mod.cjs.map +1 -1
  138. package/dist/tsup/serve-test-suite/mod.js +1114 -29
  139. package/dist/tsup/serve-test-suite/mod.js.map +1 -1
  140. package/dist/tsup/test/mod.cjs +84 -11
  141. package/dist/tsup/test/mod.cjs.map +1 -1
  142. package/dist/tsup/test/mod.d.cts +10 -5
  143. package/dist/tsup/test/mod.d.ts +10 -5
  144. package/dist/tsup/test/mod.js +85 -11
  145. package/dist/tsup/test/mod.js.map +1 -1
  146. package/dist/tsup/utils.cjs +10 -4
  147. package/dist/tsup/utils.cjs.map +1 -1
  148. package/dist/tsup/utils.d.cts +72 -2
  149. package/dist/tsup/utils.d.ts +72 -2
  150. package/dist/tsup/utils.js +9 -2
  151. package/dist/tsup/v3-DnYObHH3.d.cts +279 -0
  152. package/dist/tsup/v3-DnYObHH3.d.ts +279 -0
  153. package/dist/tsup/workflow/mod.cjs +16 -0
  154. package/dist/tsup/workflow/mod.cjs.map +1 -0
  155. package/dist/tsup/workflow/mod.d.cts +83 -0
  156. package/dist/tsup/workflow/mod.d.ts +83 -0
  157. package/dist/tsup/workflow/mod.js +16 -0
  158. package/dist/tsup/workflow/mod.js.map +1 -0
  159. package/package.json +62 -5
  160. package/src/actor/config.ts +478 -68
  161. package/src/actor/conn/mod.ts +68 -16
  162. package/src/actor/conn/state-manager.ts +2 -2
  163. package/src/actor/contexts/action.ts +20 -12
  164. package/src/actor/contexts/base/actor.ts +137 -7
  165. package/src/actor/contexts/base/conn-init.ts +27 -7
  166. package/src/actor/contexts/base/conn.ts +27 -18
  167. package/src/actor/contexts/before-action-response.ts +9 -2
  168. package/src/actor/contexts/before-connect.ts +7 -2
  169. package/src/actor/contexts/connect.ts +9 -2
  170. package/src/actor/contexts/create-conn-state.ts +7 -2
  171. package/src/actor/contexts/create-vars.ts +16 -3
  172. package/src/actor/contexts/create.ts +16 -3
  173. package/src/actor/contexts/destroy.ts +9 -3
  174. package/src/actor/contexts/disconnect.ts +10 -4
  175. package/src/actor/contexts/index.ts +4 -3
  176. package/src/actor/contexts/request.ts +23 -6
  177. package/src/actor/contexts/run.ts +47 -0
  178. package/src/actor/contexts/sleep.ts +9 -3
  179. package/src/actor/contexts/state-change.ts +9 -3
  180. package/src/actor/contexts/wake.ts +9 -3
  181. package/src/actor/contexts/websocket.ts +23 -6
  182. package/src/actor/database.ts +8 -18
  183. package/src/actor/definition.ts +20 -6
  184. package/src/actor/driver.ts +32 -3
  185. package/src/actor/errors.ts +127 -0
  186. package/src/actor/instance/connection-manager.ts +183 -80
  187. package/src/actor/instance/event-manager.ts +26 -15
  188. package/src/actor/instance/keys.ts +117 -0
  189. package/src/actor/instance/mod.ts +784 -174
  190. package/src/actor/instance/queue-manager.ts +603 -0
  191. package/src/actor/instance/queue.ts +287 -0
  192. package/src/actor/instance/schedule-manager.ts +49 -7
  193. package/src/actor/instance/state-manager.ts +35 -11
  194. package/src/actor/instance/traces-driver.ts +128 -0
  195. package/src/actor/mod.ts +26 -2
  196. package/src/actor/protocol/old.ts +28 -13
  197. package/src/actor/protocol/serde.ts +1 -1
  198. package/src/actor/router-endpoints.ts +177 -21
  199. package/src/actor/router-websocket-endpoints.ts +18 -29
  200. package/src/actor/router.ts +177 -0
  201. package/src/actor/schema.ts +291 -0
  202. package/src/actor/utils.ts +40 -0
  203. package/src/client/actor-common.ts +1 -1
  204. package/src/client/actor-conn.ts +100 -33
  205. package/src/client/actor-handle.ts +61 -33
  206. package/src/client/client.ts +2 -4
  207. package/src/client/config.ts +1 -1
  208. package/src/client/mod.browser.ts +2 -0
  209. package/src/client/mod.ts +1 -4
  210. package/src/client/queue.ts +146 -0
  211. package/src/client/utils.ts +1 -1
  212. package/src/common/log.ts +1 -1
  213. package/src/common/utils.ts +3 -3
  214. package/src/db/config.ts +100 -0
  215. package/src/db/drizzle/mod.ts +226 -0
  216. package/src/db/drizzle/sqlite-core.ts +22 -0
  217. package/src/db/mod.ts +125 -0
  218. package/src/db/shared.ts +92 -0
  219. package/src/db/sqlite-vfs.ts +12 -0
  220. package/src/driver-helpers/mod.ts +1 -0
  221. package/src/driver-test-suite/mod.ts +69 -43
  222. package/src/driver-test-suite/tests/access-control.ts +218 -0
  223. package/src/driver-test-suite/tests/actor-db-raw.ts +73 -0
  224. package/src/driver-test-suite/tests/actor-db.ts +394 -0
  225. package/src/driver-test-suite/tests/actor-inspector.ts +259 -358
  226. package/src/driver-test-suite/tests/actor-kv.ts +41 -20
  227. package/src/driver-test-suite/tests/actor-queue.ts +324 -0
  228. package/src/driver-test-suite/tests/actor-run.ts +181 -0
  229. package/src/driver-test-suite/tests/actor-schedule.ts +5 -2
  230. package/src/driver-test-suite/tests/actor-sleep.ts +3 -3
  231. package/src/driver-test-suite/tests/actor-stateless.ts +70 -0
  232. package/src/driver-test-suite/tests/actor-workflow.ts +108 -0
  233. package/src/driver-test-suite/tests/manager-driver.ts +11 -0
  234. package/src/driver-test-suite/tests/raw-http-request-properties.ts +1 -1
  235. package/src/driver-test-suite/tests/raw-websocket.ts +12 -12
  236. package/src/drivers/default.ts +7 -2
  237. package/src/drivers/engine/actor-driver.ts +45 -37
  238. package/src/drivers/engine/config.ts +1 -1
  239. package/src/drivers/file-system/actor.ts +20 -2
  240. package/src/drivers/file-system/global-state.ts +569 -258
  241. package/src/drivers/file-system/kv-limits.ts +70 -0
  242. package/src/drivers/file-system/manager.ts +22 -6
  243. package/src/drivers/file-system/mod.ts +39 -16
  244. package/src/drivers/file-system/sqlite-runtime.ts +210 -0
  245. package/src/inspector/actor-inspector.ts +224 -102
  246. package/src/inspector/config.ts +1 -1
  247. package/src/inspector/handler.ts +102 -20
  248. package/src/inspector/mod.browser.ts +8 -0
  249. package/src/inspector/mod.ts +2 -0
  250. package/src/inspector/serve-ui.ts +40 -0
  251. package/src/inspector/transport.ts +18 -0
  252. package/src/inspector/utils.ts +5 -39
  253. package/src/manager/gateway.ts +1 -1
  254. package/src/manager/protocol/mod.ts +1 -1
  255. package/src/manager/protocol/query.ts +1 -1
  256. package/src/manager/router-schema.ts +1 -1
  257. package/src/manager/router.ts +38 -12
  258. package/src/manager-api/actors.ts +1 -1
  259. package/src/manager-api/common.ts +1 -1
  260. package/src/registry/config/driver.ts +1 -1
  261. package/src/registry/config/index.ts +212 -43
  262. package/src/registry/config/legacy-runner.ts +1 -1
  263. package/src/registry/config/runner.ts +1 -1
  264. package/src/registry/config/serverless.ts +1 -1
  265. package/src/registry/index.ts +7 -5
  266. package/src/remote-manager-driver/api-utils.ts +1 -1
  267. package/src/schemas/actor-inspector/mod.ts +1 -1
  268. package/src/schemas/actor-inspector/versioned.ts +195 -8
  269. package/src/schemas/actor-persist/versioned.ts +87 -7
  270. package/src/schemas/client-protocol/mod.ts +1 -1
  271. package/src/schemas/client-protocol/versioned.ts +127 -11
  272. package/src/schemas/client-protocol-zod/mod.ts +16 -1
  273. package/src/schemas/persist/mod.ts +1 -0
  274. package/src/schemas/transport/mod.ts +1 -0
  275. package/src/serde.ts +1 -1
  276. package/src/serve-test-suite/mod.ts +10 -9
  277. package/src/test/mod.ts +15 -56
  278. package/src/utils/endpoint-parser.test.ts +1 -1
  279. package/src/utils/endpoint-parser.ts +1 -1
  280. package/src/utils/env-vars.ts +12 -1
  281. package/src/utils/node.ts +15 -2
  282. package/src/utils.test.ts +34 -0
  283. package/src/utils.ts +140 -6
  284. package/src/workflow/constants.ts +2 -0
  285. package/src/workflow/context.ts +532 -0
  286. package/src/workflow/driver.ts +191 -0
  287. package/src/workflow/inspector.ts +268 -0
  288. package/src/workflow/mod.ts +122 -0
  289. package/dist/tsup/chunk-2IJTYN6K.cjs +0 -278
  290. package/dist/tsup/chunk-2IJTYN6K.cjs.map +0 -1
  291. package/dist/tsup/chunk-2XQS746M.cjs.map +0 -1
  292. package/dist/tsup/chunk-3VP5CSHV.cjs +0 -114
  293. package/dist/tsup/chunk-3VP5CSHV.cjs.map +0 -1
  294. package/dist/tsup/chunk-AQFSQMBG.js +0 -114
  295. package/dist/tsup/chunk-AQFSQMBG.js.map +0 -1
  296. package/dist/tsup/chunk-E6ZE2YEA.js +0 -664
  297. package/dist/tsup/chunk-E6ZE2YEA.js.map +0 -1
  298. package/dist/tsup/chunk-FJ3KTN4V.js.map +0 -1
  299. package/dist/tsup/chunk-GBENOENJ.cjs +0 -8
  300. package/dist/tsup/chunk-GBENOENJ.cjs.map +0 -1
  301. package/dist/tsup/chunk-GD7UXGOE.cjs +0 -4762
  302. package/dist/tsup/chunk-GD7UXGOE.cjs.map +0 -1
  303. package/dist/tsup/chunk-GMAVRZSF.js.map +0 -1
  304. package/dist/tsup/chunk-H4TB4X25.cjs.map +0 -1
  305. package/dist/tsup/chunk-JDAD2YFA.js.map +0 -1
  306. package/dist/tsup/chunk-KCOVZOPS.js +0 -1946
  307. package/dist/tsup/chunk-KCOVZOPS.js.map +0 -1
  308. package/dist/tsup/chunk-KDFWJKMJ.cjs +0 -664
  309. package/dist/tsup/chunk-KDFWJKMJ.cjs.map +0 -1
  310. package/dist/tsup/chunk-LFVF5SCU.js.map +0 -1
  311. package/dist/tsup/chunk-Q6W7RJJP.js.map +0 -1
  312. package/dist/tsup/chunk-RUW5CZ5Z.cjs +0 -1949
  313. package/dist/tsup/chunk-RUW5CZ5Z.cjs.map +0 -1
  314. package/dist/tsup/chunk-RZW2DNND.cjs.map +0 -1
  315. package/dist/tsup/chunk-TCOEBUUE.js +0 -278
  316. package/dist/tsup/chunk-TCOEBUUE.js.map +0 -1
  317. package/dist/tsup/chunk-X35U3YNX.cjs.map +0 -1
  318. package/dist/tsup/keys-Chhy4ylv.d.cts +0 -8
  319. package/dist/tsup/keys-Chhy4ylv.d.ts +0 -8
  320. package/dist/tsup/v1-Gq4avTK3.d.cts +0 -240
  321. package/dist/tsup/v1-Gq4avTK3.d.ts +0 -240
  322. /package/dist/tsup/{chunk-XXGJCOL6.js.map → chunk-A6YIZWTK.js.map} +0 -0
@@ -1,3 +1,12 @@
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";
1
10
  import invariant from "invariant";
2
11
  import type { ActorKey } from "@/actor/mod";
3
12
  import type { Client } from "@/client/client";
@@ -11,7 +20,11 @@ import {
11
20
  CONN_VERSIONED,
12
21
  } from "@/schemas/actor-persist/versioned";
13
22
  import { EXTRA_ERROR_LOG } from "@/utils";
14
- import type { ActorConfig } from "../config";
23
+ import { getRivetExperimentalOtel } from "@/utils/env-vars";
24
+ import {
25
+ type ActorConfig,
26
+ getRunFunction,
27
+ } from "../config";
15
28
  import type { ConnDriver } from "../conn/driver";
16
29
  import { createHttpDriver } from "../conn/drivers/http";
17
30
  import {
@@ -25,17 +38,24 @@ import {
25
38
  type PersistedConn,
26
39
  } from "../conn/persisted";
27
40
  import {
28
- type ActionContext,
41
+ ActionContext,
29
42
  ActorContext,
30
43
  RequestContext,
31
44
  WebSocketContext,
32
45
  } from "../contexts";
46
+
33
47
  import type { AnyDatabaseProvider, InferDatabaseClient } from "../database";
34
48
  import type { ActorDriver } from "../driver";
35
49
  import * as errors from "../errors";
36
50
  import { serializeActorKey } from "../keys";
37
51
  import { processMessage } from "../protocol/old";
38
52
  import { Schedule } from "../schedule";
53
+ import {
54
+ type EventSchemaConfig,
55
+ getEventCanSubscribe,
56
+ getQueueCanPublish,
57
+ type QueueSchemaConfig,
58
+ } from "../schema";
39
59
  import {
40
60
  assertUnreachable,
41
61
  DeadlineError,
@@ -49,8 +69,10 @@ import {
49
69
  convertActorFromBarePersisted,
50
70
  type PersistedActor,
51
71
  } from "./persisted";
72
+ import { QueueManager } from "./queue-manager";
52
73
  import { ScheduleManager } from "./schedule-manager";
53
74
  import { type SaveStateOptions, StateManager } from "./state-manager";
75
+ import { ActorTracesDriver } from "./traces-driver";
54
76
 
55
77
  export type { SaveStateOptions };
56
78
 
@@ -59,47 +81,71 @@ enum CanSleep {
59
81
  NotReady,
60
82
  NotStarted,
61
83
  ActiveConns,
84
+ ActiveDisconnectCallbacks,
62
85
  ActiveHonoHttpRequests,
86
+ ActiveKeepAwake,
87
+ ActiveRun,
63
88
  }
64
89
 
65
90
  /** Actor type alias with all `any` types. Used for `extends` in classes referencing this actor. */
66
- export type AnyActorInstance = ActorInstance<any, any, any, any, any, any>;
91
+ export type AnyActorInstance = ActorInstance<
92
+ any,
93
+ any,
94
+ any,
95
+ any,
96
+ any,
97
+ any,
98
+ any,
99
+ any
100
+ >;
67
101
 
68
102
  export type ExtractActorState<A extends AnyActorInstance> =
69
- A extends ActorInstance<infer State, any, any, any, any, any>
103
+ A extends ActorInstance<infer State, any, any, any, any, any, any, any>
70
104
  ? State
71
105
  : never;
72
106
 
73
107
  export type ExtractActorConnParams<A extends AnyActorInstance> =
74
- A extends ActorInstance<any, infer ConnParams, any, any, any, any>
108
+ A extends ActorInstance<any, infer ConnParams, any, any, any, any, any, any>
75
109
  ? ConnParams
76
110
  : never;
77
111
 
78
112
  export type ExtractActorConnState<A extends AnyActorInstance> =
79
- A extends ActorInstance<any, any, infer ConnState, any, any, any>
113
+ A extends ActorInstance<any, any, infer ConnState, any, any, any, any, any>
80
114
  ? ConnState
81
115
  : never;
82
116
 
83
117
  // MARK: - Main ActorInstance Class
84
- export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
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
+ > {
85
128
  // MARK: - Core Properties
86
- actorContext: ActorContext<S, CP, CS, V, I, DB>;
87
- #config: ActorConfig<S, CP, CS, V, I, DB>;
129
+ actorContext: ActorContext<S, CP, CS, V, I, DB, E, Q>;
130
+ #config: ActorConfig<S, CP, CS, V, I, DB, E, Q>;
88
131
  driver!: ActorDriver;
89
132
  #inlineClient!: Client<Registry<any>>;
90
133
  #actorId!: string;
91
134
  #name!: string;
92
135
  #key!: ActorKey;
136
+ #actorKeyString!: string;
93
137
  #region!: string;
94
138
 
95
139
  // MARK: - Managers
96
- connectionManager!: ConnectionManager<S, CP, CS, V, I, DB>;
140
+ connectionManager!: ConnectionManager<S, CP, CS, V, I, DB, E, Q>;
141
+
142
+ stateManager!: StateManager<S, CP, CS, I, E, Q>;
97
143
 
98
- stateManager!: StateManager<S, CP, CS, I>;
144
+ eventManager!: EventManager<S, CP, CS, V, I, DB, E, Q>;
99
145
 
100
- eventManager!: EventManager<S, CP, CS, V, I, DB>;
146
+ #scheduleManager!: ScheduleManager<S, CP, CS, V, I, DB, E, Q>;
101
147
 
102
- #scheduleManager!: ScheduleManager<S, CP, CS, V, I, DB>;
148
+ queueManager!: QueueManager<S, CP, CS, V, I, DB, E, Q>;
103
149
 
104
150
  // MARK: - Logging
105
151
  #log!: Logger;
@@ -126,25 +172,34 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
126
172
 
127
173
  // MARK: - Variables & Database
128
174
  #vars?: V;
129
- #db!: InferDatabaseClient<DB>;
175
+ #db?: InferDatabaseClient<DB>;
176
+ #sqliteVfs?: SqliteVfs;
130
177
 
131
178
  // MARK: - Background Tasks
132
179
  #backgroundPromises: Promise<void>[] = [];
180
+ #runPromise?: Promise<void>;
181
+ #runHandlerActive = false;
182
+ #activeQueueWaitCount = 0;
133
183
 
134
184
  // MARK: - HTTP/WebSocket Tracking
135
185
  #activeHonoHttpRequests = 0;
186
+ #activeKeepAwakeCount = 0;
136
187
 
137
188
  // MARK: - Deprecated (kept for compatibility)
138
189
  #schedule!: Schedule;
139
190
 
140
191
  // MARK: - Inspector
141
192
  #inspectorToken?: string;
142
- #inspector = new ActorInspector(this);
193
+ #inspector: ActorInspector;
194
+
195
+ // MARK: - Tracing
196
+ #traces!: Traces<OtlpExportTraceServiceRequestJson>;
143
197
 
144
198
  // MARK: - Constructor
145
- constructor(config: ActorConfig<S, CP, CS, V, I, DB>) {
199
+ constructor(config: ActorConfig<S, CP, CS, V, I, DB, E, Q>) {
146
200
  this.#config = config;
147
201
  this.actorContext = new ActorContext(this);
202
+ this.#inspector = new ActorInspector(this);
148
203
  }
149
204
 
150
205
  // MARK: - Public Getters
@@ -186,11 +241,73 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
186
241
  return this.#inspector;
187
242
  }
188
243
 
244
+ get traces(): Traces<OtlpExportTraceServiceRequestJson> {
245
+ return this.#traces;
246
+ }
247
+
189
248
  get inspectorToken(): string | undefined {
190
249
  return this.#inspectorToken;
191
250
  }
192
251
 
193
- get conns(): Map<ConnId, Conn<S, CP, CS, V, I, DB>> {
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>> {
194
311
  return this.connectionManager.connections;
195
312
  }
196
313
 
@@ -206,7 +323,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
206
323
  return Object.keys(this.#config.actions ?? {});
207
324
  }
208
325
 
209
- get config(): ActorConfig<S, CP, CS, V, I, DB> {
326
+ get config(): ActorConfig<S, CP, CS, V, I, DB, E, Q> {
210
327
  return this.#config;
211
328
  }
212
329
 
@@ -260,8 +377,12 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
260
377
  this.#actorId = actorId;
261
378
  this.#name = name;
262
379
  this.#key = key;
380
+ this.#actorKeyString = serializeActorKey(this.#key);
263
381
  this.#region = region;
264
382
 
383
+ // Initialize tracing
384
+ this.#initializeTraces();
385
+
265
386
  // Initialize logging
266
387
  this.#initializeLogging();
267
388
 
@@ -269,6 +390,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
269
390
  this.connectionManager = new ConnectionManager(this);
270
391
  this.stateManager = new StateManager(this, actorDriver, this.#config);
271
392
  this.eventManager = new EventManager(this);
393
+ this.queueManager = new QueueManager(this, actorDriver);
272
394
  this.#scheduleManager = new ScheduleManager(
273
395
  this,
274
396
  actorDriver,
@@ -281,6 +403,8 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
281
403
  // Load state
282
404
  await this.#loadState();
283
405
 
406
+ await this.queueManager.initialize();
407
+
284
408
  // Generate or load inspector token
285
409
  await this.#initializeInspectorToken();
286
410
 
@@ -318,6 +442,9 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
318
442
  // timer
319
443
  this.resetSleepTimer();
320
444
 
445
+ // Start run handler in background (does not block startup)
446
+ this.#startRunHandler();
447
+
321
448
  // Trigger any pending alarms
322
449
  await this.onAlarm();
323
450
  }
@@ -333,6 +460,13 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
333
460
  throw new errors.InternalError("Actor is stopping");
334
461
  }
335
462
 
463
+ async cleanupPersistedConnections(reason?: string): Promise<number> {
464
+ this.assertReady(true);
465
+ return await this.connectionManager.cleanupPersistedHibernatableConnections(
466
+ reason,
467
+ );
468
+ }
469
+
336
470
  // MARK: - Stop
337
471
  async onStop(mode: "sleep" | "destroy") {
338
472
  if (this.#stopCalled) {
@@ -345,46 +479,53 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
345
479
  mode,
346
480
  });
347
481
 
348
- // Clear sleep timeout
349
- if (this.#sleepTimeout) {
350
- clearTimeout(this.#sleepTimeout);
351
- this.#sleepTimeout = undefined;
352
- }
353
-
354
- // Abort listeners
355
482
  try {
356
- this.#abortController.abort();
357
- } catch {}
358
-
359
- // Call onStop lifecycle
360
- if (mode === "sleep") {
361
- await this.#callOnSleep();
362
- } else if (mode === "destroy") {
363
- await this.#callOnDestroy();
364
- } else {
365
- assertUnreachable(mode);
366
- }
483
+ // Clear sleep timeout
484
+ if (this.#sleepTimeout) {
485
+ clearTimeout(this.#sleepTimeout);
486
+ this.#sleepTimeout = undefined;
487
+ }
367
488
 
368
- // Disconnect non-hibernatable connections
369
- await this.#disconnectConnections();
489
+ // Abort listeners
490
+ try {
491
+ this.#abortController.abort();
492
+ } catch { }
370
493
 
371
- // Wait for background tasks
372
- await this.#waitBackgroundPromises(
373
- this.#config.options.waitUntilTimeout,
374
- );
494
+ // Wait for run handler to complete
495
+ await this.#waitForRunHandler(this.#config.options.runStopTimeout);
375
496
 
376
- // Clear timeouts and save state
377
- this.#rLog.info({ msg: "clearing pending save timeouts" });
378
- this.stateManager.clearPendingSaveTimeout();
379
- this.#rLog.info({ msg: "saving state immediately" });
380
- await this.stateManager.saveState({
381
- immediate: true,
382
- allowStoppingState: true,
383
- });
497
+ // Call onStop lifecycle
498
+ if (mode === "sleep") {
499
+ await this.#callOnSleep();
500
+ } else if (mode === "destroy") {
501
+ await this.#callOnDestroy();
502
+ } else {
503
+ assertUnreachable(mode);
504
+ }
505
+
506
+ // Disconnect non-hibernatable connections
507
+ await this.#disconnectConnections();
508
+
509
+ // Wait for background tasks
510
+ await this.#waitBackgroundPromises(
511
+ this.#config.options.waitUntilTimeout,
512
+ );
513
+
514
+ // Clear timeouts and save state
515
+ this.#rLog.info({ msg: "clearing pending save timeouts" });
516
+ this.stateManager.clearPendingSaveTimeout();
517
+ this.#rLog.info({ msg: "saving state immediately" });
518
+ await this.stateManager.saveState({
519
+ immediate: true,
520
+ allowStoppingState: true,
521
+ });
384
522
 
385
- // Wait for write queues
386
- await this.stateManager.waitForPendingWrites();
387
- await this.#scheduleManager.waitForPendingAlarmWrites();
523
+ // Wait for write queues
524
+ await this.stateManager.waitForPendingWrites();
525
+ await this.#scheduleManager.waitForPendingAlarmWrites();
526
+ } finally {
527
+ await this.#cleanupDatabase();
528
+ }
388
529
  }
389
530
 
390
531
  // MARK: - Sleep
@@ -468,49 +609,71 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
468
609
  async processMessage(
469
610
  message: {
470
611
  body:
471
- | {
472
- tag: "ActionRequest";
473
- val: { id: bigint; name: string; args: unknown };
474
- }
475
- | {
476
- tag: "SubscriptionRequest";
477
- val: { eventName: string; subscribe: boolean };
478
- };
612
+ | {
613
+ tag: "ActionRequest";
614
+ val: { id: bigint; name: string; args: unknown };
615
+ }
616
+ | {
617
+ tag: "SubscriptionRequest";
618
+ val: { eventName: string; subscribe: boolean };
619
+ };
479
620
  },
480
- conn: Conn<S, CP, CS, V, I, DB>,
621
+ conn: Conn<S, CP, CS, V, I, DB, E, Q>,
481
622
  ) {
482
623
  await processMessage(message, this, conn, {
483
624
  onExecuteAction: async (ctx, name, args) => {
484
- this.inspector.emitter.emit("eventFired", {
485
- type: "action",
486
- name,
487
- args,
488
- connId: conn.id,
489
- });
490
625
  return await this.executeAction(ctx, name, args);
491
626
  },
492
627
  onSubscribe: async (eventName, conn) => {
493
- this.inspector.emitter.emit("eventFired", {
494
- type: "subscribe",
495
- eventName,
496
- connId: conn.id,
497
- });
498
628
  this.eventManager.addSubscription(eventName, conn, false);
499
629
  },
500
630
  onUnsubscribe: async (eventName, conn) => {
501
- this.inspector.emitter.emit("eventFired", {
502
- type: "unsubscribe",
503
- eventName,
504
- connId: conn.id,
505
- });
506
631
  this.eventManager.removeSubscription(eventName, conn, false);
507
632
  },
508
633
  });
509
634
  }
510
635
 
636
+ async assertCanSubscribe(
637
+ ctx: ActionContext<S, CP, CS, V, I, DB, E, Q>,
638
+ eventName: string,
639
+ ): Promise<void> {
640
+ const canSubscribe = getEventCanSubscribe(this.#config.events, eventName);
641
+ if (!canSubscribe) {
642
+ return;
643
+ }
644
+
645
+ const result = await canSubscribe(ctx);
646
+ if (typeof result !== "boolean") {
647
+ throw new errors.InvalidCanSubscribeResponse();
648
+ }
649
+ if (!result) {
650
+ throw new errors.Forbidden();
651
+ }
652
+ }
653
+
654
+ async assertCanPublish(
655
+ ctx: ActionContext<S, CP, CS, V, I, DB, E, Q>,
656
+ queueName: string,
657
+ ): Promise<void> {
658
+ const canPublish = getQueueCanPublish<
659
+ ActionContext<S, CP, CS, V, I, DB, E, Q>
660
+ >(this.#config.queues, queueName);
661
+ if (!canPublish) {
662
+ return;
663
+ }
664
+
665
+ const result = await canPublish(ctx);
666
+ if (typeof result !== "boolean") {
667
+ throw new errors.InvalidCanPublishResponse();
668
+ }
669
+ if (!result) {
670
+ throw new errors.Forbidden();
671
+ }
672
+ }
673
+
511
674
  // MARK: - Action Execution
512
675
  async executeAction(
513
- ctx: ActionContext<S, CP, CS, V, I, DB>,
676
+ ctx: ActionContext<S, CP, CS, V, I, DB, E, Q>,
514
677
  actionName: string,
515
678
  args: unknown[],
516
679
  ): Promise<unknown> {
@@ -532,54 +695,82 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
532
695
  throw new errors.ActionNotFound(actionName);
533
696
  }
534
697
 
535
- try {
536
- this.#rLog.debug({
537
- msg: "executing action",
538
- actionName,
539
- args,
540
- });
698
+ this.#activeKeepAwakeCount++;
699
+ this.resetSleepTimer();
700
+ const actionSpan = this.startTraceSpan(`actor.action.${actionName}`, {
701
+ "rivet.action.name": actionName,
702
+ });
703
+ let spanEnded = false;
541
704
 
542
- const outputOrPromise = actionFunction.call(
543
- undefined,
544
- ctx,
545
- ...args,
546
- );
705
+ try {
706
+ return await this.#traces.withSpan(actionSpan, async () => {
707
+ this.#rLog.debug({
708
+ msg: "executing action",
709
+ actionName,
710
+ args,
711
+ });
547
712
 
548
- let output: unknown;
549
- if (outputOrPromise instanceof Promise) {
550
- output = await deadline(
551
- outputOrPromise,
552
- this.#config.options.actionTimeout,
713
+ const outputOrPromise = actionFunction.call(
714
+ undefined,
715
+ ctx,
716
+ ...args,
553
717
  );
554
- } else {
555
- output = outputOrPromise;
556
- }
557
718
 
558
- // Process through onBeforeActionResponse if configured
559
- if (this.#config.onBeforeActionResponse) {
560
- try {
561
- const processedOutput = this.#config.onBeforeActionResponse(
562
- this.actorContext,
563
- actionName,
564
- args,
565
- output,
719
+ let output: unknown;
720
+ const maybeThenable = outputOrPromise as {
721
+ then?: (
722
+ onfulfilled?: unknown,
723
+ onrejected?: unknown,
724
+ ) => unknown;
725
+ };
726
+ if (maybeThenable && typeof maybeThenable.then === "function") {
727
+ output = await deadline(
728
+ Promise.resolve(outputOrPromise),
729
+ this.#config.options.actionTimeout,
566
730
  );
567
- if (processedOutput instanceof Promise) {
568
- output = await processedOutput;
569
- } else {
570
- output = processedOutput;
731
+ } else {
732
+ output = outputOrPromise;
733
+ }
734
+
735
+ // Process through onBeforeActionResponse if configured
736
+ if (this.#config.onBeforeActionResponse) {
737
+ try {
738
+ output = await this.runInTraceSpan(
739
+ "actor.onBeforeActionResponse",
740
+ { "rivet.action.name": actionName },
741
+ () =>
742
+ this.#config.onBeforeActionResponse!(
743
+ this.actorContext,
744
+ actionName,
745
+ args,
746
+ output,
747
+ ),
748
+ );
749
+ } catch (error) {
750
+ this.#rLog.error({
751
+ msg: "error in `onBeforeActionResponse`",
752
+ error: stringifyError(error),
753
+ });
571
754
  }
572
- } catch (error) {
573
- this.#rLog.error({
574
- msg: "error in `onBeforeActionResponse`",
575
- error: stringifyError(error),
576
- });
577
755
  }
578
- }
579
756
 
580
- return output;
757
+ return output;
758
+ });
581
759
  } catch (error) {
582
- if (error instanceof DeadlineError) {
760
+ const isTimeout = error instanceof DeadlineError;
761
+ const message = isTimeout
762
+ ? "ActionTimedOut"
763
+ : stringifyError(error);
764
+ this.#traces.setAttributes(actionSpan, {
765
+ "error.message": message,
766
+ "error.type":
767
+ error instanceof Error ? error.name : typeof error,
768
+ });
769
+ this.#traces.endSpan(actionSpan, {
770
+ status: { code: "ERROR", message },
771
+ });
772
+ spanEnded = true;
773
+ if (isTimeout) {
583
774
  throw new errors.ActionTimedOut();
584
775
  }
585
776
  this.#rLog.error({
@@ -589,13 +780,27 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
589
780
  });
590
781
  throw error;
591
782
  } finally {
783
+ if (!spanEnded && actionSpan.isActive()) {
784
+ this.#traces.endSpan(actionSpan, {
785
+ status: { code: "OK" },
786
+ });
787
+ }
788
+ this.#activeKeepAwakeCount--;
789
+ if (this.#activeKeepAwakeCount < 0) {
790
+ this.#activeKeepAwakeCount = 0;
791
+ this.#rLog.warn({
792
+ msg: "active keep awake count went below 0, this is a RivetKit bug",
793
+ ...EXTRA_ERROR_LOG,
794
+ });
795
+ }
796
+ this.resetSleepTimer();
592
797
  this.stateManager.savePersistThrottled();
593
798
  }
594
799
  }
595
800
 
596
801
  // MARK: - HTTP/WebSocket Handlers
597
802
  async handleRawRequest(
598
- conn: Conn<S, CP, CS, V, I, DB>,
803
+ conn: Conn<S, CP, CS, V, I, DB, E, Q>,
599
804
  request: Request,
600
805
  ): Promise<Response> {
601
806
  this.assertReady();
@@ -603,27 +808,38 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
603
808
  if (!this.#config.onRequest) {
604
809
  throw new errors.RequestHandlerNotDefined();
605
810
  }
606
-
607
- try {
608
- const ctx = new RequestContext(this, conn, request);
609
- const response = await this.#config.onRequest(ctx, request);
610
- if (!response) {
611
- throw new errors.InvalidRequestHandlerResponse();
612
- }
613
- return response;
614
- } catch (error) {
615
- this.#rLog.error({
616
- msg: "onRequest error",
617
- error: stringifyError(error),
618
- });
619
- throw error;
620
- } finally {
621
- this.stateManager.savePersistThrottled();
811
+ const onRequest = this.#config.onRequest;
812
+
813
+ return await this.runInTraceSpan(
814
+ "actor.onRequest",
815
+ {
816
+ "http.method": request.method,
817
+ "http.url": request.url,
818
+ "rivet.conn.id": conn.id,
819
+ },
820
+ async () => {
821
+ const ctx = new RequestContext(this, conn, request);
822
+ try {
823
+ const response = await onRequest(ctx, request);
824
+ if (!response) {
825
+ throw new errors.InvalidRequestHandlerResponse();
826
+ }
827
+ return response;
828
+ } catch (error) {
829
+ this.#rLog.error({
830
+ msg: "onRequest error",
831
+ error: stringifyError(error),
832
+ });
833
+ throw error;
834
+ } finally {
835
+ this.stateManager.savePersistThrottled();
836
+ }
837
+ },
838
+ );
622
839
  }
623
- }
624
840
 
625
841
  handleRawWebSocket(
626
- conn: Conn<S, CP, CS, V, I, DB>,
842
+ conn: Conn<S, CP, CS, V, I, DB, E, Q>,
627
843
  websocket: UniversalWebSocket,
628
844
  request?: Request,
629
845
  ) {
@@ -635,6 +851,12 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
635
851
  throw new errors.InternalError("onWebSocket handler not defined");
636
852
  }
637
853
 
854
+ const span = this.startTraceSpan("actor.onWebSocket", {
855
+ "http.url": request?.url,
856
+ "rivet.conn.id": conn.id,
857
+ });
858
+ let spanEnded = false;
859
+
638
860
  try {
639
861
  // Reset sleep timer when handling WebSocket
640
862
  this.resetSleepTimer();
@@ -643,17 +865,50 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
643
865
  const ctx = new WebSocketContext(this, conn, request);
644
866
 
645
867
  // NOTE: This is async and will run in the background
646
- const voidOrPromise = this.#config.onWebSocket(ctx, websocket);
868
+ const voidOrPromise = this.#traces.withSpan(span, () =>
869
+ this.#config.onWebSocket!(ctx, websocket),
870
+ );
647
871
 
648
872
  // Save changes from the WebSocket open
649
873
  if (voidOrPromise instanceof Promise) {
650
- voidOrPromise.then(() => {
651
- this.stateManager.savePersistThrottled();
652
- });
874
+ voidOrPromise
875
+ .then(() => {
876
+ if (!spanEnded) {
877
+ this.endTraceSpan(span, { code: "OK" });
878
+ spanEnded = true;
879
+ }
880
+ })
881
+ .catch((error) => {
882
+ if (!spanEnded) {
883
+ this.endTraceSpan(span, {
884
+ code: "ERROR",
885
+ message: stringifyError(error),
886
+ });
887
+ spanEnded = true;
888
+ }
889
+ this.#rLog.error({
890
+ msg: "onWebSocket error",
891
+ error: stringifyError(error),
892
+ });
893
+ })
894
+ .finally(() => {
895
+ this.stateManager.savePersistThrottled();
896
+ });
653
897
  } else {
898
+ if (!spanEnded) {
899
+ this.endTraceSpan(span, { code: "OK" });
900
+ spanEnded = true;
901
+ }
654
902
  this.stateManager.savePersistThrottled();
655
903
  }
656
904
  } catch (error) {
905
+ if (!spanEnded) {
906
+ this.endTraceSpan(span, {
907
+ code: "ERROR",
908
+ message: stringifyError(error),
909
+ });
910
+ spanEnded = true;
911
+ }
657
912
  this.#rLog.error({
658
913
  msg: "onWebSocket error",
659
914
  error: stringifyError(error),
@@ -693,11 +948,135 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
693
948
  this.#backgroundPromises.push(nonfailablePromise);
694
949
  }
695
950
 
951
+ /**
952
+ * Prevents the actor from sleeping while the given promise is running.
953
+ *
954
+ * Use this when performing async operations in the `run` handler or other
955
+ * background contexts where you need to ensure the actor stays awake.
956
+ *
957
+ * Returns the resolved value and resets the sleep timer on completion.
958
+ * Errors are propagated to the caller.
959
+ */
960
+ async keepAwake<T>(promise: Promise<T>): Promise<T> {
961
+ this.assertReady();
962
+
963
+ this.#activeKeepAwakeCount++;
964
+ this.resetSleepTimer();
965
+
966
+ try {
967
+ return await promise;
968
+ } finally {
969
+ this.#activeKeepAwakeCount--;
970
+ if (this.#activeKeepAwakeCount < 0) {
971
+ this.#activeKeepAwakeCount = 0;
972
+ this.#rLog.warn({
973
+ msg: "active keep awake count went below 0, this is a RivetKit bug",
974
+ ...EXTRA_ERROR_LOG,
975
+ });
976
+ }
977
+ this.resetSleepTimer();
978
+ }
979
+ }
980
+
981
+ beginQueueWait() {
982
+ this.assertReady(true);
983
+ this.#activeQueueWaitCount++;
984
+ this.resetSleepTimer();
985
+ }
986
+
987
+ endQueueWait() {
988
+ this.#activeQueueWaitCount--;
989
+ if (this.#activeQueueWaitCount < 0) {
990
+ this.#activeQueueWaitCount = 0;
991
+ this.#rLog.warn({
992
+ msg: "active queue wait count went below 0, this is a RivetKit bug",
993
+ ...EXTRA_ERROR_LOG,
994
+ });
995
+ }
996
+ this.resetSleepTimer();
997
+ }
998
+
696
999
  // MARK: - Private Helper Methods
1000
+ #initializeTraces() {
1001
+ if (getRivetExperimentalOtel()) {
1002
+ // Experimental mode persists trace data to actor storage so inspector
1003
+ // queries can return OTel payloads.
1004
+ this.#traces = createTraces({
1005
+ driver: new ActorTracesDriver(this.driver, this.#actorId),
1006
+ });
1007
+ } else {
1008
+ // Keep the tracing API calls active while disabling trace persistence
1009
+ // until the experimental flag is enabled.
1010
+ this.#traces = createNoopTraces();
1011
+ }
1012
+ }
1013
+
1014
+ #traceAttributes(
1015
+ attributes?: Record<string, unknown>,
1016
+ ): Record<string, unknown> {
1017
+ return {
1018
+ "rivet.actor.id": this.#actorId,
1019
+ "rivet.actor.name": this.#name,
1020
+ "rivet.actor.key": this.#actorKeyString,
1021
+ "rivet.actor.region": this.#region,
1022
+ ...(attributes ?? {}),
1023
+ };
1024
+ }
1025
+
1026
+ #patchLoggerForTraces(logger: Logger) {
1027
+ const levels: Array<
1028
+ "trace" | "debug" | "info" | "warn" | "error" | "fatal"
1029
+ > = ["trace", "debug", "info", "warn", "error", "fatal"];
1030
+ for (const level of levels) {
1031
+ const original = logger[level].bind(logger) as (
1032
+ ...args: any[]
1033
+ ) => unknown;
1034
+ logger[level] = ((...args: unknown[]) => {
1035
+ this.#emitLogEvent(level, args);
1036
+ return original(...(args as any[]));
1037
+ }) as Logger[typeof level];
1038
+ }
1039
+ }
1040
+
1041
+ #emitLogEvent(level: string, args: unknown[]) {
1042
+ const span = this.#traces.getCurrentSpan();
1043
+ if (!span || !span.isActive()) {
1044
+ return;
1045
+ }
1046
+
1047
+ let message: string | undefined;
1048
+ if (args.length >= 2) {
1049
+ message = String(args[1]);
1050
+ } else if (args.length === 1) {
1051
+ const [value] = args;
1052
+ if (typeof value === "string") {
1053
+ message = value;
1054
+ } else if (
1055
+ typeof value === "number" ||
1056
+ typeof value === "boolean"
1057
+ ) {
1058
+ message = String(value);
1059
+ } else if (value && typeof value === "object") {
1060
+ const maybeMsg = (value as { msg?: unknown }).msg;
1061
+ if (maybeMsg !== undefined) {
1062
+ message = String(maybeMsg);
1063
+ }
1064
+ }
1065
+ }
1066
+
1067
+ this.#traces.emitEvent(span, "log", {
1068
+ attributes: this.#traceAttributes({
1069
+ "log.level": level,
1070
+ ...(message ? { "log.message": message } : {}),
1071
+ }),
1072
+ timeUnixMs: Date.now(),
1073
+ });
1074
+ }
1075
+
697
1076
  #initializeLogging() {
698
1077
  const logParams = {
699
1078
  actor: this.#name,
700
- key: serializeActorKey(this.#key),
1079
+ key: this.#actorKeyString,
701
1080
  actorId: this.#actorId,
702
1081
  };
703
1082
 
@@ -716,6 +1095,9 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
716
1095
  logParams,
717
1096
  ),
718
1097
  );
1098
+
1099
+ this.#patchLoggerForTraces(this.#log);
1100
+ this.#patchLoggerForTraces(this.#rLog);
719
1101
  }
720
1102
 
721
1103
  async #loadState() {
@@ -753,9 +1135,9 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
753
1135
 
754
1136
  // Call onCreate lifecycle
755
1137
  if (this.#config.onCreate) {
756
- await this.#config.onCreate(
757
- this.actorContext as any,
758
- persistData.input!,
1138
+ const onCreate = this.#config.onCreate;
1139
+ await this.runInTraceSpan("actor.onCreate", undefined, () =>
1140
+ onCreate(this.actorContext as any, persistData.input!),
759
1141
  );
760
1142
  }
761
1143
  }
@@ -821,18 +1203,24 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
821
1203
  async #initializeVars() {
822
1204
  let vars: V | undefined;
823
1205
  if ("createVars" in this.#config) {
824
- const dataOrPromise = this.#config.createVars(
825
- this.actorContext as any,
826
- this.driver.getContext(this.#actorId),
1206
+ const createVars = this.#config.createVars;
1207
+ vars = await this.runInTraceSpan(
1208
+ "actor.createVars",
1209
+ undefined,
1210
+ () => {
1211
+ const dataOrPromise = createVars!(
1212
+ this.actorContext as any,
1213
+ this.driver.getContext(this.#actorId),
1214
+ );
1215
+ if (dataOrPromise instanceof Promise) {
1216
+ return deadline(
1217
+ dataOrPromise,
1218
+ this.#config.options.createVarsTimeout,
1219
+ );
1220
+ }
1221
+ return dataOrPromise;
1222
+ },
827
1223
  );
828
- if (dataOrPromise instanceof Promise) {
829
- vars = await deadline(
830
- dataOrPromise,
831
- this.#config.options.createVarsTimeout,
832
- );
833
- } else {
834
- vars = dataOrPromise;
835
- }
836
1224
  } else if ("vars" in this.#config) {
837
1225
  vars = structuredClone(this.#config.vars);
838
1226
  } else {
@@ -846,21 +1234,31 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
846
1234
  async #callOnStart() {
847
1235
  this.#rLog.info({ msg: "actor starting" });
848
1236
  if (this.#config.onWake) {
849
- const result = this.#config.onWake(this.actorContext);
850
- if (result instanceof Promise) {
851
- await result;
852
- }
1237
+ const onWake = this.#config.onWake;
1238
+ await this.runInTraceSpan("actor.onWake", undefined, () =>
1239
+ onWake(this.actorContext),
1240
+ );
853
1241
  }
854
1242
  }
855
1243
 
856
1244
  async #callOnSleep() {
857
1245
  if (this.#config.onSleep) {
1246
+ const onSleep = this.#config.onSleep;
858
1247
  try {
859
1248
  this.#rLog.debug({ msg: "calling onSleep" });
860
- const result = this.#config.onSleep(this.actorContext);
861
- if (result instanceof Promise) {
862
- await deadline(result, this.#config.options.onSleepTimeout);
863
- }
1249
+ await this.runInTraceSpan(
1250
+ "actor.onSleep",
1251
+ undefined,
1252
+ async () => {
1253
+ const result = onSleep(this.actorContext);
1254
+ if (result instanceof Promise) {
1255
+ await deadline(
1256
+ result,
1257
+ this.#config.options.onSleepTimeout,
1258
+ );
1259
+ }
1260
+ },
1261
+ );
864
1262
  this.#rLog.debug({ msg: "onSleep completed" });
865
1263
  } catch (error) {
866
1264
  if (error instanceof DeadlineError) {
@@ -877,15 +1275,22 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
877
1275
 
878
1276
  async #callOnDestroy() {
879
1277
  if (this.#config.onDestroy) {
1278
+ const onDestroy = this.#config.onDestroy;
880
1279
  try {
881
1280
  this.#rLog.debug({ msg: "calling onDestroy" });
882
- const result = this.#config.onDestroy(this.actorContext);
883
- if (result instanceof Promise) {
884
- await deadline(
885
- result,
886
- this.#config.options.onDestroyTimeout,
887
- );
888
- }
1281
+ await this.runInTraceSpan(
1282
+ "actor.onDestroy",
1283
+ undefined,
1284
+ async () => {
1285
+ const result = onDestroy(this.actorContext);
1286
+ if (result instanceof Promise) {
1287
+ await deadline(
1288
+ result,
1289
+ this.#config.options.onDestroyTimeout,
1290
+ );
1291
+ }
1292
+ },
1293
+ );
889
1294
  this.#rLog.debug({ msg: "onDestroy completed" });
890
1295
  } catch (error) {
891
1296
  if (error instanceof DeadlineError) {
@@ -900,15 +1305,212 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
900
1305
  }
901
1306
  }
902
1307
 
1308
+ #startRunHandler() {
1309
+ const runFn = getRunFunction(this.#config.run);
1310
+ if (!runFn) return;
1311
+
1312
+ this.#rLog.debug({ msg: "starting run handler" });
1313
+ this.#runHandlerActive = true;
1314
+ this.resetSleepTimer();
1315
+
1316
+ const runSpan = this.startTraceSpan("actor.run");
1317
+ const runResult = this.#traces.withSpan(runSpan, () =>
1318
+ runFn(this.actorContext),
1319
+ );
1320
+
1321
+ if (runResult instanceof Promise) {
1322
+ this.#runPromise = runResult
1323
+ .then(() => {
1324
+ if (this.#stopCalled) {
1325
+ if (runSpan.isActive()) {
1326
+ this.endTraceSpan(runSpan, { code: "OK" });
1327
+ }
1328
+ this.#rLog.debug({
1329
+ msg: "run handler exited during actor stop",
1330
+ });
1331
+ return;
1332
+ }
1333
+
1334
+ // Run handler exited normally - this should crash the actor
1335
+ this.emitTraceEvent(
1336
+ "actor.crash",
1337
+ { "rivet.actor.reason": "run_exited" },
1338
+ runSpan,
1339
+ );
1340
+ this.endTraceSpan(runSpan, {
1341
+ code: "ERROR",
1342
+ message: "run exited unexpectedly",
1343
+ });
1344
+ this.#rLog.warn({
1345
+ msg: "run handler exited unexpectedly, crashing actor to reschedule",
1346
+ });
1347
+ this.startDestroy();
1348
+ })
1349
+ .catch((error) => {
1350
+ if (this.#stopCalled) {
1351
+ if (runSpan.isActive()) {
1352
+ this.endTraceSpan(runSpan, { code: "OK" });
1353
+ }
1354
+ this.#rLog.debug({
1355
+ msg: "run handler threw during actor stop",
1356
+ error: stringifyError(error),
1357
+ });
1358
+ return;
1359
+ }
1360
+
1361
+ // Run handler threw an error - crash the actor
1362
+ this.emitTraceEvent(
1363
+ "actor.crash",
1364
+ {
1365
+ "rivet.actor.reason": "run_error",
1366
+ "error.message": stringifyError(error),
1367
+ },
1368
+ runSpan,
1369
+ );
1370
+ this.endTraceSpan(runSpan, {
1371
+ code: "ERROR",
1372
+ message: stringifyError(error),
1373
+ });
1374
+ this.#rLog.error({
1375
+ msg: "run handler threw error, crashing actor to reschedule",
1376
+ error: stringifyError(error),
1377
+ });
1378
+ this.startDestroy();
1379
+ })
1380
+ .finally(() => {
1381
+ this.#runHandlerActive = false;
1382
+ this.resetSleepTimer();
1383
+ });
1384
+ } else if (runSpan.isActive()) {
1385
+ this.endTraceSpan(runSpan, { code: "OK" });
1386
+ this.#runHandlerActive = false;
1387
+ this.resetSleepTimer();
1388
+ }
1389
+ }
1390
+
1391
+ async #waitForRunHandler(timeoutMs: number) {
1392
+ if (!this.#runPromise) {
1393
+ return;
1394
+ }
1395
+
1396
+ this.#rLog.debug({ msg: "waiting for run handler to complete" });
1397
+
1398
+ const timedOut = await Promise.race([
1399
+ this.#runPromise.then(() => false).catch(() => false),
1400
+ new Promise<true>((resolve) =>
1401
+ setTimeout(() => resolve(true), timeoutMs),
1402
+ ),
1403
+ ]);
1404
+
1405
+ if (timedOut) {
1406
+ this.#rLog.warn({
1407
+ 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",
1408
+ timeoutMs,
1409
+ });
1410
+ } else {
1411
+ this.#rLog.debug({ msg: "run handler completed" });
1412
+ }
1413
+ }
1414
+
903
1415
  async #setupDatabase() {
904
- if ("db" in this.#config && this.#config.db) {
905
- const client = await this.#config.db.createClient({
906
- getDatabase: () => this.driver.getDatabase(this.#actorId),
1416
+ if (!("db" in this.#config) || !this.#config.db) {
1417
+ return;
1418
+ }
1419
+
1420
+ let client: InferDatabaseClient<DB> | undefined;
1421
+ try {
1422
+ // Every actor gets its own SqliteVfs/@rivetkit/sqlite instance. The async
1423
+ // @rivetkit/sqlite build is not re-entrant, and sharing one instance across
1424
+ // actors can cause cross-actor contention and runtime corruption.
1425
+ if (!this.#sqliteVfs && this.driver.createSqliteVfs) {
1426
+ this.#sqliteVfs = await this.driver.createSqliteVfs();
1427
+ }
1428
+
1429
+ client = await this.#config.db.createClient({
1430
+ actorId: this.#actorId,
1431
+ overrideRawDatabaseClient: this.driver.overrideRawDatabaseClient
1432
+ ? () => this.driver.overrideRawDatabaseClient!(this.#actorId)
1433
+ : undefined,
1434
+ overrideDrizzleDatabaseClient: this.driver.overrideDrizzleDatabaseClient
1435
+ ? () => this.driver.overrideDrizzleDatabaseClient!(this.#actorId)
1436
+ : undefined,
1437
+ kv: {
1438
+ batchPut: (entries) => this.driver.kvBatchPut(this.#actorId, entries),
1439
+ batchGet: (keys) => this.driver.kvBatchGet(this.#actorId, keys),
1440
+ batchDelete: (keys) => this.driver.kvBatchDelete(this.#actorId, keys),
1441
+ },
1442
+ sqliteVfs: this.#sqliteVfs,
907
1443
  });
908
1444
  this.#rLog.info({ msg: "database migration starting" });
909
1445
  await this.#config.db.onMigrate?.(client);
910
1446
  this.#rLog.info({ msg: "database migration complete" });
911
1447
  this.#db = client;
1448
+ } catch (error) {
1449
+ if (client) {
1450
+ try {
1451
+ await this.#config.db.onDestroy?.(client);
1452
+ } catch (cleanupError) {
1453
+ this.#rLog.error({
1454
+ msg: "database setup cleanup failed",
1455
+ error: stringifyError(cleanupError),
1456
+ });
1457
+ }
1458
+ }
1459
+ if (this.#sqliteVfs) {
1460
+ try {
1461
+ await this.#sqliteVfs.destroy();
1462
+ } catch (cleanupError) {
1463
+ this.#rLog.error({
1464
+ msg: "sqlite vfs teardown after setup failure failed",
1465
+ error: stringifyError(cleanupError),
1466
+ });
1467
+ }
1468
+ }
1469
+ this.#sqliteVfs = undefined;
1470
+ if (error instanceof Error) {
1471
+ this.#rLog.error({
1472
+ msg: "database setup failed",
1473
+ error: stringifyError(error),
1474
+ });
1475
+ throw error;
1476
+ }
1477
+ const wrappedError = new Error(`Database setup failed: ${String(error)}`);
1478
+ this.#rLog.error({
1479
+ msg: "database setup failed with non-Error object",
1480
+ error: String(error),
1481
+ errorType: typeof error,
1482
+ });
1483
+ throw wrappedError;
1484
+ }
1485
+ }
1486
+
1487
+ async #cleanupDatabase() {
1488
+ const client = this.#db;
1489
+ const sqliteVfs = this.#sqliteVfs;
1490
+ const dbConfig = "db" in this.#config ? this.#config.db : undefined;
1491
+ this.#db = undefined;
1492
+ this.#sqliteVfs = undefined;
1493
+
1494
+ if (client && dbConfig) {
1495
+ try {
1496
+ await dbConfig.onDestroy?.(client);
1497
+ } catch (error) {
1498
+ this.#rLog.error({
1499
+ msg: "database cleanup failed",
1500
+ error: stringifyError(error),
1501
+ });
1502
+ }
1503
+ }
1504
+
1505
+ if (sqliteVfs) {
1506
+ try {
1507
+ await sqliteVfs.destroy();
1508
+ } catch (error) {
1509
+ this.#rLog.error({
1510
+ msg: "sqlite vfs cleanup failed",
1511
+ error: stringifyError(error),
1512
+ });
1513
+ }
912
1514
  }
913
1515
  }
914
1516
 
@@ -1010,6 +1612,10 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
1010
1612
  if (!this.#started) return CanSleep.NotReady;
1011
1613
  if (this.#activeHonoHttpRequests > 0)
1012
1614
  return CanSleep.ActiveHonoHttpRequests;
1615
+ if (this.#activeKeepAwakeCount > 0) return CanSleep.ActiveKeepAwake;
1616
+ if (this.#runHandlerActive && this.#activeQueueWaitCount === 0) {
1617
+ return CanSleep.ActiveRun;
1618
+ }
1013
1619
 
1014
1620
  for (const _conn of this.connectionManager.connections.values()) {
1015
1621
  // TODO: Add back
@@ -1018,6 +1624,10 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
1018
1624
  // }
1019
1625
  }
1020
1626
 
1627
+ if (this.connectionManager.pendingDisconnectCount > 0) {
1628
+ return CanSleep.ActiveDisconnectCallbacks;
1629
+ }
1630
+
1021
1631
  return CanSleep.Yes;
1022
1632
  }
1023
1633