rivetkit 2.0.4 → 2.0.6

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 (140) hide show
  1. package/dist/tsup/actor/errors.cjs +2 -2
  2. package/dist/tsup/actor/errors.js +1 -1
  3. package/dist/tsup/actor-router-consts-BK6arfy8.d.cts +17 -0
  4. package/dist/tsup/actor-router-consts-BK6arfy8.d.ts +17 -0
  5. package/dist/tsup/chunk-2K3JMDAN.js +232 -0
  6. package/dist/tsup/chunk-2K3JMDAN.js.map +1 -0
  7. package/dist/tsup/chunk-42I3OZ3Q.js +15 -0
  8. package/dist/tsup/chunk-42I3OZ3Q.js.map +1 -0
  9. package/dist/tsup/{chunk-XJQHKJ4P.js → chunk-4CKHQRXG.js} +1650 -4147
  10. package/dist/tsup/chunk-4CKHQRXG.js.map +1 -0
  11. package/dist/tsup/{chunk-6LJT3QRL.cjs → chunk-5JBFVV4C.cjs} +37 -12
  12. package/dist/tsup/chunk-5JBFVV4C.cjs.map +1 -0
  13. package/dist/tsup/{chunk-SBHHJ6QS.cjs → chunk-5QGQK44L.cjs} +2 -2
  14. package/dist/tsup/{chunk-SBHHJ6QS.cjs.map → chunk-5QGQK44L.cjs.map} +1 -1
  15. package/dist/tsup/{chunk-IH6CKNDW.cjs → chunk-6P6RA47N.cjs} +9 -9
  16. package/dist/tsup/{chunk-IH6CKNDW.cjs.map → chunk-6P6RA47N.cjs.map} +1 -1
  17. package/dist/tsup/chunk-7OUKNSTU.js +1043 -0
  18. package/dist/tsup/chunk-7OUKNSTU.js.map +1 -0
  19. package/dist/tsup/{chunk-LWNKVZG5.cjs → chunk-DIAYNQTE.cjs} +13 -25
  20. package/dist/tsup/chunk-DIAYNQTE.cjs.map +1 -0
  21. package/dist/tsup/{chunk-3F2YSRJL.js → chunk-G75SVQON.js} +4 -4
  22. package/dist/tsup/{chunk-QNNXFOQV.cjs → chunk-KG3C7MKR.cjs} +3 -3
  23. package/dist/tsup/{chunk-QNNXFOQV.cjs.map → chunk-KG3C7MKR.cjs.map} +1 -1
  24. package/dist/tsup/chunk-KUPQZYUQ.cjs +15 -0
  25. package/dist/tsup/chunk-KUPQZYUQ.cjs.map +1 -0
  26. package/dist/tsup/{chunk-4CXBCT26.cjs → chunk-MRRT2CZD.cjs} +7 -7
  27. package/dist/tsup/{chunk-4CXBCT26.cjs.map → chunk-MRRT2CZD.cjs.map} +1 -1
  28. package/dist/tsup/chunk-NTCUGYSD.cjs +1043 -0
  29. package/dist/tsup/chunk-NTCUGYSD.cjs.map +1 -0
  30. package/dist/tsup/{chunk-PQY7KKTL.js → chunk-RGQR2J7S.js} +32 -7
  31. package/dist/tsup/{chunk-PQY7KKTL.js.map → chunk-RGQR2J7S.js.map} +1 -1
  32. package/dist/tsup/chunk-TCUI5JFE.cjs +232 -0
  33. package/dist/tsup/chunk-TCUI5JFE.cjs.map +1 -0
  34. package/dist/tsup/chunk-TWGATZ3X.cjs +3676 -0
  35. package/dist/tsup/chunk-TWGATZ3X.cjs.map +1 -0
  36. package/dist/tsup/chunk-UFWAK3X2.cjs +3796 -0
  37. package/dist/tsup/chunk-UFWAK3X2.cjs.map +1 -0
  38. package/dist/tsup/chunk-UTI5NCES.cjs +20 -0
  39. package/dist/tsup/{chunk-4R73YDN3.cjs.map → chunk-UTI5NCES.cjs.map} +1 -1
  40. package/dist/tsup/{chunk-QK72M5JB.js → chunk-VCEHU56K.js} +2 -2
  41. package/dist/tsup/{chunk-HI3HWJRC.js → chunk-VPV4MWXR.js} +4 -4
  42. package/dist/tsup/{chunk-HI3HWJRC.js.map → chunk-VPV4MWXR.js.map} +1 -1
  43. package/dist/tsup/chunk-W6LN7AF5.js +3676 -0
  44. package/dist/tsup/chunk-W6LN7AF5.js.map +1 -0
  45. package/dist/tsup/{chunk-LV2S3OU3.js → chunk-WC2PSJWN.js} +2 -2
  46. package/dist/tsup/{chunk-NFU2BBT5.js → chunk-YPZFLUO6.js} +2 -2
  47. package/dist/tsup/chunk-YPZFLUO6.js.map +1 -0
  48. package/dist/tsup/{chunk-H26RP6GD.js → chunk-ZYLTS2EM.js} +3 -15
  49. package/dist/tsup/chunk-ZYLTS2EM.js.map +1 -0
  50. package/dist/tsup/client/mod.cjs +10 -10
  51. package/dist/tsup/client/mod.d.cts +2 -2
  52. package/dist/tsup/client/mod.d.ts +2 -2
  53. package/dist/tsup/client/mod.js +9 -9
  54. package/dist/tsup/common/log.cjs +4 -4
  55. package/dist/tsup/common/log.js +3 -3
  56. package/dist/tsup/common/websocket.cjs +5 -5
  57. package/dist/tsup/common/websocket.js +4 -4
  58. package/dist/tsup/{connection-BI-6UIBJ.d.ts → connection-BLemxi4f.d.ts} +23 -12
  59. package/dist/tsup/{connection-Dyd4NLGW.d.cts → connection-CpDIydXf.d.cts} +23 -12
  60. package/dist/tsup/driver-helpers/mod.cjs +6 -6
  61. package/dist/tsup/driver-helpers/mod.d.cts +2 -2
  62. package/dist/tsup/driver-helpers/mod.d.ts +2 -2
  63. package/dist/tsup/driver-helpers/mod.js +5 -5
  64. package/dist/tsup/driver-test-suite/mod.cjs +614 -140
  65. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  66. package/dist/tsup/driver-test-suite/mod.d.cts +2 -2
  67. package/dist/tsup/driver-test-suite/mod.d.ts +2 -2
  68. package/dist/tsup/driver-test-suite/mod.js +575 -101
  69. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  70. package/dist/tsup/inspector/mod.cjs +8 -6
  71. package/dist/tsup/inspector/mod.cjs.map +1 -1
  72. package/dist/tsup/inspector/mod.js +10 -8
  73. package/dist/tsup/mod.cjs +12 -9
  74. package/dist/tsup/mod.cjs.map +1 -1
  75. package/dist/tsup/mod.d.cts +52 -7
  76. package/dist/tsup/mod.d.ts +52 -7
  77. package/dist/tsup/mod.js +18 -15
  78. package/dist/tsup/test/mod.cjs +12 -10
  79. package/dist/tsup/test/mod.cjs.map +1 -1
  80. package/dist/tsup/test/mod.d.cts +1 -1
  81. package/dist/tsup/test/mod.d.ts +1 -1
  82. package/dist/tsup/test/mod.js +11 -9
  83. package/dist/tsup/utils.cjs +5 -3
  84. package/dist/tsup/utils.cjs.map +1 -1
  85. package/dist/tsup/utils.d.cts +18 -1
  86. package/dist/tsup/utils.d.ts +18 -1
  87. package/dist/tsup/utils.js +4 -2
  88. package/package.json +4 -4
  89. package/src/actor/errors.ts +1 -1
  90. package/src/actor/mod.ts +5 -3
  91. package/src/actor/router-endpoints.ts +11 -33
  92. package/src/actor/router.ts +11 -9
  93. package/src/client/actor-conn.ts +9 -8
  94. package/src/client/actor-handle.ts +0 -1
  95. package/src/client/client.ts +1 -1
  96. package/src/client/mod.ts +1 -1
  97. package/src/client/raw-utils.ts +2 -2
  98. package/src/client/utils.ts +1 -1
  99. package/src/common/actor-router-consts.ts +38 -0
  100. package/src/driver-helpers/mod.ts +1 -1
  101. package/src/driver-test-suite/mod.ts +1 -1
  102. package/src/driver-test-suite/test-inline-client-driver.ts +588 -0
  103. package/src/driver-test-suite/tests/actor-error-handling.ts +4 -12
  104. package/src/driver-test-suite/tests/actor-inspector.ts +2 -1
  105. package/src/driver-test-suite/utils.ts +16 -10
  106. package/src/drivers/engine/actor-driver.ts +18 -17
  107. package/src/drivers/file-system/global-state.ts +3 -1
  108. package/src/drivers/file-system/manager.ts +16 -21
  109. package/src/manager/driver.ts +1 -1
  110. package/src/manager/protocol/query.ts +1 -1
  111. package/src/manager/router.ts +373 -5
  112. package/src/registry/mod.ts +36 -35
  113. package/src/registry/run-config.ts +16 -1
  114. package/src/registry/serve.ts +8 -3
  115. package/src/remote-manager-driver/actor-http-client.ts +3 -1
  116. package/src/remote-manager-driver/actor-websocket-client.ts +4 -3
  117. package/src/remote-manager-driver/api-utils.ts +4 -1
  118. package/src/remote-manager-driver/mod.ts +4 -6
  119. package/src/utils.ts +53 -0
  120. package/dist/tsup/chunk-4R73YDN3.cjs +0 -20
  121. package/dist/tsup/chunk-6LJT3QRL.cjs.map +0 -1
  122. package/dist/tsup/chunk-GICQ3YCU.cjs +0 -1792
  123. package/dist/tsup/chunk-GICQ3YCU.cjs.map +0 -1
  124. package/dist/tsup/chunk-H26RP6GD.js.map +0 -1
  125. package/dist/tsup/chunk-HLLF4B4Q.js +0 -1792
  126. package/dist/tsup/chunk-HLLF4B4Q.js.map +0 -1
  127. package/dist/tsup/chunk-LWNKVZG5.cjs.map +0 -1
  128. package/dist/tsup/chunk-NFU2BBT5.js.map +0 -1
  129. package/dist/tsup/chunk-TQ62L3X7.js +0 -325
  130. package/dist/tsup/chunk-TQ62L3X7.js.map +0 -1
  131. package/dist/tsup/chunk-VO7ZRVVD.cjs +0 -6293
  132. package/dist/tsup/chunk-VO7ZRVVD.cjs.map +0 -1
  133. package/dist/tsup/chunk-WHBPJNGW.cjs +0 -325
  134. package/dist/tsup/chunk-WHBPJNGW.cjs.map +0 -1
  135. package/dist/tsup/chunk-XJQHKJ4P.js.map +0 -1
  136. package/dist/tsup/router-endpoints-BTe_Rsdn.d.cts +0 -65
  137. package/dist/tsup/router-endpoints-CBSrKHmo.d.ts +0 -65
  138. /package/dist/tsup/{chunk-3F2YSRJL.js.map → chunk-G75SVQON.js.map} +0 -0
  139. /package/dist/tsup/{chunk-QK72M5JB.js.map → chunk-VCEHU56K.js.map} +0 -0
  140. /package/dist/tsup/{chunk-LV2S3OU3.js.map → chunk-WC2PSJWN.js.map} +0 -0
