rivetkit 2.0.24-rc.1 → 2.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/dist/schemas/actor-persist/v2.ts +3 -3
  2. package/dist/schemas/actor-persist/v3.ts +274 -0
  3. package/dist/schemas/client-protocol/v2.ts +432 -0
  4. package/dist/schemas/file-system-driver/v2.ts +136 -0
  5. package/dist/tsup/actor/errors.cjs +2 -4
  6. package/dist/tsup/actor/errors.cjs.map +1 -1
  7. package/dist/tsup/actor/errors.d.cts +7 -10
  8. package/dist/tsup/actor/errors.d.ts +7 -10
  9. package/dist/tsup/actor/errors.js +9 -11
  10. package/dist/tsup/{actor-router-consts-B3Lu87yJ.d.cts → actor-router-consts-DzI2szci.d.cts} +5 -9
  11. package/dist/tsup/{actor-router-consts-B3Lu87yJ.d.ts → actor-router-consts-DzI2szci.d.ts} +5 -9
  12. package/dist/tsup/{chunk-HHFKKVLR.cjs → chunk-3543NCSN.cjs} +45 -57
  13. package/dist/tsup/chunk-3543NCSN.cjs.map +1 -0
  14. package/dist/tsup/chunk-4SHILYS5.cjs +5694 -0
  15. package/dist/tsup/chunk-4SHILYS5.cjs.map +1 -0
  16. package/dist/tsup/{chunk-ZTH3KYFH.cjs → chunk-5BZO5XPS.cjs} +3 -3
  17. package/dist/tsup/{chunk-ZTH3KYFH.cjs.map → chunk-5BZO5XPS.cjs.map} +1 -1
  18. package/dist/tsup/{chunk-PLUN2NQT.js → chunk-BAIGSF64.js} +189 -187
  19. package/dist/tsup/chunk-BAIGSF64.js.map +1 -0
  20. package/dist/tsup/{chunk-SHVX2QUR.cjs → chunk-CHLZBSI2.cjs} +17 -17
  21. package/dist/tsup/chunk-CHLZBSI2.cjs.map +1 -0
  22. package/dist/tsup/chunk-D3SLADUD.cjs +512 -0
  23. package/dist/tsup/chunk-D3SLADUD.cjs.map +1 -0
  24. package/dist/tsup/{chunk-KSRXX3Z4.cjs → chunk-D6762AOA.cjs} +20 -25
  25. package/dist/tsup/chunk-D6762AOA.cjs.map +1 -0
  26. package/dist/tsup/{chunk-7L65NNWP.cjs → chunk-DLK5YCTN.cjs} +187 -185
  27. package/dist/tsup/chunk-DLK5YCTN.cjs.map +1 -0
  28. package/dist/tsup/{chunk-YBG6R7LX.js → chunk-DUJQWGYD.js} +3 -7
  29. package/dist/tsup/chunk-DUJQWGYD.js.map +1 -0
  30. package/dist/tsup/{chunk-CD33GT6Z.js → chunk-EIPANQMF.js} +2 -2
  31. package/dist/tsup/{chunk-2JYPS5YM.cjs → chunk-ESMTDP7G.cjs} +6 -6
  32. package/dist/tsup/chunk-ESMTDP7G.cjs.map +1 -0
  33. package/dist/tsup/{chunk-VHGY7PU5.cjs → chunk-FVAKREFB.cjs} +1900 -1737
  34. package/dist/tsup/chunk-FVAKREFB.cjs.map +1 -0
  35. package/dist/tsup/{chunk-BLK27ES3.js → chunk-I3XT7WOF.js} +44 -56
  36. package/dist/tsup/chunk-I3XT7WOF.js.map +1 -0
  37. package/dist/tsup/{chunk-YBHYXIP6.js → chunk-IMDS5T42.js} +3 -3
  38. package/dist/tsup/chunk-IMDS5T42.js.map +1 -0
  39. package/dist/tsup/{chunk-INNFK746.cjs → chunk-J3HZJF2P.cjs} +10 -14
  40. package/dist/tsup/chunk-J3HZJF2P.cjs.map +1 -0
  41. package/dist/tsup/{chunk-BYMKMOBS.js → chunk-MBBJUHSP.js} +1844 -1681
  42. package/dist/tsup/chunk-MBBJUHSP.js.map +1 -0
  43. package/dist/tsup/{chunk-BOMZS2TJ.js → chunk-MO5CB6MD.js} +9 -9
  44. package/dist/tsup/chunk-MO5CB6MD.js.map +1 -0
  45. package/dist/tsup/chunk-OFOTPKAH.js +512 -0
  46. package/dist/tsup/chunk-OFOTPKAH.js.map +1 -0
  47. package/dist/tsup/{chunk-G64QUEDJ.js → chunk-W6RDS6NW.js} +23 -28
  48. package/dist/tsup/chunk-W6RDS6NW.js.map +1 -0
  49. package/dist/tsup/{chunk-36JJ4IQB.cjs → chunk-YC5DUHPM.cjs} +4 -8
  50. package/dist/tsup/chunk-YC5DUHPM.cjs.map +1 -0
  51. package/dist/tsup/{chunk-FX7TWFQR.js → chunk-YC7YPM2T.js} +2 -6
  52. package/dist/tsup/chunk-YC7YPM2T.js.map +1 -0
  53. package/dist/tsup/{chunk-227FEWMB.js → chunk-ZSPU5R4C.js} +3322 -2251
  54. package/dist/tsup/chunk-ZSPU5R4C.js.map +1 -0
  55. package/dist/tsup/client/mod.cjs +9 -9
  56. package/dist/tsup/client/mod.d.cts +5 -7
  57. package/dist/tsup/client/mod.d.ts +5 -7
  58. package/dist/tsup/client/mod.js +8 -8
  59. package/dist/tsup/common/log.cjs +3 -3
  60. package/dist/tsup/common/log.js +2 -2
  61. package/dist/tsup/common/websocket.cjs +4 -4
  62. package/dist/tsup/common/websocket.js +3 -3
  63. package/dist/tsup/{conn-B3Vhbgnd.d.ts → config-BRDYDraU.d.cts} +1119 -1047
  64. package/dist/tsup/{conn-DJWL3nGx.d.cts → config-Bo-blHpJ.d.ts} +1119 -1047
  65. package/dist/tsup/driver-helpers/mod.cjs +5 -13
  66. package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
  67. package/dist/tsup/driver-helpers/mod.d.cts +11 -9
  68. package/dist/tsup/driver-helpers/mod.d.ts +11 -9
  69. package/dist/tsup/driver-helpers/mod.js +14 -22
  70. package/dist/tsup/driver-test-suite/mod.cjs +474 -303
  71. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  72. package/dist/tsup/driver-test-suite/mod.d.cts +6 -9
  73. package/dist/tsup/driver-test-suite/mod.d.ts +6 -9
  74. package/dist/tsup/driver-test-suite/mod.js +1085 -914
  75. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  76. package/dist/tsup/inspector/mod.cjs +6 -6
  77. package/dist/tsup/inspector/mod.d.cts +5 -7
  78. package/dist/tsup/inspector/mod.d.ts +5 -7
  79. package/dist/tsup/inspector/mod.js +5 -5
  80. package/dist/tsup/mod.cjs +10 -16
  81. package/dist/tsup/mod.cjs.map +1 -1
  82. package/dist/tsup/mod.d.cts +23 -25
  83. package/dist/tsup/mod.d.ts +23 -25
  84. package/dist/tsup/mod.js +17 -23
  85. package/dist/tsup/test/mod.cjs +11 -11
  86. package/dist/tsup/test/mod.d.cts +4 -6
  87. package/dist/tsup/test/mod.d.ts +4 -6
  88. package/dist/tsup/test/mod.js +10 -10
  89. package/dist/tsup/utils.cjs +3 -5
  90. package/dist/tsup/utils.cjs.map +1 -1
  91. package/dist/tsup/utils.d.cts +1 -2
  92. package/dist/tsup/utils.d.ts +1 -2
  93. package/dist/tsup/utils.js +2 -4
  94. package/package.json +13 -6
  95. package/src/actor/config.ts +56 -44
  96. package/src/actor/conn/driver.ts +61 -0
  97. package/src/actor/conn/drivers/http.ts +17 -0
  98. package/src/actor/conn/drivers/raw-request.ts +24 -0
  99. package/src/actor/conn/drivers/raw-websocket.ts +65 -0
  100. package/src/actor/conn/drivers/websocket.ts +129 -0
  101. package/src/actor/conn/mod.ts +232 -0
  102. package/src/actor/conn/persisted.ts +81 -0
  103. package/src/actor/conn/state-manager.ts +196 -0
  104. package/src/actor/contexts/action.ts +23 -0
  105. package/src/actor/{context.ts → contexts/actor.ts} +19 -8
  106. package/src/actor/contexts/conn-init.ts +31 -0
  107. package/src/actor/contexts/conn.ts +48 -0
  108. package/src/actor/contexts/create-conn-state.ts +13 -0
  109. package/src/actor/contexts/on-before-connect.ts +13 -0
  110. package/src/actor/contexts/on-connect.ts +22 -0
  111. package/src/actor/contexts/request.ts +48 -0
  112. package/src/actor/contexts/websocket.ts +48 -0
  113. package/src/actor/definition.ts +3 -3
  114. package/src/actor/driver.ts +36 -5
  115. package/src/actor/errors.ts +19 -24
  116. package/src/actor/instance/connection-manager.ts +465 -0
  117. package/src/actor/instance/event-manager.ts +292 -0
  118. package/src/actor/instance/kv.ts +15 -0
  119. package/src/actor/instance/mod.ts +1107 -0
  120. package/src/actor/instance/persisted.ts +67 -0
  121. package/src/actor/instance/schedule-manager.ts +349 -0
  122. package/src/actor/instance/state-manager.ts +502 -0
  123. package/src/actor/mod.ts +13 -16
  124. package/src/actor/protocol/old.ts +131 -43
  125. package/src/actor/protocol/serde.ts +19 -4
  126. package/src/actor/router-endpoints.ts +61 -586
  127. package/src/actor/router-websocket-endpoints.ts +408 -0
  128. package/src/actor/router.ts +63 -197
  129. package/src/actor/schedule.ts +1 -1
  130. package/src/client/actor-conn.ts +183 -249
  131. package/src/client/actor-handle.ts +29 -6
  132. package/src/client/client.ts +0 -4
  133. package/src/client/config.ts +1 -4
  134. package/src/client/mod.ts +0 -1
  135. package/src/client/raw-utils.ts +3 -3
  136. package/src/client/utils.ts +85 -39
  137. package/src/common/actor-router-consts.ts +5 -12
  138. package/src/common/{inline-websocket-adapter2.ts → inline-websocket-adapter.ts} +26 -48
  139. package/src/common/log.ts +1 -1
  140. package/src/common/router.ts +28 -17
  141. package/src/common/utils.ts +2 -0
  142. package/src/driver-helpers/mod.ts +7 -10
  143. package/src/driver-helpers/utils.ts +18 -9
  144. package/src/driver-test-suite/mod.ts +26 -50
  145. package/src/driver-test-suite/test-inline-client-driver.ts +27 -51
  146. package/src/driver-test-suite/tests/actor-conn-hibernation.ts +150 -0
  147. package/src/driver-test-suite/tests/actor-conn-state.ts +1 -4
  148. package/src/driver-test-suite/tests/actor-conn.ts +5 -9
  149. package/src/driver-test-suite/tests/actor-destroy.ts +294 -0
  150. package/src/driver-test-suite/tests/actor-driver.ts +0 -7
  151. package/src/driver-test-suite/tests/actor-handle.ts +12 -12
  152. package/src/driver-test-suite/tests/actor-metadata.ts +1 -1
  153. package/src/driver-test-suite/tests/manager-driver.ts +1 -1
  154. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +8 -8
  155. package/src/driver-test-suite/tests/raw-http-request-properties.ts +6 -5
  156. package/src/driver-test-suite/tests/raw-http.ts +5 -5
  157. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +7 -7
  158. package/src/driver-test-suite/tests/request-access.ts +4 -4
  159. package/src/driver-test-suite/utils.ts +6 -10
  160. package/src/drivers/engine/actor-driver.ts +614 -424
  161. package/src/drivers/engine/mod.ts +0 -1
  162. package/src/drivers/file-system/actor.ts +24 -12
  163. package/src/drivers/file-system/global-state.ts +427 -37
  164. package/src/drivers/file-system/manager.ts +71 -83
  165. package/src/drivers/file-system/mod.ts +3 -0
  166. package/src/drivers/file-system/utils.ts +18 -8
  167. package/src/engine-process/mod.ts +38 -38
  168. package/src/inspector/utils.ts +7 -5
  169. package/src/manager/driver.ts +11 -4
  170. package/src/manager/gateway.ts +4 -29
  171. package/src/manager/protocol/mod.ts +0 -2
  172. package/src/manager/protocol/query.ts +0 -4
  173. package/src/manager/router.ts +67 -64
  174. package/src/manager-api/actors.ts +13 -0
  175. package/src/mod.ts +1 -3
  176. package/src/registry/mod.ts +20 -20
  177. package/src/registry/serve.ts +9 -14
  178. package/src/remote-manager-driver/actor-websocket-client.ts +1 -16
  179. package/src/remote-manager-driver/api-endpoints.ts +13 -1
  180. package/src/remote-manager-driver/api-utils.ts +8 -0
  181. package/src/remote-manager-driver/metadata.ts +58 -0
  182. package/src/remote-manager-driver/mod.ts +47 -62
  183. package/src/remote-manager-driver/ws-proxy.ts +1 -1
  184. package/src/schemas/actor-persist/mod.ts +1 -1
  185. package/src/schemas/actor-persist/versioned.ts +56 -31
  186. package/src/schemas/client-protocol/mod.ts +1 -1
  187. package/src/schemas/client-protocol/versioned.ts +41 -21
  188. package/src/schemas/client-protocol-zod/mod.ts +103 -0
  189. package/src/schemas/file-system-driver/mod.ts +1 -1
  190. package/src/schemas/file-system-driver/versioned.ts +42 -19
  191. package/src/serde.ts +33 -11
  192. package/src/test/mod.ts +7 -3
  193. package/src/utils/node.ts +173 -0
  194. package/src/utils.ts +0 -4
  195. package/dist/tsup/chunk-227FEWMB.js.map +0 -1
  196. package/dist/tsup/chunk-2JYPS5YM.cjs.map +0 -1
  197. package/dist/tsup/chunk-36JJ4IQB.cjs.map +0 -1
  198. package/dist/tsup/chunk-7L65NNWP.cjs.map +0 -1
  199. package/dist/tsup/chunk-BLK27ES3.js.map +0 -1
  200. package/dist/tsup/chunk-BOMZS2TJ.js.map +0 -1
  201. package/dist/tsup/chunk-BYMKMOBS.js.map +0 -1
  202. package/dist/tsup/chunk-FX7TWFQR.js.map +0 -1
  203. package/dist/tsup/chunk-G64QUEDJ.js.map +0 -1
  204. package/dist/tsup/chunk-HHFKKVLR.cjs.map +0 -1
  205. package/dist/tsup/chunk-INNFK746.cjs.map +0 -1
  206. package/dist/tsup/chunk-KSRXX3Z4.cjs.map +0 -1
  207. package/dist/tsup/chunk-O44LFKSB.cjs +0 -4623
  208. package/dist/tsup/chunk-O44LFKSB.cjs.map +0 -1
  209. package/dist/tsup/chunk-PLUN2NQT.js.map +0 -1
  210. package/dist/tsup/chunk-S4UJG7ZE.js +0 -1119
  211. package/dist/tsup/chunk-S4UJG7ZE.js.map +0 -1
  212. package/dist/tsup/chunk-SHVX2QUR.cjs.map +0 -1
  213. package/dist/tsup/chunk-VFB23BYZ.cjs +0 -1119
  214. package/dist/tsup/chunk-VFB23BYZ.cjs.map +0 -1
  215. package/dist/tsup/chunk-VHGY7PU5.cjs.map +0 -1
  216. package/dist/tsup/chunk-YBG6R7LX.js.map +0 -1
  217. package/dist/tsup/chunk-YBHYXIP6.js.map +0 -1
  218. package/src/actor/action.ts +0 -178
  219. package/src/actor/conn-drivers.ts +0 -216
  220. package/src/actor/conn-socket.ts +0 -8
  221. package/src/actor/conn.ts +0 -272
  222. package/src/actor/instance.ts +0 -2336
  223. package/src/actor/persisted.ts +0 -49
  224. package/src/actor/unstable-react.ts +0 -110
  225. package/src/driver-test-suite/tests/actor-reconnect.ts +0 -170
  226. package/src/drivers/engine/kv.ts +0 -3
  227. package/src/manager/hono-websocket-adapter.ts +0 -393
  228. /package/dist/tsup/{chunk-CD33GT6Z.js.map → chunk-EIPANQMF.js.map} +0 -0
