rivetkit 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/schemas/actor-persist/v1.ts +228 -0
- package/dist/schemas/client-protocol/v1.ts +429 -0
- package/dist/schemas/file-system-driver/v1.ts +102 -0
- package/dist/tsup/actor/errors.cjs +69 -0
- package/dist/tsup/actor/errors.cjs.map +1 -0
- package/dist/tsup/actor/errors.d.cts +143 -0
- package/dist/tsup/actor/errors.d.ts +143 -0
- package/dist/tsup/actor/errors.js +69 -0
- package/dist/tsup/actor/errors.js.map +1 -0
- package/dist/tsup/chunk-2CRLFV6Z.cjs +202 -0
- package/dist/tsup/chunk-2CRLFV6Z.cjs.map +1 -0
- package/dist/tsup/chunk-3H7O2A7I.js +525 -0
- package/dist/tsup/chunk-3H7O2A7I.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-4NSUQZ2H.js +1790 -0
- package/dist/tsup/chunk-4NSUQZ2H.js.map +1 -0
- package/dist/tsup/chunk-6PDXBYI5.js +132 -0
- package/dist/tsup/chunk-6PDXBYI5.js.map +1 -0
- package/dist/tsup/chunk-6WKQDDUD.cjs +1790 -0
- package/dist/tsup/chunk-6WKQDDUD.cjs.map +1 -0
- package/dist/tsup/chunk-CTBOSFUH.cjs +116 -0
- package/dist/tsup/chunk-CTBOSFUH.cjs.map +1 -0
- package/dist/tsup/chunk-EGVZZFE2.js +2857 -0
- package/dist/tsup/chunk-EGVZZFE2.js.map +1 -0
- package/dist/tsup/chunk-FCCPJNMA.cjs +132 -0
- package/dist/tsup/chunk-FCCPJNMA.cjs.map +1 -0
- package/dist/tsup/chunk-FLMTTN27.js +244 -0
- package/dist/tsup/chunk-FLMTTN27.js.map +1 -0
- package/dist/tsup/chunk-GIR3AFFI.cjs +315 -0
- package/dist/tsup/chunk-GIR3AFFI.cjs.map +1 -0
- package/dist/tsup/chunk-INGJP237.js +315 -0
- package/dist/tsup/chunk-INGJP237.js.map +1 -0
- package/dist/tsup/chunk-KJCJLKRM.js +116 -0
- package/dist/tsup/chunk-KJCJLKRM.js.map +1 -0
- package/dist/tsup/chunk-KUPQZYUQ.cjs +15 -0
- package/dist/tsup/chunk-KUPQZYUQ.cjs.map +1 -0
- package/dist/tsup/chunk-O2MBYIXO.cjs +2857 -0
- package/dist/tsup/chunk-O2MBYIXO.cjs.map +1 -0
- package/dist/tsup/chunk-OGAPU3UG.cjs +525 -0
- package/dist/tsup/chunk-OGAPU3UG.cjs.map +1 -0
- package/dist/tsup/chunk-OV6AYD4S.js +4406 -0
- package/dist/tsup/chunk-OV6AYD4S.js.map +1 -0
- package/dist/tsup/chunk-PO4VLDWA.js +47 -0
- package/dist/tsup/chunk-PO4VLDWA.js.map +1 -0
- package/dist/tsup/chunk-R2OPSKIV.cjs +244 -0
- package/dist/tsup/chunk-R2OPSKIV.cjs.map +1 -0
- package/dist/tsup/chunk-TZJKSBUQ.cjs +47 -0
- package/dist/tsup/chunk-TZJKSBUQ.cjs.map +1 -0
- package/dist/tsup/chunk-UBUC5C3G.cjs +189 -0
- package/dist/tsup/chunk-UBUC5C3G.cjs.map +1 -0
- package/dist/tsup/chunk-UIM22YJL.cjs +4406 -0
- package/dist/tsup/chunk-UIM22YJL.cjs.map +1 -0
- package/dist/tsup/chunk-URVFQMYI.cjs +230 -0
- package/dist/tsup/chunk-URVFQMYI.cjs.map +1 -0
- package/dist/tsup/chunk-UVUPOS46.js +230 -0
- package/dist/tsup/chunk-UVUPOS46.js.map +1 -0
- package/dist/tsup/chunk-VRRHBNJC.js +189 -0
- package/dist/tsup/chunk-VRRHBNJC.js.map +1 -0
- package/dist/tsup/chunk-XFSS33EQ.js +202 -0
- package/dist/tsup/chunk-XFSS33EQ.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 +26 -0
- package/dist/tsup/client/mod.d.ts +26 -0
- package/dist/tsup/client/mod.js +32 -0
- package/dist/tsup/client/mod.js.map +1 -0
- package/dist/tsup/common/log.cjs +13 -0
- package/dist/tsup/common/log.cjs.map +1 -0
- package/dist/tsup/common/log.d.cts +20 -0
- package/dist/tsup/common/log.d.ts +20 -0
- package/dist/tsup/common/log.js +13 -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-CpqORuCq.d.cts +218 -0
- package/dist/tsup/common-CpqORuCq.d.ts +218 -0
- package/dist/tsup/connection-BR_Ve4ku.d.cts +2117 -0
- package/dist/tsup/connection-BwUMoe6n.d.ts +2117 -0
- package/dist/tsup/driver-helpers/mod.cjs +33 -0
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
- package/dist/tsup/driver-helpers/mod.d.cts +18 -0
- package/dist/tsup/driver-helpers/mod.d.ts +18 -0
- package/dist/tsup/driver-helpers/mod.js +33 -0
- package/dist/tsup/driver-helpers/mod.js.map +1 -0
- package/dist/tsup/driver-test-suite/mod.cjs +4619 -0
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
- package/dist/tsup/driver-test-suite/mod.d.cts +57 -0
- package/dist/tsup/driver-test-suite/mod.d.ts +57 -0
- package/dist/tsup/driver-test-suite/mod.js +4619 -0
- package/dist/tsup/driver-test-suite/mod.js.map +1 -0
- package/dist/tsup/inspector/mod.cjs +53 -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 +53 -0
- package/dist/tsup/inspector/mod.js.map +1 -0
- package/dist/tsup/mod.cjs +73 -0
- package/dist/tsup/mod.cjs.map +1 -0
- package/dist/tsup/mod.d.cts +100 -0
- package/dist/tsup/mod.d.ts +100 -0
- package/dist/tsup/mod.js +73 -0
- package/dist/tsup/mod.js.map +1 -0
- package/dist/tsup/router-endpoints-AYkXG8Tl.d.cts +66 -0
- package/dist/tsup/router-endpoints-DAbqVFx2.d.ts +66 -0
- package/dist/tsup/test/mod.cjs +21 -0
- package/dist/tsup/test/mod.cjs.map +1 -0
- package/dist/tsup/test/mod.d.cts +27 -0
- package/dist/tsup/test/mod.d.ts +27 -0
- package/dist/tsup/test/mod.js +21 -0
- package/dist/tsup/test/mod.js.map +1 -0
- package/dist/tsup/utils-CT0cv4jd.d.cts +17 -0
- package/dist/tsup/utils-CT0cv4jd.d.ts +17 -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 +182 -0
- package/src/actor/config.ts +765 -0
- package/src/actor/connection.ts +260 -0
- package/src/actor/context.ts +171 -0
- package/src/actor/database.ts +23 -0
- package/src/actor/definition.ts +86 -0
- package/src/actor/driver.ts +84 -0
- package/src/actor/errors.ts +360 -0
- package/src/actor/generic-conn-driver.ts +234 -0
- package/src/actor/instance.ts +1800 -0
- package/src/actor/log.ts +15 -0
- package/src/actor/mod.ts +113 -0
- package/src/actor/persisted.ts +42 -0
- package/src/actor/protocol/old.ts +281 -0
- package/src/actor/protocol/serde.ts +131 -0
- package/src/actor/router-endpoints.ts +685 -0
- package/src/actor/router.ts +263 -0
- package/src/actor/schedule.ts +17 -0
- package/src/actor/unstable-react.ts +110 -0
- package/src/actor/utils.ts +98 -0
- package/src/client/actor-common.ts +30 -0
- package/src/client/actor-conn.ts +804 -0
- package/src/client/actor-handle.ts +208 -0
- package/src/client/client.ts +623 -0
- package/src/client/errors.ts +41 -0
- package/src/client/http-client-driver.ts +326 -0
- package/src/client/log.ts +7 -0
- package/src/client/mod.ts +56 -0
- package/src/client/raw-utils.ts +92 -0
- package/src/client/test.ts +44 -0
- package/src/client/utils.ts +150 -0
- package/src/common/eventsource-interface.ts +47 -0
- package/src/common/eventsource.ts +80 -0
- package/src/common/fake-event-source.ts +266 -0
- package/src/common/inline-websocket-adapter2.ts +445 -0
- package/src/common/log-levels.ts +27 -0
- package/src/common/log.ts +139 -0
- package/src/common/logfmt.ts +228 -0
- package/src/common/network.ts +2 -0
- package/src/common/router.ts +87 -0
- package/src/common/utils.ts +322 -0
- package/src/common/versioned-data.ts +95 -0
- package/src/common/websocket-interface.ts +49 -0
- package/src/common/websocket.ts +43 -0
- package/src/driver-helpers/mod.ts +22 -0
- package/src/driver-helpers/utils.ts +17 -0
- package/src/driver-test-suite/log.ts +7 -0
- package/src/driver-test-suite/mod.ts +213 -0
- package/src/driver-test-suite/test-inline-client-driver.ts +402 -0
- package/src/driver-test-suite/tests/action-features.ts +136 -0
- package/src/driver-test-suite/tests/actor-auth.ts +591 -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 +259 -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 +365 -0
- package/src/driver-test-suite/tests/raw-http-direct-registry.ts +226 -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 +392 -0
- package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
- package/src/driver-test-suite/tests/request-access.ts +244 -0
- package/src/driver-test-suite/utils.ts +68 -0
- package/src/drivers/default.ts +31 -0
- package/src/drivers/engine/actor-driver.ts +360 -0
- package/src/drivers/engine/api-endpoints.ts +128 -0
- package/src/drivers/engine/api-utils.ts +70 -0
- package/src/drivers/engine/config.ts +39 -0
- package/src/drivers/engine/keys.test.ts +266 -0
- package/src/drivers/engine/keys.ts +89 -0
- package/src/drivers/engine/kv.ts +3 -0
- package/src/drivers/engine/log.ts +7 -0
- package/src/drivers/engine/manager-driver.ts +391 -0
- package/src/drivers/engine/mod.ts +36 -0
- package/src/drivers/engine/ws-proxy.ts +170 -0
- package/src/drivers/file-system/actor.ts +91 -0
- package/src/drivers/file-system/global-state.ts +673 -0
- package/src/drivers/file-system/log.ts +7 -0
- package/src/drivers/file-system/manager.ts +306 -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/inline-client-driver/log.ts +7 -0
- package/src/inline-client-driver/mod.ts +385 -0
- package/src/inspector/actor.ts +298 -0
- package/src/inspector/config.ts +83 -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/auth.ts +121 -0
- package/src/manager/driver.ts +80 -0
- package/src/manager/hono-websocket-adapter.ts +333 -0
- package/src/manager/log.ts +7 -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 +1792 -0
- package/src/mod.ts +20 -0
- package/src/registry/config.ts +32 -0
- package/src/registry/log.ts +7 -0
- package/src/registry/mod.ts +124 -0
- package/src/registry/run-config.ts +54 -0
- package/src/registry/serve.ts +53 -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 +84 -0
- package/src/test/config.ts +16 -0
- package/src/test/log.ts +7 -0
- package/src/test/mod.ts +153 -0
- package/src/utils.ts +172 -0
- package/README.md +0 -13
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
import * as cbor from "cbor-x";
|
|
2
|
+
import type { Context as HonoContext, HonoRequest } from "hono";
|
|
3
|
+
import { type SSEStreamingApi, streamSSE } from "hono/streaming";
|
|
4
|
+
import type { WSContext } from "hono/ws";
|
|
5
|
+
import { ActionContext } from "@/actor/action";
|
|
6
|
+
import type { AnyConn } from "@/actor/connection";
|
|
7
|
+
import {
|
|
8
|
+
CONNECTION_DRIVER_HTTP,
|
|
9
|
+
CONNECTION_DRIVER_SSE,
|
|
10
|
+
CONNECTION_DRIVER_WEBSOCKET,
|
|
11
|
+
generateConnId,
|
|
12
|
+
generateConnToken,
|
|
13
|
+
} from "@/actor/connection";
|
|
14
|
+
import * as errors from "@/actor/errors";
|
|
15
|
+
import type { AnyActorInstance } from "@/actor/instance";
|
|
16
|
+
import type { InputData } from "@/actor/protocol/serde";
|
|
17
|
+
import { type Encoding, EncodingSchema } from "@/actor/protocol/serde";
|
|
18
|
+
import type { UpgradeWebSocketArgs } from "@/common/inline-websocket-adapter2";
|
|
19
|
+
import { deconstructError, stringifyError } from "@/common/utils";
|
|
20
|
+
import type { UniversalWebSocket } from "@/common/websocket-interface";
|
|
21
|
+
import { HonoWebSocketAdapter } from "@/manager/hono-websocket-adapter";
|
|
22
|
+
import type { RunConfig } from "@/registry/run-config";
|
|
23
|
+
import type * as protocol from "@/schemas/client-protocol/mod";
|
|
24
|
+
import {
|
|
25
|
+
HTTP_ACTION_REQUEST_VERSIONED,
|
|
26
|
+
HTTP_ACTION_RESPONSE_VERSIONED,
|
|
27
|
+
TO_SERVER_VERSIONED,
|
|
28
|
+
} from "@/schemas/client-protocol/versioned";
|
|
29
|
+
import {
|
|
30
|
+
contentTypeForEncoding,
|
|
31
|
+
deserializeWithEncoding,
|
|
32
|
+
serializeWithEncoding,
|
|
33
|
+
} from "@/serde";
|
|
34
|
+
import { bufferToArrayBuffer } from "@/utils";
|
|
35
|
+
import type { ActorDriver } from "./driver";
|
|
36
|
+
import type {
|
|
37
|
+
GenericHttpDriverState,
|
|
38
|
+
GenericSseDriverState,
|
|
39
|
+
GenericWebSocketDriverState,
|
|
40
|
+
} from "./generic-conn-driver";
|
|
41
|
+
import { logger } from "./log";
|
|
42
|
+
import { parseMessage } from "./protocol/old";
|
|
43
|
+
|
|
44
|
+
export interface ConnectWebSocketOpts {
|
|
45
|
+
req?: HonoRequest;
|
|
46
|
+
encoding: Encoding;
|
|
47
|
+
actorId: string;
|
|
48
|
+
params: unknown;
|
|
49
|
+
authData: unknown;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ConnectWebSocketOutput {
|
|
53
|
+
onOpen: (ws: WSContext) => void;
|
|
54
|
+
onMessage: (message: protocol.ToServer) => void;
|
|
55
|
+
onClose: () => void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ConnectSseOpts {
|
|
59
|
+
req?: HonoRequest;
|
|
60
|
+
encoding: Encoding;
|
|
61
|
+
params: unknown;
|
|
62
|
+
actorId: string;
|
|
63
|
+
authData: unknown;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ConnectSseOutput {
|
|
67
|
+
onOpen: (stream: SSEStreamingApi) => void;
|
|
68
|
+
onClose: () => Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface ActionOpts {
|
|
72
|
+
req?: HonoRequest;
|
|
73
|
+
params: unknown;
|
|
74
|
+
actionName: string;
|
|
75
|
+
actionArgs: unknown[];
|
|
76
|
+
actorId: string;
|
|
77
|
+
authData: unknown;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ActionOutput {
|
|
81
|
+
output: unknown;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface ConnsMessageOpts {
|
|
85
|
+
req?: HonoRequest;
|
|
86
|
+
connId: string;
|
|
87
|
+
connToken: string;
|
|
88
|
+
message: protocol.ToServer;
|
|
89
|
+
actorId: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface FetchOpts {
|
|
93
|
+
request: Request;
|
|
94
|
+
actorId: string;
|
|
95
|
+
authData: unknown;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface WebSocketOpts {
|
|
99
|
+
request: Request;
|
|
100
|
+
websocket: UniversalWebSocket;
|
|
101
|
+
actorId: string;
|
|
102
|
+
authData: unknown;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Creates a WebSocket connection handler
|
|
107
|
+
*/
|
|
108
|
+
export async function handleWebSocketConnect(
|
|
109
|
+
req: Request | undefined,
|
|
110
|
+
runConfig: RunConfig,
|
|
111
|
+
actorDriver: ActorDriver,
|
|
112
|
+
actorId: string,
|
|
113
|
+
encoding: Encoding,
|
|
114
|
+
parameters: unknown,
|
|
115
|
+
authData: unknown,
|
|
116
|
+
): Promise<UpgradeWebSocketArgs> {
|
|
117
|
+
const exposeInternalError = req ? getRequestExposeInternalError(req) : false;
|
|
118
|
+
|
|
119
|
+
// Setup promise for the init handlers since all other behavior depends on this
|
|
120
|
+
const {
|
|
121
|
+
promise: handlersPromise,
|
|
122
|
+
resolve: handlersResolve,
|
|
123
|
+
reject: handlersReject,
|
|
124
|
+
} = Promise.withResolvers<{
|
|
125
|
+
conn: AnyConn;
|
|
126
|
+
actor: AnyActorInstance;
|
|
127
|
+
connId: string;
|
|
128
|
+
}>();
|
|
129
|
+
|
|
130
|
+
// Pre-load the actor to catch errors early
|
|
131
|
+
let actor: AnyActorInstance;
|
|
132
|
+
try {
|
|
133
|
+
actor = await actorDriver.loadActor(actorId);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
// Return handler that immediately closes with error
|
|
136
|
+
return {
|
|
137
|
+
onOpen: (_evt: any, ws: WSContext) => {
|
|
138
|
+
const { code } = deconstructError(
|
|
139
|
+
error,
|
|
140
|
+
logger(),
|
|
141
|
+
{
|
|
142
|
+
wsEvent: "open",
|
|
143
|
+
},
|
|
144
|
+
exposeInternalError,
|
|
145
|
+
);
|
|
146
|
+
ws.close(1011, code);
|
|
147
|
+
},
|
|
148
|
+
onMessage: (_evt: { data: any }, ws: WSContext) => {
|
|
149
|
+
ws.close(1011, "Actor not loaded");
|
|
150
|
+
},
|
|
151
|
+
onClose: (_event: any, _ws: WSContext) => {},
|
|
152
|
+
onError: (_error: unknown) => {},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
onOpen: (_evt: any, ws: WSContext) => {
|
|
158
|
+
logger().debug("websocket open");
|
|
159
|
+
|
|
160
|
+
// Run async operations in background
|
|
161
|
+
(async () => {
|
|
162
|
+
try {
|
|
163
|
+
const connId = generateConnId();
|
|
164
|
+
const connToken = generateConnToken();
|
|
165
|
+
const connState = await actor.prepareConn(parameters, req);
|
|
166
|
+
|
|
167
|
+
// Save socket
|
|
168
|
+
const connGlobalState =
|
|
169
|
+
actorDriver.getGenericConnGlobalState(actorId);
|
|
170
|
+
connGlobalState.websockets.set(connId, ws);
|
|
171
|
+
logger().debug("registered websocket for conn", {
|
|
172
|
+
actorId,
|
|
173
|
+
totalCount: connGlobalState.websockets.size,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Create connection
|
|
177
|
+
const conn = await actor.createConn(
|
|
178
|
+
connId,
|
|
179
|
+
connToken,
|
|
180
|
+
parameters,
|
|
181
|
+
connState,
|
|
182
|
+
CONNECTION_DRIVER_WEBSOCKET,
|
|
183
|
+
{ encoding } satisfies GenericWebSocketDriverState,
|
|
184
|
+
authData,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// Unblock other handlers
|
|
188
|
+
handlersResolve({ conn, actor, connId });
|
|
189
|
+
} catch (error) {
|
|
190
|
+
handlersReject(error);
|
|
191
|
+
|
|
192
|
+
const { code } = deconstructError(
|
|
193
|
+
error,
|
|
194
|
+
logger(),
|
|
195
|
+
{
|
|
196
|
+
wsEvent: "open",
|
|
197
|
+
},
|
|
198
|
+
exposeInternalError,
|
|
199
|
+
);
|
|
200
|
+
ws.close(1011, code);
|
|
201
|
+
}
|
|
202
|
+
})();
|
|
203
|
+
},
|
|
204
|
+
onMessage: (evt: { data: any }, ws: WSContext) => {
|
|
205
|
+
// Handle message asynchronously
|
|
206
|
+
handlersPromise
|
|
207
|
+
.then(({ conn, actor }) => {
|
|
208
|
+
logger().debug("received message");
|
|
209
|
+
|
|
210
|
+
const value = evt.data.valueOf() as InputData;
|
|
211
|
+
parseMessage(value, {
|
|
212
|
+
encoding: encoding,
|
|
213
|
+
maxIncomingMessageSize: runConfig.maxIncomingMessageSize,
|
|
214
|
+
})
|
|
215
|
+
.then((message) => {
|
|
216
|
+
actor.processMessage(message, conn).catch((error) => {
|
|
217
|
+
const { code } = deconstructError(
|
|
218
|
+
error,
|
|
219
|
+
logger(),
|
|
220
|
+
{
|
|
221
|
+
wsEvent: "message",
|
|
222
|
+
},
|
|
223
|
+
exposeInternalError,
|
|
224
|
+
);
|
|
225
|
+
ws.close(1011, code);
|
|
226
|
+
});
|
|
227
|
+
})
|
|
228
|
+
.catch((error) => {
|
|
229
|
+
const { code } = deconstructError(
|
|
230
|
+
error,
|
|
231
|
+
logger(),
|
|
232
|
+
{
|
|
233
|
+
wsEvent: "message",
|
|
234
|
+
},
|
|
235
|
+
exposeInternalError,
|
|
236
|
+
);
|
|
237
|
+
ws.close(1011, code);
|
|
238
|
+
});
|
|
239
|
+
})
|
|
240
|
+
.catch((error) => {
|
|
241
|
+
const { code } = deconstructError(
|
|
242
|
+
error,
|
|
243
|
+
logger(),
|
|
244
|
+
{
|
|
245
|
+
wsEvent: "message",
|
|
246
|
+
},
|
|
247
|
+
exposeInternalError,
|
|
248
|
+
);
|
|
249
|
+
ws.close(1011, code);
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
onClose: (
|
|
253
|
+
event: {
|
|
254
|
+
wasClean: boolean;
|
|
255
|
+
code: number;
|
|
256
|
+
reason: string;
|
|
257
|
+
},
|
|
258
|
+
ws: WSContext,
|
|
259
|
+
) => {
|
|
260
|
+
if (event.wasClean) {
|
|
261
|
+
logger().info("websocket closed", {
|
|
262
|
+
code: event.code,
|
|
263
|
+
reason: event.reason,
|
|
264
|
+
wasClean: event.wasClean,
|
|
265
|
+
});
|
|
266
|
+
} else {
|
|
267
|
+
logger().warn("websocket closed", {
|
|
268
|
+
code: event.code,
|
|
269
|
+
reason: event.reason,
|
|
270
|
+
wasClean: event.wasClean,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// HACK: Close socket in order to fix bug with Cloudflare leaving WS in closing state
|
|
275
|
+
// https://github.com/cloudflare/workerd/issues/2569
|
|
276
|
+
ws.close(1000, "hack_force_close");
|
|
277
|
+
|
|
278
|
+
// Handle cleanup asynchronously
|
|
279
|
+
handlersPromise
|
|
280
|
+
.then(({ conn, actor, connId }) => {
|
|
281
|
+
const connGlobalState =
|
|
282
|
+
actorDriver.getGenericConnGlobalState(actorId);
|
|
283
|
+
const didDelete = connGlobalState.websockets.delete(connId);
|
|
284
|
+
if (didDelete) {
|
|
285
|
+
logger().info("removing websocket for conn", {
|
|
286
|
+
totalCount: connGlobalState.websockets.size,
|
|
287
|
+
});
|
|
288
|
+
} else {
|
|
289
|
+
logger().warn("websocket does not exist for conn", {
|
|
290
|
+
actorId,
|
|
291
|
+
totalCount: connGlobalState.websockets.size,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
actor.__removeConn(conn);
|
|
296
|
+
})
|
|
297
|
+
.catch((error) => {
|
|
298
|
+
deconstructError(
|
|
299
|
+
error,
|
|
300
|
+
logger(),
|
|
301
|
+
{ wsEvent: "close" },
|
|
302
|
+
exposeInternalError,
|
|
303
|
+
);
|
|
304
|
+
});
|
|
305
|
+
},
|
|
306
|
+
onError: (_error: unknown) => {
|
|
307
|
+
try {
|
|
308
|
+
// Actors don't need to know about this, since it's abstracted away
|
|
309
|
+
logger().warn("websocket error");
|
|
310
|
+
} catch (error) {
|
|
311
|
+
deconstructError(
|
|
312
|
+
error,
|
|
313
|
+
logger(),
|
|
314
|
+
{ wsEvent: "error" },
|
|
315
|
+
exposeInternalError,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Creates an SSE connection handler
|
|
324
|
+
*/
|
|
325
|
+
export async function handleSseConnect(
|
|
326
|
+
c: HonoContext,
|
|
327
|
+
_runConfig: RunConfig,
|
|
328
|
+
actorDriver: ActorDriver,
|
|
329
|
+
actorId: string,
|
|
330
|
+
authData: unknown,
|
|
331
|
+
) {
|
|
332
|
+
const encoding = getRequestEncoding(c.req);
|
|
333
|
+
const parameters = getRequestConnParams(c.req);
|
|
334
|
+
|
|
335
|
+
// Return the main handler with all async work inside
|
|
336
|
+
return streamSSE(c, async (stream) => {
|
|
337
|
+
let actor: AnyActorInstance | undefined;
|
|
338
|
+
let connId: string | undefined;
|
|
339
|
+
let connToken: string | undefined;
|
|
340
|
+
let connState: unknown;
|
|
341
|
+
let conn: AnyConn | undefined;
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
// Do all async work inside the handler
|
|
345
|
+
actor = await actorDriver.loadActor(actorId);
|
|
346
|
+
connId = generateConnId();
|
|
347
|
+
connToken = generateConnToken();
|
|
348
|
+
connState = await actor.prepareConn(parameters, c.req.raw);
|
|
349
|
+
|
|
350
|
+
logger().debug("sse open");
|
|
351
|
+
|
|
352
|
+
// Save stream
|
|
353
|
+
actorDriver
|
|
354
|
+
.getGenericConnGlobalState(actorId)
|
|
355
|
+
.sseStreams.set(connId, stream);
|
|
356
|
+
|
|
357
|
+
// Create connection
|
|
358
|
+
conn = await actor.createConn(
|
|
359
|
+
connId,
|
|
360
|
+
connToken,
|
|
361
|
+
parameters,
|
|
362
|
+
connState,
|
|
363
|
+
CONNECTION_DRIVER_SSE,
|
|
364
|
+
{ encoding } satisfies GenericSseDriverState,
|
|
365
|
+
authData,
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
// Wait for close
|
|
369
|
+
const abortResolver = Promise.withResolvers();
|
|
370
|
+
|
|
371
|
+
// Handle stream abort (when client closes the connection)
|
|
372
|
+
stream.onAbort(async () => {
|
|
373
|
+
try {
|
|
374
|
+
logger().debug("sse stream aborted");
|
|
375
|
+
|
|
376
|
+
// Cleanup
|
|
377
|
+
if (connId) {
|
|
378
|
+
actorDriver
|
|
379
|
+
.getGenericConnGlobalState(actorId)
|
|
380
|
+
.sseStreams.delete(connId);
|
|
381
|
+
}
|
|
382
|
+
if (conn && actor) {
|
|
383
|
+
actor.__removeConn(conn);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
abortResolver.resolve(undefined);
|
|
387
|
+
} catch (error) {
|
|
388
|
+
logger().error("error closing sse connection", { error });
|
|
389
|
+
abortResolver.resolve(undefined);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// HACK: Will throw if not configured
|
|
394
|
+
try {
|
|
395
|
+
c.executionCtx.waitUntil(abortResolver.promise);
|
|
396
|
+
} catch {}
|
|
397
|
+
|
|
398
|
+
// Wait until connection aborted
|
|
399
|
+
await abortResolver.promise;
|
|
400
|
+
} catch (error) {
|
|
401
|
+
logger().error("error in sse connection", { error });
|
|
402
|
+
|
|
403
|
+
// Cleanup on error
|
|
404
|
+
if (connId !== undefined) {
|
|
405
|
+
actorDriver
|
|
406
|
+
.getGenericConnGlobalState(actorId)
|
|
407
|
+
.sseStreams.delete(connId);
|
|
408
|
+
}
|
|
409
|
+
if (conn && actor !== undefined) {
|
|
410
|
+
actor.__removeConn(conn);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Close the stream on error
|
|
414
|
+
stream.close();
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Creates an action handler
|
|
421
|
+
*/
|
|
422
|
+
export async function handleAction(
|
|
423
|
+
c: HonoContext,
|
|
424
|
+
_runConfig: RunConfig,
|
|
425
|
+
actorDriver: ActorDriver,
|
|
426
|
+
actionName: string,
|
|
427
|
+
actorId: string,
|
|
428
|
+
authData: unknown,
|
|
429
|
+
) {
|
|
430
|
+
const encoding = getRequestEncoding(c.req);
|
|
431
|
+
const parameters = getRequestConnParams(c.req);
|
|
432
|
+
|
|
433
|
+
logger().debug("handling action", { actionName, encoding });
|
|
434
|
+
|
|
435
|
+
// Validate incoming request
|
|
436
|
+
const arrayBuffer = await c.req.arrayBuffer();
|
|
437
|
+
const request = deserializeWithEncoding(
|
|
438
|
+
encoding,
|
|
439
|
+
new Uint8Array(arrayBuffer),
|
|
440
|
+
HTTP_ACTION_REQUEST_VERSIONED,
|
|
441
|
+
);
|
|
442
|
+
const actionArgs = cbor.decode(new Uint8Array(request.args));
|
|
443
|
+
|
|
444
|
+
// Invoke the action
|
|
445
|
+
let actor: AnyActorInstance | undefined;
|
|
446
|
+
let conn: AnyConn | undefined;
|
|
447
|
+
let output: unknown | undefined;
|
|
448
|
+
try {
|
|
449
|
+
actor = await actorDriver.loadActor(actorId);
|
|
450
|
+
|
|
451
|
+
// Create conn
|
|
452
|
+
const connState = await actor.prepareConn(parameters, c.req.raw);
|
|
453
|
+
conn = await actor.createConn(
|
|
454
|
+
generateConnId(),
|
|
455
|
+
generateConnToken(),
|
|
456
|
+
parameters,
|
|
457
|
+
connState,
|
|
458
|
+
CONNECTION_DRIVER_HTTP,
|
|
459
|
+
{} satisfies GenericHttpDriverState,
|
|
460
|
+
authData,
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
// Call action
|
|
464
|
+
const ctx = new ActionContext(actor.actorContext!, conn!);
|
|
465
|
+
output = await actor.executeAction(ctx, actionName, actionArgs);
|
|
466
|
+
} finally {
|
|
467
|
+
if (conn) {
|
|
468
|
+
actor?.__removeConn(conn);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Send response
|
|
473
|
+
const responseData: protocol.HttpActionResponse = {
|
|
474
|
+
output: bufferToArrayBuffer(cbor.encode(output)),
|
|
475
|
+
};
|
|
476
|
+
const serialized = serializeWithEncoding(
|
|
477
|
+
encoding,
|
|
478
|
+
responseData,
|
|
479
|
+
HTTP_ACTION_RESPONSE_VERSIONED,
|
|
480
|
+
);
|
|
481
|
+
return c.body(serialized as Uint8Array, 200, {
|
|
482
|
+
"Content-Type": contentTypeForEncoding(encoding),
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Create a connection message handler
|
|
488
|
+
*/
|
|
489
|
+
export async function handleConnectionMessage(
|
|
490
|
+
c: HonoContext,
|
|
491
|
+
_runConfig: RunConfig,
|
|
492
|
+
actorDriver: ActorDriver,
|
|
493
|
+
connId: string,
|
|
494
|
+
connToken: string,
|
|
495
|
+
actorId: string,
|
|
496
|
+
) {
|
|
497
|
+
const encoding = getRequestEncoding(c.req);
|
|
498
|
+
|
|
499
|
+
// Validate incoming request
|
|
500
|
+
const arrayBuffer = await c.req.arrayBuffer();
|
|
501
|
+
const message = deserializeWithEncoding(
|
|
502
|
+
encoding,
|
|
503
|
+
new Uint8Array(arrayBuffer),
|
|
504
|
+
TO_SERVER_VERSIONED,
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
const actor = await actorDriver.loadActor(actorId);
|
|
508
|
+
|
|
509
|
+
// Find connection
|
|
510
|
+
const conn = actor.conns.get(connId);
|
|
511
|
+
if (!conn) {
|
|
512
|
+
throw new errors.ConnNotFound(connId);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Authenticate connection
|
|
516
|
+
if (conn._token !== connToken) {
|
|
517
|
+
throw new errors.IncorrectConnToken();
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Process message
|
|
521
|
+
await actor.processMessage(message, conn);
|
|
522
|
+
|
|
523
|
+
return c.json({});
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
export async function handleRawWebSocketHandler(
|
|
527
|
+
req: Request | undefined,
|
|
528
|
+
path: string,
|
|
529
|
+
actorDriver: ActorDriver,
|
|
530
|
+
actorId: string,
|
|
531
|
+
authData: unknown,
|
|
532
|
+
): Promise<UpgradeWebSocketArgs> {
|
|
533
|
+
const actor = await actorDriver.loadActor(actorId);
|
|
534
|
+
|
|
535
|
+
// Return WebSocket event handlers
|
|
536
|
+
return {
|
|
537
|
+
onOpen: (_evt: any, ws: any) => {
|
|
538
|
+
// Wrap the Hono WebSocket in our adapter
|
|
539
|
+
const adapter = new HonoWebSocketAdapter(ws);
|
|
540
|
+
|
|
541
|
+
// Store adapter reference on the WebSocket for event handlers
|
|
542
|
+
(ws as any).__adapter = adapter;
|
|
543
|
+
|
|
544
|
+
// Extract the path after prefix and preserve query parameters
|
|
545
|
+
// Use URL API for cleaner parsing
|
|
546
|
+
const url = new URL(path, "http://actor");
|
|
547
|
+
const pathname = url.pathname.replace(/^\/raw\/websocket/, "") || "/";
|
|
548
|
+
const normalizedPath = pathname + url.search;
|
|
549
|
+
|
|
550
|
+
let newRequest: Request;
|
|
551
|
+
if (req) {
|
|
552
|
+
newRequest = new Request(`http://actor${normalizedPath}`, req);
|
|
553
|
+
} else {
|
|
554
|
+
newRequest = new Request(`http://actor${normalizedPath}`, {
|
|
555
|
+
method: "GET",
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
logger().debug("rewriting websocket url", {
|
|
560
|
+
from: path,
|
|
561
|
+
to: newRequest.url,
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
// Call the actor's onWebSocket handler with the adapted WebSocket
|
|
565
|
+
actor.handleWebSocket(adapter, {
|
|
566
|
+
request: newRequest,
|
|
567
|
+
auth: authData,
|
|
568
|
+
});
|
|
569
|
+
},
|
|
570
|
+
onMessage: (event: any, ws: any) => {
|
|
571
|
+
// Find the adapter for this WebSocket
|
|
572
|
+
const adapter = (ws as any).__adapter;
|
|
573
|
+
if (adapter) {
|
|
574
|
+
adapter._handleMessage(event);
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
onClose: (evt: any, ws: any) => {
|
|
578
|
+
// Find the adapter for this WebSocket
|
|
579
|
+
const adapter = (ws as any).__adapter;
|
|
580
|
+
if (adapter) {
|
|
581
|
+
adapter._handleClose(evt?.code || 1006, evt?.reason || "");
|
|
582
|
+
}
|
|
583
|
+
},
|
|
584
|
+
onError: (error: any, ws: any) => {
|
|
585
|
+
// Find the adapter for this WebSocket
|
|
586
|
+
const adapter = (ws as any).__adapter;
|
|
587
|
+
if (adapter) {
|
|
588
|
+
adapter._handleError(error);
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Helper to get the connection encoding from a request
|
|
595
|
+
export function getRequestEncoding(req: HonoRequest): Encoding {
|
|
596
|
+
const encodingParam = req.header(HEADER_ENCODING);
|
|
597
|
+
if (!encodingParam) {
|
|
598
|
+
throw new errors.InvalidEncoding("undefined");
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
const result = EncodingSchema.safeParse(encodingParam);
|
|
602
|
+
if (!result.success) {
|
|
603
|
+
throw new errors.InvalidEncoding(encodingParam as string);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return result.data;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
export function getRequestExposeInternalError(req: Request): boolean {
|
|
610
|
+
const param = req.headers.get(HEADER_EXPOSE_INTERNAL_ERROR);
|
|
611
|
+
if (!param) {
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return param === "true";
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
export function getRequestQuery(c: HonoContext): unknown {
|
|
619
|
+
// Get query parameters for actor lookup
|
|
620
|
+
const queryParam = c.req.header(HEADER_ACTOR_QUERY);
|
|
621
|
+
if (!queryParam) {
|
|
622
|
+
logger().error("missing query parameter");
|
|
623
|
+
throw new errors.InvalidRequest("missing query");
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Parse the query JSON and validate with schema
|
|
627
|
+
try {
|
|
628
|
+
const parsed = JSON.parse(queryParam);
|
|
629
|
+
return parsed;
|
|
630
|
+
} catch (error) {
|
|
631
|
+
logger().error("invalid query json", { error });
|
|
632
|
+
throw new errors.InvalidQueryJSON(error);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
export const HEADER_ACTOR_QUERY = "X-RivetKit-Query";
|
|
637
|
+
|
|
638
|
+
export const HEADER_ENCODING = "X-RivetKit-Encoding";
|
|
639
|
+
|
|
640
|
+
// Internal header
|
|
641
|
+
export const HEADER_EXPOSE_INTERNAL_ERROR = "X-RivetKit-Expose-Internal-Error";
|
|
642
|
+
|
|
643
|
+
// IMPORTANT: Params must be in headers or in an E2EE part of the request (i.e. NOT the URL or query string) in order to ensure that tokens can be securely passed in params.
|
|
644
|
+
export const HEADER_CONN_PARAMS = "X-RivetKit-Conn-Params";
|
|
645
|
+
|
|
646
|
+
// Internal header
|
|
647
|
+
export const HEADER_AUTH_DATA = "X-RivetKit-Auth-Data";
|
|
648
|
+
|
|
649
|
+
export const HEADER_ACTOR_ID = "X-RivetKit-Actor";
|
|
650
|
+
|
|
651
|
+
export const HEADER_CONN_ID = "X-RivetKit-Conn";
|
|
652
|
+
|
|
653
|
+
export const HEADER_CONN_TOKEN = "X-RivetKit-Conn-Token";
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Headers that publics can send from public clients.
|
|
657
|
+
*
|
|
658
|
+
* Used for CORS.
|
|
659
|
+
**/
|
|
660
|
+
export const ALLOWED_PUBLIC_HEADERS = [
|
|
661
|
+
"Content-Type",
|
|
662
|
+
"User-Agent",
|
|
663
|
+
HEADER_ACTOR_QUERY,
|
|
664
|
+
HEADER_ENCODING,
|
|
665
|
+
HEADER_CONN_PARAMS,
|
|
666
|
+
HEADER_ACTOR_ID,
|
|
667
|
+
HEADER_CONN_ID,
|
|
668
|
+
HEADER_CONN_TOKEN,
|
|
669
|
+
];
|
|
670
|
+
|
|
671
|
+
// Helper to get connection parameters for the request
|
|
672
|
+
export function getRequestConnParams(req: HonoRequest): unknown {
|
|
673
|
+
const paramsParam = req.header(HEADER_CONN_PARAMS);
|
|
674
|
+
if (!paramsParam) {
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
try {
|
|
679
|
+
return JSON.parse(paramsParam);
|
|
680
|
+
} catch (err) {
|
|
681
|
+
throw new errors.InvalidParams(
|
|
682
|
+
`Invalid params JSON: ${stringifyError(err)}`,
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
}
|