@@ -6,10 +6,26 @@ import { Runner } from "@rivetkit/engine-runner";
6
6
  import * as cbor from "cbor-x";
7
7
  import { WSContext } from "hono/ws";
8
8
  import invariant from "invariant";
9
+ import { lookupInRegistry } from "@/actor/definition";
10
+ import {
11
+ createGenericConnDrivers,
12
+ GenericConnGlobalState,
13
+ } from "@/actor/generic-conn-driver";
9
14
  import { deserializeActorKey } from "@/actor/keys";
10
15
  import { EncodingSchema } from "@/actor/protocol/serde";
16
+ import { type ActorRouter, createActorRouter } from "@/actor/router";
17
+ import {
18
+ handleRawWebSocketHandler,
19
+ handleWebSocketConnect,
20
+ } from "@/actor/router-endpoints";
11
21
  import type { Client } from "@/client/client";
22
+ import {
23
+ PATH_CONNECT_WEBSOCKET,
24
+ PATH_RAW_WEBSOCKET_PREFIX,
25
+ } from "@/common/actor-router-consts";
26
+ import type { UpgradeWebSocketArgs } from "@/common/inline-websocket-adapter2";
12
27
  import { getLogger } from "@/common/log";
28
+ import type { UniversalWebSocket } from "@/common/websocket-interface";
13
29
  import {
14
30
  type ActorDriver,
15
31
  type AnyActorInstance,
@@ -19,23 +35,8 @@ import {
19
35
  type ManagerDriver,
20
36
  serializeEmptyPersistData,
21
37
  } from "@/driver-helpers/mod";
22
- import type {
23
- ActorRouter,
24
- RegistryConfig,
25
- RunConfig,
26
- UniversalWebSocket,
27
- UpgradeWebSocketArgs,
28
- } from "@/mod";
29
- import {
30
- createActorRouter,
31
- createGenericConnDrivers,
32
- GenericConnGlobalState,
33
- handleRawWebSocketHandler,
34
- handleWebSocketConnect,
35
- lookupInRegistry,
36
- PATH_CONNECT_WEBSOCKET,
37
- PATH_RAW_WEBSOCKET_PREFIX,
38
- } from "@/mod";
38
+ import type { RegistryConfig } from "@/registry/config";
39
+ import type { RunConfig } from "@/registry/run-config";
39
40
  import type { Config } from "./config";
40
41
  import { KEYS } from "./kv";
41
42
  import { logger } from "./log";
@@ -451,7 +451,9 @@ export class FileSystemGlobalState {
451
451
  // Get the actor metadata
452
452
  const entry = await this.loadActor(actorId);
453
453
  if (!entry.state) {
454
- throw new Error(`Actor does exist and cannot be started: ${actorId}`);
454
+ throw new Error(
455
+ `Actor does not exist and cannot be started: "${actorId}"`,
456
+ );
455
457
  }
456
458
 
457
459
  // Actor already starting
@@ -142,10 +142,10 @@ export class FileSystemManagerDriver implements ManagerDriver {
142
142
  encoding: Encoding,
143
143
  params: unknown,
144
144
  ): Promise<UniversalWebSocket> {
145
- // TODO:
146
-
147
145
  // Handle raw WebSocket paths
148
- if (path === PATH_CONNECT_WEBSOCKET) {
146
+ const pathOnly = path.split("?")[0];
147
+ const normalizedPath = pathOnly.startsWith("/") ? pathOnly : `/${pathOnly}`;
148
+ if (normalizedPath === PATH_CONNECT_WEBSOCKET) {
149
149
  // Handle standard connect
150
150
  const wsHandler = await handleWebSocketConnect(
151
151
  undefined,
@@ -158,16 +158,14 @@ export class FileSystemManagerDriver implements ManagerDriver {
158
158
  );
159
159
  return new InlineWebSocketAdapter2(wsHandler);
160
160
  } else if (
161
- path.startsWith(PATH_RAW_WEBSOCKET_PREFIX) ||
162
- path === "/raw/websocket"
161
+ normalizedPath.startsWith(PATH_RAW_WEBSOCKET_PREFIX) ||
162
+ normalizedPath === "/raw/websocket"
163
163
  ) {
164
164
  // Handle websocket proxy
165
- // Normalize path to include trailing slash if missing
166
- const normalizedPath =
167
- path === "/raw/websocket" ? "/raw/websocket/" : path;
165
+ // Use the full path with query parameters
168
166
  const wsHandler = await handleRawWebSocketHandler(
169
167
  undefined,
170
- normalizedPath,
168
+ path,
171
169
  this.#actorDriver,
172
170
  actorId,
173
171
  undefined,
@@ -194,13 +192,14 @@ export class FileSystemManagerDriver implements ManagerDriver {
194
192
  actorId: string,
195
193
  encoding: Encoding,
196
194
  connParams: unknown,
197
- authData: unknown,
198
195
  ): Promise<Response> {
199
196
  const upgradeWebSocket = this.#runConfig.getUpgradeWebSocket?.();
200
197
  invariant(upgradeWebSocket, "missing getUpgradeWebSocket");
201
198
 
202
199
  // Handle raw WebSocket paths
203
- if (path === PATH_CONNECT_WEBSOCKET) {
200
+ const pathOnly = path.split("?")[0];
201
+ const normalizedPath = pathOnly.startsWith("/") ? pathOnly : `/${pathOnly}`;
202
+ if (normalizedPath === PATH_CONNECT_WEBSOCKET) {
204
203
  // Handle standard connect
205
204
  const wsHandler = await handleWebSocketConnect(
206
205
  c.req.raw,
@@ -209,26 +208,22 @@ export class FileSystemManagerDriver implements ManagerDriver {
209
208
  actorId,
210
209
  encoding,
211
210
  connParams,
212
- authData,
211
+ undefined,
213
212
  );
214
-
215
213
  return upgradeWebSocket(() => wsHandler)(c, noopNext());
216
214
  } else if (
217
- path.startsWith(PATH_RAW_WEBSOCKET_PREFIX) ||
218
- path === "/raw/websocket"
215
+ normalizedPath.startsWith(PATH_RAW_WEBSOCKET_PREFIX) ||
216
+ normalizedPath === "/raw/websocket"
219
217
  ) {
220
218
  // Handle websocket proxy
221
- // Normalize path to include trailing slash if missing
222
- const normalizedPath =
223
- path === "/raw/websocket" ? "/raw/websocket/" : path;
219
+ // Use the full path with query parameters
224
220
  const wsHandler = await handleRawWebSocketHandler(
225
221
  c.req.raw,
226
- normalizedPath,
222
+ path,
227
223
  this.#actorDriver,
228
224
  actorId,
229
- authData,
225
+ undefined,
230
226
  );
231
-
232
227
  return upgradeWebSocket(() => wsHandler)(c, noopNext());
233
228
  } else {
234
229
  throw new Error(`Unreachable path: ${path}`);
@@ -1,8 +1,8 @@
1
1
  import type { Env, Hono, Context as HonoContext } from "hono";
2
2
  import type { ActorKey, Encoding, UniversalWebSocket } from "@/actor/mod";
3
3
  import type { ManagerInspector } from "@/inspector/manager";
4
- import type { RunConfig } from "@/mod";
5
4
  import type { RegistryConfig } from "@/registry/config";
5
+ import type { RunConfig } from "@/registry/run-config";
6
6
 
7
7
  export type ManagerDriverBuilder = (
8
8
  registryConfig: RegistryConfig,
@@ -7,7 +7,7 @@ import {
7
7
  HEADER_CONN_PARAMS,
8
8
  HEADER_CONN_TOKEN,
9
9
  HEADER_ENCODING,
10
- } from "@/actor/router-endpoints";
10
+ } from "@/common/actor-router-consts";
11
11
 
12
12
  // Maximum size of a key component in bytes
13
13
  // Set to 128 bytes to allow for separators and escape characters in the full key
@@ -3,6 +3,8 @@ import * as cbor from "cbor-x";
3
3
  import { Hono } from "hono";
4
4
  import { cors as corsMiddleware } from "hono/cors";
5
5
  import { createMiddleware } from "hono/factory";
6
+ import type { WSContext } from "hono/ws";
7
+ import invariant from "invariant";
6
8
  import { z } from "zod";
7
9
  import {
8
10
  ActorNotFound,
@@ -11,11 +13,18 @@ import {
11
13
  Unsupported,
12
14
  WebSocketsNotEnabled,
13
15
  } from "@/actor/errors";
16
+ import type { Encoding } from "@/client/mod";
14
17
  import {
15
18
  handleRouteError,
16
19
  handleRouteNotFound,
17
20
  loggerMiddleware,
18
21
  } from "@/common/router";
22
+ import { deconstructError, noopNext } from "@/common/utils";
23
+ import { HEADER_ACTOR_ID } from "@/driver-helpers/mod";
24
+ import type {
25
+ TestInlineDriverCallRequest,
26
+ TestInlineDriverCallResponse,
27
+ } from "@/driver-test-suite/test-inline-client-driver";
19
28
  import { createManagerInspectorRouter } from "@/inspector/manager";
20
29
  import { secureInspector } from "@/inspector/utils";
21
30
  import {
@@ -32,8 +41,10 @@ import {
32
41
  ActorsGetOrCreateByIdResponseSchema,
33
42
  } from "@/manager-api/routes/actors-get-or-create-by-id";
34
43
  import { RivetIdSchema } from "@/manager-api/routes/common";
44
+ import type { UniversalWebSocket, UpgradeWebSocketArgs } from "@/mod";
35
45
  import type { RegistryConfig } from "@/registry/config";
36
46
  import type { RunConfig } from "@/registry/run-config";
47
+ import { stringifyError } from "@/utils";
37
48
  import type { ManagerDriver } from "./driver";
38
49
  import { logger } from "./log";
39
50
 
@@ -137,9 +148,10 @@ export function createManagerRouter(
137
148
  const proxyUrl = new URL(`http://actor${url.pathname}${url.search}`);
138
149
 
139
150
  const proxyRequest = new Request(proxyUrl, {
140
- method: c.req.method,
151
+ method: c.req.raw.method,
141
152
  headers: proxyHeaders,
142
153
  body: c.req.raw.body,
154
+ signal: c.req.raw.signal,
143
155
  });
144
156
 
145
157
  return await managerDriver.proxyRequest(c, proxyRequest, actorId);
@@ -288,8 +300,8 @@ export function createManagerRouter(
288
300
  actor_id: actorOutput.actorId,
289
301
  name: actorOutput.name,
290
302
  key: actorOutput.key,
291
- namespace_id: "", // Not available from driver
292
- runner_name_selector: "", // Not available from driver
303
+ namespace_id: "default", // Assert default namespace
304
+ runner_name_selector: "rivetkit", // Assert rivetkit runner
293
305
  create_ts: Date.now(), // Not available from driver
294
306
  connectable_ts: null,
295
307
  destroy_ts: null,
@@ -350,8 +362,8 @@ export function createManagerRouter(
350
362
  actor_id: actorOutput.actorId,
351
363
  name: actorOutput.name,
352
364
  key: actorOutput.key,
353
- namespace_id: "", // Not available from driver
354
- runner_name_selector: body.runner_name_selector,
365
+ namespace_id: "default", // Assert default namespace
366
+ runner_name_selector: "rivetkit", // Assert rivetkit runner
355
367
  create_ts: Date.now(),
356
368
  connectable_ts: null,
357
369
  destroy_ts: null,
@@ -387,6 +399,139 @@ export function createManagerRouter(
387
399
  // });
388
400
  // }
389
401
 
402
+ if (registryConfig.test.enabled) {
403
+ // Add HTTP endpoint to test the inline client
404
+ //
405
+ // We have to do this in a router since this needs to run in the same server as the RivetKit registry. Some test contexts to not run in the same server.
406
+ router.post(".test/inline-driver/call", async (c) => {
407
+ // TODO: use openapi instead
408
+ const buffer = await c.req.arrayBuffer();
409
+ const { encoding, transport, method, args }: TestInlineDriverCallRequest =
410
+ cbor.decode(new Uint8Array(buffer));
411
+
412
+ logger().debug({
413
+ msg: "received inline request",
414
+ encoding,
415
+ transport,
416
+ method,
417
+ args,
418
+ });
419
+
420
+ // Forward inline driver request
421
+ let response: TestInlineDriverCallResponse<unknown>;
422
+ try {
423
+ const output = await ((managerDriver as any)[method] as any)(...args);
424
+ response = { ok: output };
425
+ } catch (rawErr) {
426
+ const err = deconstructError(rawErr, logger(), {}, true);
427
+ response = { err };
428
+ }
429
+
430
+ return c.body(cbor.encode(response));
431
+ });
432
+
433
+ router.get(".test/inline-driver/connect-websocket/*", async (c) => {
434
+ const upgradeWebSocket = runConfig.getUpgradeWebSocket?.();
435
+ invariant(upgradeWebSocket, "websockets not supported on this platform");
436
+
437
+ return upgradeWebSocket(async (c: any) => {
438
+ const {
439
+ path,
440
+ actorId,
441
+ params: paramsRaw,
442
+ encodingKind,
443
+ } = c.req.query() as {
444
+ path: string;
445
+ actorId: string;
446
+ params?: string;
447
+ encodingKind: Encoding;
448
+ };
449
+ const params =
450
+ paramsRaw !== undefined ? JSON.parse(paramsRaw) : undefined;
451
+
452
+ logger().debug({
453
+ msg: "received test inline driver websocket",
454
+ actorId,
455
+ params,
456
+ encodingKind,
457
+ path: path,
458
+ });
459
+
460
+ // Connect to the actor using the inline client driver - this returns a Promise<WebSocket>
461
+ const clientWsPromise = managerDriver.openWebSocket(
462
+ path,
463
+ actorId,
464
+ encodingKind,
465
+ params,
466
+ );
467
+
468
+ return await createTestWebSocketProxy(clientWsPromise, "standard");
469
+ })(c, noopNext());
470
+ });
471
+
472
+ router.all(".test/inline-driver/send-request/*", async (c) => {
473
+ // Extract parameters from headers
474
+ const actorId = c.req.header(HEADER_ACTOR_ID);
475
+
476
+ if (!actorId) {
477
+ return c.text("Missing required headers", 400);
478
+ }
479
+
480
+ // Extract the path after /send-request/
481
+ const pathOnly =
482
+ c.req.path.split("/.test/inline-driver/send-request/")[1] || "";
483
+
484
+ // Include query string
485
+ const url = new URL(c.req.url);
486
+ const pathWithQuery = pathOnly + url.search;
487
+
488
+ logger().debug({
489
+ msg: "received test inline driver raw http",
490
+ actorId,
491
+ path: pathWithQuery,
492
+ method: c.req.method,
493
+ });
494
+
495
+ try {
496
+ // Forward the request using the inline client driver
497
+ const response = await managerDriver.sendRequest(
498
+ actorId,
499
+ new Request(`http://actor/${pathWithQuery}`, {
500
+ method: c.req.method,
501
+ headers: c.req.raw.headers,
502
+ body: c.req.raw.body,
503
+ }),
504
+ );
505
+
506
+ // Return the response directly
507
+ return response;
508
+ } catch (error) {
509
+ logger().error({
510
+ msg: "error in test inline raw http",
511
+ error: stringifyError(error),
512
+ });
513
+
514
+ // Return error response
515
+ const err = deconstructError(error, logger(), {}, true);
516
+ return c.json(
517
+ {
518
+ error: {
519
+ code: err.code,
520
+ message: err.message,
521
+ metadata: err.metadata,
522
+ },
523
+ },
524
+ err.statusCode,
525
+ );
526
+ }
527
+ });
528
+ }
529
+
530
+ managerDriver.modifyManagerRouter?.(
531
+ registryConfig,
532
+ router as unknown as Hono,
533
+ );
534
+
390
535
  if (runConfig.inspector?.enabled) {
391
536
  if (!managerDriver.inspector) {
392
537
  throw new Unsupported("inspector");
@@ -410,3 +555,226 @@ export function createManagerRouter(
410
555
 
411
556
  return { router: router as Hono, openapi: router };
412
557
  }
558
+ /**
559
+ * Creates a WebSocket proxy for test endpoints that forwards messages between server and client WebSockets
560
+ */
561
+ async function createTestWebSocketProxy(
562
+ clientWsPromise: Promise<UniversalWebSocket>,
563
+ connectionType: string,
564
+ ): Promise<UpgradeWebSocketArgs> {
565
+ // Store a reference to the resolved WebSocket
566
+ let clientWs: UniversalWebSocket | null = null;
567
+ try {
568
+ // Resolve the client WebSocket promise
569
+ logger().debug({ msg: "awaiting client websocket promise" });
570
+ const ws = await clientWsPromise;
571
+ clientWs = ws;
572
+ logger().debug({
573
+ msg: "client websocket promise resolved",
574
+ constructor: ws?.constructor.name,
575
+ });
576
+
577
+ // Wait for ws to open
578
+ await new Promise<void>((resolve, reject) => {
579
+ const onOpen = () => {
580
+ logger().debug({ msg: "test websocket connection opened" });
581
+ resolve();
582
+ };
583
+ const onError = (error: any) => {
584
+ logger().error({ msg: "test websocket connection failed", error });
585
+ reject(
586
+ new Error(`Failed to open WebSocket: ${error.message || error}`),
587
+ );
588
+ };
589
+ ws.addEventListener("open", onOpen);
590
+ ws.addEventListener("error", onError);
591
+ });
592
+ } catch (error) {
593
+ logger().error({
594
+ msg: `failed to establish client ${connectionType} websocket connection`,
595
+ error,
596
+ });
597
+ return {
598
+ onOpen: (_evt, serverWs) => {
599
+ serverWs.close(1011, "Failed to establish connection");
600
+ },
601
+ onMessage: () => {},
602
+ onError: () => {},
603
+ onClose: () => {},
604
+ };
605
+ }
606
+
607
+ // Create WebSocket proxy handlers to relay messages between client and server
608
+ return {
609
+ onOpen: (_evt: any, serverWs: WSContext) => {
610
+ logger().debug({
611
+ msg: `test ${connectionType} websocket connection opened`,
612
+ });
613
+
614
+ // Check WebSocket type
615
+ logger().debug({
616
+ msg: "clientWs info",
617
+ constructor: clientWs.constructor.name,
618
+ hasAddEventListener: typeof clientWs.addEventListener === "function",
619
+ readyState: clientWs.readyState,
620
+ });
621
+
622
+ // Add message handler to forward messages from client to server
623
+ clientWs.addEventListener("message", (clientEvt: MessageEvent) => {
624
+ logger().debug({
625
+ msg: `test ${connectionType} websocket connection message from client`,
626
+ dataType: typeof clientEvt.data,
627
+ isBlob: clientEvt.data instanceof Blob,
628
+ isArrayBuffer: clientEvt.data instanceof ArrayBuffer,
629
+ dataConstructor: clientEvt.data?.constructor?.name,
630
+ dataStr:
631
+ typeof clientEvt.data === "string"
632
+ ? clientEvt.data.substring(0, 100)
633
+ : undefined,
634
+ });
635
+
636
+ if (serverWs.readyState === 1) {
637
+ // OPEN
638
+ // Handle Blob data
639
+ if (clientEvt.data instanceof Blob) {
640
+ clientEvt.data
641
+ .arrayBuffer()
642
+ .then((buffer) => {
643
+ logger().debug({
644
+ msg: "converted client blob to arraybuffer, sending to server",
645
+ bufferSize: buffer.byteLength,
646
+ });
647
+ serverWs.send(buffer as any);
648
+ })
649
+ .catch((error) => {
650
+ logger().error({
651
+ msg: "failed to convert blob to arraybuffer",
652
+ error,
653
+ });
654
+ });
655
+ } else {
656
+ logger().debug({
657
+ msg: "sending client data directly to server",
658
+ dataType: typeof clientEvt.data,
659
+ dataLength:
660
+ typeof clientEvt.data === "string"
661
+ ? clientEvt.data.length
662
+ : undefined,
663
+ });
664
+ serverWs.send(clientEvt.data as any);
665
+ }
666
+ }
667
+ });
668
+
669
+ // Add close handler to close server when client closes
670
+ clientWs.addEventListener("close", (clientEvt: any) => {
671
+ logger().debug({
672
+ msg: `test ${connectionType} websocket connection closed`,
673
+ });
674
+
675
+ if (serverWs.readyState !== 3) {
676
+ // Not CLOSED
677
+ serverWs.close(clientEvt.code, clientEvt.reason);
678
+ }
679
+ });
680
+
681
+ // Add error handler
682
+ clientWs.addEventListener("error", () => {
683
+ logger().debug({
684
+ msg: `test ${connectionType} websocket connection error`,
685
+ });
686
+
687
+ if (serverWs.readyState !== 3) {
688
+ // Not CLOSED
689
+ serverWs.close(1011, "Error in client websocket");
690
+ }
691
+ });
692
+ },
693
+ onMessage: (evt: { data: any }) => {
694
+ logger().debug({
695
+ msg: "received message from server",
696
+ dataType: typeof evt.data,
697
+ isBlob: evt.data instanceof Blob,
698
+ isArrayBuffer: evt.data instanceof ArrayBuffer,
699
+ dataConstructor: evt.data?.constructor?.name,
700
+ dataStr:
701
+ typeof evt.data === "string" ? evt.data.substring(0, 100) : undefined,
702
+ });
703
+
704
+ // Forward messages from server websocket to client websocket
705
+ if (clientWs.readyState === 1) {
706
+ // OPEN
707
+ // Handle Blob data
708
+ if (evt.data instanceof Blob) {
709
+ evt.data
710
+ .arrayBuffer()
711
+ .then((buffer) => {
712
+ logger().debug({
713
+ msg: "converted blob to arraybuffer, sending",
714
+ bufferSize: buffer.byteLength,
715
+ });
716
+ clientWs.send(buffer);
717
+ })
718
+ .catch((error) => {
719
+ logger().error({
720
+ msg: "failed to convert blob to arraybuffer",
721
+ error,
722
+ });
723
+ });
724
+ } else {
725
+ logger().debug({
726
+ msg: "sending data directly",
727
+ dataType: typeof evt.data,
728
+ dataLength:
729
+ typeof evt.data === "string" ? evt.data.length : undefined,
730
+ });
731
+ clientWs.send(evt.data);
732
+ }
733
+ }
734
+ },
735
+ onClose: (
736
+ event: {
737
+ wasClean: boolean;
738
+ code: number;
739
+ reason: string;
740
+ },
741
+ serverWs: WSContext,
742
+ ) => {
743
+ logger().debug({
744
+ msg: `server ${connectionType} websocket closed`,
745
+ wasClean: event.wasClean,
746
+ code: event.code,
747
+ reason: event.reason,
748
+ });
749
+
750
+ // HACK: Close socket in order to fix bug with Cloudflare leaving WS in closing state
751
+ // https://github.com/cloudflare/workerd/issues/2569
752
+ serverWs.close(1000, "hack_force_close");
753
+
754
+ // Close the client websocket when the server websocket closes
755
+ if (
756
+ clientWs &&
757
+ clientWs.readyState !== clientWs.CLOSED &&
758
+ clientWs.readyState !== clientWs.CLOSING
759
+ ) {
760
+ // Don't pass code/message since this may affect how close events are triggered
761
+ clientWs.close(1000, event.reason);
762
+ }
763
+ },
764
+ onError: (error: unknown) => {
765
+ logger().error({
766
+ msg: `error in server ${connectionType} websocket`,
767
+ error,
768
+ });
769
+
770
+ // Close the client websocket on error
771
+ if (
772
+ clientWs &&
773
+ clientWs.readyState !== clientWs.CLOSED &&
774
+ clientWs.readyState !== clientWs.CLOSING
775
+ ) {
776
+ clientWs.close(1011, "Error in server websocket");
777
+ }
778
+ },
779
+ };
780
+ }