rivetkit 2.0.2 → 2.0.4
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/README.md +3 -5
- package/dist/schemas/actor-persist/v1.ts +225 -0
- package/dist/schemas/client-protocol/v1.ts +435 -0
- package/dist/schemas/file-system-driver/v1.ts +102 -0
- package/dist/tsup/actor/errors.cjs +77 -0
- package/dist/tsup/actor/errors.cjs.map +1 -0
- package/dist/tsup/actor/errors.d.cts +156 -0
- package/dist/tsup/actor/errors.d.ts +156 -0
- package/dist/tsup/actor/errors.js +77 -0
- package/dist/tsup/actor/errors.js.map +1 -0
- package/dist/tsup/chunk-3F2YSRJL.js +117 -0
- package/dist/tsup/chunk-3F2YSRJL.js.map +1 -0
- package/dist/tsup/chunk-4CXBCT26.cjs +250 -0
- package/dist/tsup/chunk-4CXBCT26.cjs.map +1 -0
- package/dist/tsup/chunk-4R73YDN3.cjs +20 -0
- package/dist/tsup/chunk-4R73YDN3.cjs.map +1 -0
- package/dist/tsup/chunk-6LJT3QRL.cjs +539 -0
- package/dist/tsup/chunk-6LJT3QRL.cjs.map +1 -0
- package/dist/tsup/chunk-GICQ3YCU.cjs +1792 -0
- package/dist/tsup/chunk-GICQ3YCU.cjs.map +1 -0
- package/dist/tsup/chunk-H26RP6GD.js +251 -0
- package/dist/tsup/chunk-H26RP6GD.js.map +1 -0
- package/dist/tsup/chunk-HI3HWJRC.js +20 -0
- package/dist/tsup/chunk-HI3HWJRC.js.map +1 -0
- package/dist/tsup/chunk-HLLF4B4Q.js +1792 -0
- package/dist/tsup/chunk-HLLF4B4Q.js.map +1 -0
- package/dist/tsup/chunk-IH6CKNDW.cjs +117 -0
- package/dist/tsup/chunk-IH6CKNDW.cjs.map +1 -0
- package/dist/tsup/chunk-LV2S3OU3.js +250 -0
- package/dist/tsup/chunk-LV2S3OU3.js.map +1 -0
- package/dist/tsup/chunk-LWNKVZG5.cjs +251 -0
- package/dist/tsup/chunk-LWNKVZG5.cjs.map +1 -0
- package/dist/tsup/chunk-NFU2BBT5.js +374 -0
- package/dist/tsup/chunk-NFU2BBT5.js.map +1 -0
- package/dist/tsup/chunk-PQY7KKTL.js +539 -0
- package/dist/tsup/chunk-PQY7KKTL.js.map +1 -0
- package/dist/tsup/chunk-QK72M5JB.js +45 -0
- package/dist/tsup/chunk-QK72M5JB.js.map +1 -0
- package/dist/tsup/chunk-QNNXFOQV.cjs +45 -0
- package/dist/tsup/chunk-QNNXFOQV.cjs.map +1 -0
- package/dist/tsup/chunk-SBHHJ6QS.cjs +374 -0
- package/dist/tsup/chunk-SBHHJ6QS.cjs.map +1 -0
- package/dist/tsup/chunk-TQ62L3X7.js +325 -0
- package/dist/tsup/chunk-TQ62L3X7.js.map +1 -0
- package/dist/tsup/chunk-VO7ZRVVD.cjs +6293 -0
- package/dist/tsup/chunk-VO7ZRVVD.cjs.map +1 -0
- package/dist/tsup/chunk-WHBPJNGW.cjs +325 -0
- package/dist/tsup/chunk-WHBPJNGW.cjs.map +1 -0
- package/dist/tsup/chunk-XJQHKJ4P.js +6293 -0
- package/dist/tsup/chunk-XJQHKJ4P.js.map +1 -0
- package/dist/tsup/client/mod.cjs +32 -0
- package/dist/tsup/client/mod.cjs.map +1 -0
- package/dist/tsup/client/mod.d.cts +20 -0
- package/dist/tsup/client/mod.d.ts +20 -0
- package/dist/tsup/client/mod.js +32 -0
- package/dist/tsup/client/mod.js.map +1 -0
- package/dist/tsup/common/log.cjs +21 -0
- package/dist/tsup/common/log.cjs.map +1 -0
- package/dist/tsup/common/log.d.cts +26 -0
- package/dist/tsup/common/log.d.ts +26 -0
- package/dist/tsup/common/log.js +21 -0
- package/dist/tsup/common/log.js.map +1 -0
- package/dist/tsup/common/websocket.cjs +10 -0
- package/dist/tsup/common/websocket.cjs.map +1 -0
- package/dist/tsup/common/websocket.d.cts +3 -0
- package/dist/tsup/common/websocket.d.ts +3 -0
- package/dist/tsup/common/websocket.js +10 -0
- package/dist/tsup/common/websocket.js.map +1 -0
- package/dist/tsup/common-CXCe7s6i.d.cts +218 -0
- package/dist/tsup/common-CXCe7s6i.d.ts +218 -0
- package/dist/tsup/connection-BI-6UIBJ.d.ts +2087 -0
- package/dist/tsup/connection-Dyd4NLGW.d.cts +2087 -0
- package/dist/tsup/driver-helpers/mod.cjs +30 -0
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
- package/dist/tsup/driver-helpers/mod.d.cts +17 -0
- package/dist/tsup/driver-helpers/mod.d.ts +17 -0
- package/dist/tsup/driver-helpers/mod.js +30 -0
- package/dist/tsup/driver-helpers/mod.js.map +1 -0
- package/dist/tsup/driver-test-suite/mod.cjs +3411 -0
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
- package/dist/tsup/driver-test-suite/mod.d.cts +63 -0
- package/dist/tsup/driver-test-suite/mod.d.ts +63 -0
- package/dist/tsup/driver-test-suite/mod.js +3411 -0
- package/dist/tsup/driver-test-suite/mod.js.map +1 -0
- package/dist/tsup/inspector/mod.cjs +51 -0
- package/dist/tsup/inspector/mod.cjs.map +1 -0
- package/dist/tsup/inspector/mod.d.cts +408 -0
- package/dist/tsup/inspector/mod.d.ts +408 -0
- package/dist/tsup/inspector/mod.js +51 -0
- package/dist/tsup/inspector/mod.js.map +1 -0
- package/dist/tsup/mod.cjs +67 -0
- package/dist/tsup/mod.cjs.map +1 -0
- package/dist/tsup/mod.d.cts +105 -0
- package/dist/tsup/mod.d.ts +105 -0
- package/dist/tsup/mod.js +67 -0
- package/dist/tsup/mod.js.map +1 -0
- package/dist/tsup/router-endpoints-BTe_Rsdn.d.cts +65 -0
- package/dist/tsup/router-endpoints-CBSrKHmo.d.ts +65 -0
- package/dist/tsup/test/mod.cjs +17 -0
- package/dist/tsup/test/mod.cjs.map +1 -0
- package/dist/tsup/test/mod.d.cts +26 -0
- package/dist/tsup/test/mod.d.ts +26 -0
- package/dist/tsup/test/mod.js +17 -0
- package/dist/tsup/test/mod.js.map +1 -0
- package/dist/tsup/utils-fwx3o3K9.d.cts +18 -0
- package/dist/tsup/utils-fwx3o3K9.d.ts +18 -0
- package/dist/tsup/utils.cjs +26 -0
- package/dist/tsup/utils.cjs.map +1 -0
- package/dist/tsup/utils.d.cts +36 -0
- package/dist/tsup/utils.d.ts +36 -0
- package/dist/tsup/utils.js +26 -0
- package/dist/tsup/utils.js.map +1 -0
- package/package.json +208 -5
- package/src/actor/action.ts +178 -0
- package/src/actor/config.ts +497 -0
- package/src/actor/connection.ts +257 -0
- package/src/actor/context.ts +168 -0
- package/src/actor/database.ts +23 -0
- package/src/actor/definition.ts +82 -0
- package/src/actor/driver.ts +84 -0
- package/src/actor/errors.ts +422 -0
- package/src/actor/generic-conn-driver.ts +246 -0
- package/src/actor/instance.ts +1844 -0
- package/src/actor/keys.test.ts +266 -0
- package/src/actor/keys.ts +89 -0
- package/src/actor/log.ts +6 -0
- package/src/actor/mod.ts +108 -0
- package/src/actor/persisted.ts +42 -0
- package/src/actor/protocol/old.ts +297 -0
- package/src/actor/protocol/serde.ts +131 -0
- package/src/actor/router-endpoints.ts +688 -0
- package/src/actor/router.ts +265 -0
- package/src/actor/schedule.ts +17 -0
- package/src/actor/unstable-react.ts +110 -0
- package/src/actor/utils.ts +102 -0
- package/src/client/actor-common.ts +30 -0
- package/src/client/actor-conn.ts +865 -0
- package/src/client/actor-handle.ts +268 -0
- package/src/client/actor-query.ts +65 -0
- package/src/client/client.ts +554 -0
- package/src/client/config.ts +44 -0
- package/src/client/errors.ts +42 -0
- package/src/client/log.ts +5 -0
- package/src/client/mod.ts +60 -0
- package/src/client/raw-utils.ts +149 -0
- package/src/client/test.ts +44 -0
- package/src/client/utils.ts +152 -0
- package/src/common/eventsource-interface.ts +47 -0
- package/src/common/eventsource.ts +80 -0
- package/src/common/fake-event-source.ts +267 -0
- package/src/common/inline-websocket-adapter2.ts +454 -0
- package/src/common/log-levels.ts +27 -0
- package/src/common/log.ts +214 -0
- package/src/common/logfmt.ts +219 -0
- package/src/common/network.ts +2 -0
- package/src/common/router.ts +80 -0
- package/src/common/utils.ts +336 -0
- package/src/common/versioned-data.ts +95 -0
- package/src/common/websocket-interface.ts +49 -0
- package/src/common/websocket.ts +42 -0
- package/src/driver-helpers/mod.ts +22 -0
- package/src/driver-helpers/utils.ts +17 -0
- package/src/driver-test-suite/log.ts +5 -0
- package/src/driver-test-suite/mod.ts +239 -0
- package/src/driver-test-suite/tests/action-features.ts +136 -0
- package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
- package/src/driver-test-suite/tests/actor-conn.ts +349 -0
- package/src/driver-test-suite/tests/actor-driver.ts +25 -0
- package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
- package/src/driver-test-suite/tests/actor-handle.ts +292 -0
- package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
- package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
- package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
- package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
- package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
- package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
- package/src/driver-test-suite/tests/actor-state.ts +54 -0
- package/src/driver-test-suite/tests/actor-vars.ts +93 -0
- package/src/driver-test-suite/tests/manager-driver.ts +367 -0
- package/src/driver-test-suite/tests/raw-http-direct-registry.ts +227 -0
- package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
- package/src/driver-test-suite/tests/raw-http.ts +347 -0
- package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +393 -0
- package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
- package/src/driver-test-suite/tests/request-access.ts +230 -0
- package/src/driver-test-suite/utils.ts +71 -0
- package/src/drivers/default.ts +34 -0
- package/src/drivers/engine/actor-driver.ts +369 -0
- package/src/drivers/engine/config.ts +31 -0
- package/src/drivers/engine/kv.ts +3 -0
- package/src/drivers/engine/log.ts +5 -0
- package/src/drivers/engine/mod.ts +35 -0
- package/src/drivers/file-system/actor.ts +91 -0
- package/src/drivers/file-system/global-state.ts +686 -0
- package/src/drivers/file-system/log.ts +5 -0
- package/src/drivers/file-system/manager.ts +329 -0
- package/src/drivers/file-system/mod.ts +48 -0
- package/src/drivers/file-system/utils.ts +109 -0
- package/src/globals.d.ts +6 -0
- package/src/inspector/actor.ts +298 -0
- package/src/inspector/config.ts +88 -0
- package/src/inspector/log.ts +5 -0
- package/src/inspector/manager.ts +86 -0
- package/src/inspector/mod.ts +2 -0
- package/src/inspector/protocol/actor.ts +10 -0
- package/src/inspector/protocol/common.ts +196 -0
- package/src/inspector/protocol/manager.ts +10 -0
- package/src/inspector/protocol/mod.ts +2 -0
- package/src/inspector/utils.ts +76 -0
- package/src/manager/driver.ts +88 -0
- package/src/manager/hono-websocket-adapter.ts +342 -0
- package/src/manager/log.ts +5 -0
- package/src/manager/mod.ts +2 -0
- package/src/manager/protocol/mod.ts +24 -0
- package/src/manager/protocol/query.ts +89 -0
- package/src/manager/router.ts +412 -0
- package/src/manager-api/routes/actors-create.ts +16 -0
- package/src/manager-api/routes/actors-delete.ts +4 -0
- package/src/manager-api/routes/actors-get-by-id.ts +7 -0
- package/src/manager-api/routes/actors-get-or-create-by-id.ts +29 -0
- package/src/manager-api/routes/actors-get.ts +7 -0
- package/src/manager-api/routes/common.ts +18 -0
- package/src/mod.ts +18 -0
- package/src/registry/config.ts +32 -0
- package/src/registry/log.ts +5 -0
- package/src/registry/mod.ts +157 -0
- package/src/registry/run-config.ts +52 -0
- package/src/registry/serve.ts +52 -0
- package/src/remote-manager-driver/actor-http-client.ts +72 -0
- package/src/remote-manager-driver/actor-websocket-client.ts +63 -0
- package/src/remote-manager-driver/api-endpoints.ts +79 -0
- package/src/remote-manager-driver/api-utils.ts +43 -0
- package/src/remote-manager-driver/log.ts +5 -0
- package/src/remote-manager-driver/mod.ts +274 -0
- package/src/remote-manager-driver/ws-proxy.ts +180 -0
- package/src/schemas/actor-persist/mod.ts +1 -0
- package/src/schemas/actor-persist/versioned.ts +25 -0
- package/src/schemas/client-protocol/mod.ts +1 -0
- package/src/schemas/client-protocol/versioned.ts +63 -0
- package/src/schemas/file-system-driver/mod.ts +1 -0
- package/src/schemas/file-system-driver/versioned.ts +28 -0
- package/src/serde.ts +90 -0
- package/src/test/config.ts +16 -0
- package/src/test/log.ts +5 -0
- package/src/test/mod.ts +154 -0
- package/src/utils.ts +172 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { createMiddleware } from "hono/factory";
|
|
3
|
+
import type { RunConfig } from "@/mod";
|
|
4
|
+
import type { RunConfigInput } from "@/registry/run-config";
|
|
5
|
+
import { inspectorLogger } from "./log";
|
|
6
|
+
|
|
7
|
+
export function compareSecrets(providedSecret: string, validSecret: string) {
|
|
8
|
+
// Early length check to avoid unnecessary processing
|
|
9
|
+
if (providedSecret.length !== validSecret.length) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const encoder = new TextEncoder();
|
|
14
|
+
|
|
15
|
+
const a = encoder.encode(providedSecret);
|
|
16
|
+
const b = encoder.encode(validSecret);
|
|
17
|
+
|
|
18
|
+
if (a.byteLength !== b.byteLength) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Perform timing-safe comparison
|
|
23
|
+
if (!crypto.timingSafeEqual(a, b)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const secureInspector = (runConfig: RunConfig) =>
|
|
30
|
+
createMiddleware(async (c, next) => {
|
|
31
|
+
if (!runConfig.inspector.enabled) {
|
|
32
|
+
return c.text("Inspector is not enabled", 503);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const userToken = c.req.header("Authorization")?.replace("Bearer ", "");
|
|
36
|
+
if (!userToken) {
|
|
37
|
+
return c.text("Unauthorized", 401);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const inspectorToken = runConfig.inspector.token?.();
|
|
41
|
+
if (!inspectorToken) {
|
|
42
|
+
return c.text("Unauthorized", 401);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const isValid = compareSecrets(userToken, inspectorToken);
|
|
46
|
+
|
|
47
|
+
if (!isValid) {
|
|
48
|
+
return c.text("Unauthorized", 401);
|
|
49
|
+
}
|
|
50
|
+
await next();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export function getInspectorUrl(runConfig: RunConfigInput | undefined) {
|
|
54
|
+
if (!runConfig?.inspector?.enabled) {
|
|
55
|
+
return "disabled";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const accessToken = runConfig?.inspector?.token?.();
|
|
59
|
+
|
|
60
|
+
if (!accessToken) {
|
|
61
|
+
inspectorLogger().warn(
|
|
62
|
+
"Inspector Token is not set, but Inspector is enabled. Please set it in the run configuration `inspector.token` or via `RIVETKIT_INSPECTOR_TOKEN` environment variable. Inspector will not be accessible.",
|
|
63
|
+
);
|
|
64
|
+
return "disabled";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const url = new URL("https://inspect.rivet.dev");
|
|
68
|
+
|
|
69
|
+
url.searchParams.set("t", accessToken);
|
|
70
|
+
|
|
71
|
+
if (runConfig?.inspector?.defaultEndpoint) {
|
|
72
|
+
url.searchParams.set("u", runConfig.inspector.defaultEndpoint);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return url.href;
|
|
76
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Env, Hono, Context as HonoContext } from "hono";
|
|
2
|
+
import type { ActorKey, Encoding, UniversalWebSocket } from "@/actor/mod";
|
|
3
|
+
import type { ManagerInspector } from "@/inspector/manager";
|
|
4
|
+
import type { RunConfig } from "@/mod";
|
|
5
|
+
import type { RegistryConfig } from "@/registry/config";
|
|
6
|
+
|
|
7
|
+
export type ManagerDriverBuilder = (
|
|
8
|
+
registryConfig: RegistryConfig,
|
|
9
|
+
runConfig: RunConfig,
|
|
10
|
+
) => ManagerDriver;
|
|
11
|
+
|
|
12
|
+
export interface ManagerDriver {
|
|
13
|
+
getForId(input: GetForIdInput): Promise<ActorOutput | undefined>;
|
|
14
|
+
getWithKey(input: GetWithKeyInput): Promise<ActorOutput | undefined>;
|
|
15
|
+
getOrCreateWithKey(input: GetOrCreateWithKeyInput): Promise<ActorOutput>;
|
|
16
|
+
createActor(input: CreateInput): Promise<ActorOutput>;
|
|
17
|
+
|
|
18
|
+
sendRequest(actorId: string, actorRequest: Request): Promise<Response>;
|
|
19
|
+
openWebSocket(
|
|
20
|
+
path: string,
|
|
21
|
+
actorId: string,
|
|
22
|
+
encoding: Encoding,
|
|
23
|
+
params: unknown,
|
|
24
|
+
): Promise<UniversalWebSocket>;
|
|
25
|
+
proxyRequest(
|
|
26
|
+
c: HonoContext,
|
|
27
|
+
actorRequest: Request,
|
|
28
|
+
actorId: string,
|
|
29
|
+
): Promise<Response>;
|
|
30
|
+
proxyWebSocket(
|
|
31
|
+
c: HonoContext,
|
|
32
|
+
path: string,
|
|
33
|
+
actorId: string,
|
|
34
|
+
encoding: Encoding,
|
|
35
|
+
params: unknown,
|
|
36
|
+
authData: unknown,
|
|
37
|
+
): Promise<Response>;
|
|
38
|
+
|
|
39
|
+
displayInformation(): ManagerDisplayInformation;
|
|
40
|
+
|
|
41
|
+
extraStartupLog?: () => Record<string, unknown>;
|
|
42
|
+
|
|
43
|
+
modifyManagerRouter?: (registryConfig: RegistryConfig, router: Hono) => void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
readonly inspector?: ManagerInspector;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ManagerDisplayInformation {
|
|
52
|
+
name: string;
|
|
53
|
+
properties: Record<string, string>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface GetForIdInput<E extends Env = any> {
|
|
57
|
+
c?: HonoContext | undefined;
|
|
58
|
+
name: string;
|
|
59
|
+
actorId: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface GetWithKeyInput<E extends Env = any> {
|
|
63
|
+
c?: HonoContext | undefined;
|
|
64
|
+
name: string;
|
|
65
|
+
key: ActorKey;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface GetOrCreateWithKeyInput<E extends Env = any> {
|
|
69
|
+
c?: HonoContext | undefined;
|
|
70
|
+
name: string;
|
|
71
|
+
key: ActorKey;
|
|
72
|
+
input?: unknown;
|
|
73
|
+
region?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface CreateInput<E extends Env = any> {
|
|
77
|
+
c?: HonoContext | undefined;
|
|
78
|
+
name: string;
|
|
79
|
+
key: ActorKey;
|
|
80
|
+
input?: unknown;
|
|
81
|
+
region?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface ActorOutput {
|
|
85
|
+
actorId: string;
|
|
86
|
+
name: string;
|
|
87
|
+
key: ActorKey;
|
|
88
|
+
}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import type { WSContext } from "hono/ws";
|
|
2
|
+
import type {
|
|
3
|
+
RivetCloseEvent,
|
|
4
|
+
RivetEvent,
|
|
5
|
+
RivetMessageEvent,
|
|
6
|
+
UniversalWebSocket,
|
|
7
|
+
} from "@/common/websocket-interface";
|
|
8
|
+
import { logger } from "./log";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* HonoWebSocketAdapter provides a WebSocket-like interface over WSContext
|
|
12
|
+
* for raw WebSocket handling in actors
|
|
13
|
+
*/
|
|
14
|
+
export class HonoWebSocketAdapter implements UniversalWebSocket {
|
|
15
|
+
// WebSocket readyState values
|
|
16
|
+
readonly CONNECTING = 0 as const;
|
|
17
|
+
readonly OPEN = 1 as const;
|
|
18
|
+
readonly CLOSING = 2 as const;
|
|
19
|
+
readonly CLOSED = 3 as const;
|
|
20
|
+
|
|
21
|
+
#ws: WSContext;
|
|
22
|
+
#readyState: 0 | 1 | 2 | 3 = 1; // Start as OPEN since WSContext is already connected
|
|
23
|
+
#eventListeners: Map<string, Set<(event: any) => void>> = new Map();
|
|
24
|
+
#closeCode?: number;
|
|
25
|
+
#closeReason?: string;
|
|
26
|
+
|
|
27
|
+
constructor(ws: WSContext) {
|
|
28
|
+
this.#ws = ws;
|
|
29
|
+
|
|
30
|
+
// The WSContext is already open when we receive it
|
|
31
|
+
this.#readyState = this.OPEN;
|
|
32
|
+
|
|
33
|
+
// Immediately fire the open event
|
|
34
|
+
setTimeout(() => {
|
|
35
|
+
this.#fireEvent("open", { type: "open", target: this });
|
|
36
|
+
}, 0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get readyState(): 0 | 1 | 2 | 3 {
|
|
40
|
+
return this.#readyState;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get binaryType(): "arraybuffer" | "blob" {
|
|
44
|
+
return "arraybuffer";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
set binaryType(value: "arraybuffer" | "blob") {
|
|
48
|
+
// Ignored for now - always use arraybuffer
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get bufferedAmount(): number {
|
|
52
|
+
return 0; // Not tracked in WSContext
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get extensions(): string {
|
|
56
|
+
return ""; // Not available in WSContext
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get protocol(): string {
|
|
60
|
+
return ""; // Not available in WSContext
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get url(): string {
|
|
64
|
+
return ""; // Not available in WSContext
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void {
|
|
68
|
+
if (this.readyState !== this.OPEN) {
|
|
69
|
+
throw new Error("WebSocket is not open");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
logger().debug({
|
|
74
|
+
msg: "bridge sending data",
|
|
75
|
+
dataType: typeof data,
|
|
76
|
+
isString: typeof data === "string",
|
|
77
|
+
isArrayBuffer: data instanceof ArrayBuffer,
|
|
78
|
+
dataStr:
|
|
79
|
+
typeof data === "string" ? data.substring(0, 100) : "<non-string>",
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (typeof data === "string") {
|
|
83
|
+
(this.#ws as any).send(data);
|
|
84
|
+
} else if (data instanceof ArrayBuffer) {
|
|
85
|
+
(this.#ws as any).send(data);
|
|
86
|
+
} else if (ArrayBuffer.isView(data)) {
|
|
87
|
+
// Convert ArrayBufferView to ArrayBuffer
|
|
88
|
+
const buffer = data.buffer.slice(
|
|
89
|
+
data.byteOffset,
|
|
90
|
+
data.byteOffset + data.byteLength,
|
|
91
|
+
);
|
|
92
|
+
// Check if it's a SharedArrayBuffer and convert to ArrayBuffer
|
|
93
|
+
if (buffer instanceof SharedArrayBuffer) {
|
|
94
|
+
const arrayBuffer = new ArrayBuffer(buffer.byteLength);
|
|
95
|
+
new Uint8Array(arrayBuffer).set(new Uint8Array(buffer));
|
|
96
|
+
(this.#ws as any).send(arrayBuffer);
|
|
97
|
+
} else {
|
|
98
|
+
(this.#ws as any).send(buffer);
|
|
99
|
+
}
|
|
100
|
+
} else if (data instanceof Blob) {
|
|
101
|
+
// Convert Blob to ArrayBuffer
|
|
102
|
+
data
|
|
103
|
+
.arrayBuffer()
|
|
104
|
+
.then((buffer) => {
|
|
105
|
+
(this.#ws as any).send(buffer);
|
|
106
|
+
})
|
|
107
|
+
.catch((error) => {
|
|
108
|
+
logger().error({
|
|
109
|
+
msg: "failed to convert blob to arraybuffer",
|
|
110
|
+
error,
|
|
111
|
+
});
|
|
112
|
+
this.#fireEvent("error", { type: "error", target: this, error });
|
|
113
|
+
});
|
|
114
|
+
} else {
|
|
115
|
+
// Try to convert to string as a fallback
|
|
116
|
+
logger().warn({
|
|
117
|
+
msg: "unsupported data type, converting to string",
|
|
118
|
+
dataType: typeof data,
|
|
119
|
+
data,
|
|
120
|
+
});
|
|
121
|
+
(this.#ws as any).send(String(data));
|
|
122
|
+
}
|
|
123
|
+
} catch (error) {
|
|
124
|
+
logger().error({ msg: "error sending websocket data", error });
|
|
125
|
+
this.#fireEvent("error", { type: "error", target: this, error });
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
close(code = 1000, reason = ""): void {
|
|
131
|
+
if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this.#readyState = this.CLOSING;
|
|
136
|
+
this.#closeCode = code;
|
|
137
|
+
this.#closeReason = reason;
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
(this.#ws as any).close(code, reason);
|
|
141
|
+
|
|
142
|
+
// Update state and fire close event
|
|
143
|
+
this.#readyState = this.CLOSED;
|
|
144
|
+
this.#fireEvent("close", {
|
|
145
|
+
type: "close",
|
|
146
|
+
target: this,
|
|
147
|
+
code,
|
|
148
|
+
reason,
|
|
149
|
+
wasClean: code === 1000,
|
|
150
|
+
});
|
|
151
|
+
} catch (error) {
|
|
152
|
+
logger().error({ msg: "error closing websocket", error });
|
|
153
|
+
this.#readyState = this.CLOSED;
|
|
154
|
+
this.#fireEvent("close", {
|
|
155
|
+
type: "close",
|
|
156
|
+
target: this,
|
|
157
|
+
code: 1006,
|
|
158
|
+
reason: "Abnormal closure",
|
|
159
|
+
wasClean: false,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
addEventListener(type: string, listener: (event: any) => void): void {
|
|
165
|
+
if (!this.#eventListeners.has(type)) {
|
|
166
|
+
this.#eventListeners.set(type, new Set());
|
|
167
|
+
}
|
|
168
|
+
this.#eventListeners.get(type)!.add(listener);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
removeEventListener(type: string, listener: (event: any) => void): void {
|
|
172
|
+
const listeners = this.#eventListeners.get(type);
|
|
173
|
+
if (listeners) {
|
|
174
|
+
listeners.delete(listener);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
dispatchEvent(event: RivetEvent): boolean {
|
|
179
|
+
const listeners = this.#eventListeners.get(event.type);
|
|
180
|
+
if (listeners) {
|
|
181
|
+
for (const listener of listeners) {
|
|
182
|
+
try {
|
|
183
|
+
listener(event);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
logger().error({
|
|
186
|
+
msg: `error in ${event.type} event listener`,
|
|
187
|
+
error,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Internal method to handle incoming messages from WSContext
|
|
196
|
+
_handleMessage(data: any): void {
|
|
197
|
+
// Hono may pass either raw data or a MessageEvent-like object
|
|
198
|
+
let messageData: string | ArrayBuffer | ArrayBufferView;
|
|
199
|
+
|
|
200
|
+
if (typeof data === "string") {
|
|
201
|
+
messageData = data;
|
|
202
|
+
} else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
|
|
203
|
+
messageData = data;
|
|
204
|
+
} else if (data && typeof data === "object" && "data" in data) {
|
|
205
|
+
// Handle MessageEvent-like objects
|
|
206
|
+
messageData = data.data;
|
|
207
|
+
} else {
|
|
208
|
+
// Fallback - shouldn't happen in normal operation
|
|
209
|
+
messageData = String(data);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
logger().debug({
|
|
213
|
+
msg: "bridge handling message",
|
|
214
|
+
dataType: typeof messageData,
|
|
215
|
+
isArrayBuffer: messageData instanceof ArrayBuffer,
|
|
216
|
+
dataStr: typeof messageData === "string" ? messageData : "<binary>",
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
this.#fireEvent("message", {
|
|
220
|
+
type: "message",
|
|
221
|
+
target: this,
|
|
222
|
+
data: messageData,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Internal method to handle close from WSContext
|
|
227
|
+
_handleClose(code: number, reason: string): void {
|
|
228
|
+
// HACK: Close socket in order to fix bug with Cloudflare leaving WS in closing state
|
|
229
|
+
// https://github.com/cloudflare/workerd/issues/2569
|
|
230
|
+
(this.#ws as any).close(1000, "hack_force_close");
|
|
231
|
+
|
|
232
|
+
if (this.readyState === this.CLOSED) return;
|
|
233
|
+
|
|
234
|
+
this.#readyState = this.CLOSED;
|
|
235
|
+
this.#closeCode = code;
|
|
236
|
+
this.#closeReason = reason;
|
|
237
|
+
|
|
238
|
+
this.#fireEvent("close", {
|
|
239
|
+
type: "close",
|
|
240
|
+
target: this,
|
|
241
|
+
code,
|
|
242
|
+
reason,
|
|
243
|
+
wasClean: code === 1000,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Internal method to handle errors from WSContext
|
|
248
|
+
_handleError(error: any): void {
|
|
249
|
+
this.#fireEvent("error", {
|
|
250
|
+
type: "error",
|
|
251
|
+
target: this,
|
|
252
|
+
error,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
#fireEvent(type: string, event: any): void {
|
|
257
|
+
const listeners = this.#eventListeners.get(type);
|
|
258
|
+
if (listeners) {
|
|
259
|
+
for (const listener of listeners) {
|
|
260
|
+
try {
|
|
261
|
+
listener(event);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
logger().error({ msg: `error in ${type} event listener`, error });
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Also check for on* properties
|
|
269
|
+
switch (type) {
|
|
270
|
+
case "open":
|
|
271
|
+
if (this.#onopen) {
|
|
272
|
+
try {
|
|
273
|
+
this.#onopen(event);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
logger().error({ msg: "error in onopen handler", error });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
break;
|
|
279
|
+
case "close":
|
|
280
|
+
if (this.#onclose) {
|
|
281
|
+
try {
|
|
282
|
+
this.#onclose(event);
|
|
283
|
+
} catch (error) {
|
|
284
|
+
logger().error({ msg: "error in onclose handler", error });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
break;
|
|
288
|
+
case "error":
|
|
289
|
+
if (this.#onerror) {
|
|
290
|
+
try {
|
|
291
|
+
this.#onerror(event);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
logger().error({ msg: "error in onerror handler", error });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
break;
|
|
297
|
+
case "message":
|
|
298
|
+
if (this.#onmessage) {
|
|
299
|
+
try {
|
|
300
|
+
this.#onmessage(event);
|
|
301
|
+
} catch (error) {
|
|
302
|
+
logger().error({ msg: "error in onmessage handler", error });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Event handler properties with getters/setters
|
|
310
|
+
#onopen: ((event: RivetEvent) => void) | null = null;
|
|
311
|
+
#onclose: ((event: RivetCloseEvent) => void) | null = null;
|
|
312
|
+
#onerror: ((event: RivetEvent) => void) | null = null;
|
|
313
|
+
#onmessage: ((event: RivetMessageEvent) => void) | null = null;
|
|
314
|
+
|
|
315
|
+
get onopen(): ((event: RivetEvent) => void) | null {
|
|
316
|
+
return this.#onopen;
|
|
317
|
+
}
|
|
318
|
+
set onopen(handler: ((event: RivetEvent) => void) | null) {
|
|
319
|
+
this.#onopen = handler;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
get onclose(): ((event: RivetCloseEvent) => void) | null {
|
|
323
|
+
return this.#onclose;
|
|
324
|
+
}
|
|
325
|
+
set onclose(handler: ((event: RivetCloseEvent) => void) | null) {
|
|
326
|
+
this.#onclose = handler;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
get onerror(): ((event: RivetEvent) => void) | null {
|
|
330
|
+
return this.#onerror;
|
|
331
|
+
}
|
|
332
|
+
set onerror(handler: ((event: RivetEvent) => void) | null) {
|
|
333
|
+
this.#onerror = handler;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
get onmessage(): ((event: RivetMessageEvent) => void) | null {
|
|
337
|
+
return this.#onmessage;
|
|
338
|
+
}
|
|
339
|
+
set onmessage(handler: ((event: RivetMessageEvent) => void) | null) {
|
|
340
|
+
this.#onmessage = handler;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { TransportSchema } from "@/actor/protocol/old";
|
|
3
|
+
import { ActorQuerySchema } from "./query";
|
|
4
|
+
|
|
5
|
+
export * from "./query";
|
|
6
|
+
|
|
7
|
+
export const ActorsRequestSchema = z.object({
|
|
8
|
+
query: ActorQuerySchema,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const ActorsResponseSchema = z.object({
|
|
12
|
+
actorId: z.string(),
|
|
13
|
+
supportedTransports: z.array(TransportSchema),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
//export const RivetConfigResponseSchema = z.object({
|
|
17
|
+
// endpoint: z.string(),
|
|
18
|
+
// project: z.string().optional(),
|
|
19
|
+
// environment: z.string().optional(),
|
|
20
|
+
//});
|
|
21
|
+
|
|
22
|
+
export type ActorsRequest = z.infer<typeof ActorsRequestSchema>;
|
|
23
|
+
export type ActorsResponse = z.infer<typeof ActorsResponseSchema>;
|
|
24
|
+
//export type RivetConfigResponse = z.infer<typeof RivetConfigResponseSchema>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { EncodingSchema } from "@/actor/protocol/serde";
|
|
3
|
+
import {
|
|
4
|
+
HEADER_ACTOR_ID,
|
|
5
|
+
HEADER_ACTOR_QUERY,
|
|
6
|
+
HEADER_CONN_ID,
|
|
7
|
+
HEADER_CONN_PARAMS,
|
|
8
|
+
HEADER_CONN_TOKEN,
|
|
9
|
+
HEADER_ENCODING,
|
|
10
|
+
} from "@/actor/router-endpoints";
|
|
11
|
+
|
|
12
|
+
// Maximum size of a key component in bytes
|
|
13
|
+
// Set to 128 bytes to allow for separators and escape characters in the full key
|
|
14
|
+
// Cloudflare's maximum key size is 512 bytes, so we need to be significantly smaller
|
|
15
|
+
export const MAX_ACTOR_KEY_SIZE = 128;
|
|
16
|
+
|
|
17
|
+
export const ActorKeySchema = z.array(z.string().max(MAX_ACTOR_KEY_SIZE));
|
|
18
|
+
|
|
19
|
+
export type ActorKey = z.infer<typeof ActorKeySchema>;
|
|
20
|
+
|
|
21
|
+
export const CreateRequestSchema = z.object({
|
|
22
|
+
name: z.string(),
|
|
23
|
+
key: ActorKeySchema,
|
|
24
|
+
input: z.unknown().optional(),
|
|
25
|
+
region: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const GetForKeyRequestSchema = z.object({
|
|
29
|
+
name: z.string(),
|
|
30
|
+
key: ActorKeySchema,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const GetOrCreateRequestSchema = z.object({
|
|
34
|
+
name: z.string(),
|
|
35
|
+
key: ActorKeySchema,
|
|
36
|
+
input: z.unknown().optional(),
|
|
37
|
+
region: z.string().optional(),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const ActorQuerySchema = z.union([
|
|
41
|
+
z.object({
|
|
42
|
+
getForId: z.object({
|
|
43
|
+
name: z.string(),
|
|
44
|
+
actorId: z.string(),
|
|
45
|
+
}),
|
|
46
|
+
}),
|
|
47
|
+
z.object({
|
|
48
|
+
getForKey: GetForKeyRequestSchema,
|
|
49
|
+
}),
|
|
50
|
+
z.object({
|
|
51
|
+
getOrCreateForKey: GetOrCreateRequestSchema,
|
|
52
|
+
}),
|
|
53
|
+
z.object({
|
|
54
|
+
create: CreateRequestSchema,
|
|
55
|
+
}),
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
export const ConnectRequestSchema = z.object({
|
|
59
|
+
query: ActorQuerySchema.describe(HEADER_ACTOR_QUERY),
|
|
60
|
+
encoding: EncodingSchema.describe(HEADER_ENCODING),
|
|
61
|
+
connParams: z.string().optional().describe(HEADER_CONN_PARAMS),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const ConnectWebSocketRequestSchema = z.object({
|
|
65
|
+
query: ActorQuerySchema.describe("query"),
|
|
66
|
+
encoding: EncodingSchema.describe("encoding"),
|
|
67
|
+
connParams: z.unknown().optional().describe("conn_params"),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export const ConnMessageRequestSchema = z.object({
|
|
71
|
+
actorId: z.string().describe(HEADER_ACTOR_ID),
|
|
72
|
+
connId: z.string().describe(HEADER_CONN_ID),
|
|
73
|
+
encoding: EncodingSchema.describe(HEADER_ENCODING),
|
|
74
|
+
connToken: z.string().describe(HEADER_CONN_TOKEN),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
export const ResolveRequestSchema = z.object({
|
|
78
|
+
query: ActorQuerySchema.describe(HEADER_ACTOR_QUERY),
|
|
79
|
+
connParams: z.string().optional().describe(HEADER_CONN_PARAMS),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export type ActorQuery = z.infer<typeof ActorQuerySchema>;
|
|
83
|
+
export type GetForKeyRequest = z.infer<typeof GetForKeyRequestSchema>;
|
|
84
|
+
export type GetOrCreateRequest = z.infer<typeof GetOrCreateRequestSchema>;
|
|
85
|
+
export type ConnectQuery = z.infer<typeof ConnectRequestSchema>;
|
|
86
|
+
/**
|
|
87
|
+
* Interface representing a request to create a actor.
|
|
88
|
+
*/
|
|
89
|
+
export type CreateRequest = z.infer<typeof CreateRequestSchema>;
|