@rivetkit/cloudflare-workers 2.0.5 → 2.0.7-rc.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivetkit/cloudflare-workers",
3
- "version": "2.0.5",
3
+ "version": "2.0.7-rc.1",
4
4
  "description": "Cloudflare Workers adapter for RivetKit actors",
5
5
  "keywords": [
6
6
  "rivetkit",
@@ -29,7 +29,10 @@
29
29
  },
30
30
  "./tsconfig": "./dist/tsconfig.json"
31
31
  },
32
- "sideEffects": false,
32
+ "sideEffects": [
33
+ "./dist/chunk-*.js",
34
+ "./dist/chunk-*.cjs"
35
+ ],
33
36
  "devDependencies": {
34
37
  "@cloudflare/workers-types": "^4.20250129.0",
35
38
  "@types/invariant": "^2",
@@ -43,7 +46,7 @@
43
46
  "invariant": "^2.2.4",
44
47
  "zod": "^3.25.76",
45
48
  "hono": "4.8.3",
46
- "rivetkit": "2.0.5"
49
+ "rivetkit": "2.0.7-rc.1"
47
50
  },
48
51
  "stableVersion": "0.8.0",
49
52
  "scripts": {
@@ -4,17 +4,14 @@ import type {
4
4
  RegistryConfig,
5
5
  RunConfig,
6
6
  } from "rivetkit";
7
- import {
8
- createGenericConnDrivers,
9
- GenericConnGlobalState,
10
- lookupInRegistry,
11
- } from "rivetkit";
7
+ import { lookupInRegistry } from "rivetkit";
12
8
  import type { Client } from "rivetkit/client";
13
9
  import type {
14
10
  ActorDriver,
15
11
  AnyActorInstance,
16
12
  ManagerDriver,
17
13
  } from "rivetkit/driver-helpers";
14
+ import { promiseWithResolvers } from "rivetkit/utils";
18
15
  import { KEYS } from "./actor-handler-do";
19
16
 
20
17
  interface DurableObjectGlobalState {
@@ -49,8 +46,8 @@ export interface DriverContext {
49
46
  // Actor handler to track running instances
50
47
  class ActorHandler {
51
48
  actor?: AnyActorInstance;
52
- actorPromise?: PromiseWithResolvers<void> = Promise.withResolvers();
53
- genericConnGlobalState = new GenericConnGlobalState();
49
+ actorPromise?: ReturnType<typeof promiseWithResolvers<void>> =
50
+ promiseWithResolvers();
54
51
  }
55
52
 
56
53
  export class CloudflareActorsActorDriver implements ActorDriver {
@@ -114,11 +111,7 @@ export class CloudflareActorsActorDriver implements ActorDriver {
114
111
  handler.actor = definition.instantiate();
115
112
 
116
113
  // Start actor
117
- const connDrivers = createGenericConnDrivers(
118
- handler.genericConnGlobalState,
119
- );
120
114
  await handler.actor.start(
121
- connDrivers,
122
115
  this,
123
116
  this.#inlineClient,
124
117
  actorId,
@@ -134,14 +127,6 @@ export class CloudflareActorsActorDriver implements ActorDriver {
134
127
  return handler.actor;
135
128
  }
136
129
 
137
- getGenericConnGlobalState(actorId: string): GenericConnGlobalState {
138
- const handler = this.#actors.get(actorId);
139
- if (!handler) {
140
- throw new Error(`Actor ${actorId} not loaded`);
141
- }
142
- return handler.genericConnGlobalState;
143
- }
144
-
145
130
  getContext(actorId: string): DriverContext {
146
131
  const state = this.#globalState.getDOState(actorId);
147
132
  return { state: state.ctx };
@@ -3,7 +3,12 @@ import type { ExecutionContext } from "hono";
3
3
  import invariant from "invariant";
4
4
  import type { ActorKey, ActorRouter, Registry, RunConfig } from "rivetkit";
5
5
  import { createActorRouter, createClientWithDriver } from "rivetkit";
6
- import { serializeEmptyPersistData } from "rivetkit/driver-helpers";
6
+ import type { ActorDriver } from "rivetkit/driver-helpers";
7
+ import {
8
+ type ManagerDriver,
9
+ serializeEmptyPersistData,
10
+ } from "rivetkit/driver-helpers";
11
+ import { promiseWithResolvers } from "rivetkit/utils";
7
12
  import {
8
13
  CloudflareDurableObjectGlobalState,
9
14
  createCloudflareActorsActorDriverBuilder,
@@ -38,6 +43,7 @@ export type DurableObjectConstructor = new (
38
43
 
39
44
  interface LoadedActor {
40
45
  actorRouter: ActorRouter;
46
+ actorDriver: ActorDriver;
41
47
  }
42
48
 
43
49
  export function createActorDurableObject(
@@ -60,7 +66,7 @@ export function createActorDurableObject(
60
66
  implements ActorHandlerInterface
61
67
  {
62
68
  #initialized?: InitializedData;
63
- #initializedPromise?: PromiseWithResolvers<void>;
69
+ #initializedPromise?: ReturnType<typeof promiseWithResolvers<void>>;
64
70
 
65
71
  #actor?: LoadedActor;
66
72
 
@@ -71,7 +77,7 @@ export function createActorDurableObject(
71
77
  if (this.#initializedPromise) {
72
78
  await this.#initializedPromise.promise;
73
79
  } else {
74
- this.#initializedPromise = Promise.withResolvers();
80
+ this.#initializedPromise = promiseWithResolvers();
75
81
  const res = await this.ctx.storage.get([
76
82
  KEYS.NAME,
77
83
  KEYS.KEY,
@@ -118,6 +124,8 @@ export function createActorDurableObject(
118
124
  runConfig,
119
125
  );
120
126
 
127
+ configureInspectorAccessToken(registry.config, managerDriver);
128
+
121
129
  // Create inline client
122
130
  const inlineClient = createClientWithDriver(managerDriver);
123
131
 
@@ -135,6 +143,7 @@ export function createActorDurableObject(
135
143
  // Save actor
136
144
  this.#actor = {
137
145
  actorRouter,
146
+ actorDriver,
138
147
  };
139
148
 
140
149
  // Initialize the actor instance with proper metadata
@@ -174,26 +183,18 @@ export function createActorDurableObject(
174
183
  }
175
184
 
176
185
  async alarm(): Promise<void> {
177
- await this.#loadActor();
186
+ const { actorDriver } = await this.#loadActor();
178
187
  const actorId = this.ctx.id.toString();
179
188
 
180
- // Get the actor driver
181
- invariant(runConfig.driver, "runConfig.driver");
182
- const managerDriver = runConfig.driver.manager(
183
- registry.config,
184
- runConfig,
185
- );
186
- const inlineClient = createClientWithDriver(managerDriver);
187
- const actorDriver = runConfig.driver.actor(
188
- registry.config,
189
- runConfig,
190
- managerDriver,
191
- inlineClient,
192
- );
193
-
194
189
  // Load the actor instance and trigger alarm
195
190
  const actor = await actorDriver.loadActor(actorId);
196
191
  await actor._onAlarm();
197
192
  }
198
193
  };
199
194
  }
195
+ function configureInspectorAccessToken(
196
+ config: any,
197
+ managerDriver: ManagerDriver,
198
+ ) {
199
+ throw new Error("Function not implemented.");
200
+ }
@@ -6,11 +6,15 @@ import {
6
6
  type GetForIdInput,
7
7
  type GetOrCreateWithKeyInput,
8
8
  type GetWithKeyInput,
9
- HEADER_AUTH_DATA,
10
- HEADER_CONN_PARAMS,
11
- HEADER_ENCODING,
12
9
  type ManagerDisplayInformation,
13
10
  type ManagerDriver,
11
+ WS_PROTOCOL_ACTOR,
12
+ WS_PROTOCOL_CONN_ID,
13
+ WS_PROTOCOL_CONN_PARAMS,
14
+ WS_PROTOCOL_CONN_TOKEN,
15
+ WS_PROTOCOL_ENCODING,
16
+ WS_PROTOCOL_STANDARD,
17
+ WS_PROTOCOL_TARGET,
14
18
  } from "rivetkit/driver-helpers";
15
19
  import { ActorAlreadyExists, InternalError } from "rivetkit/errors";
16
20
  import { getCloudflareAmbientEnv } from "./handler";
@@ -68,6 +72,8 @@ export class CloudflareActorsManagerDriver implements ManagerDriver {
68
72
  actorId: string,
69
73
  encoding: Encoding,
70
74
  params: unknown,
75
+ connId?: string,
76
+ connToken?: string,
71
77
  ): Promise<UniversalWebSocket> {
72
78
  const env = getCloudflareAmbientEnv();
73
79
 
@@ -81,19 +87,32 @@ export class CloudflareActorsManagerDriver implements ManagerDriver {
81
87
  const id = env.ACTOR_DO.idFromString(actorId);
82
88
  const stub = env.ACTOR_DO.get(id);
83
89
 
90
+ const protocols: string[] = [];
91
+ protocols.push(WS_PROTOCOL_STANDARD);
92
+ protocols.push(`${WS_PROTOCOL_TARGET}actor`);
93
+ protocols.push(`${WS_PROTOCOL_ACTOR}${actorId}`);
94
+ protocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`);
95
+ if (params) {
96
+ protocols.push(
97
+ `${WS_PROTOCOL_CONN_PARAMS}${encodeURIComponent(JSON.stringify(params))}`,
98
+ );
99
+ }
100
+ if (connId) {
101
+ protocols.push(`${WS_PROTOCOL_CONN_ID}${connId}`);
102
+ }
103
+ if (connToken) {
104
+ protocols.push(`${WS_PROTOCOL_CONN_TOKEN}${connToken}`);
105
+ }
106
+
84
107
  const headers: Record<string, string> = {
85
108
  Upgrade: "websocket",
86
109
  Connection: "Upgrade",
87
- [HEADER_ENCODING]: encoding,
110
+ "sec-websocket-protocol": protocols.join(", "),
88
111
  };
89
- if (params) {
90
- headers[HEADER_CONN_PARAMS] = JSON.stringify(params);
91
- }
92
- // HACK: See packages/drivers/cloudflare-workers/src/websocket.ts
93
- headers["sec-websocket-protocol"] = "rivetkit";
94
112
 
95
113
  // Use the path parameter to determine the URL
96
- const url = `http://actor${path}`;
114
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
115
+ const url = `http://actor${normalizedPath}`;
97
116
 
98
117
  logger().debug({ msg: "rewriting websocket url", from: path, to: url });
99
118
 
@@ -104,7 +123,7 @@ export class CloudflareActorsManagerDriver implements ManagerDriver {
104
123
 
105
124
  if (!webSocket) {
106
125
  throw new InternalError(
107
- "missing websocket connection in response from DO",
126
+ `missing websocket connection in response from DO\n\nStatus: ${response.status}\nResponse: ${await response.text()}`,
108
127
  );
109
128
  }
110
129
 
@@ -151,7 +170,6 @@ export class CloudflareActorsManagerDriver implements ManagerDriver {
151
170
  actorId: string,
152
171
  encoding: Encoding,
153
172
  params: unknown,
154
- authData: unknown,
155
173
  ): Promise<Response> {
156
174
  logger().debug({
157
175
  msg: "forwarding websocket to durable object",
@@ -187,14 +205,18 @@ export class CloudflareActorsManagerDriver implements ManagerDriver {
187
205
  }
188
206
  }
189
207
 
190
- // Add RivetKit headers
191
- actorRequest.headers.set(HEADER_ENCODING, encoding);
208
+ // Build protocols for WebSocket connection
209
+ const protocols: string[] = [];
210
+ protocols.push(WS_PROTOCOL_STANDARD);
211
+ protocols.push(`${WS_PROTOCOL_TARGET}actor`);
212
+ protocols.push(`${WS_PROTOCOL_ACTOR}${actorId}`);
213
+ protocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`);
192
214
  if (params) {
193
- actorRequest.headers.set(HEADER_CONN_PARAMS, JSON.stringify(params));
194
- }
195
- if (authData) {
196
- actorRequest.headers.set(HEADER_AUTH_DATA, JSON.stringify(authData));
215
+ protocols.push(
216
+ `${WS_PROTOCOL_CONN_PARAMS}${encodeURIComponent(JSON.stringify(params))}`,
217
+ );
197
218
  }
219
+ actorRequest.headers.set("sec-websocket-protocol", protocols.join(", "));
198
220
 
199
221
  const id = c.env.ACTOR_DO.idFromString(actorId);
200
222
  const stub = c.env.ACTOR_DO.get(id);
package/src/websocket.ts CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  import type { UpgradeWebSocket, WSEvents, WSReadyState } from "hono/ws";
6
6
  import { defineWebSocketHelper, WSContext } from "hono/ws";
7
+ import { WS_PROTOCOL_STANDARD } from "rivetkit/driver-helpers";
7
8
 
8
9
  // Based on https://github.com/honojs/hono/issues/1153#issuecomment-1767321332
9
10
  export const upgradeWebSocket: UpgradeWebSocket<
@@ -57,14 +58,24 @@ export const upgradeWebSocket: UpgradeWebSocket<
57
58
  // we have to do this after `server.accept() is called`
58
59
  events.onOpen?.(new Event("open"), wsContext);
59
60
 
61
+ // Build response headers
62
+ const headers: Record<string, string> = {};
63
+
64
+ // Set Sec-WebSocket-Protocol if does not exist
65
+ const protocols = c.req.header("Sec-WebSocket-Protocol");
66
+ if (
67
+ typeof protocols === "string" &&
68
+ protocols
69
+ .split(",")
70
+ .map((x) => x.trim())
71
+ .includes(WS_PROTOCOL_STANDARD)
72
+ ) {
73
+ headers["Sec-WebSocket-Protocol"] = WS_PROTOCOL_STANDARD;
74
+ }
75
+
60
76
  return new Response(null, {
61
77
  status: 101,
62
- headers: {
63
- // HACK: Required in order for Cloudflare to not error with "Network connection lost"
64
- //
65
- // This bug undocumented. Cannot easily reproduce outside of RivetKit.
66
- "Sec-WebSocket-Protocol": "rivetkit",
67
- },
78
+ headers,
68
79
  webSocket: client,
69
80
  });
70
81
  });