rivetkit 2.0.24-rc.1 → 2.0.25-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 (231) hide show
  1. package/dist/schemas/actor-persist/v1.ts +6 -0
  2. package/dist/schemas/actor-persist/v2.ts +9 -3
  3. package/dist/schemas/actor-persist/v3.ts +280 -0
  4. package/dist/schemas/client-protocol/v1.ts +6 -0
  5. package/dist/schemas/client-protocol/v2.ts +438 -0
  6. package/dist/schemas/file-system-driver/v1.ts +6 -0
  7. package/dist/schemas/file-system-driver/v2.ts +142 -0
  8. package/dist/tsup/actor/errors.cjs +2 -4
  9. package/dist/tsup/actor/errors.cjs.map +1 -1
  10. package/dist/tsup/actor/errors.d.cts +7 -10
  11. package/dist/tsup/actor/errors.d.ts +7 -10
  12. package/dist/tsup/actor/errors.js +9 -11
  13. package/dist/tsup/{actor-router-consts-B3Lu87yJ.d.cts → actor-router-consts-DzI2szci.d.cts} +5 -9
  14. package/dist/tsup/{actor-router-consts-B3Lu87yJ.d.ts → actor-router-consts-DzI2szci.d.ts} +5 -9
  15. package/dist/tsup/{chunk-ZTH3KYFH.cjs → chunk-3FG5OJ3G.cjs} +3 -3
  16. package/dist/tsup/{chunk-ZTH3KYFH.cjs.map → chunk-3FG5OJ3G.cjs.map} +1 -1
  17. package/dist/tsup/{chunk-BLK27ES3.js → chunk-6JN6W6G3.js} +44 -56
  18. package/dist/tsup/chunk-6JN6W6G3.js.map +1 -0
  19. package/dist/tsup/chunk-7IBNNGQ2.js +514 -0
  20. package/dist/tsup/chunk-7IBNNGQ2.js.map +1 -0
  21. package/dist/tsup/{chunk-36JJ4IQB.cjs → chunk-AZATXPR4.cjs} +4 -8
  22. package/dist/tsup/chunk-AZATXPR4.cjs.map +1 -0
  23. package/dist/tsup/chunk-B7MENRD5.cjs +5694 -0
  24. package/dist/tsup/chunk-B7MENRD5.cjs.map +1 -0
  25. package/dist/tsup/{chunk-BOMZS2TJ.js → chunk-BBVFDEYD.js} +9 -9
  26. package/dist/tsup/chunk-BBVFDEYD.js.map +1 -0
  27. package/dist/tsup/{chunk-KSRXX3Z4.cjs → chunk-D6762AOA.cjs} +20 -25
  28. package/dist/tsup/chunk-D6762AOA.cjs.map +1 -0
  29. package/dist/tsup/{chunk-2JYPS5YM.cjs → chunk-E63WZNMR.cjs} +6 -6
  30. package/dist/tsup/chunk-E63WZNMR.cjs.map +1 -0
  31. package/dist/tsup/{chunk-YBG6R7LX.js → chunk-EDGN4OC7.js} +3 -7
  32. package/dist/tsup/chunk-EDGN4OC7.js.map +1 -0
  33. package/dist/tsup/{chunk-BYMKMOBS.js → chunk-FLOQ3UWM.js} +1844 -1681
  34. package/dist/tsup/chunk-FLOQ3UWM.js.map +1 -0
  35. package/dist/tsup/{chunk-7L65NNWP.cjs → chunk-H7GV5DIW.cjs} +187 -185
  36. package/dist/tsup/chunk-H7GV5DIW.cjs.map +1 -0
  37. package/dist/tsup/{chunk-227FEWMB.js → chunk-HZYZ7JSF.js} +3322 -2251
  38. package/dist/tsup/chunk-HZYZ7JSF.js.map +1 -0
  39. package/dist/tsup/{chunk-FX7TWFQR.js → chunk-IDJK7ILQ.js} +2 -6
  40. package/dist/tsup/chunk-IDJK7ILQ.js.map +1 -0
  41. package/dist/tsup/{chunk-VHGY7PU5.cjs → chunk-ILFXA4AL.cjs} +1900 -1737
  42. package/dist/tsup/chunk-ILFXA4AL.cjs.map +1 -0
  43. package/dist/tsup/chunk-MV6M3FDL.cjs +514 -0
  44. package/dist/tsup/chunk-MV6M3FDL.cjs.map +1 -0
  45. package/dist/tsup/{chunk-PLUN2NQT.js → chunk-NWBKMCWC.js} +189 -187
  46. package/dist/tsup/chunk-NWBKMCWC.js.map +1 -0
  47. package/dist/tsup/{chunk-CD33GT6Z.js → chunk-QIHBDXTO.js} +2 -2
  48. package/dist/tsup/{chunk-G64QUEDJ.js → chunk-W6RDS6NW.js} +23 -28
  49. package/dist/tsup/chunk-W6RDS6NW.js.map +1 -0
  50. package/dist/tsup/{chunk-INNFK746.cjs → chunk-WQU4M4ZC.cjs} +10 -14
  51. package/dist/tsup/chunk-WQU4M4ZC.cjs.map +1 -0
  52. package/dist/tsup/{chunk-SHVX2QUR.cjs → chunk-XKZA47XS.cjs} +17 -17
  53. package/dist/tsup/chunk-XKZA47XS.cjs.map +1 -0
  54. package/dist/tsup/{chunk-HHFKKVLR.cjs → chunk-YHWIOWVA.cjs} +45 -57
  55. package/dist/tsup/chunk-YHWIOWVA.cjs.map +1 -0
  56. package/dist/tsup/{chunk-YBHYXIP6.js → chunk-YVL6IRUM.js} +3 -3
  57. package/dist/tsup/chunk-YVL6IRUM.js.map +1 -0
  58. package/dist/tsup/client/mod.cjs +9 -9
  59. package/dist/tsup/client/mod.d.cts +5 -7
  60. package/dist/tsup/client/mod.d.ts +5 -7
  61. package/dist/tsup/client/mod.js +8 -8
  62. package/dist/tsup/common/log.cjs +3 -3
  63. package/dist/tsup/common/log.js +2 -2
  64. package/dist/tsup/common/websocket.cjs +4 -4
  65. package/dist/tsup/common/websocket.js +3 -3
  66. package/dist/tsup/{conn-B3Vhbgnd.d.ts → config-BRDYDraU.d.cts} +1119 -1047
  67. package/dist/tsup/{conn-DJWL3nGx.d.cts → config-Bo-blHpJ.d.ts} +1119 -1047
  68. package/dist/tsup/driver-helpers/mod.cjs +5 -13
  69. package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
  70. package/dist/tsup/driver-helpers/mod.d.cts +11 -9
  71. package/dist/tsup/driver-helpers/mod.d.ts +11 -9
  72. package/dist/tsup/driver-helpers/mod.js +14 -22
  73. package/dist/tsup/driver-test-suite/mod.cjs +474 -303
  74. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  75. package/dist/tsup/driver-test-suite/mod.d.cts +6 -9
  76. package/dist/tsup/driver-test-suite/mod.d.ts +6 -9
  77. package/dist/tsup/driver-test-suite/mod.js +1085 -914
  78. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  79. package/dist/tsup/inspector/mod.cjs +6 -6
  80. package/dist/tsup/inspector/mod.d.cts +5 -7
  81. package/dist/tsup/inspector/mod.d.ts +5 -7
  82. package/dist/tsup/inspector/mod.js +5 -5
  83. package/dist/tsup/mod.cjs +10 -16
  84. package/dist/tsup/mod.cjs.map +1 -1
  85. package/dist/tsup/mod.d.cts +23 -25
  86. package/dist/tsup/mod.d.ts +23 -25
  87. package/dist/tsup/mod.js +17 -23
  88. package/dist/tsup/test/mod.cjs +11 -11
  89. package/dist/tsup/test/mod.d.cts +4 -6
  90. package/dist/tsup/test/mod.d.ts +4 -6
  91. package/dist/tsup/test/mod.js +10 -10
  92. package/dist/tsup/utils.cjs +3 -5
  93. package/dist/tsup/utils.cjs.map +1 -1
  94. package/dist/tsup/utils.d.cts +1 -2
  95. package/dist/tsup/utils.d.ts +1 -2
  96. package/dist/tsup/utils.js +2 -4
  97. package/package.json +13 -6
  98. package/src/actor/config.ts +56 -44
  99. package/src/actor/conn/driver.ts +61 -0
  100. package/src/actor/conn/drivers/http.ts +17 -0
  101. package/src/actor/conn/drivers/raw-request.ts +24 -0
  102. package/src/actor/conn/drivers/raw-websocket.ts +65 -0
  103. package/src/actor/conn/drivers/websocket.ts +129 -0
  104. package/src/actor/conn/mod.ts +232 -0
  105. package/src/actor/conn/persisted.ts +81 -0
  106. package/src/actor/conn/state-manager.ts +196 -0
  107. package/src/actor/contexts/action.ts +23 -0
  108. package/src/actor/{context.ts → contexts/actor.ts} +19 -8
  109. package/src/actor/contexts/conn-init.ts +31 -0
  110. package/src/actor/contexts/conn.ts +48 -0
  111. package/src/actor/contexts/create-conn-state.ts +13 -0
  112. package/src/actor/contexts/on-before-connect.ts +13 -0
  113. package/src/actor/contexts/on-connect.ts +22 -0
  114. package/src/actor/contexts/request.ts +48 -0
  115. package/src/actor/contexts/websocket.ts +48 -0
  116. package/src/actor/definition.ts +3 -3
  117. package/src/actor/driver.ts +36 -5
  118. package/src/actor/errors.ts +19 -24
  119. package/src/actor/instance/connection-manager.ts +465 -0
  120. package/src/actor/instance/event-manager.ts +292 -0
  121. package/src/actor/instance/kv.ts +15 -0
  122. package/src/actor/instance/mod.ts +1107 -0
  123. package/src/actor/instance/persisted.ts +67 -0
  124. package/src/actor/instance/schedule-manager.ts +349 -0
  125. package/src/actor/instance/state-manager.ts +502 -0
  126. package/src/actor/mod.ts +13 -16
  127. package/src/actor/protocol/old.ts +131 -43
  128. package/src/actor/protocol/serde.ts +19 -4
  129. package/src/actor/router-endpoints.ts +61 -586
  130. package/src/actor/router-websocket-endpoints.ts +408 -0
  131. package/src/actor/router.ts +63 -197
  132. package/src/actor/schedule.ts +1 -1
  133. package/src/client/actor-conn.ts +183 -249
  134. package/src/client/actor-handle.ts +29 -6
  135. package/src/client/client.ts +0 -4
  136. package/src/client/config.ts +1 -4
  137. package/src/client/mod.ts +0 -1
  138. package/src/client/raw-utils.ts +3 -3
  139. package/src/client/utils.ts +85 -39
  140. package/src/common/actor-router-consts.ts +5 -12
  141. package/src/common/{inline-websocket-adapter2.ts → inline-websocket-adapter.ts} +26 -48
  142. package/src/common/log.ts +1 -1
  143. package/src/common/router.ts +28 -17
  144. package/src/common/utils.ts +2 -0
  145. package/src/driver-helpers/mod.ts +7 -10
  146. package/src/driver-helpers/utils.ts +18 -9
  147. package/src/driver-test-suite/mod.ts +26 -50
  148. package/src/driver-test-suite/test-inline-client-driver.ts +27 -51
  149. package/src/driver-test-suite/tests/actor-conn-hibernation.ts +150 -0
  150. package/src/driver-test-suite/tests/actor-conn-state.ts +1 -4
  151. package/src/driver-test-suite/tests/actor-conn.ts +5 -9
  152. package/src/driver-test-suite/tests/actor-destroy.ts +294 -0
  153. package/src/driver-test-suite/tests/actor-driver.ts +0 -7
  154. package/src/driver-test-suite/tests/actor-handle.ts +12 -12
  155. package/src/driver-test-suite/tests/actor-metadata.ts +1 -1
  156. package/src/driver-test-suite/tests/manager-driver.ts +1 -1
  157. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +8 -8
  158. package/src/driver-test-suite/tests/raw-http-request-properties.ts +6 -5
  159. package/src/driver-test-suite/tests/raw-http.ts +5 -5
  160. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +7 -7
  161. package/src/driver-test-suite/tests/request-access.ts +4 -4
  162. package/src/driver-test-suite/utils.ts +6 -10
  163. package/src/drivers/engine/actor-driver.ts +614 -424
  164. package/src/drivers/engine/mod.ts +0 -1
  165. package/src/drivers/file-system/actor.ts +24 -12
  166. package/src/drivers/file-system/global-state.ts +427 -37
  167. package/src/drivers/file-system/manager.ts +71 -83
  168. package/src/drivers/file-system/mod.ts +3 -0
  169. package/src/drivers/file-system/utils.ts +18 -8
  170. package/src/engine-process/mod.ts +38 -38
  171. package/src/inspector/utils.ts +7 -5
  172. package/src/manager/driver.ts +11 -4
  173. package/src/manager/gateway.ts +4 -29
  174. package/src/manager/protocol/mod.ts +0 -2
  175. package/src/manager/protocol/query.ts +0 -4
  176. package/src/manager/router.ts +67 -64
  177. package/src/manager-api/actors.ts +13 -0
  178. package/src/mod.ts +1 -3
  179. package/src/registry/mod.ts +20 -20
  180. package/src/registry/serve.ts +9 -14
  181. package/src/remote-manager-driver/actor-websocket-client.ts +1 -16
  182. package/src/remote-manager-driver/api-endpoints.ts +13 -1
  183. package/src/remote-manager-driver/api-utils.ts +8 -0
  184. package/src/remote-manager-driver/metadata.ts +58 -0
  185. package/src/remote-manager-driver/mod.ts +47 -62
  186. package/src/remote-manager-driver/ws-proxy.ts +1 -1
  187. package/src/schemas/actor-persist/mod.ts +1 -1
  188. package/src/schemas/actor-persist/versioned.ts +56 -31
  189. package/src/schemas/client-protocol/mod.ts +1 -1
  190. package/src/schemas/client-protocol/versioned.ts +41 -21
  191. package/src/schemas/client-protocol-zod/mod.ts +103 -0
  192. package/src/schemas/file-system-driver/mod.ts +1 -1
  193. package/src/schemas/file-system-driver/versioned.ts +42 -19
  194. package/src/serde.ts +33 -11
  195. package/src/test/mod.ts +7 -3
  196. package/src/utils/node.ts +173 -0
  197. package/src/utils.ts +0 -4
  198. package/dist/tsup/chunk-227FEWMB.js.map +0 -1
  199. package/dist/tsup/chunk-2JYPS5YM.cjs.map +0 -1
  200. package/dist/tsup/chunk-36JJ4IQB.cjs.map +0 -1
  201. package/dist/tsup/chunk-7L65NNWP.cjs.map +0 -1
  202. package/dist/tsup/chunk-BLK27ES3.js.map +0 -1
  203. package/dist/tsup/chunk-BOMZS2TJ.js.map +0 -1
  204. package/dist/tsup/chunk-BYMKMOBS.js.map +0 -1
  205. package/dist/tsup/chunk-FX7TWFQR.js.map +0 -1
  206. package/dist/tsup/chunk-G64QUEDJ.js.map +0 -1
  207. package/dist/tsup/chunk-HHFKKVLR.cjs.map +0 -1
  208. package/dist/tsup/chunk-INNFK746.cjs.map +0 -1
  209. package/dist/tsup/chunk-KSRXX3Z4.cjs.map +0 -1
  210. package/dist/tsup/chunk-O44LFKSB.cjs +0 -4623
  211. package/dist/tsup/chunk-O44LFKSB.cjs.map +0 -1
  212. package/dist/tsup/chunk-PLUN2NQT.js.map +0 -1
  213. package/dist/tsup/chunk-S4UJG7ZE.js +0 -1119
  214. package/dist/tsup/chunk-S4UJG7ZE.js.map +0 -1
  215. package/dist/tsup/chunk-SHVX2QUR.cjs.map +0 -1
  216. package/dist/tsup/chunk-VFB23BYZ.cjs +0 -1119
  217. package/dist/tsup/chunk-VFB23BYZ.cjs.map +0 -1
  218. package/dist/tsup/chunk-VHGY7PU5.cjs.map +0 -1
  219. package/dist/tsup/chunk-YBG6R7LX.js.map +0 -1
  220. package/dist/tsup/chunk-YBHYXIP6.js.map +0 -1
  221. package/src/actor/action.ts +0 -178
  222. package/src/actor/conn-drivers.ts +0 -216
  223. package/src/actor/conn-socket.ts +0 -8
  224. package/src/actor/conn.ts +0 -272
  225. package/src/actor/instance.ts +0 -2336
  226. package/src/actor/persisted.ts +0 -49
  227. package/src/actor/unstable-react.ts +0 -110
  228. package/src/driver-test-suite/tests/actor-reconnect.ts +0 -170
  229. package/src/drivers/engine/kv.ts +0 -3
  230. package/src/manager/hono-websocket-adapter.ts +0 -393
  231. /package/dist/tsup/{chunk-CD33GT6Z.js.map → chunk-QIHBDXTO.js.map} +0 -0
