rivetkit 2.0.1 → 2.0.3

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 (253) hide show
  1. package/dist/schemas/actor-persist/v1.ts +228 -0
  2. package/dist/schemas/client-protocol/v1.ts +429 -0
  3. package/dist/schemas/file-system-driver/v1.ts +102 -0
  4. package/dist/tsup/actor/errors.cjs +69 -0
  5. package/dist/tsup/actor/errors.cjs.map +1 -0
  6. package/dist/tsup/actor/errors.d.cts +143 -0
  7. package/dist/tsup/actor/errors.d.ts +143 -0
  8. package/dist/tsup/actor/errors.js +69 -0
  9. package/dist/tsup/actor/errors.js.map +1 -0
  10. package/dist/tsup/chunk-2CRLFV6Z.cjs +202 -0
  11. package/dist/tsup/chunk-2CRLFV6Z.cjs.map +1 -0
  12. package/dist/tsup/chunk-3H7O2A7I.js +525 -0
  13. package/dist/tsup/chunk-3H7O2A7I.js.map +1 -0
  14. package/dist/tsup/chunk-42I3OZ3Q.js +15 -0
  15. package/dist/tsup/chunk-42I3OZ3Q.js.map +1 -0
  16. package/dist/tsup/chunk-4NSUQZ2H.js +1790 -0
  17. package/dist/tsup/chunk-4NSUQZ2H.js.map +1 -0
  18. package/dist/tsup/chunk-6PDXBYI5.js +132 -0
  19. package/dist/tsup/chunk-6PDXBYI5.js.map +1 -0
  20. package/dist/tsup/chunk-6WKQDDUD.cjs +1790 -0
  21. package/dist/tsup/chunk-6WKQDDUD.cjs.map +1 -0
  22. package/dist/tsup/chunk-CTBOSFUH.cjs +116 -0
  23. package/dist/tsup/chunk-CTBOSFUH.cjs.map +1 -0
  24. package/dist/tsup/chunk-EGVZZFE2.js +2857 -0
  25. package/dist/tsup/chunk-EGVZZFE2.js.map +1 -0
  26. package/dist/tsup/chunk-FCCPJNMA.cjs +132 -0
  27. package/dist/tsup/chunk-FCCPJNMA.cjs.map +1 -0
  28. package/dist/tsup/chunk-FLMTTN27.js +244 -0
  29. package/dist/tsup/chunk-FLMTTN27.js.map +1 -0
  30. package/dist/tsup/chunk-GIR3AFFI.cjs +315 -0
  31. package/dist/tsup/chunk-GIR3AFFI.cjs.map +1 -0
  32. package/dist/tsup/chunk-INGJP237.js +315 -0
  33. package/dist/tsup/chunk-INGJP237.js.map +1 -0
  34. package/dist/tsup/chunk-KJCJLKRM.js +116 -0
  35. package/dist/tsup/chunk-KJCJLKRM.js.map +1 -0
  36. package/dist/tsup/chunk-KUPQZYUQ.cjs +15 -0
  37. package/dist/tsup/chunk-KUPQZYUQ.cjs.map +1 -0
  38. package/dist/tsup/chunk-O2MBYIXO.cjs +2857 -0
  39. package/dist/tsup/chunk-O2MBYIXO.cjs.map +1 -0
  40. package/dist/tsup/chunk-OGAPU3UG.cjs +525 -0
  41. package/dist/tsup/chunk-OGAPU3UG.cjs.map +1 -0
  42. package/dist/tsup/chunk-OV6AYD4S.js +4406 -0
  43. package/dist/tsup/chunk-OV6AYD4S.js.map +1 -0
  44. package/dist/tsup/chunk-PO4VLDWA.js +47 -0
  45. package/dist/tsup/chunk-PO4VLDWA.js.map +1 -0
  46. package/dist/tsup/chunk-R2OPSKIV.cjs +244 -0
  47. package/dist/tsup/chunk-R2OPSKIV.cjs.map +1 -0
  48. package/dist/tsup/chunk-TZJKSBUQ.cjs +47 -0
  49. package/dist/tsup/chunk-TZJKSBUQ.cjs.map +1 -0
  50. package/dist/tsup/chunk-UBUC5C3G.cjs +189 -0
  51. package/dist/tsup/chunk-UBUC5C3G.cjs.map +1 -0
  52. package/dist/tsup/chunk-UIM22YJL.cjs +4406 -0
  53. package/dist/tsup/chunk-UIM22YJL.cjs.map +1 -0
  54. package/dist/tsup/chunk-URVFQMYI.cjs +230 -0
  55. package/dist/tsup/chunk-URVFQMYI.cjs.map +1 -0
  56. package/dist/tsup/chunk-UVUPOS46.js +230 -0
  57. package/dist/tsup/chunk-UVUPOS46.js.map +1 -0
  58. package/dist/tsup/chunk-VRRHBNJC.js +189 -0
  59. package/dist/tsup/chunk-VRRHBNJC.js.map +1 -0
  60. package/dist/tsup/chunk-XFSS33EQ.js +202 -0
  61. package/dist/tsup/chunk-XFSS33EQ.js.map +1 -0
  62. package/dist/tsup/client/mod.cjs +32 -0
  63. package/dist/tsup/client/mod.cjs.map +1 -0
  64. package/dist/tsup/client/mod.d.cts +26 -0
  65. package/dist/tsup/client/mod.d.ts +26 -0
  66. package/dist/tsup/client/mod.js +32 -0
  67. package/dist/tsup/client/mod.js.map +1 -0
  68. package/dist/tsup/common/log.cjs +13 -0
  69. package/dist/tsup/common/log.cjs.map +1 -0
  70. package/dist/tsup/common/log.d.cts +20 -0
  71. package/dist/tsup/common/log.d.ts +20 -0
  72. package/dist/tsup/common/log.js +13 -0
  73. package/dist/tsup/common/log.js.map +1 -0
  74. package/dist/tsup/common/websocket.cjs +10 -0
  75. package/dist/tsup/common/websocket.cjs.map +1 -0
  76. package/dist/tsup/common/websocket.d.cts +3 -0
  77. package/dist/tsup/common/websocket.d.ts +3 -0
  78. package/dist/tsup/common/websocket.js +10 -0
  79. package/dist/tsup/common/websocket.js.map +1 -0
  80. package/dist/tsup/common-CpqORuCq.d.cts +218 -0
  81. package/dist/tsup/common-CpqORuCq.d.ts +218 -0
  82. package/dist/tsup/connection-BR_Ve4ku.d.cts +2117 -0
  83. package/dist/tsup/connection-BwUMoe6n.d.ts +2117 -0
  84. package/dist/tsup/driver-helpers/mod.cjs +33 -0
  85. package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
  86. package/dist/tsup/driver-helpers/mod.d.cts +18 -0
  87. package/dist/tsup/driver-helpers/mod.d.ts +18 -0
  88. package/dist/tsup/driver-helpers/mod.js +33 -0
  89. package/dist/tsup/driver-helpers/mod.js.map +1 -0
  90. package/dist/tsup/driver-test-suite/mod.cjs +4619 -0
  91. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
  92. package/dist/tsup/driver-test-suite/mod.d.cts +57 -0
  93. package/dist/tsup/driver-test-suite/mod.d.ts +57 -0
  94. package/dist/tsup/driver-test-suite/mod.js +4619 -0
  95. package/dist/tsup/driver-test-suite/mod.js.map +1 -0
  96. package/dist/tsup/inspector/mod.cjs +53 -0
  97. package/dist/tsup/inspector/mod.cjs.map +1 -0
  98. package/dist/tsup/inspector/mod.d.cts +408 -0
  99. package/dist/tsup/inspector/mod.d.ts +408 -0
  100. package/dist/tsup/inspector/mod.js +53 -0
  101. package/dist/tsup/inspector/mod.js.map +1 -0
  102. package/dist/tsup/mod.cjs +73 -0
  103. package/dist/tsup/mod.cjs.map +1 -0
  104. package/dist/tsup/mod.d.cts +100 -0
  105. package/dist/tsup/mod.d.ts +100 -0
  106. package/dist/tsup/mod.js +73 -0
  107. package/dist/tsup/mod.js.map +1 -0
  108. package/dist/tsup/router-endpoints-AYkXG8Tl.d.cts +66 -0
  109. package/dist/tsup/router-endpoints-DAbqVFx2.d.ts +66 -0
  110. package/dist/tsup/test/mod.cjs +21 -0
  111. package/dist/tsup/test/mod.cjs.map +1 -0
  112. package/dist/tsup/test/mod.d.cts +27 -0
  113. package/dist/tsup/test/mod.d.ts +27 -0
  114. package/dist/tsup/test/mod.js +21 -0
  115. package/dist/tsup/test/mod.js.map +1 -0
  116. package/dist/tsup/utils-CT0cv4jd.d.cts +17 -0
  117. package/dist/tsup/utils-CT0cv4jd.d.ts +17 -0
  118. package/dist/tsup/utils.cjs +26 -0
  119. package/dist/tsup/utils.cjs.map +1 -0
  120. package/dist/tsup/utils.d.cts +36 -0
  121. package/dist/tsup/utils.d.ts +36 -0
  122. package/dist/tsup/utils.js +26 -0
  123. package/dist/tsup/utils.js.map +1 -0
  124. package/package.json +208 -5
  125. package/src/actor/action.ts +182 -0
  126. package/src/actor/config.ts +765 -0
  127. package/src/actor/connection.ts +260 -0
  128. package/src/actor/context.ts +171 -0
  129. package/src/actor/database.ts +23 -0
  130. package/src/actor/definition.ts +86 -0
  131. package/src/actor/driver.ts +84 -0
  132. package/src/actor/errors.ts +360 -0
  133. package/src/actor/generic-conn-driver.ts +234 -0
  134. package/src/actor/instance.ts +1800 -0
  135. package/src/actor/log.ts +15 -0
  136. package/src/actor/mod.ts +113 -0
  137. package/src/actor/persisted.ts +42 -0
  138. package/src/actor/protocol/old.ts +281 -0
  139. package/src/actor/protocol/serde.ts +131 -0
  140. package/src/actor/router-endpoints.ts +685 -0
  141. package/src/actor/router.ts +263 -0
  142. package/src/actor/schedule.ts +17 -0
  143. package/src/actor/unstable-react.ts +110 -0
  144. package/src/actor/utils.ts +98 -0
  145. package/src/client/actor-common.ts +30 -0
  146. package/src/client/actor-conn.ts +804 -0
  147. package/src/client/actor-handle.ts +208 -0
  148. package/src/client/client.ts +623 -0
  149. package/src/client/errors.ts +41 -0
  150. package/src/client/http-client-driver.ts +326 -0
  151. package/src/client/log.ts +7 -0
  152. package/src/client/mod.ts +56 -0
  153. package/src/client/raw-utils.ts +92 -0
  154. package/src/client/test.ts +44 -0
  155. package/src/client/utils.ts +150 -0
  156. package/src/common/eventsource-interface.ts +47 -0
  157. package/src/common/eventsource.ts +80 -0
  158. package/src/common/fake-event-source.ts +266 -0
  159. package/src/common/inline-websocket-adapter2.ts +445 -0
  160. package/src/common/log-levels.ts +27 -0
  161. package/src/common/log.ts +139 -0
  162. package/src/common/logfmt.ts +228 -0
  163. package/src/common/network.ts +2 -0
  164. package/src/common/router.ts +87 -0
  165. package/src/common/utils.ts +322 -0
  166. package/src/common/versioned-data.ts +95 -0
  167. package/src/common/websocket-interface.ts +49 -0
  168. package/src/common/websocket.ts +43 -0
  169. package/src/driver-helpers/mod.ts +22 -0
  170. package/src/driver-helpers/utils.ts +17 -0
  171. package/src/driver-test-suite/log.ts +7 -0
  172. package/src/driver-test-suite/mod.ts +213 -0
  173. package/src/driver-test-suite/test-inline-client-driver.ts +402 -0
  174. package/src/driver-test-suite/tests/action-features.ts +136 -0
  175. package/src/driver-test-suite/tests/actor-auth.ts +591 -0
  176. package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
  177. package/src/driver-test-suite/tests/actor-conn.ts +349 -0
  178. package/src/driver-test-suite/tests/actor-driver.ts +25 -0
  179. package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
  180. package/src/driver-test-suite/tests/actor-handle.ts +259 -0
  181. package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
  182. package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
  183. package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
  184. package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
  185. package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
  186. package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
  187. package/src/driver-test-suite/tests/actor-state.ts +54 -0
  188. package/src/driver-test-suite/tests/actor-vars.ts +93 -0
  189. package/src/driver-test-suite/tests/manager-driver.ts +365 -0
  190. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +226 -0
  191. package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
  192. package/src/driver-test-suite/tests/raw-http.ts +347 -0
  193. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +392 -0
  194. package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
  195. package/src/driver-test-suite/tests/request-access.ts +244 -0
  196. package/src/driver-test-suite/utils.ts +68 -0
  197. package/src/drivers/default.ts +31 -0
  198. package/src/drivers/engine/actor-driver.ts +360 -0
  199. package/src/drivers/engine/api-endpoints.ts +128 -0
  200. package/src/drivers/engine/api-utils.ts +70 -0
  201. package/src/drivers/engine/config.ts +39 -0
  202. package/src/drivers/engine/keys.test.ts +266 -0
  203. package/src/drivers/engine/keys.ts +89 -0
  204. package/src/drivers/engine/kv.ts +3 -0
  205. package/src/drivers/engine/log.ts +7 -0
  206. package/src/drivers/engine/manager-driver.ts +391 -0
  207. package/src/drivers/engine/mod.ts +36 -0
  208. package/src/drivers/engine/ws-proxy.ts +170 -0
  209. package/src/drivers/file-system/actor.ts +91 -0
  210. package/src/drivers/file-system/global-state.ts +673 -0
  211. package/src/drivers/file-system/log.ts +7 -0
  212. package/src/drivers/file-system/manager.ts +306 -0
  213. package/src/drivers/file-system/mod.ts +48 -0
  214. package/src/drivers/file-system/utils.ts +109 -0
  215. package/src/globals.d.ts +6 -0
  216. package/src/inline-client-driver/log.ts +7 -0
  217. package/src/inline-client-driver/mod.ts +385 -0
  218. package/src/inspector/actor.ts +298 -0
  219. package/src/inspector/config.ts +83 -0
  220. package/src/inspector/log.ts +5 -0
  221. package/src/inspector/manager.ts +86 -0
  222. package/src/inspector/mod.ts +2 -0
  223. package/src/inspector/protocol/actor.ts +10 -0
  224. package/src/inspector/protocol/common.ts +196 -0
  225. package/src/inspector/protocol/manager.ts +10 -0
  226. package/src/inspector/protocol/mod.ts +2 -0
  227. package/src/inspector/utils.ts +76 -0
  228. package/src/manager/auth.ts +121 -0
  229. package/src/manager/driver.ts +80 -0
  230. package/src/manager/hono-websocket-adapter.ts +333 -0
  231. package/src/manager/log.ts +7 -0
  232. package/src/manager/mod.ts +2 -0
  233. package/src/manager/protocol/mod.ts +24 -0
  234. package/src/manager/protocol/query.ts +89 -0
  235. package/src/manager/router.ts +1792 -0
  236. package/src/mod.ts +20 -0
  237. package/src/registry/config.ts +32 -0
  238. package/src/registry/log.ts +7 -0
  239. package/src/registry/mod.ts +124 -0
  240. package/src/registry/run-config.ts +54 -0
  241. package/src/registry/serve.ts +53 -0
  242. package/src/schemas/actor-persist/mod.ts +1 -0
  243. package/src/schemas/actor-persist/versioned.ts +25 -0
  244. package/src/schemas/client-protocol/mod.ts +1 -0
  245. package/src/schemas/client-protocol/versioned.ts +63 -0
  246. package/src/schemas/file-system-driver/mod.ts +1 -0
  247. package/src/schemas/file-system-driver/versioned.ts +28 -0
  248. package/src/serde.ts +84 -0
  249. package/src/test/config.ts +16 -0
  250. package/src/test/log.ts +7 -0
  251. package/src/test/mod.ts +153 -0
  252. package/src/utils.ts +172 -0
  253. package/README.md +0 -13