@@ -0,0 +1,232 @@
1
+ import * as cbor from "cbor-x";
2
+ import type * as protocol from "@/schemas/client-protocol/mod";
3
+ import { TO_CLIENT_VERSIONED } from "@/schemas/client-protocol/versioned";
4
+ import {
5
+ type ToClient as ToClientJson,
6
+ ToClientSchema,
7
+ } from "@/schemas/client-protocol-zod/mod";
8
+ import { bufferToArrayBuffer } from "@/utils";
9
+ import type { AnyDatabaseProvider } from "../database";
10
+ import { InternalError } from "../errors";
11
+ import type { ActorInstance } from "../instance/mod";
12
+ import { CachedSerializer } from "../protocol/serde";
13
+ import type { ConnDriver } from "./driver";
14
+ import { type ConnDataInput, StateManager } from "./state-manager";
15
+
16
+ export type ConnId = string;
17
+
18
+ export type AnyConn = Conn<any, any, any, any, any, any>;
19
+
20
+ export const CONN_CONNECTED_SYMBOL = Symbol("connected");
21
+ export const CONN_SPEAKS_RIVETKIT_SYMBOL = Symbol("speaksRivetKit");
22
+ export const CONN_DRIVER_SYMBOL = Symbol("driver");
23
+ export const CONN_ACTOR_SYMBOL = Symbol("actor");
24
+ export const CONN_STATE_MANAGER_SYMBOL = Symbol("stateManager");
25
+ export const CONN_SEND_MESSAGE_SYMBOL = Symbol("sendMessage");
26
+
27
+ /**
28
+ * Represents a client connection to a actor.
29
+ *
30
+ * Manages connection-specific data and controls the connection lifecycle.
31
+ *
32
+ * @see {@link https://rivet.dev/docs/connections|Connection Documentation}
33
+ */
34
+ export class Conn<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
35
+ #actor: ActorInstance<S, CP, CS, V, I, DB>;
36
+
37
+ get [CONN_ACTOR_SYMBOL](): ActorInstance<S, CP, CS, V, I, DB> {
38
+ return this.#actor;
39
+ }
40
+
41
+ #stateManager!: StateManager<CP, CS>;
42
+
43
+ get [CONN_STATE_MANAGER_SYMBOL]() {
44
+ return this.#stateManager;
45
+ }
46
+
47
+ /**
48
+ * Connections exist before being connected to an actor. If true, this
49
+ * connection has been connected.
50
+ **/
51
+ [CONN_CONNECTED_SYMBOL] = false;
52
+
53
+ /**
54
+ * If undefined, then no socket is connected to this conn
55
+ */
56
+ [CONN_DRIVER_SYMBOL]?: ConnDriver;
57
+
58
+ /**
59
+ * If this connection is speaking the RivetKit protocol. If false, this is
60
+ * a raw connection for WebSocket or fetch or inspector.
61
+ **/
62
+ get [CONN_SPEAKS_RIVETKIT_SYMBOL](): boolean {
63
+ return this[CONN_DRIVER_SYMBOL]?.rivetKitProtocol !== undefined;
64
+ }
65
+
66
+ subscriptions: Set<string> = new Set<string>();
67
+
68
+ #assertConnected() {
69
+ if (!this[CONN_CONNECTED_SYMBOL])
70
+ throw new InternalError(
71
+ "Connection not connected yet. This happens when trying to use the connection in onBeforeConnect or createConnState.",
72
+ );
73
+ }
74
+
75
+ // MARK: - Public Getters
76
+ get params(): CP {
77
+ return this.#stateManager.ephemeralData.parameters;
78
+ }
79
+
80
+ /**
81
+ * Gets the current state of the connection.
82
+ *
83
+ * Throws an error if the state is not enabled.
84
+ */
85
+ get state(): CS {
86
+ return this.#stateManager.state;
87
+ }
88
+
89
+ /**
90
+ * Sets the state of the connection.
91
+ *
92
+ * Throws an error if the state is not enabled.
93
+ */
94
+ set state(value: CS) {
95
+ this.#stateManager.state = value;
96
+ }
97
+
98
+ /**
99
+ * Unique identifier for the connection.
100
+ */
101
+ get id(): ConnId {
102
+ return this.#stateManager.ephemeralData.id;
103
+ }
104
+
105
+ /**
106
+ * @experimental
107
+ *
108
+ * If the underlying connection can hibernate.
109
+ */
110
+ get isHibernatable(): boolean {
111
+ return this[CONN_DRIVER_SYMBOL]?.hibernatable !== undefined;
112
+ }
113
+
114
+ /**
115
+ * Initializes a new instance of the Connection class.
116
+ *
117
+ * This should only be constructed by {@link Actor}.
118
+ *
119
+ * @protected
120
+ */
121
+ constructor(
122
+ actor: ActorInstance<S, CP, CS, V, I, DB>,
123
+ data: ConnDataInput<CP, CS>,
124
+ ) {
125
+ this.#actor = actor;
126
+ this.#stateManager = new StateManager(this, data);
127
+ }
128
+
129
+ /**
130
+ * Sends a raw message to the underlying connection.
131
+ */
132
+ [CONN_SEND_MESSAGE_SYMBOL](message: CachedSerializer<any, any, any>) {
133
+ if (this[CONN_DRIVER_SYMBOL]) {
134
+ const driver = this[CONN_DRIVER_SYMBOL];
135
+
136
+ if (driver.rivetKitProtocol) {
137
+ driver.rivetKitProtocol.sendMessage(this.#actor, this, message);
138
+ } else {
139
+ this.#actor.rLog.warn({
140
+ msg: "attempting to send RivetKit protocol message to connection that does not support it",
141
+ conn: this.id,
142
+ });
143
+ }
144
+ } else {
145
+ this.#actor.rLog.warn({
146
+ msg: "missing connection driver state for send message",
147
+ conn: this.id,
148
+ });
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Sends an event with arguments to the client.
154
+ *
155
+ * @param eventName - The name of the event.
156
+ * @param args - The arguments for the event.
157
+ * @see {@link https://rivet.dev/docs/events|Events Documentation}
158
+ */
159
+ send(eventName: string, ...args: unknown[]) {
160
+ this.#assertConnected();
161
+ if (!this[CONN_SPEAKS_RIVETKIT_SYMBOL]) {
162
+ this.#actor.rLog.warn({
163
+ msg: "cannot send messages to this connection type",
164
+ connId: this.id,
165
+ connType: this[CONN_DRIVER_SYMBOL]?.type,
166
+ });
167
+ }
168
+
169
+ this.#actor.inspector.emitter.emit("eventFired", {
170
+ type: "event",
171
+ eventName,
172
+ args,
173
+ connId: this.id,
174
+ });
175
+ const eventData = { name: eventName, args };
176
+ this[CONN_SEND_MESSAGE_SYMBOL](
177
+ new CachedSerializer(
178
+ eventData,
179
+ TO_CLIENT_VERSIONED,
180
+ ToClientSchema,
181
+ // JSON: args is the raw value (array of arguments)
182
+ (value): ToClientJson => ({
183
+ body: {
184
+ tag: "Event" as const,
185
+ val: {
186
+ name: value.name,
187
+ args: value.args,
188
+ },
189
+ },
190
+ }),
191
+ // BARE/CBOR: args needs to be CBOR-encoded to ArrayBuffer
192
+ (value): protocol.ToClient => ({
193
+ body: {
194
+ tag: "Event" as const,
195
+ val: {
196
+ name: value.name,
197
+ args: bufferToArrayBuffer(cbor.encode(value.args)),
198
+ },
199
+ },
200
+ }),
201
+ ),
202
+ );
203
+ }
204
+
205
+ /**
206
+ * Disconnects the client with an optional reason.
207
+ *
208
+ * @param reason - The reason for disconnection.
209
+ */
210
+ async disconnect(reason?: string) {
211
+ if (this[CONN_DRIVER_SYMBOL]) {
212
+ const driver = this[CONN_DRIVER_SYMBOL];
213
+ if (driver.disconnect) {
214
+ driver.disconnect(this.#actor, this, reason);
215
+ } else {
216
+ this.#actor.rLog.debug({
217
+ msg: "no disconnect handler for conn driver",
218
+ conn: this.id,
219
+ });
220
+ }
221
+
222
+ this.#actor.connectionManager.connDisconnected(this);
223
+ } else {
224
+ this.#actor.rLog.warn({
225
+ msg: "missing connection driver state for disconnect",
226
+ conn: this.id,
227
+ });
228
+ }
229
+
230
+ this[CONN_DRIVER_SYMBOL] = undefined;
231
+ }
232
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Persisted data structures for connections.
3
+ *
4
+ * Keep this file in sync with the Connection section of rivetkit-typescript/packages/rivetkit/schemas/actor-persist/
5
+ */
6
+
7
+ import * as cbor from "cbor-x";
8
+ import type * as persistSchema from "@/schemas/actor-persist/mod";
9
+ import { bufferToArrayBuffer } from "@/utils";
10
+
11
+ export type GatewayId = ArrayBuffer;
12
+ export type RequestId = ArrayBuffer;
13
+
14
+ export type Cbor = ArrayBuffer;
15
+
16
+ // MARK: Connection
17
+ /** Event subscription for connection */
18
+ export interface PersistedSubscription {
19
+ eventName: string;
20
+ }
21
+
22
+ /** Connection associated with hibernatable WebSocket that should persist across lifecycles */
23
+ export interface PersistedConn<CP, CS> {
24
+ /** Connection ID generated by RivetKit */
25
+ id: string;
26
+ parameters: CP;
27
+ state: CS;
28
+ subscriptions: PersistedSubscription[];
29
+ gatewayId: GatewayId;
30
+ requestId: RequestId;
31
+ serverMessageIndex: number;
32
+ clientMessageIndex: number;
33
+ requestPath: string;
34
+ requestHeaders: Record<string, string>;
35
+ }
36
+
37
+ /**
38
+ * Converts persisted connection data to BARE schema format for serialization.
39
+ * @throws {Error} If the connection is ephemeral (not hibernatable)
40
+ */
41
+ export function convertConnToBarePersistedConn<CP, CS>(
42
+ persist: PersistedConn<CP, CS>,
43
+ ): persistSchema.Conn {
44
+ return {
45
+ id: persist.id,
46
+ parameters: bufferToArrayBuffer(cbor.encode(persist.parameters)),
47
+ state: bufferToArrayBuffer(cbor.encode(persist.state)),
48
+ subscriptions: persist.subscriptions.map((sub) => ({
49
+ eventName: sub.eventName,
50
+ })),
51
+ gatewayId: persist.gatewayId,
52
+ requestId: persist.requestId,
53
+ serverMessageIndex: persist.serverMessageIndex,
54
+ clientMessageIndex: persist.clientMessageIndex,
55
+ requestPath: persist.requestPath,
56
+ requestHeaders: new Map(Object.entries(persist.requestHeaders)),
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Converts BARE schema format to persisted connection data.
62
+ * @throws {Error} If the connection is ephemeral (not hibernatable)
63
+ */
64
+ export function convertConnFromBarePersistedConn<CP, CS>(
65
+ bareData: persistSchema.Conn,
66
+ ): PersistedConn<CP, CS> {
67
+ return {
68
+ id: bareData.id,
69
+ parameters: cbor.decode(new Uint8Array(bareData.parameters)),
70
+ state: cbor.decode(new Uint8Array(bareData.state)),
71
+ subscriptions: bareData.subscriptions.map((sub) => ({
72
+ eventName: sub.eventName,
73
+ })),
74
+ gatewayId: bareData.gatewayId,
75
+ requestId: bareData.requestId,
76
+ serverMessageIndex: bareData.serverMessageIndex,
77
+ clientMessageIndex: bareData.clientMessageIndex,
78
+ requestPath: bareData.requestPath,
79
+ requestHeaders: Object.fromEntries(bareData.requestHeaders),
80
+ };
81
+ }
@@ -0,0 +1,196 @@
1
+ import type { HibernatingWebSocketMetadata } from "@rivetkit/engine-runner";
2
+ import * as cbor from "cbor-x";
3
+ import invariant from "invariant";
4
+ import onChange from "on-change";
5
+ import { isCborSerializable } from "@/common/utils";
6
+ import * as errors from "../errors";
7
+ import { assertUnreachable } from "../utils";
8
+ import { CONN_ACTOR_SYMBOL, type Conn } from "./mod";
9
+ import type { PersistedConn } from "./persisted";
10
+
11
+ /** Pick a subset of persisted data used to represent ephemeral connections */
12
+ export type EphemeralConn<CP, CS> = Pick<
13
+ PersistedConn<CP, CS>,
14
+ "id" | "parameters" | "state"
15
+ >;
16
+
17
+ export type ConnDataInput<CP, CS> =
18
+ | { ephemeral: EphemeralConn<CP, CS> }
19
+ | { hibernatable: PersistedConn<CP, CS> };
20
+
21
+ export type ConnData<CP, CS> =
22
+ | {
23
+ ephemeral: {
24
+ /** In-memory data representing this connection */
25
+ data: EphemeralConn<CP, CS>;
26
+ };
27
+ }
28
+ | {
29
+ hibernatable: {
30
+ /** Persisted data with on-change proxy */
31
+ data: PersistedConn<CP, CS>;
32
+ /** Raw persisted data without proxy */
33
+ dataRaw: PersistedConn<CP, CS>;
34
+ };
35
+ };
36
+
37
+ /**
38
+ * Manages connection state persistence, proxying, and change tracking.
39
+ * Handles automatic state change detection for connection-specific state.
40
+ */
41
+ export class StateManager<CP, CS> {
42
+ #conn: Conn<any, CP, CS, any, any, any>;
43
+
44
+ /**
45
+ * Data representing this connection.
46
+ *
47
+ * This is stored as a struct for both ephemeral and hibernatable conns in
48
+ * order to keep the separation clear between the two.
49
+ */
50
+ #data!: ConnData<CP, CS>;
51
+
52
+ constructor(
53
+ conn: Conn<any, CP, CS, any, any, any>,
54
+ data: ConnDataInput<CP, CS>,
55
+ ) {
56
+ this.#conn = conn;
57
+
58
+ if ("ephemeral" in data) {
59
+ this.#data = { ephemeral: { data: data.ephemeral } };
60
+ } else if ("hibernatable" in data) {
61
+ // Listen for changes to the object
62
+ const persistRaw = data.hibernatable;
63
+ const persist = onChange(
64
+ persistRaw,
65
+ (
66
+ path: string,
67
+ value: any,
68
+ _previousValue: any,
69
+ _applyData: any,
70
+ ) => {
71
+ this.#handleChange(path, value);
72
+ },
73
+ { ignoreDetached: true },
74
+ );
75
+ this.#data = {
76
+ hibernatable: { data: persist, dataRaw: persistRaw },
77
+ };
78
+ } else {
79
+ assertUnreachable(data);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Returns the ephemeral or persisted data for this connectioned.
85
+ *
86
+ * This property is used to be able to treat both memory & persist conns
87
+ * identical by looking up the correct underlying data structure.
88
+ */
89
+ get ephemeralData(): EphemeralConn<CP, CS> {
90
+ if ("hibernatable" in this.#data) {
91
+ return this.#data.hibernatable.data;
92
+ } else if ("ephemeral" in this.#data) {
93
+ return this.#data.ephemeral.data;
94
+ } else {
95
+ return assertUnreachable(this.#data);
96
+ }
97
+ }
98
+
99
+ get hibernatableData(): PersistedConn<CP, CS> | undefined {
100
+ if ("hibernatable" in this.#data) {
101
+ return this.#data.hibernatable.data;
102
+ } else {
103
+ return undefined;
104
+ }
105
+ }
106
+
107
+ hibernatableDataOrError(): PersistedConn<CP, CS> {
108
+ const hibernatable = this.hibernatableData;
109
+ invariant(hibernatable, "missing hibernatable data");
110
+ return hibernatable;
111
+ }
112
+
113
+ get hibernatableDataRaw(): PersistedConn<CP, CS> | undefined {
114
+ if ("hibernatable" in this.#data) {
115
+ return this.#data.hibernatable.dataRaw;
116
+ } else {
117
+ return undefined;
118
+ }
119
+ }
120
+
121
+ get stateEnabled(): boolean {
122
+ return this.#conn[CONN_ACTOR_SYMBOL].connStateEnabled;
123
+ }
124
+
125
+ get state(): CS {
126
+ this.#validateStateEnabled();
127
+ const state = this.ephemeralData.state;
128
+ if (!state) throw new Error("state should exists");
129
+ return state;
130
+ }
131
+
132
+ set state(value: CS) {
133
+ this.#validateStateEnabled();
134
+ this.ephemeralData.state = value;
135
+ }
136
+
137
+ #validateStateEnabled() {
138
+ if (!this.#conn[CONN_ACTOR_SYMBOL].connStateEnabled) {
139
+ throw new errors.ConnStateNotEnabled();
140
+ }
141
+ }
142
+
143
+ #handleChange(path: string, value: any) {
144
+ // NOTE: This will only be called for hibernatable conns since only
145
+ // hibernatable conns have the on-change proxy
146
+
147
+ // Validate CBOR serializability for state changes
148
+ if (path.startsWith("state")) {
149
+ let invalidPath = "";
150
+ if (
151
+ !isCborSerializable(
152
+ value,
153
+ (invalidPathPart: string) => {
154
+ invalidPath = invalidPathPart;
155
+ },
156
+ "",
157
+ )
158
+ ) {
159
+ throw new errors.InvalidStateType({
160
+ path: path + (invalidPath ? `.${invalidPath}` : ""),
161
+ });
162
+ }
163
+ }
164
+
165
+ this.#conn[CONN_ACTOR_SYMBOL].rLog.debug({
166
+ msg: "conn onChange triggered",
167
+ connId: this.#conn.id,
168
+ path,
169
+ });
170
+
171
+ // Notify actor that this connection has changed
172
+ this.#conn[
173
+ CONN_ACTOR_SYMBOL
174
+ ].connectionManager.markConnWithPersistChanged(this.#conn);
175
+ }
176
+
177
+ addSubscription({ eventName }: { eventName: string }) {
178
+ const hibernatable = this.hibernatableData;
179
+ if (!hibernatable) return;
180
+ hibernatable.subscriptions.push({
181
+ eventName,
182
+ });
183
+ }
184
+
185
+ removeSubscription({ eventName }: { eventName: string }) {
186
+ const hibernatable = this.hibernatableData;
187
+ if (!hibernatable) return;
188
+ const subIdx = hibernatable.subscriptions.findIndex(
189
+ (s) => s.eventName === eventName,
190
+ );
191
+ if (subIdx !== -1) {
192
+ hibernatable.subscriptions.splice(subIdx, 1);
193
+ }
194
+ return subIdx !== -1;
195
+ }
196
+ }
@@ -0,0 +1,23 @@
1
+ import type { Conn } from "../conn/mod";
2
+ import type { AnyDatabaseProvider } from "../database";
3
+ import type { ActorInstance } from "../instance/mod";
4
+ import { ConnContext } from "./conn";
5
+
6
+ /**
7
+ * Context for a remote procedure call.
8
+ */
9
+ export class ActionContext<
10
+ TState,
11
+ TConnParams,
12
+ TConnState,
13
+ TVars,
14
+ TInput,
15
+ TDatabase extends AnyDatabaseProvider,
16
+ > extends ConnContext<
17
+ TState,
18
+ TConnParams,
19
+ TConnState,
20
+ TVars,
21
+ TInput,
22
+ TDatabase
23
+ > {}
@@ -2,10 +2,10 @@ import type { ActorKey } from "@/actor/mod";
2
2
  import type { Client } from "@/client/client";