@@ -4,6 +4,7 @@ import invariant from "invariant";
4
4
  import { deserializeActorKey, serializeActorKey } from "@/actor/keys";
5
5
  import { generateRandomString } from "@/actor/utils";
6
6
  import type { ClientConfig } from "@/client/client";
7
+ import type { MetadataResponse } from "@/common/router";
7
8
  import { noopNext, stringifyError } from "@/common/utils";
8
9
  import type {
9
10
  ActorOutput,
@@ -11,6 +12,7 @@ import type {
11
12
  GetForIdInput,
12
13
  GetOrCreateWithKeyInput,
13
14
  GetWithKeyInput,
15
+ ListActorsInput,
14
16
  ManagerDisplayInformation,
15
17
  ManagerDriver,
16
18
  } from "@/driver-helpers/mod";
@@ -29,9 +31,11 @@ import {
29
31
  getActorByKey,
30
32
  getMetadata,
31
33
  getOrCreateActor,
34
+ listActorsByName,
32
35
  } from "./api-endpoints";
33
36
  import { EngineApiError, getEndpoint } from "./api-utils";
34
37
  import { logger } from "./log";
38
+ import { lookupMetadataCached } from "./metadata";
35
39
  import { createWebSocketProxy } from "./ws-proxy";
36
40
 
37
41
  // TODO:
@@ -48,9 +52,6 @@ import { createWebSocketProxy } from "./ws-proxy";
48
52
  // };
49
53
  // })();
50
54
 
51
- // Global cache to store metadata check promises for each endpoint
52
- const metadataCheckCache = new Map<string, Promise<void>>();
53
-
54
55
  export class RemoteManagerDriver implements ManagerDriver {
55
56
  #config: ClientConfig;
56
57
  #metadataPromise: Promise<void> | undefined;
@@ -63,64 +64,38 @@ export class RemoteManagerDriver implements ManagerDriver {
63
64
  logger().info(
64
65
  "detected next.js build phase, disabling health check",
65
66
  );
66
- runConfig.disableHealthCheck = true;
67
+ runConfig.disableMetadataLookup = true;
67
68
  }
68
69
 
69
- this.#config = runConfig;
70
+ // Clone config so we can mutate the endpoint in #metadataPromise
71
+ // NOTE: This is a shallow clone, so mutating nested properties will not do anything
72
+ this.#config = { ...runConfig };
70
73
 
71
74
  // Perform metadata check if enabled
72
- if (!runConfig.disableHealthCheck) {
73
- this.#metadataPromise = this.#performMetadataCheck(runConfig);
74
- this.#metadataPromise.catch((error) => {
75
- logger().error({
76
- msg: "metadata check failed",
77
- error:
78
- error instanceof Error ? error.message : String(error),
79
- });
80
- });
81
- }
82
- }
83
-
84
- async #performMetadataCheck(config: ClientConfig): Promise<void> {
85
- const endpoint = getEndpoint(config);
75
+ if (!runConfig.disableMetadataLookup) {
76
+ // This should never error, since it uses pRetry. If it does for
77
+ // any reason, we'll surface the error anywhere #metadataPromise is
78
+ // awaited.
79
+ this.#metadataPromise = lookupMetadataCached(this.#config).then(
80
+ (metadataData) => {
81
+ // Override endpoint for all future requests
82
+ if (metadataData.clientEndpoint) {
83
+ this.#config.endpoint = metadataData.clientEndpoint;
84
+ logger().info({
85
+ msg: "overriding cached client endpoint",
86
+ endpoint: metadataData.clientEndpoint,
87
+ });
88
+ }
86
89
 
87
- // Check if metadata check is already in progress or completed for this endpoint
88
- const existingPromise = metadataCheckCache.get(endpoint);
89
- if (existingPromise) {
90
- return existingPromise;
91
- }
92
-
93
- // Create and store the promise immediately to prevent racing requests
94
- const metadataCheckPromise = (async () => {
95
- try {
96
- const metadataData = await getMetadata(config);
97
-
98
- if (metadataData.clientEndpoint) {
99
90
  logger().info({
100
- msg: "received new client endpoint from metadata",
101
- endpoint: metadataData.clientEndpoint,
91
+ msg: "connected to rivetkit manager",
92
+ runtime: metadataData.runtime,
93
+ version: metadataData.version,
94
+ runner: metadataData.runner,
102
95
  });
103
- this.#config.endpoint = metadataData.clientEndpoint;
104
- }
105
-
106
- // Log successful metadata check with runtime and version info
107
- logger().info({
108
- msg: "connected to rivetkit manager",
109
- runtime: metadataData.runtime,
110
- version: metadataData.version,
111
- runner: metadataData.runner,
112
- });
113
- } catch (error) {
114
- logger().error({
115
- msg: "health check failed, validate the Rivet endpoint is configured correctly",
116
- endpoint,
117
- error: stringifyError(error),
118
- });
119
- }
120
- })();
121
-
122
- metadataCheckCache.set(endpoint, metadataCheckPromise);
123
- return metadataCheckPromise;
96
+ },
97
+ );
98
+ }
124
99
  }
