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.
- package/dist/tsup/actor/errors.cjs +2 -2
- package/dist/tsup/actor/errors.js +1 -1
- package/dist/tsup/actor-router-consts-BK6arfy8.d.cts +17 -0
- package/dist/tsup/actor-router-consts-BK6arfy8.d.ts +17 -0
- package/dist/tsup/chunk-2K3JMDAN.js +232 -0
- package/dist/tsup/chunk-2K3JMDAN.js.map +1 -0
- package/dist/tsup/chunk-42I3OZ3Q.js +15 -0
- package/dist/tsup/chunk-42I3OZ3Q.js.map +1 -0
- package/dist/tsup/{chunk-XJQHKJ4P.js → chunk-4CKHQRXG.js} +1650 -4147
- package/dist/tsup/chunk-4CKHQRXG.js.map +1 -0
- package/dist/tsup/{chunk-6LJT3QRL.cjs → chunk-5JBFVV4C.cjs} +37 -12
- package/dist/tsup/chunk-5JBFVV4C.cjs.map +1 -0
- package/dist/tsup/{chunk-SBHHJ6QS.cjs → chunk-5QGQK44L.cjs} +2 -2
- package/dist/tsup/{chunk-SBHHJ6QS.cjs.map → chunk-5QGQK44L.cjs.map} +1 -1
- package/dist/tsup/{chunk-IH6CKNDW.cjs → chunk-6P6RA47N.cjs} +9 -9
- package/dist/tsup/{chunk-IH6CKNDW.cjs.map → chunk-6P6RA47N.cjs.map} +1 -1
- package/dist/tsup/chunk-7OUKNSTU.js +1043 -0
- package/dist/tsup/chunk-7OUKNSTU.js.map +1 -0
- package/dist/tsup/{chunk-LWNKVZG5.cjs → chunk-DIAYNQTE.cjs} +13 -25
- package/dist/tsup/chunk-DIAYNQTE.cjs.map +1 -0
- package/dist/tsup/{chunk-3F2YSRJL.js → chunk-G75SVQON.js} +4 -4
- package/dist/tsup/{chunk-QNNXFOQV.cjs → chunk-KG3C7MKR.cjs} +3 -3
- package/dist/tsup/{chunk-QNNXFOQV.cjs.map → chunk-KG3C7MKR.cjs.map} +1 -1
- package/dist/tsup/chunk-KUPQZYUQ.cjs +15 -0
- package/dist/tsup/chunk-KUPQZYUQ.cjs.map +1 -0
- package/dist/tsup/{chunk-4CXBCT26.cjs → chunk-MRRT2CZD.cjs} +7 -7
- package/dist/tsup/{chunk-4CXBCT26.cjs.map → chunk-MRRT2CZD.cjs.map} +1 -1
- package/dist/tsup/chunk-NTCUGYSD.cjs +1043 -0
- package/dist/tsup/chunk-NTCUGYSD.cjs.map +1 -0
- package/dist/tsup/{chunk-PQY7KKTL.js → chunk-RGQR2J7S.js} +32 -7
- package/dist/tsup/{chunk-PQY7KKTL.js.map → chunk-RGQR2J7S.js.map} +1 -1
- package/dist/tsup/chunk-TCUI5JFE.cjs +232 -0
- package/dist/tsup/chunk-TCUI5JFE.cjs.map +1 -0
- package/dist/tsup/chunk-TWGATZ3X.cjs +3676 -0
- package/dist/tsup/chunk-TWGATZ3X.cjs.map +1 -0
- package/dist/tsup/chunk-UFWAK3X2.cjs +3796 -0
- package/dist/tsup/chunk-UFWAK3X2.cjs.map +1 -0
- package/dist/tsup/chunk-UTI5NCES.cjs +20 -0
- package/dist/tsup/{chunk-4R73YDN3.cjs.map → chunk-UTI5NCES.cjs.map} +1 -1
- package/dist/tsup/{chunk-QK72M5JB.js → chunk-VCEHU56K.js} +2 -2
- package/dist/tsup/{chunk-HI3HWJRC.js → chunk-VPV4MWXR.js} +4 -4
- package/dist/tsup/{chunk-HI3HWJRC.js.map → chunk-VPV4MWXR.js.map} +1 -1
- package/dist/tsup/chunk-W6LN7AF5.js +3676 -0
- package/dist/tsup/chunk-W6LN7AF5.js.map +1 -0
- package/dist/tsup/{chunk-LV2S3OU3.js → chunk-WC2PSJWN.js} +2 -2
- package/dist/tsup/{chunk-NFU2BBT5.js → chunk-YPZFLUO6.js} +2 -2
- package/dist/tsup/chunk-YPZFLUO6.js.map +1 -0
- package/dist/tsup/{chunk-H26RP6GD.js → chunk-ZYLTS2EM.js} +3 -15
- package/dist/tsup/chunk-ZYLTS2EM.js.map +1 -0
- package/dist/tsup/client/mod.cjs +10 -10
- package/dist/tsup/client/mod.d.cts +2 -2
- package/dist/tsup/client/mod.d.ts +2 -2
- package/dist/tsup/client/mod.js +9 -9
- package/dist/tsup/common/log.cjs +4 -4
- package/dist/tsup/common/log.js +3 -3
- package/dist/tsup/common/websocket.cjs +5 -5
- package/dist/tsup/common/websocket.js +4 -4
- package/dist/tsup/{connection-BI-6UIBJ.d.ts → connection-BLemxi4f.d.ts} +23 -12
- package/dist/tsup/{connection-Dyd4NLGW.d.cts → connection-CpDIydXf.d.cts} +23 -12
- package/dist/tsup/driver-helpers/mod.cjs +6 -6
- package/dist/tsup/driver-helpers/mod.d.cts +2 -2
- package/dist/tsup/driver-helpers/mod.d.ts +2 -2
- package/dist/tsup/driver-helpers/mod.js +5 -5
- package/dist/tsup/driver-test-suite/mod.cjs +614 -140
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
- package/dist/tsup/driver-test-suite/mod.d.cts +2 -2
- package/dist/tsup/driver-test-suite/mod.d.ts +2 -2
- package/dist/tsup/driver-test-suite/mod.js +575 -101
- package/dist/tsup/driver-test-suite/mod.js.map +1 -1
- package/dist/tsup/inspector/mod.cjs +8 -6
- package/dist/tsup/inspector/mod.cjs.map +1 -1
- package/dist/tsup/inspector/mod.js +10 -8
- package/dist/tsup/mod.cjs +12 -9
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +52 -7
- package/dist/tsup/mod.d.ts +52 -7
- package/dist/tsup/mod.js +18 -15
- package/dist/tsup/test/mod.cjs +12 -10
- package/dist/tsup/test/mod.cjs.map +1 -1
- package/dist/tsup/test/mod.d.cts +1 -1
- package/dist/tsup/test/mod.d.ts +1 -1
- package/dist/tsup/test/mod.js +11 -9
- package/dist/tsup/utils.cjs +5 -3
- package/dist/tsup/utils.cjs.map +1 -1
- package/dist/tsup/utils.d.cts +18 -1
- package/dist/tsup/utils.d.ts +18 -1
- package/dist/tsup/utils.js +4 -2
- package/package.json +4 -4
- package/src/actor/errors.ts +1 -1
- package/src/actor/mod.ts +5 -3
- package/src/actor/router-endpoints.ts +11 -33
- package/src/actor/router.ts +11 -9
- package/src/client/actor-conn.ts +9 -8
- package/src/client/actor-handle.ts +0 -1
- package/src/client/client.ts +1 -1
- package/src/client/mod.ts +1 -1
- package/src/client/raw-utils.ts +2 -2
- package/src/client/utils.ts +1 -1
- package/src/common/actor-router-consts.ts +38 -0
- package/src/driver-helpers/mod.ts +1 -1
- package/src/driver-test-suite/mod.ts +1 -1
- package/src/driver-test-suite/test-inline-client-driver.ts +588 -0
- package/src/driver-test-suite/tests/actor-error-handling.ts +4 -12
- package/src/driver-test-suite/tests/actor-inspector.ts +2 -1
- package/src/driver-test-suite/utils.ts +16 -10
- package/src/drivers/engine/actor-driver.ts +18 -17
- package/src/drivers/file-system/global-state.ts +3 -1
- package/src/drivers/file-system/manager.ts +16 -21
- package/src/manager/driver.ts +1 -1
- package/src/manager/protocol/query.ts +1 -1
- package/src/manager/router.ts +373 -5
- package/src/registry/mod.ts +36 -35
- package/src/registry/run-config.ts +16 -1
- package/src/registry/serve.ts +8 -3
- package/src/remote-manager-driver/actor-http-client.ts +3 -1
- package/src/remote-manager-driver/actor-websocket-client.ts +4 -3
- package/src/remote-manager-driver/api-utils.ts +4 -1
- package/src/remote-manager-driver/mod.ts +4 -6
- package/src/utils.ts +53 -0
- package/dist/tsup/chunk-4R73YDN3.cjs +0 -20
- package/dist/tsup/chunk-6LJT3QRL.cjs.map +0 -1
- package/dist/tsup/chunk-GICQ3YCU.cjs +0 -1792
- package/dist/tsup/chunk-GICQ3YCU.cjs.map +0 -1
- package/dist/tsup/chunk-H26RP6GD.js.map +0 -1
- package/dist/tsup/chunk-HLLF4B4Q.js +0 -1792
- package/dist/tsup/chunk-HLLF4B4Q.js.map +0 -1
- package/dist/tsup/chunk-LWNKVZG5.cjs.map +0 -1
- package/dist/tsup/chunk-NFU2BBT5.js.map +0 -1
- package/dist/tsup/chunk-TQ62L3X7.js +0 -325
- package/dist/tsup/chunk-TQ62L3X7.js.map +0 -1
- package/dist/tsup/chunk-VO7ZRVVD.cjs +0 -6293
- package/dist/tsup/chunk-VO7ZRVVD.cjs.map +0 -1
- package/dist/tsup/chunk-WHBPJNGW.cjs +0 -325
- package/dist/tsup/chunk-WHBPJNGW.cjs.map +0 -1
- package/dist/tsup/chunk-XJQHKJ4P.js.map +0 -1
- package/dist/tsup/router-endpoints-BTe_Rsdn.d.cts +0 -65
- package/dist/tsup/router-endpoints-CBSrKHmo.d.ts +0 -65
- /package/dist/tsup/{chunk-3F2YSRJL.js.map → chunk-G75SVQON.js.map} +0 -0
- /package/dist/tsup/{chunk-QK72M5JB.js.map → chunk-VCEHU56K.js.map} +0 -0
- /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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
162
|
-
|
|
161
|
+
normalizedPath.startsWith(PATH_RAW_WEBSOCKET_PREFIX) ||
|
|
162
|
+
normalizedPath === "/raw/websocket"
|
|
163
163
|
) {
|
|
164
164
|
// Handle websocket proxy
|
|
165
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
211
|
+
undefined,
|
|
213
212
|
);
|
|
214
|
-
|
|
215
213
|
return upgradeWebSocket(() => wsHandler)(c, noopNext());
|
|
216
214
|
} else if (
|
|
217
|
-
|
|
218
|
-
|
|
215
|
+
normalizedPath.startsWith(PATH_RAW_WEBSOCKET_PREFIX) ||
|
|
216
|
+
normalizedPath === "/raw/websocket"
|
|
219
217
|
) {
|
|
220
218
|
// Handle websocket proxy
|
|
221
|
-
//
|
|
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
|
-
|
|
222
|
+
path,
|
|
227
223
|
this.#actorDriver,
|
|
228
224
|
actorId,
|
|
229
|
-
|
|
225
|
+
undefined,
|
|
230
226
|
);
|
|
231
|
-
|
|
232
227
|
return upgradeWebSocket(() => wsHandler)(c, noopNext());
|
|
233
228
|
} else {
|
|
234
229
|
throw new Error(`Unreachable path: ${path}`);
|
package/src/manager/driver.ts
CHANGED
|
@@ -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
|
|
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
|
package/src/manager/router.ts
CHANGED
|
@@ -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: "", //
|
|
292
|
-
runner_name_selector: "", //
|
|
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: "", //
|
|
354
|
-
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
|
+
}
|