3
3
  import type { Logger } from "@/common/log";
4
4
  import type { Registry } from "@/registry/mod";
5
- import type { Conn, ConnId } from "./conn";
6
- import type { AnyDatabaseProvider, InferDatabaseClient } from "./database";
7
- import type { ActorInstance, SaveStateOptions } from "./instance";
8
- import type { Schedule } from "./schedule";
5
+ import type { Conn, ConnId } from "../conn/mod";
6
+ import type { AnyDatabaseProvider, InferDatabaseClient } from "../database";
7
+ import type { ActorInstance, SaveStateOptions } from "../instance/mod";
8
+ import type { Schedule } from "../schedule";
9
9
 
10
10
  /**
11
11
  * ActorContext class that provides access to actor methods and state
@@ -60,7 +60,7 @@ export class ActorContext<
60
60
  * @param args - The arguments to send with the event.
61
61
  */
62
62
  broadcast<Args extends Array<unknown>>(name: string, ...args: Args): void {
63
- this.#actor._broadcast(name, ...args);
63
+ this.#actor.eventManager.broadcast(name, ...args);
64
64
  return;
65
65
  }
66
66
 
@@ -138,14 +138,14 @@ export class ActorContext<
138
138
  * @param opts - Options for saving the state.
139
139
  */
140
140
  async saveState(opts: SaveStateOptions): Promise<void> {
141
- return this.#actor.saveState(opts);
141
+ return this.#actor.stateManager.saveState(opts);
142
142
  }