125
100
 
126
101
  async getForId({
@@ -282,6 +257,24 @@ export class RemoteManagerDriver implements ManagerDriver {
282
257
  };
283
258
  }
284
259
 
260
+ async listActors({ c, name }: ListActorsInput): Promise<ActorOutput[]> {
261
+ // Wait for metadata check to complete if in progress
262
+ if (this.#metadataPromise) {
263
+ await this.#metadataPromise;
264
+ }
265
+
266
+ logger().debug({ msg: "listing actors via engine api", name });
267
+
268
+ const response = await listActorsByName(this.#config, name);
269
+
270
+ return response.actors.map((actor) => ({
271
+ actorId: actor.actor_id,
272
+ name: actor.name,
273
+ key: deserializeActorKey(actor.key),
274
+ createTs: actor.create_ts,
275
+ }));
276
+ }
277
+
285
278
  async destroyActor(actorId: string): Promise<void> {
286
279
  // Wait for metadata check to complete if in progress
287
280
  if (this.#metadataPromise) {
@@ -316,8 +309,6 @@ export class RemoteManagerDriver implements ManagerDriver {
316
309
  actorId: string,
317
310
  encoding: Encoding,
318
311
  params: unknown,
319
- connId?: string,
320
- connToken?: string,
321
312
  ): Promise<UniversalWebSocket> {
322
313
  // Wait for metadata check to complete if in progress
323
314
  if (this.#metadataPromise) {
@@ -330,8 +321,6 @@ export class RemoteManagerDriver implements ManagerDriver {
330
321
  actorId,
331
322
  encoding,
332
323
  params,
333
- connId,
334
- connToken,
335
324
  );
336
325
  }
337
326
 
@@ -358,8 +347,6 @@ export class RemoteManagerDriver implements ManagerDriver {
358
347
  actorId: string,
359
348
  encoding: Encoding,
360
349
  params: unknown,
361
- connId?: string,
362
- connToken?: string,
363
350
  ): Promise<Response> {
364
351
  // Wait for metadata check to complete if in progress
365
352
  if (this.#metadataPromise) {
@@ -385,8 +372,6 @@ export class RemoteManagerDriver implements ManagerDriver {
385
372
  this.#config,
386
373
  encoding,
387
374
  params,
388
- connId,
389
- connToken,
390
375
  );
391
376
  const args = await createWebSocketProxy(c, wsGuardUrl, protocols);
392
377
 
@@ -1,8 +1,8 @@
1
1
  import type { Context as HonoContext } from "hono";
2
2
  import type { WSContext } from "hono/ws";
3
+ import type { UpgradeWebSocketArgs } from "@/actor/router-websocket-endpoints";
3
4
  import { stringifyError } from "@/common/utils";
4
5
  import { importWebSocket } from "@/common/websocket";
5
- import type { UpgradeWebSocketArgs } from "@/mod";
6
6
  import { logger } from "./log";
7
7
 
8
8
  /**
@@ -1 +1 @@
1
- export * from "../../../dist/schemas/actor-persist/v2";
1
+ export * from "../../../dist/schemas/actor-persist/v3";
@@ -3,39 +3,64 @@ import {
3
3
  type MigrationFn,
4
4
  } from "@/common/versioned-data";
5
5
  import type * as v1 from "../../../dist/schemas/actor-persist/v1";
6
- import * as v2 from "../../../dist/schemas/actor-persist/v2";
6
+ import type * as v2 from "../../../dist/schemas/actor-persist/v2";
7
+ import * as v3 from "../../../dist/schemas/actor-persist/v3";
7
8
 
8
- export const CURRENT_VERSION = 2;
9
+ export const CURRENT_VERSION = 3;
9
10
 
10
- export type CurrentPersistedActor = v2.PersistedActor;
11
- export type CurrentPersistedConnection = v2.PersistedConnection;
12
- export type CurrentPersistedSubscription = v2.PersistedSubscription;
13
- export type CurrentGenericPersistedScheduleEvent =
14
- v2.GenericPersistedScheduleEvent;
15
- export type CurrentPersistedScheduleEventKind = v2.PersistedScheduleEventKind;
16
- export type CurrentPersistedScheduleEvent = v2.PersistedScheduleEvent;
17
- export type CurrentPersistedHibernatableWebSocket =
18
- v2.PersistedHibernatableWebSocket;
11
+ const migrations = new Map<number, MigrationFn<any, any>>([
12
+ [
13
+ 1,
14
+ (v1Data: v1.PersistedActor): v2.PersistedActor => ({
15
+ ...v1Data,
16
+ connections: v1Data.connections.map((conn) => ({
17
+ ...conn,
18
+ hibernatableRequestId: null,
19
+ })),
20
+ hibernatableWebSockets: [],
21
+ }),
22
+ ],
23
+ [
24
+ 2,
25
+ (v2Data: v2.PersistedActor): v3.Actor => {
26
+ // Transform scheduled events from nested structure to flat structure
27
+ const scheduledEvents: v3.ScheduleEvent[] =
28
+ v2Data.scheduledEvents.map((event) => {
29
+ // Extract action and args from the kind wrapper
30
+ if (event.kind.tag === "GenericPersistedScheduleEvent") {
31
+ return {
32
+ eventId: event.eventId,
33
+ timestamp: event.timestamp,
34
+ action: event.kind.val.action,
35
+ args: event.kind.val.args,
36
+ };
37
+ }
38
+ // Fallback for unknown kinds
39
+ throw new Error(
40
+ `Unknown schedule event kind: ${event.kind.tag}`,
41
+ );
42
+ });
19
43
 
20
- const migrations = new Map<number, MigrationFn<any, any>>();
44
+ return {
45
+ input: v2Data.input,
46
+ hasInitialized: v2Data.hasInitialized,
47
+ state: v2Data.state,
48
+ scheduledEvents,
49
+ };
50
+ },
51
+ ],
52
+ ]);
21
53
 
22
- // Migration from v1 to v2: Add hibernatableWebSocket field
23
- migrations.set(
24
- 1,
25
- (v1Data: v1.PersistedActor): v2.PersistedActor => ({
26
- ...v1Data,
27
- connections: v1Data.connections.map((conn) => ({
28
- ...conn,
29
- hibernatableRequestId: null,
30
- })),
31
- hibernatableWebSocket: [],
32
- }),
33
- );
54
+ export const ACTOR_VERSIONED = createVersionedDataHandler<v3.Actor>({
55
+ currentVersion: CURRENT_VERSION,
56
+ migrations,
57
+ serializeVersion: (data) => v3.encodeActor(data),
58
+ deserializeVersion: (bytes) => v3.decodeActor(bytes),
59
+ });
34
60
 
35
- export const PERSISTED_ACTOR_VERSIONED =
36
- createVersionedDataHandler<CurrentPersistedActor>({
37
- currentVersion: CURRENT_VERSION,
38
- migrations,
39
- serializeVersion: (data) => v2.encodePersistedActor(data),
40
- deserializeVersion: (bytes) => v2.decodePersistedActor(bytes),
41
- });
61
+ export const CONN_VERSIONED = createVersionedDataHandler<v3.Conn>({
62
+ currentVersion: CURRENT_VERSION,
63
+ migrations: new Map(),
64
+ serializeVersion: (data) => v3.encodeConn(data),
65
+ deserializeVersion: (bytes) => v3.decodeConn(bytes),
66
+ });
@@ -1 +1 @@
1
- export * from "../../../dist/schemas/client-protocol/v1";
1
+ export * from "../../../dist/schemas/client-protocol/v2";
@@ -2,52 +2,72 @@ import {
2
2
  createVersionedDataHandler,
3
3
  type MigrationFn,
4
4
  } from "@/common/versioned-data";
5
- import * as v1 from "../../../dist/schemas/client-protocol/v1";
5
+ import type * as v1 from "../../../dist/schemas/client-protocol/v1";
6
+ import * as v2 from "../../../dist/schemas/client-protocol/v2";
6
7
 
7
- export const CURRENT_VERSION = 1;
8
+ export const CURRENT_VERSION = 2;
8
9
 
9
10
  const migrations = new Map<number, MigrationFn<any, any>>();
10
11
 
11
- export const TO_SERVER_VERSIONED = createVersionedDataHandler<v1.ToServer>({
12
+ // Migration from v1 to v2: Remove connectionToken from Init message
13
+ migrations.set(1, (v1Data: v1.ToClient): v2.ToClient => {
14
+ // Handle Init message specifically to remove connectionToken
15
+ if (v1Data.body.tag === "Init") {
16
+ const { actorId, connectionId } = v1Data.body.val as v1.Init;
17
+ return {
18
+ body: {
19
+ tag: "Init",
20
+ val: {
21
+ actorId,
22
+ connectionId,
23
+ },
24
+ },
25
+ };
26
+ }
27
+ // All other messages are unchanged
28
+ return v1Data as unknown as v2.ToClient;
29
+ });
30
+
31
+ export const TO_SERVER_VERSIONED = createVersionedDataHandler<v2.ToServer>({
12
32
  currentVersion: CURRENT_VERSION,
13
33
  migrations,
14
- serializeVersion: (data) => v1.encodeToServer(data),
15
- deserializeVersion: (bytes) => v1.decodeToServer(bytes),
34
+ serializeVersion: (data) => v2.encodeToServer(data),
35
+ deserializeVersion: (bytes) => v2.decodeToServer(bytes),
16
36
  });
17
37
 
18
- export const TO_CLIENT_VERSIONED = createVersionedDataHandler<v1.ToClient>({
38
+ export const TO_CLIENT_VERSIONED = createVersionedDataHandler<v2.ToClient>({
19
39
  currentVersion: CURRENT_VERSION,
20
40
  migrations,
21
- serializeVersion: (data) => v1.encodeToClient(data),
22
- deserializeVersion: (bytes) => v1.decodeToClient(bytes),
41
+ serializeVersion: (data) => v2.encodeToClient(data),
42
+ deserializeVersion: (bytes) => v2.decodeToClient(bytes),
23
43
  });
24
44
 
25
45
  export const HTTP_ACTION_REQUEST_VERSIONED =
26
- createVersionedDataHandler<v1.HttpActionRequest>({
46
+ createVersionedDataHandler<v2.HttpActionRequest>({
27
47
  currentVersion: CURRENT_VERSION,
28
48
  migrations,
29
- serializeVersion: (data) => v1.encodeHttpActionRequest(data),
30
- deserializeVersion: (bytes) => v1.decodeHttpActionRequest(bytes),
49
+ serializeVersion: (data) => v2.encodeHttpActionRequest(data),
50
+ deserializeVersion: (bytes) => v2.decodeHttpActionRequest(bytes),
31
51
  });
32
52
 
33
53
  export const HTTP_ACTION_RESPONSE_VERSIONED =
34
- createVersionedDataHandler<v1.HttpActionResponse>({
54
+ createVersionedDataHandler<v2.HttpActionResponse>({
35
55
  currentVersion: CURRENT_VERSION,
36
56
  migrations,
37
- serializeVersion: (data) => v1.encodeHttpActionResponse(data),
38
- deserializeVersion: (bytes) => v1.decodeHttpActionResponse(bytes),
57
+ serializeVersion: (data) => v2.encodeHttpActionResponse(data),
58
+ deserializeVersion: (bytes) => v2.decodeHttpActionResponse(bytes),
39
59
  });
40
60
 
41
61
  export const HTTP_RESPONSE_ERROR_VERSIONED =
42
- createVersionedDataHandler<v1.HttpResponseError>({
62
+ createVersionedDataHandler<v2.HttpResponseError>({
43
63
  currentVersion: CURRENT_VERSION,
44
64
  migrations,
45
- serializeVersion: (data) => v1.encodeHttpResponseError(data),
46
- deserializeVersion: (bytes) => v1.decodeHttpResponseError(bytes),
65
+ serializeVersion: (data) => v2.encodeHttpResponseError(data),
66
+ deserializeVersion: (bytes) => v2.decodeHttpResponseError(bytes),
47
67
  });
48
68
 
49
69
  export const HTTP_RESOLVE_REQUEST_VERSIONED =
50
- createVersionedDataHandler<v1.HttpResolveRequest>({
70
+ createVersionedDataHandler<v2.HttpResolveRequest>({
51
71
  currentVersion: CURRENT_VERSION,
52
72
  migrations,
53
73
  serializeVersion: (_) => new Uint8Array(),
@@ -55,9 +75,9 @@ export const HTTP_RESOLVE_REQUEST_VERSIONED =
55
75
  });
56
76
 
57
77
  export const HTTP_RESOLVE_RESPONSE_VERSIONED =
58
- createVersionedDataHandler<v1.HttpResolveResponse>({
78
+ createVersionedDataHandler<v2.HttpResolveResponse>({
59
79
  currentVersion: CURRENT_VERSION,
60
80
  migrations,
61
- serializeVersion: (data) => v1.encodeHttpResolveResponse(data),
62
- deserializeVersion: (bytes) => v1.decodeHttpResolveResponse(bytes),
81
+ serializeVersion: (data) => v2.encodeHttpResolveResponse(data),
82
+ deserializeVersion: (bytes) => v2.decodeHttpResolveResponse(bytes),
63
83
  });
@@ -0,0 +1,103 @@
1
+ import { z } from "zod";
2
+
3
+ // Helper schemas
4
+ const UintSchema = z.bigint();
5
+ const OptionalUintSchema = UintSchema.nullable();
6
+
7
+ // MARK: Message To Client
8
+ export const InitSchema = z.object({
9
+ actorId: z.string(),
10
+ connectionId: z.string(),
11
+ });
12
+ export type Init = z.infer<typeof InitSchema>;
13
+
14
+ export const ErrorSchema = z.object({
15
+ group: z.string(),
16
+ code: z.string(),
17
+ message: z.string(),
18
+ metadata: z.unknown().optional(),
19
+ actionId: OptionalUintSchema,
20
+ });
21
+ export type Error = z.infer<typeof ErrorSchema>;
22
+
23
+ export const ActionResponseSchema = z.object({
24
+ id: UintSchema,
25
+ output: z.unknown(),
26
+ });
27
+ export type ActionResponse = z.infer<typeof ActionResponseSchema>;
28
+
29
+ export const EventSchema = z.object({
30
+ name: z.string(),
31
+ args: z.unknown(),
32
+ });
33
+ export type Event = z.infer<typeof EventSchema>;
34
+
35
+ export const ToClientBodySchema = z.discriminatedUnion("tag", [
36
+ z.object({ tag: z.literal("Init"), val: InitSchema }),
37
+ z.object({ tag: z.literal("Error"), val: ErrorSchema }),
38
+ z.object({ tag: z.literal("ActionResponse"), val: ActionResponseSchema }),
39
+ z.object({ tag: z.literal("Event"), val: EventSchema }),
40
+ ]);
41
+ export type ToClientBody = z.infer<typeof ToClientBodySchema>;
42
+
43
+ export const ToClientSchema = z.object({
44
+ body: ToClientBodySchema,
45
+ });
46
+ export type ToClient = z.infer<typeof ToClientSchema>;
47
+
48
+ // MARK: Message To Server
49
+ export const ActionRequestSchema = z.object({
50
+ id: UintSchema,
51
+ name: z.string(),
52
+ args: z.unknown(),
53
+ });
54
+ export type ActionRequest = z.infer<typeof ActionRequestSchema>;
55
+
56
+ export const SubscriptionRequestSchema = z.object({
57
+ eventName: z.string(),
58
+ subscribe: z.boolean(),
59
+ });
60
+ export type SubscriptionRequest = z.infer<typeof SubscriptionRequestSchema>;
61
+
62
+ export const ToServerBodySchema = z.discriminatedUnion("tag", [
63
+ z.object({ tag: z.literal("ActionRequest"), val: ActionRequestSchema }),
64
+ z.object({
65
+ tag: z.literal("SubscriptionRequest"),
66
+ val: SubscriptionRequestSchema,
67
+ }),
68
+ ]);
69
+ export type ToServerBody = z.infer<typeof ToServerBodySchema>;
70
+
71
+ export const ToServerSchema = z.object({
72
+ body: ToServerBodySchema,
73
+ });
74
+ export type ToServer = z.infer<typeof ToServerSchema>;
75
+
76
+ // MARK: HTTP Action
77
+ export const HttpActionRequestSchema = z.object({
78
+ args: z.unknown(),
79
+ });
80
+ export type HttpActionRequest = z.infer<typeof HttpActionRequestSchema>;
81
+
82
+ export const HttpActionResponseSchema = z.object({
83
+ output: z.unknown(),
84
+ });
85
+ export type HttpActionResponse = z.infer<typeof HttpActionResponseSchema>;
86
+
87
+ // MARK: HTTP Error
88
+ export const HttpResponseErrorSchema = z.object({
89
+ group: z.string(),
90
+ code: z.string(),
91
+ message: z.string(),
92
+ metadata: z.unknown().optional(),
93
+ });
94
+ export type HttpResponseError = z.infer<typeof HttpResponseErrorSchema>;
95
+
96
+ // MARK: HTTP Resolve
97
+ export const HttpResolveRequestSchema = z.null();
98
+ export type HttpResolveRequest = z.infer<typeof HttpResolveRequestSchema>;
99
+
100
+ export const HttpResolveResponseSchema = z.object({
101
+ actorId: z.string(),
102
+ });
103
+ export type HttpResolveResponse = z.infer<typeof HttpResolveResponseSchema>;
@@ -1 +1 @@
1
- export * from "../../../dist/schemas/file-system-driver/v1";
1
+ export * from "../../../dist/schemas/file-system-driver/v2";
@@ -2,27 +2,50 @@ import {
2
2
  createVersionedDataHandler,
3
3
  type MigrationFn,
4
4
  } from "@/common/versioned-data";
5
- import * as v1 from "../../../dist/schemas/file-system-driver/v1";
5
+ import { bufferToArrayBuffer } from "@/utils";
6
+ import type * as v1 from "../../../dist/schemas/file-system-driver/v1";
7
+ import * as v2 from "../../../dist/schemas/file-system-driver/v2";
6
8
 
7
- export const CURRENT_VERSION = 1;
9
+ export const CURRENT_VERSION = 2;
8
10
 
9
- export type CurrentActorState = v1.ActorState;
10
- export type CurrentActorAlarm = v1.ActorAlarm;
11
+ const migrations = new Map<number, MigrationFn<any, any>>([
12
+ [
13
+ 2,
14
+ (v1State: v1.ActorState): v2.ActorState => {
15
+ // Create a new kvStorage list with the legacy persist data
16
+ const kvStorage: v2.ActorKvEntry[] = [];
11
17
 
12
- const migrations = new Map<number, MigrationFn<any, any>>();
18
+ // Store the legacy persist data under key [1]
19
+ if (v1State.persistedData) {
20
+ // Key [1] as Uint8Array
21
+ const key = new Uint8Array([1]);
22
+ kvStorage.push({
23
+ key: bufferToArrayBuffer(key),
24
+ value: v1State.persistedData,
25
+ });
26
+ }
13
27
 
14
- export const ACTOR_STATE_VERSIONED =
15
- createVersionedDataHandler<CurrentActorState>({
16
- currentVersion: CURRENT_VERSION,
17
- migrations,
18
- serializeVersion: (data) => v1.encodeActorState(data),
19
- deserializeVersion: (bytes) => v1.decodeActorState(bytes),
20
- });
28
+ return {
29
+ actorId: v1State.actorId,
30
+ name: v1State.name,
31
+ key: v1State.key,
32
+ kvStorage,
33
+ createdAt: v1State.createdAt,
34
+ };
35
+ },
36
+ ],
37
+ ]);
21
38
 
22
- export const ACTOR_ALARM_VERSIONED =
23
- createVersionedDataHandler<CurrentActorAlarm>({
24
- currentVersion: CURRENT_VERSION,
25
- migrations,
26
- serializeVersion: (data) => v1.encodeActorAlarm(data),
27
- deserializeVersion: (bytes) => v1.decodeActorAlarm(bytes),
28
- });
39
+ export const ACTOR_STATE_VERSIONED = createVersionedDataHandler<v2.ActorState>({
40
+ currentVersion: CURRENT_VERSION,
41
+ migrations,
42
+ serializeVersion: (data) => v2.encodeActorState(data),
43
+ deserializeVersion: (bytes) => v2.decodeActorState(bytes),
44
+ });
45
+
46
+ export const ACTOR_ALARM_VERSIONED = createVersionedDataHandler<v2.ActorAlarm>({
47
+ currentVersion: CURRENT_VERSION,
48
+ migrations,
49
+ serializeVersion: (data) => v2.encodeActorAlarm(data),
50
+ deserializeVersion: (bytes) => v2.decodeActorAlarm(bytes),
51
+ });
package/src/serde.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as cbor from "cbor-x";
2
2
  import invariant from "invariant";
3
+ import type { z } from "zod";
3
4
  import { assertUnreachable } from "@/common/utils";
4
5
  import type { VersionedDataHandler } from "@/common/versioned-data";
5
6
  import type { Encoding } from "@/mod";
@@ -52,46 +53,65 @@ export function wsBinaryTypeForEncoding(
52
53
  }
53
54
  }
54
55
 
55
- export function serializeWithEncoding<T>(
56
+ export function serializeWithEncoding<TBare, TJson, T = TBare>(
56
57
  encoding: Encoding,
57
58
  value: T,
58
- versionedDataHandler: VersionedDataHandler<T> | undefined,
59
+ versionedDataHandler: VersionedDataHandler<TBare> | undefined,
60
+ zodSchema: z.ZodType<TJson>,
61
+ toJson: (value: T) => TJson,
62
+ toBare: (value: T) => TBare,
59
63
  ): Uint8Array | string {
60
64
  if (encoding === "json") {
61
- return jsonStringifyCompat(value);
65
+ const jsonValue = toJson(value);
66
+ const validated = zodSchema.parse(jsonValue);
67
+ return jsonStringifyCompat(validated);
62
68
  } else if (encoding === "cbor") {
63
- return cbor.encode(value);
69
+ const jsonValue = toJson(value);
70
+ const validated = zodSchema.parse(jsonValue);
71
+ return cbor.encode(validated);
64
72
  } else if (encoding === "bare") {
65
73
  if (!versionedDataHandler) {
66
74
  throw new Error(
67
75
  "VersionedDataHandler is required for 'bare' encoding",
68
76
  );
69
77
  }
70
- return versionedDataHandler.serializeWithEmbeddedVersion(value);
78
+ const bareValue = toBare(value);
79
+ return versionedDataHandler.serializeWithEmbeddedVersion(bareValue);
71
80
  } else {
72
81
  assertUnreachable(encoding);
73
82
  }
74
83
  }
75
84
 
76
- export function deserializeWithEncoding<T>(
85
+ export function deserializeWithEncoding<TBare, TJson, T = TBare>(
77
86
  encoding: Encoding,
78
87
  buffer: Uint8Array | string,
79
- versionedDataHandler: VersionedDataHandler<T> | undefined,
88
+ versionedDataHandler: VersionedDataHandler<TBare> | undefined,
89
+ zodSchema: z.ZodType<TJson>,
90
+ fromJson: (value: TJson) => T,
91
+ fromBare: (value: TBare) => T,
80
92
  ): T {
81
93
  if (encoding === "json") {
94
+ let parsed: unknown;
82
95
  if (typeof buffer === "string") {
83
- return jsonParseCompat(buffer);
96
+ parsed = jsonParseCompat(buffer);
84
97
  } else {
85
98
  const decoder = new TextDecoder("utf-8");
86
99
  const jsonString = decoder.decode(buffer);
87
- return jsonParseCompat(jsonString);
100
+ parsed = jsonParseCompat(jsonString);
88
101
  }
102
+ const validated = zodSchema.parse(parsed);
103
+ return fromJson(validated);
89
104
  } else if (encoding === "cbor") {
90
105
  invariant(
91
106
  typeof buffer !== "string",
92
107
  "buffer cannot be string for cbor encoding",
93
108
  );
94
- return cbor.decode(buffer);
109
+ // Decode CBOR to get JavaScript values (similar to JSON.parse)
110
+ const decoded: unknown = cbor.decode(buffer);
111
+ // Validate with Zod schema (CBOR produces same structure as JSON)
112
+ const validated = zodSchema.parse(decoded);
113
+ // CBOR decoding produces JS objects, use fromJson
114
+ return fromJson(validated);
95
115
  } else if (encoding === "bare") {
96
116
  invariant(
97
117
  typeof buffer !== "string",
@@ -102,7 +122,9 @@ export function deserializeWithEncoding<T>(
102
122
  "VersionedDataHandler is required for 'bare' encoding",
103
123
  );
104
124
  }
105
- return versionedDataHandler.deserializeWithEmbeddedVersion(buffer);
125
+ const bareValue =
126
+ versionedDataHandler.deserializeWithEmbeddedVersion(buffer);
127
+ return fromBare(bareValue);
106
128
  } else {
107
129
  assertUnreachable(encoding);
108
130
  }