@@ -0,0 +1,326 @@
1
+ import * as cbor from "cbor-x";
2
+ import type { Context as HonoContext } from "hono";
3
+ import type { WebSocket } from "ws";
4
+ import type { Encoding } from "@/actor/protocol/serde";
5
+ import {
6
+ HEADER_ACTOR_ID,
7
+ HEADER_ACTOR_QUERY,
8
+ HEADER_CONN_ID,
9
+ HEADER_CONN_PARAMS,
10
+ HEADER_CONN_TOKEN,
11
+ HEADER_ENCODING,
12
+ } from "@/actor/router-endpoints";
13
+ import { importEventSource } from "@/common/eventsource";
14
+ import type { UniversalEventSource } from "@/common/eventsource-interface";
15
+ import { importWebSocket } from "@/common/websocket";
16
+ import type { ActorQuery } from "@/manager/protocol/query";
17
+ import type * as protocol from "@/schemas/client-protocol/mod";
18
+ import {
19
+ HTTP_ACTION_REQUEST_VERSIONED,
20
+ HTTP_ACTION_RESPONSE_VERSIONED,
21
+ HTTP_RESOLVE_REQUEST_VERSIONED,
22
+ HTTP_RESOLVE_RESPONSE_VERSIONED,
23
+ TO_SERVER_VERSIONED,
24
+ } from "@/schemas/client-protocol/versioned";
25
+ import { serializeWithEncoding, wsBinaryTypeForEncoding } from "@/serde";
26
+ import { assertUnreachable, bufferToArrayBuffer, httpUserAgent } from "@/utils";
27
+ import type { ClientDriver } from "./client";
28
+ import * as errors from "./errors";
29
+ import { logger } from "./log";
30
+ import { sendHttpRequest } from "./utils";
31
+
32
+ /**
33
+ * Client driver that communicates with the manager via HTTP.
34
+ */
35
+ export function createHttpClientDriver(managerEndpoint: string): ClientDriver {
36
+ // Lazily import the dynamic imports so we don't have to turn `createClient` in to an async fn
37
+ const dynamicImports = (async () => {
38
+ // Import dynamic dependencies
39
+ const [WebSocket, EventSource] = await Promise.all([
40
+ importWebSocket(),
41
+ importEventSource(),
42
+ ]);
43
+ return {
44
+ WebSocket,
45
+ EventSource,
46
+ };
47
+ })();
48
+
49
+ const driver: ClientDriver = {
50
+ action: async <Args extends Array<unknown> = unknown[], Response = unknown>(
51
+ _c: HonoContext | undefined,
52
+ actorQuery: ActorQuery,
53
+ encoding: Encoding,
54
+ params: unknown,
55
+ name: string,
56
+ args: Args,
57
+ opts: { signal?: AbortSignal } | undefined,
58
+ ): Promise<Response> => {
59
+ logger().debug("actor handle action", {
60
+ name,
61
+ args,
62
+ query: actorQuery,
63
+ });
64
+
65
+ const responseData = await sendHttpRequest<
66
+ protocol.HttpActionRequest,
67
+ protocol.HttpActionResponse
68
+ >({
69
+ url: `${managerEndpoint}/registry/actors/actions/${encodeURIComponent(name)}`,
70
+ method: "POST",
71
+ headers: {
72
+ [HEADER_ENCODING]: encoding,
73
+ [HEADER_ACTOR_QUERY]: JSON.stringify(actorQuery),
74
+ ...(params !== undefined
75
+ ? { [HEADER_CONN_PARAMS]: JSON.stringify(params) }
76
+ : {}),
77
+ },
78
+ body: {
79
+ args: bufferToArrayBuffer(cbor.encode(args)),
80
+ } satisfies protocol.HttpActionRequest,
81
+ encoding: encoding,
82
+ signal: opts?.signal,
83
+ requestVersionedDataHandler: HTTP_ACTION_REQUEST_VERSIONED,
84
+ responseVersionedDataHandler: HTTP_ACTION_RESPONSE_VERSIONED,
85
+ });
86
+
87
+ return cbor.decode(new Uint8Array(responseData.output));
88
+ },
89
+
90
+ resolveActorId: async (
91
+ _c: HonoContext | undefined,
92
+ actorQuery: ActorQuery,
93
+ encodingKind: Encoding,
94
+ params: unknown,
95
+ ): Promise<string> => {
96
+ logger().debug("resolving actor ID", { query: actorQuery });
97
+
98
+ try {
99
+ const result = await sendHttpRequest<
100
+ null,
101
+ protocol.HttpResolveResponse
102
+ >({
103
+ url: `${managerEndpoint}/registry/actors/resolve`,
104
+ method: "POST",
105
+ headers: {
106
+ [HEADER_ENCODING]: encodingKind,
107
+ [HEADER_ACTOR_QUERY]: JSON.stringify(actorQuery),
108
+ ...(params !== undefined
109
+ ? { [HEADER_CONN_PARAMS]: JSON.stringify(params) }
110
+ : {}),
111
+ },
112
+ body: null,
113
+ encoding: encodingKind,
114
+ requestVersionedDataHandler: HTTP_RESOLVE_REQUEST_VERSIONED,
115
+ responseVersionedDataHandler: HTTP_RESOLVE_RESPONSE_VERSIONED,
116
+ });
117
+
118
+ logger().debug("resolved actor ID", { actorId: result.actorId });
119
+ return result.actorId;
120
+ } catch (error) {
121
+ logger().error("failed to resolve actor ID", { error });
122
+ if (error instanceof errors.ActorError) {
123
+ throw error;
124
+ } else {
125
+ throw new errors.InternalError(
126
+ `Failed to resolve actor ID: ${String(error)}`,
127
+ );
128
+ }
129
+ }
130
+ },
131
+
132
+ connectWebSocket: async (
133
+ _c: HonoContext | undefined,
134
+ actorQuery: ActorQuery,
135
+ encodingKind: Encoding,
136
+ params: unknown,
137
+ ): Promise<WebSocket> => {
138
+ const { WebSocket } = await dynamicImports;
139
+
140
+ const endpoint = managerEndpoint
141
+ .replace(/^http:/, "ws:")
142
+ .replace(/^https:/, "wss:");
143
+ const url = `${endpoint}/registry/actors/connect/websocket`;
144
+
145
+ // Pass sensitive data via protocol
146
+ const protocol = [
147
+ `query.${encodeURIComponent(JSON.stringify(actorQuery))}`,
148
+ `encoding.${encodingKind}`,
149
+ ];
150
+ if (params)
151
+ protocol.push(
152
+ `conn_params.${encodeURIComponent(JSON.stringify(params))}`,
153
+ );
154
+
155
+ // HACK: See packages/drivers/cloudflare-workers/src/websocket.ts
156
+ protocol.push("rivetkit");
157
+
158
+ logger().debug("connecting to websocket", { url });
159
+ const ws = new WebSocket(url, protocol);
160
+ // HACK: Bun bug prevents changing binary type, so we ignore the error https://github.com/oven-sh/bun/issues/17005
161
+ try {
162
+ ws.binaryType = wsBinaryTypeForEncoding(encodingKind);
163
+ } catch (error) {}
164
+
165
+ // Node & web WebSocket types not compatible
166
+ return ws as any;
167
+ },
168
+
169
+ connectSse: async (
170
+ _c: HonoContext | undefined,
171
+ actorQuery: ActorQuery,
172
+ encodingKind: Encoding,
173
+ params: unknown,
174
+ ): Promise<UniversalEventSource> => {
175
+ const { EventSource } = await dynamicImports;
176
+
177
+ const url = `${managerEndpoint}/registry/actors/connect/sse`;
178
+
179
+ logger().debug("connecting to sse", { url });
180
+ const eventSource = new EventSource(url, {
181
+ fetch: (input, init) => {
182
+ return fetch(input, {
183
+ ...init,
184
+ headers: {
185
+ ...init?.headers,
186
+ "User-Agent": httpUserAgent(),
187
+ [HEADER_ENCODING]: encodingKind,
188
+ [HEADER_ACTOR_QUERY]: JSON.stringify(actorQuery),
189
+ ...(params !== undefined
190
+ ? { [HEADER_CONN_PARAMS]: JSON.stringify(params) }
191
+ : {}),
192
+ },
193
+ credentials: "include",
194
+ });
195
+ },
196
+ });
197
+
198
+ return eventSource as UniversalEventSource;
199
+ },
200
+
201
+ sendHttpMessage: async (
202
+ _c: HonoContext | undefined,
203
+ actorId: string,
204
+ encoding: Encoding,
205
+ connectionId: string,
206
+ connectionToken: string,
207
+ message: protocol.ToServer,
208
+ ): Promise<void> => {
209
+ // TODO: Implement ordered messages, this is not guaranteed order. Needs to use an index in order to ensure we can pipeline requests efficiently.
210
+ // TODO: Validate that we're using HTTP/3 whenever possible for pipelining requests
211
+ const messageSerialized = serializeWithEncoding(
212
+ encoding,
213
+ message,
214
+ TO_SERVER_VERSIONED,
215
+ );
216
+ const res = await fetch(`${managerEndpoint}/registry/actors/message`, {
217
+ method: "POST",
218
+ headers: {
219
+ "User-Agent": httpUserAgent(),
220
+ [HEADER_ENCODING]: encoding,
221
+ [HEADER_ACTOR_ID]: actorId,
222
+ [HEADER_CONN_ID]: connectionId,
223
+ [HEADER_CONN_TOKEN]: connectionToken,
224
+ },
225
+ body: messageSerialized,
226
+ credentials: "include",
227
+ });
228
+ if (!res.ok) {
229
+ throw new errors.InternalError(
230
+ `Publish message over HTTP error (${res.statusText}):\n${await res.text()}`,
231
+ );
232
+ }
233
+
234
+ // Discard response
235
+ await res.body?.cancel();
236
+ },
237
+
238
+ rawHttpRequest: async (
239
+ _c: HonoContext | undefined,
240
+ actorQuery: ActorQuery,
241
+ encoding: Encoding,
242
+ params: unknown,
243
+ path: string,
244
+ init: RequestInit,
245
+ ): Promise<Response> => {
246
+ // Build the full URL
247
+ // Remove leading slash from path to avoid double slashes
248
+ const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
249
+ const url = `${managerEndpoint}/registry/actors/raw/http/${normalizedPath}`;
250
+
251
+ logger().debug("rewriting http url", {
252
+ from: path,
253
+ to: url,
254
+ });
255
+
256
+ // Merge headers properly
257
+ const headers = new Headers(init.headers);
258
+ headers.set("User-Agent", httpUserAgent());
259
+ headers.set(HEADER_ACTOR_QUERY, JSON.stringify(actorQuery));
260
+ headers.set(HEADER_ENCODING, encoding);
261
+ if (params !== undefined) {
262
+ headers.set(HEADER_CONN_PARAMS, JSON.stringify(params));
263
+ }
264
+
265
+ // Forward the request with query in headers
266
+ return await fetch(url, {
267
+ ...init,
268
+ headers,
269
+ });
270
+ },
271
+
272
+ rawWebSocket: async (
273
+ _c: HonoContext | undefined,
274
+ actorQuery: ActorQuery,
275
+ encoding: Encoding,
276
+ params: unknown,
277
+ path: string,
278
+ protocols: string | string[] | undefined,
279
+ ): Promise<WebSocket> => {
280
+ const { WebSocket } = await dynamicImports;
281
+
282
+ // Build the WebSocket URL with normalized path
283
+ const wsEndpoint = managerEndpoint
284
+ .replace(/^http:/, "ws:")
285
+ .replace(/^https:/, "wss:");
286
+ // Normalize path to match raw HTTP behavior
287
+ const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
288
+ const url = `${wsEndpoint}/registry/actors/raw/websocket/${normalizedPath}`;
289
+
290
+ logger().debug("rewriting websocket url", {
291
+ from: path,
292
+ to: url,
293
+ });
294
+
295
+ // Pass data via WebSocket protocol subprotocols
296
+ const protocolList: string[] = [];
297
+ protocolList.push(
298
+ `query.${encodeURIComponent(JSON.stringify(actorQuery))}`,
299
+ );
300
+ protocolList.push(`encoding.${encoding}`);
301
+ if (params) {
302
+ protocolList.push(
303
+ `conn_params.${encodeURIComponent(JSON.stringify(params))}`,
304
+ );
305
+ }
306
+
307
+ // HACK: See packages/drivers/cloudflare-workers/src/websocket.ts
308
+ protocolList.push("rivetkit");
309
+
310
+ // Add user protocols
311
+ if (protocols) {
312
+ if (Array.isArray(protocols)) {
313
+ protocolList.push(...protocols);
314
+ } else {
315
+ protocolList.push(protocols);
316
+ }
317
+ }
318
+
319
+ // Create WebSocket connection
320
+ logger().debug("opening raw websocket", { url });
321
+ return new WebSocket(url, protocolList) as any;
322
+ },
323
+ };
324
+
325
+ return driver;
326
+ }
@@ -0,0 +1,7 @@
1
+ import { getLogger } from "@/common//log";
2
+
3
+ export const LOGGER_NAME = "actor-client";
4
+
5
+ export function logger() {
6
+ return getLogger(LOGGER_NAME);
7
+ }
@@ -0,0 +1,56 @@
1
+ import type { Registry } from "@/registry/mod";
2
+ import {
3
+ type Client,
4
+ type ClientOptions,
5
+ createClientWithDriver,
6
+ } from "./client";
7
+ import { createHttpClientDriver } from "./http-client-driver";
8
+
9
+ export {
10
+ ActorDefinition,
11
+ AnyActorDefinition,
12
+ } from "@/actor/definition";
13
+ export type { Transport } from "@/actor/protocol/old";
14
+ export type { Encoding } from "@/actor/protocol/serde";
15
+ export {
16
+ ActorClientError,
17
+ ActorError,
18
+ InternalError,
19
+ MalformedResponseMessage,
20
+ ManagerError,
21
+ } from "@/client/errors";
22
+ export type { CreateRequest } from "@/manager/protocol/query";
23
+ export type { ActorActionFunction } from "./actor-common";
24
+ export type { ActorConn, EventUnsubscribe } from "./actor-conn";
25
+ export { ActorConnRaw } from "./actor-conn";
26
+ export type { ActorHandle } from "./actor-handle";
27
+ export { ActorHandleRaw } from "./actor-handle";
28
+ export type {
29
+ ActorAccessor,
30
+ Client,
31
+ ClientOptions,
32
+ ClientRaw,
33
+ CreateOptions,
34
+ ExtractActorsFromRegistry,
35
+ ExtractRegistryFromClient,
36
+ GetOptions,
37
+ GetWithIdOptions,
38
+ QueryOptions,
39
+ Region,
40
+ } from "./client";
41
+
42
+ /**
43
+ * Creates a client with the actor accessor proxy.
44
+ *
45
+ * @template A The actor application type.
46
+ * @param {string} managerEndpoint - The manager endpoint.
47
+ * @param {ClientOptions} [opts] - Options for configuring the client.
48
+ * @returns {Client<A>} - A proxied client that supports the `client.myActor.connect()` syntax.
49
+ */
50
+ export function createClient<A extends Registry<any>>(
51
+ endpoint: string,
52
+ opts?: ClientOptions,
53
+ ): Client<A> {
54
+ const driver = createHttpClientDriver(endpoint);
55
+ return createClientWithDriver<A>(driver, opts);
56
+ }
@@ -0,0 +1,92 @@
1
+ import type { ActorQuery } from "@/manager/protocol/query";
2
+ import type { ClientDriver } from "./client";
3
+
4
+ /**
5
+ * Shared implementation for raw HTTP fetch requests
6
+ */
7
+ export async function rawHttpFetch(
8
+ driver: ClientDriver,
9
+ actorQuery: ActorQuery,
10
+ params: unknown,
11
+ input: string | URL | Request,
12
+ init?: RequestInit,
13
+ ): Promise<Response> {
14
+ // Extract path and merge init options
15
+ let path: string;
16
+ let mergedInit: RequestInit = init || {};
17
+
18
+ if (typeof input === "string") {
19
+ path = input;
20
+ } else if (input instanceof URL) {
21
+ path = input.pathname + input.search;
22
+ } else if (input instanceof Request) {
23
+ // Extract path from Request URL
24
+ const url = new URL(input.url);
25
+ path = url.pathname + url.search;
26
+ // Merge Request properties with init
27
+ const requestHeaders = new Headers(input.headers);
28
+ const initHeaders = new Headers(init?.headers || {});
29
+
30
+ // Merge headers - init headers override request headers
31
+ const mergedHeaders = new Headers(requestHeaders);
32
+ for (const [key, value] of initHeaders) {
33
+ mergedHeaders.set(key, value);
34
+ }
35
+
36
+ mergedInit = {
37
+ method: input.method,
38
+ body: input.body,
39
+ mode: input.mode,
40
+ credentials: input.credentials,
41
+ redirect: input.redirect,
42
+ referrer: input.referrer,
43
+ referrerPolicy: input.referrerPolicy,
44
+ integrity: input.integrity,
45
+ keepalive: input.keepalive,
46
+ signal: input.signal,
47
+ ...mergedInit, // init overrides Request properties
48
+ headers: mergedHeaders, // headers must be set after spread to ensure proper merge
49
+ };
50
+ // Add duplex if body is present
51
+ if (mergedInit.body) {
52
+ (mergedInit as any).duplex = "half";
53
+ }
54
+ } else {
55
+ throw new TypeError("Invalid input type for fetch");
56
+ }
57
+
58
+ // Use the driver's raw HTTP method - just pass the sub-path
59
+ return await driver.rawHttpRequest(
60
+ undefined,
61
+ actorQuery,
62
+ // Force JSON so it's readable by the user
63
+ "json",
64
+ params,
65
+ path,
66
+ mergedInit,
67
+ undefined,
68
+ );
69
+ }
70
+
71
+ /**
72
+ * Shared implementation for raw WebSocket connections
73
+ */
74
+ export async function rawWebSocket(
75
+ driver: ClientDriver,
76
+ actorQuery: ActorQuery,
77
+ params: unknown,
78
+ path?: string,
79
+ protocols?: string | string[],
80
+ ): Promise<any> {
81
+ // Use the driver's raw WebSocket method
82
+ return await driver.rawWebSocket(
83
+ undefined,
84
+ actorQuery,
85
+ // Force JSON so it's readable by the user
86
+ "json",
87
+ params,
88
+ path || "",
89
+ protocols,
90
+ undefined,
91
+ );
92
+ }
@@ -0,0 +1,44 @@
1
+ //import { exec as execCallback } from "node:child_process";
2
+ //import { setupLogging } from "@/common//log";
3
+ //import type { ClientOptions } from "./client";
4
+ //import { InternalError } from "./errors";
5
+ //import { Client } from "./mod.ts";
6
+ //
7
+ ///**
8
+ // * Uses the Rivet CLI to read the manager endpoint to connect to. This allows
9
+ // * for writing tests that run locally without hardcoding the manager endpoint.
10
+ // */
11
+ //export async function readEndpointFromCli(): Promise<string> {
12
+ // // Read endpoint
13
+ // const cliPath = process.env.RIVET_CLI_PATH ?? "rivet";
14
+ //
15
+ // try {
16
+ // const { stdout, stderr } = await new Promise<{
17
+ // stdout: string;
18
+ // stderr: string;
19
+ // }>((resolve, reject) => {
20
+ // execCallback(`${cliPath} manager endpoint`, (error, stdout, stderr) => {
21
+ // if (error) reject(error);
22
+ // else resolve({ stdout, stderr });
23
+ // });
24
+ // });
25
+ //
26
+ // if (stderr) {
27
+ // throw new Error(stderr);
28
+ // }
29
+ //
30
+ // // Decode output
31
+ // return stdout.trim();
32
+ // } catch (error) {
33
+ // throw new InternalError(`Read endpoint failed: ${error}`);
34
+ // }
35
+ //}
36
+ //
37
+ //export class TestClient extends Client {
38
+ // public constructor(opts?: ClientOptions) {
39
+ // // Setup logging automatically
40
+ // setupLogging();
41
+ //
42
+ // super(readEndpointFromCli(), opts);
43
+ // }
44
+ //}
@@ -0,0 +1,150 @@
1
+ import * as cbor from "cbor-x";
2
+ import invariant from "invariant";
3
+ import { assertUnreachable } from "@/common/utils";
4
+ import type { VersionedDataHandler } from "@/common/versioned-data";
5
+ import type { Encoding } from "@/mod";
6
+ import type { HttpResponseError } from "@/schemas/client-protocol/mod";
7
+ import { HTTP_RESPONSE_ERROR_VERSIONED } from "@/schemas/client-protocol/versioned";
8
+ import {
9
+ contentTypeForEncoding,
10
+ deserializeWithEncoding,
11
+ serializeWithEncoding,
12
+ } from "@/serde";
13
+ import { httpUserAgent } from "@/utils";
14
+ import { ActorError, HttpRequestError } from "./errors";
15
+ import { logger } from "./log";
16
+
17
+ export type WebSocketMessage = string | Blob | ArrayBuffer | Uint8Array;
18
+
19
+ export function messageLength(message: WebSocketMessage): number {
20
+ if (message instanceof Blob) {
21
+ return message.size;
22
+ }
23
+ if (message instanceof ArrayBuffer) {
24
+ return message.byteLength;
25
+ }
26
+ if (message instanceof Uint8Array) {
27
+ return message.byteLength;
28
+ }
29
+ if (typeof message === "string") {
30
+ return message.length;
31
+ }
32
+ assertUnreachable(message);
33
+ }
34
+
35
+ export interface HttpRequestOpts<RequestBody, ResponseBody> {
36
+ method: string;
37
+ url: string;
38
+ headers: Record<string, string>;
39
+ body?: RequestBody;
40
+ encoding: Encoding;
41
+ skipParseResponse?: boolean;
42
+ signal?: AbortSignal;
43
+ customFetch?: (req: Request) => Promise<Response>;
44
+ requestVersionedDataHandler: VersionedDataHandler<RequestBody>;
45
+ responseVersionedDataHandler: VersionedDataHandler<ResponseBody>;
46
+ }
47
+
48
+ export async function sendHttpRequest<
49
+ RequestBody = unknown,
50
+ ResponseBody = unknown,
51
+ >(opts: HttpRequestOpts<RequestBody, ResponseBody>): Promise<ResponseBody> {
52
+ logger().debug("sending http request", {
53
+ url: opts.url,
54
+ encoding: opts.encoding,
55
+ });
56
+
57
+ // Serialize body
58
+ let contentType: string | undefined;
59
+ let bodyData: string | Uint8Array | undefined;
60
+ if (opts.method === "POST" || opts.method === "PUT") {
61
+ invariant(opts.body !== undefined, "missing body");
62
+ contentType = contentTypeForEncoding(opts.encoding);
63
+ bodyData = serializeWithEncoding<RequestBody>(
64
+ opts.encoding,
65
+ opts.body,
66
+ opts.requestVersionedDataHandler,
67
+ );
68
+ }
69
+
70
+ // Send request
71
+ let response: Response;
72
+ try {
73
+ // Make the HTTP request
74
+ response = await (opts.customFetch ?? fetch)(
75
+ new Request(opts.url, {
76
+ method: opts.method,
77
+ headers: {
78
+ ...opts.headers,
79
+ ...(contentType
80
+ ? {
81
+ "Content-Type": contentType,
82
+ }
83
+ : {}),
84
+ "User-Agent": httpUserAgent(),
85
+ },
86
+ body: bodyData,
87
+ credentials: "include",
88
+ signal: opts.signal,
89
+ }),
90
+ );
91
+ } catch (error) {
92
+ throw new HttpRequestError(`Request failed: ${error}`, {
93
+ cause: error,
94
+ });
95
+ }
96
+
97
+ // Parse response error
98
+ if (!response.ok) {
99
+ // Attempt to parse structured data
100
+ const bufferResponse = await response.arrayBuffer();
101
+ let responseData: HttpResponseError;
102
+ try {
103
+ responseData = deserializeWithEncoding(
104
+ opts.encoding,
105
+ new Uint8Array(bufferResponse),
106
+ HTTP_RESPONSE_ERROR_VERSIONED,
107
+ );
108
+ } catch (error) {
109
+ //logger().warn("failed to cleanly parse error, this is likely because a non-structured response is being served", {
110
+ // error: stringifyError(error),
111
+ //});
112
+
113
+ // Error is not structured
114
+ const textResponse = new TextDecoder("utf-8", { fatal: false }).decode(
115
+ bufferResponse,
116
+ );
117
+ throw new HttpRequestError(
118
+ `${response.statusText} (${response.status}):\n${textResponse}`,
119
+ );
120
+ }
121
+
122
+ // Throw structured error
123
+ throw new ActorError(
124
+ responseData.code,
125
+ responseData.message,
126
+ responseData.metadata
127
+ ? cbor.decode(new Uint8Array(responseData.metadata))
128
+ : undefined,
129
+ );
130
+ }
131
+
132
+ // Some requests don't need the success response to be parsed, so this can speed things up
133
+ if (opts.skipParseResponse) {
134
+ return undefined as ResponseBody;
135
+ }
136
+
137
+ // Parse the response based on encoding
138
+ try {
139
+ const buffer = new Uint8Array(await response.arrayBuffer());
140
+ return deserializeWithEncoding(
141
+ opts.encoding,
142
+ buffer,
143
+ opts.responseVersionedDataHandler,
144
+ );
145
+ } catch (error) {
146
+ throw new HttpRequestError(`Failed to parse response: ${error}`, {
147
+ cause: error,
148
+ });
149
+ }
150
+ }