143
143
 
144
144
  /**
145
145
  * Prevents the actor from sleeping until promise is complete.
146
146
  */
147
147
  waitUntil(promise: Promise<void>): void {
148
- this.#actor._waitUntil(promise);
148
+ this.#actor.waitUntil(promise);
149
149
  }
150
150
 
151
151
  /**
@@ -163,6 +163,17 @@ export class ActorContext<
163
163
  * @experimental
164
164
  */
165
165
  sleep() {
166
- this.#actor._startSleep();
166
+ this.#actor.startSleep();
167
+ }
168
+
169
+ /**
170
+ * Forces the actor to destroy.
171
+ *
172
+ * This will return immediately, then call `onStop` and `onDestroy`.
173
+ *
174
+ * @experimental
175
+ */
176
+ destroy() {
177
+ this.#actor.startDestroy();
167
178
  }
168
179
  }
@@ -0,0 +1,31 @@
1
+ import type { AnyDatabaseProvider } from "../database";
2
+ import type { ActorInstance } from "../instance/mod";
3
+ import { ActorContext } from "./actor";
4
+
5
+ /**
6
+ * Base context for connection initialization handlers.
7
+ * Extends ActorContext with request-specific functionality for connection lifecycle events.
8
+ */
9
+ export abstract class ConnInitContext<
10
+ TState,
11
+ TVars,
12
+ TInput,
13
+ TDatabase extends AnyDatabaseProvider,
14
+ > extends ActorContext<TState, undefined, undefined, TVars, TInput, TDatabase> {
15
+ /**
16
+ * The incoming request that initiated the connection.
17
+ * May be undefined for connections initiated without a direct HTTP request.
18
+ */
19
+ public readonly request: Request | undefined;
20
+
21
+ /**
22
+ * @internal
23
+ */
24
+ constructor(
25
+ actor: ActorInstance<TState, any, any, TVars, TInput, TDatabase>,
26
+ request: Request | undefined,
27
+ ) {
28
+ super(actor);
29
+ this.request = request;
30
+ }
31
+ }
@@ -0,0 +1,48 @@
1
+ import type { Conn } from "../conn/mod";
2
+ import type { AnyDatabaseProvider } from "../database";
3
+ import type { ActorInstance } from "../instance/mod";
4
+ import { ActorContext } from "./actor";
5
+
6
+ /**
7
+ * Base context for connection-based handlers.
8
+ * Extends ActorContext with connection-specific functionality.
9
+ */
10
+ export abstract class ConnContext<
11
+ TState,
12
+ TConnParams,
13
+ TConnState,
14
+ TVars,
15
+ TInput,
16
+ TDatabase extends AnyDatabaseProvider,
17
+ > extends ActorContext<
18
+ TState,
19
+ TConnParams,
20
+ TConnState,
21
+ TVars,
22
+ TInput,
23
+ TDatabase
24
+ > {
25
+ /**
26
+ * @internal
27
+ */
28
+ constructor(
29
+ actor: ActorInstance<
30
+ TState,
31
+ TConnParams,
32
+ TConnState,
33
+ TVars,
34
+ TInput,
35
+ TDatabase
36
+ >,
37
+ public readonly conn: Conn<
38
+ TState,
39
+ TConnParams,
40
+ TConnState,
41
+ TVars,
42
+ TInput,
43
+ TDatabase
44
+ >,
45
+ ) {
46
+ super(actor);
47
+ }
48
+ }
@@ -0,0 +1,13 @@
1
+ import type { AnyDatabaseProvider } from "../database";
2
+ import { ConnInitContext } from "./conn-init";
3
+
4
+ /**
5
+ * Context for the createConnState lifecycle hook.
6
+ * Called to initialize connection-specific state when a connection is created.
7
+ */
8
+ export class CreateConnStateContext<
9
+ TState,
10
+ TVars,
11
+ TInput,
12
+ TDatabase extends AnyDatabaseProvider,
13
+ > extends ConnInitContext<TState, TVars, TInput, TDatabase> {}
@@ -0,0 +1,13 @@
1
+ import type { AnyDatabaseProvider } from "../database";
2
+ import { ConnInitContext } from "./conn-init";
3
+
4
+ /**
5
+ * Context for the onBeforeConnect lifecycle hook.
6
+ * Called before a connection is established, allowing for validation and early rejection.
7
+ */
8
+ export class OnBeforeConnectContext<
9
+ TState,
10
+ TVars,
11
+ TInput,
12
+ TDatabase extends AnyDatabaseProvider,
13
+ > extends ConnInitContext<TState, TVars, TInput, TDatabase> {}