@rivetkit/cloudflare-workers 2.0.33 → 2.0.34-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/dist/mod.cjs +81 -66
- package/dist/mod.cjs.map +1 -1
- package/dist/mod.d.cts +8 -62
- package/dist/mod.d.ts +8 -62
- package/dist/mod.js +82 -67
- package/dist/mod.js.map +1 -1
- package/package.json +2 -2
- package/src/actor-driver.ts +3 -9
- package/src/actor-handler-do.ts +24 -25
- package/src/config.ts +15 -12
- package/src/handler.ts +34 -20
- package/src/manager-driver.ts +28 -11
package/dist/mod.cjs
CHANGED
|
@@ -9,23 +9,6 @@ var _driverhelpers = require('rivetkit/driver-helpers');
|
|
|
9
9
|
|
|
10
10
|
var _utils = require('rivetkit/utils');
|
|
11
11
|
|
|
12
|
-
// src/actor-id.ts
|
|
13
|
-
function buildActorId(doId, generation) {
|
|
14
|
-
return `${doId}:${generation}`;
|
|
15
|
-
}
|
|
16
|
-
function parseActorId(actorId) {
|
|
17
|
-
const parts = actorId.split(":");
|
|
18
|
-
if (parts.length !== 2) {
|
|
19
|
-
throw new Error(`Invalid actor ID format: ${actorId}`);
|
|
20
|
-
}
|
|
21
|
-
const [doId, generationStr] = parts;
|
|
22
|
-
const generation = parseInt(generationStr, 10);
|
|
23
|
-
if (Number.isNaN(generation)) {
|
|
24
|
-
throw new Error(`Invalid generation number in actor ID: ${actorId}`);
|
|
25
|
-
}
|
|
26
|
-
return [doId, generation];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
12
|
// src/actor-kv.ts
|
|
30
13
|
function kvGet(sql, key) {
|
|
31
14
|
const cursor = sql.exec(
|
|
@@ -90,12 +73,17 @@ var GLOBAL_KV_KEYS = {
|
|
|
90
73
|
// src/handler.ts
|
|
91
74
|
|
|
92
75
|
|
|
93
|
-
// src/config.ts
|
|
94
76
|
|
|
77
|
+
|
|
78
|
+
// src/config.ts
|
|
95
79
|
var _zod = require('zod');
|
|
96
|
-
var ConfigSchemaBase =
|
|
80
|
+
var ConfigSchemaBase = _zod.z.object({
|
|
97
81
|
/** Path that the Rivet manager API will be mounted. */
|
|
98
|
-
managerPath: _zod.z.string().optional().default("/rivet"),
|
|
82
|
+
managerPath: _zod.z.string().optional().default("/api/rivet"),
|
|
83
|
+
/** Runner key for authentication. */
|
|
84
|
+
runnerKey: _zod.z.string().optional(),
|
|
85
|
+
/** Disable the welcome message. */
|
|
86
|
+
noWelcome: _zod.z.boolean().optional().default(false),
|
|
99
87
|
fetch: _zod.z.custom().optional()
|
|
100
88
|
});
|
|
101
89
|
var ConfigSchema = ConfigSchemaBase.default(
|
|
@@ -114,10 +102,26 @@ var ConfigSchema = ConfigSchemaBase.default(
|
|
|
114
102
|
|
|
115
103
|
|
|
116
104
|
|
|
117
|
-
|
|
118
105
|
var _errors = require('rivetkit/errors');
|
|
119
106
|
|
|
120
107
|
|
|
108
|
+
// src/actor-id.ts
|
|
109
|
+
function buildActorId(doId, generation) {
|
|
110
|
+
return `${doId}:${generation}`;
|
|
111
|
+
}
|
|
112
|
+
function parseActorId(actorId) {
|
|
113
|
+
const parts = actorId.split(":");
|
|
114
|
+
if (parts.length !== 2) {
|
|
115
|
+
throw new Error(`Invalid actor ID format: ${actorId}`);
|
|
116
|
+
}
|
|
117
|
+
const [doId, generationStr] = parts;
|
|
118
|
+
const generation = parseInt(generationStr, 10);
|
|
119
|
+
if (Number.isNaN(generation)) {
|
|
120
|
+
throw new Error(`Invalid generation number in actor ID: ${actorId}`);
|
|
121
|
+
}
|
|
122
|
+
return [doId, generation];
|
|
123
|
+
}
|
|
124
|
+
|
|
121
125
|
// src/log.ts
|
|
122
126
|
var _log = require('rivetkit/log');
|
|
123
127
|
function logger() {
|
|
@@ -229,6 +233,7 @@ Response: ${await response.text()}`
|
|
|
229
233
|
return webSocket;
|
|
230
234
|
}
|
|
231
235
|
async proxyRequest(c, actorRequest, actorId) {
|
|
236
|
+
const env3 = getCloudflareAmbientEnv();
|
|
232
237
|
const [doId] = parseActorId(actorId);
|
|
233
238
|
logger().debug({
|
|
234
239
|
msg: "forwarding request to durable object",
|
|
@@ -237,8 +242,8 @@ Response: ${await response.text()}`
|
|
|
237
242
|
method: actorRequest.method,
|
|
238
243
|
url: actorRequest.url
|
|
239
244
|
});
|
|
240
|
-
const id =
|
|
241
|
-
const stub =
|
|
245
|
+
const id = env3.ACTOR_DO.idFromString(doId);
|
|
246
|
+
const stub = env3.ACTOR_DO.get(id);
|
|
242
247
|
return await stub.fetch(actorRequest);
|
|
243
248
|
}
|
|
244
249
|
async proxyWebSocket(c, path, actorId, encoding, params) {
|
|
@@ -283,13 +288,15 @@ Response: ${await response.text()}`
|
|
|
283
288
|
"sec-websocket-protocol",
|
|
284
289
|
protocols.join(", ")
|
|
285
290
|
);
|
|
291
|
+
const env3 = getCloudflareAmbientEnv();
|
|
286
292
|
const [doId] = parseActorId(actorId);
|
|
287
|
-
const id =
|
|
288
|
-
const stub =
|
|
293
|
+
const id = env3.ACTOR_DO.idFromString(doId);
|
|
294
|
+
const stub = env3.ACTOR_DO.get(id);
|
|
289
295
|
return await stub.fetch(actorRequest);
|
|
290
296
|
}
|
|
291
297
|
async getForId({
|
|
292
298
|
c,
|
|
299
|
+
name,
|
|
293
300
|
actorId
|
|
294
301
|
}) {
|
|
295
302
|
const env3 = getCloudflareAmbientEnv();
|
|
@@ -434,12 +441,20 @@ Response: ${await response.text()}`
|
|
|
434
441
|
}
|
|
435
442
|
displayInformation() {
|
|
436
443
|
return {
|
|
437
|
-
|
|
438
|
-
|
|
444
|
+
properties: {
|
|
445
|
+
Driver: "Cloudflare Workers"
|
|
446
|
+
}
|
|
439
447
|
};
|
|
440
448
|
}
|
|
441
|
-
|
|
442
|
-
|
|
449
|
+
setGetUpgradeWebSocket() {
|
|
450
|
+
}
|
|
451
|
+
async kvGet(actorId, key) {
|
|
452
|
+
const env3 = getCloudflareAmbientEnv();
|
|
453
|
+
const [doId] = parseActorId(actorId);
|
|
454
|
+
const id = env3.ACTOR_DO.idFromString(doId);
|
|
455
|
+
const stub = env3.ACTOR_DO.get(id);
|
|
456
|
+
const value = await stub.managerKvGet(key);
|
|
457
|
+
return value !== null ? new TextDecoder().decode(value) : null;
|
|
443
458
|
}
|
|
444
459
|
};
|
|
445
460
|
|
|
@@ -515,19 +530,25 @@ function getCloudflareAmbientEnv() {
|
|
|
515
530
|
function createInlineClient(registry, inputConfig) {
|
|
516
531
|
inputConfig = { ...inputConfig, runnerKey: "" };
|
|
517
532
|
const config = ConfigSchema.parse(inputConfig);
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
getUpgradeWebSocket: () => upgradeWebSocket
|
|
533
|
+
const ActorHandler = createActorDurableObject(
|
|
534
|
+
registry,
|
|
535
|
+
() => upgradeWebSocket
|
|
536
|
+
);
|
|
537
|
+
registry.config.noWelcome = true;
|
|
538
|
+
registry.config.inspector = {
|
|
539
|
+
enabled: false,
|
|
540
|
+
token: () => ""
|
|
527
541
|
};
|
|
528
|
-
|
|
529
|
-
const
|
|
530
|
-
|
|
542
|
+
registry.config.managerBasePath = "/";
|
|
543
|
+
const parsedConfig = registry.parseConfig();
|
|
544
|
+
const managerDriver = new CloudflareActorsManagerDriver();
|
|
545
|
+
const { router } = _driverhelpers.buildManagerRouter.call(void 0,
|
|
546
|
+
parsedConfig,
|
|
547
|
+
managerDriver,
|
|
548
|
+
() => upgradeWebSocket
|
|
549
|
+
);
|
|
550
|
+
const client = _rivetkit.createClientWithDriver.call(void 0, managerDriver);
|
|
551
|
+
return { client, fetch: router.fetch.bind(router), config, ActorHandler };
|
|
531
552
|
}
|
|
532
553
|
function createHandler(registry, inputConfig) {
|
|
533
554
|
const { client, fetch, config, ActorHandler } = createInlineClient(
|
|
@@ -550,7 +571,7 @@ function createHandler(registry, inputConfig) {
|
|
|
550
571
|
return config.fetch(request, env3, ctx);
|
|
551
572
|
} else {
|
|
552
573
|
return new Response(
|
|
553
|
-
"This is a RivetKit server.\n\nLearn more at https://
|
|
574
|
+
"This is a RivetKit server.\n\nLearn more at https://rivet.dev\n",
|
|
554
575
|
{ status: 200 }
|
|
555
576
|
);
|
|
556
577
|
}
|
|
@@ -608,13 +629,11 @@ var ActorGlobalState = (_class = class {constructor() { _class.prototype.__init.
|
|
|
608
629
|
}, _class);
|
|
609
630
|
var CloudflareActorsActorDriver = class {
|
|
610
631
|
#registryConfig;
|
|
611
|
-
#runConfig;
|
|
612
632
|
#managerDriver;
|
|
613
633
|
#inlineClient;
|
|
614
634
|
#globalState;
|
|
615
|
-
constructor(registryConfig,
|
|
635
|
+
constructor(registryConfig, managerDriver, inlineClient, globalState) {
|
|
616
636
|
this.#registryConfig = registryConfig;
|
|
617
|
-
this.#runConfig = runConfig;
|
|
618
637
|
this.#managerDriver = managerDriver;
|
|
619
638
|
this.#inlineClient = inlineClient;
|
|
620
639
|
this.#globalState = globalState;
|
|
@@ -746,10 +765,9 @@ var CloudflareActorsActorDriver = class {
|
|
|
746
765
|
}
|
|
747
766
|
};
|
|
748
767
|
function createCloudflareActorsActorDriverBuilder(globalState) {
|
|
749
|
-
return (
|
|
768
|
+
return (config, managerDriver, inlineClient) => {
|
|
750
769
|
return new CloudflareActorsActorDriver(
|
|
751
|
-
|
|
752
|
-
runConfig,
|
|
770
|
+
config,
|
|
753
771
|
managerDriver,
|
|
754
772
|
inlineClient,
|
|
755
773
|
globalState
|
|
@@ -758,9 +776,9 @@ function createCloudflareActorsActorDriverBuilder(globalState) {
|
|
|
758
776
|
}
|
|
759
777
|
|
|
760
778
|
// src/actor-handler-do.ts
|
|
761
|
-
function createActorDurableObject(registry,
|
|
779
|
+
function createActorDurableObject(registry, getUpgradeWebSocket) {
|
|
762
780
|
const globalState = new CloudflareDurableObjectGlobalState();
|
|
763
|
-
const
|
|
781
|
+
const parsedConfig = registry.parseConfig();
|
|
764
782
|
return class ActorHandler extends _cloudflareworkers.DurableObject {
|
|
765
783
|
/**
|
|
766
784
|
* This holds a strong reference to ActorGlobalState.
|
|
@@ -794,7 +812,7 @@ function createActorDurableObject(registry, rootRunConfig) {
|
|
|
794
812
|
}
|
|
795
813
|
}
|
|
796
814
|
async #loadActor() {
|
|
797
|
-
var _a;
|
|
815
|
+
var _a, _b;
|
|
798
816
|
_invariant2.default.call(void 0, this.#state, "State should be initialized");
|
|
799
817
|
if (!this.#state.initialized) {
|
|
800
818
|
const cursor = this.ctx.storage.sql.exec(
|
|
@@ -835,26 +853,19 @@ function createActorDurableObject(registry, rootRunConfig) {
|
|
|
835
853
|
if (!this.#state.initialized) throw new Error("Not initialized");
|
|
836
854
|
const actorId = this.ctx.id.toString();
|
|
837
855
|
globalState.setDOState(actorId, { ctx: this.ctx, env: _cloudflareworkers.env });
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
);
|
|
844
|
-
const inlineClient = _rivetkit.createClientWithDriver.call(void 0,
|
|
845
|
-
managerDriver,
|
|
846
|
-
runConfig
|
|
847
|
-
);
|
|
848
|
-
const actorDriver = runConfig.driver.actor(
|
|
849
|
-
registry.config,
|
|
850
|
-
runConfig,
|
|
856
|
+
const managerDriver = new CloudflareActorsManagerDriver();
|
|
857
|
+
const inlineClient = _rivetkit.createClientWithDriver.call(void 0, managerDriver);
|
|
858
|
+
const actorDriverBuilder = createCloudflareActorsActorDriverBuilder(globalState);
|
|
859
|
+
const actorDriver = actorDriverBuilder(
|
|
860
|
+
parsedConfig,
|
|
851
861
|
managerDriver,
|
|
852
862
|
inlineClient
|
|
853
863
|
);
|
|
854
864
|
const actorRouter = _rivetkit.createActorRouter.call(void 0,
|
|
855
|
-
|
|
865
|
+
parsedConfig,
|
|
856
866
|
actorDriver,
|
|
857
|
-
|
|
867
|
+
getUpgradeWebSocket,
|
|
868
|
+
_nullishCoalesce(((_b = registry.config.test) == null ? void 0 : _b.enabled), () => ( false))
|
|
858
869
|
);
|
|
859
870
|
this.#state.actor = {
|
|
860
871
|
actorRouter,
|
|
@@ -907,6 +918,10 @@ function createActorDurableObject(registry, rootRunConfig) {
|
|
|
907
918
|
});
|
|
908
919
|
return void 0;
|
|
909
920
|
}
|
|
921
|
+
/** RPC called by ManagerDriver.kvGet to read from KV. */
|
|
922
|
+
async managerKvGet(key) {
|
|
923
|
+
return kvGet(this.ctx.storage.sql, key);
|
|
924
|
+
}
|
|
910
925
|
/** RPC called by the manager to create a DO. Can optionally allow existing actors. */
|
|
911
926
|
async create(req) {
|
|
912
927
|
const checkCursor = this.ctx.storage.sql.exec(
|
package/dist/mod.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/rivet/rivet/rivetkit-typescript/packages/cloudflare-workers/dist/mod.cjs","../src/actor-handler-do.ts","../src/actor-driver.ts","../src/actor-id.ts","../src/actor-kv.ts","../src/global-kv.ts","../src/handler.ts","../src/config.ts","../src/manager-driver.ts","../src/log.ts","../src/util.ts","../src/websocket.ts"],"names":["env","invariant"],"mappings":"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","file":"/home/runner/work/rivet/rivet/rivetkit-typescript/packages/cloudflare-workers/dist/mod.cjs","sourcesContent":[null,"import { DurableObject, env } from \"cloudflare:workers\";\nimport type { ExecutionContext } from \"hono\";\nimport invariant from \"invariant\";\nimport type { ActorKey, ActorRouter, Registry, RunConfig } from \"rivetkit\";\nimport { createActorRouter, createClientWithDriver } from \"rivetkit\";\nimport type { ActorDriver, ManagerDriver } from \"rivetkit/driver-helpers\";\nimport { getInitialActorKvState } from \"rivetkit/driver-helpers\";\nimport { stringifyError } from \"rivetkit/utils\";\nimport {\n\tActorGlobalState,\n\tCloudflareDurableObjectGlobalState,\n\tcreateCloudflareActorsActorDriverBuilder,\n} from \"./actor-driver\";\nimport { buildActorId, parseActorId } from \"./actor-id\";\nimport { kvPut } from \"./actor-kv\";\nimport { GLOBAL_KV_KEYS } from \"./global-kv\";\nimport type { Bindings } from \"./handler\";\nimport { getCloudflareAmbientEnv } from \"./handler\";\nimport { logger } from \"./log\";\n\nexport interface ActorHandlerInterface extends DurableObject {\n\tcreate(req: ActorInitRequest): Promise<ActorInitResponse>;\n\tgetMetadata(): Promise<\n\t\t| {\n\t\t\t\tactorId: string;\n\t\t\t\tname: string;\n\t\t\t\tkey: ActorKey;\n\t\t\t\tdestroying: boolean;\n\t\t }\n\t\t| undefined\n\t>;\n}\n\nexport interface ActorInitRequest {\n\tname: string;\n\tkey: ActorKey;\n\tinput?: unknown;\n\tallowExisting: boolean;\n}\nexport type ActorInitResponse =\n\t| { success: { actorId: string; created: boolean } }\n\t| { error: { actorAlreadyExists: true } };\n\nexport type DurableObjectConstructor = new (\n\t...args: ConstructorParameters<typeof DurableObject<Bindings>>\n) => DurableObject<Bindings>;\n\nexport function createActorDurableObject(\n\tregistry: Registry<any>,\n\trootRunConfig: RunConfig,\n): DurableObjectConstructor {\n\tconst globalState = new CloudflareDurableObjectGlobalState();\n\n\t// Configure to use the runner role instead of server role\n\tconst runConfig = Object.assign({}, rootRunConfig, { role: \"runner\" });\n\n\t/**\n\t * Startup steps:\n\t * 1. If not already created call `initialize`, otherwise check KV to ensure it's initialized\n\t * 2. Load actor\n\t * 3. Start service requests\n\t */\n\treturn class ActorHandler\n\t\textends DurableObject<Bindings>\n\t\timplements ActorHandlerInterface\n\t{\n\t\t/**\n\t\t * This holds a strong reference to ActorGlobalState.\n\t\t * CloudflareDurableObjectGlobalState holds a weak reference so we can\n\t\t * access it elsewhere.\n\t\t **/\n\t\t#state: ActorGlobalState;\n\n\t\tconstructor(\n\t\t\t...args: ConstructorParameters<typeof DurableObject<Bindings>>\n\t\t) {\n\t\t\tsuper(...args);\n\n\t\t\t// Initialize SQL table for key-value storage\n\t\t\t//\n\t\t\t// We do this instead of using the native KV storage so we can store blob keys. The native CF KV API only supports string keys.\n\t\t\tthis.ctx.storage.sql.exec(`\n\t\t\t\tCREATE TABLE IF NOT EXISTS _rivetkit_kv_storage(\n\t\t\t\t\tkey BLOB PRIMARY KEY,\n\t\t\t\t\tvalue BLOB\n\t\t\t\t);\n\t\t\t`);\n\n\t\t\t// Initialize SQL table for actor metadata\n\t\t\t//\n\t\t\t// id always equals 1 in order to ensure that there's always exactly 1 row in this table\n\t\t\tthis.ctx.storage.sql.exec(`\n\t\t\t\tCREATE TABLE IF NOT EXISTS _rivetkit_metadata(\n\t\t\t\t\tid INTEGER PRIMARY KEY CHECK (id = 1),\n\t\t\t\t\tname TEXT NOT NULL,\n\t\t\t\t\tkey TEXT NOT NULL,\n\t\t\t\t\tdestroyed INTEGER DEFAULT 0,\n\t\t\t\t\tgeneration INTEGER DEFAULT 0\n\t\t\t\t);\n\t\t\t`);\n\n\t\t\t// Get or create the actor state from the global WeakMap\n\t\t\tconst state = globalState.getActorState(this.ctx);\n\t\t\tif (state) {\n\t\t\t\tthis.#state = state;\n\t\t\t} else {\n\t\t\t\tthis.#state = new ActorGlobalState();\n\t\t\t\tglobalState.setActorState(this.ctx, this.#state);\n\t\t\t}\n\t\t}\n\n\t\tasync #loadActor() {\n\t\t\tinvariant(this.#state, \"State should be initialized\");\n\n\t\t\t// Check if initialized\n\t\t\tif (!this.#state.initialized) {\n\t\t\t\t// Query SQL for initialization data\n\t\t\t\tconst cursor = this.ctx.storage.sql.exec(\n\t\t\t\t\t\"SELECT name, key, destroyed, generation FROM _rivetkit_metadata WHERE id = 1\",\n\t\t\t\t);\n\t\t\t\tconst result = cursor.raw().next();\n\n\t\t\t\tif (!result.done && result.value) {\n\t\t\t\t\tconst name = result.value[0] as string;\n\t\t\t\t\tconst key = JSON.parse(\n\t\t\t\t\t\tresult.value[1] as string,\n\t\t\t\t\t) as ActorKey;\n\t\t\t\t\tconst destroyed = result.value[2] as number;\n\t\t\t\t\tconst generation = result.value[3] as number;\n\n\t\t\t\t\t// Only initialize if not destroyed\n\t\t\t\t\tif (!destroyed) {\n\t\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\t\tmsg: \"already initialized\",\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\tgeneration,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis.#state.initialized = { name, key, generation };\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger().debug(\"actor is destroyed, cannot load\");\n\t\t\t\t\t\tthrow new Error(\"Actor is destroyed\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlogger().debug(\"not initialized\");\n\t\t\t\t\tthrow new Error(\"Actor is not initialized\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check if already loaded\n\t\t\tif (this.#state.actor) {\n\t\t\t\t// Assert that the cached actor has the correct generation\n\t\t\t\t// This will catch any cases where #state.actor has a stale generation\n\t\t\t\tinvariant(\n\t\t\t\t\t!this.#state.initialized ||\n\t\t\t\t\t\tthis.#state.actor.generation ===\n\t\t\t\t\t\t\tthis.#state.initialized.generation,\n\t\t\t\t\t`Stale actor cached: actor generation ${this.#state.actor.generation} != initialized generation ${this.#state.initialized?.generation}. This should not happen.`,\n\t\t\t\t);\n\t\t\t\treturn this.#state.actor;\n\t\t\t}\n\n\t\t\tif (!this.#state.initialized) throw new Error(\"Not initialized\");\n\n\t\t\t// Register DO with global state first\n\t\t\t// HACK: This leaks the DO context, but DO does not provide a native way\n\t\t\t// of knowing when the DO shuts down. We're making a broad assumption\n\t\t\t// that DO will boot a new isolate frequenlty enough that this is not an issue.\n\t\t\tconst actorId = this.ctx.id.toString();\n\t\t\tglobalState.setDOState(actorId, { ctx: this.ctx, env: env });\n\n\t\t\t// Configure actor driver\n\t\t\tinvariant(runConfig.driver, \"runConfig.driver\");\n\t\t\trunConfig.driver.actor =\n\t\t\t\tcreateCloudflareActorsActorDriverBuilder(globalState);\n\n\t\t\t// Create manager driver (we need this for the actor router)\n\t\t\tconst managerDriver = runConfig.driver.manager(\n\t\t\t\tregistry.config,\n\t\t\t\trunConfig,\n\t\t\t);\n\n\t\t\t// Create inline client\n\t\t\tconst inlineClient = createClientWithDriver(\n\t\t\t\tmanagerDriver,\n\t\t\t\trunConfig,\n\t\t\t);\n\n\t\t\t// Create actor driver\n\t\t\tconst actorDriver = runConfig.driver.actor(\n\t\t\t\tregistry.config,\n\t\t\t\trunConfig,\n\t\t\t\tmanagerDriver,\n\t\t\t\tinlineClient,\n\t\t\t);\n\n\t\t\t// Create actor router\n\t\t\tconst actorRouter = createActorRouter(\n\t\t\t\trunConfig,\n\t\t\t\tactorDriver,\n\t\t\t\tfalse,\n\t\t\t);\n\n\t\t\t// Save actor with generation\n\t\t\tthis.#state.actor = {\n\t\t\t\tactorRouter,\n\t\t\t\tactorDriver,\n\t\t\t\tgeneration: this.#state.initialized.generation,\n\t\t\t};\n\n\t\t\t// Build actor ID with generation for loading\n\t\t\tconst actorIdWithGen = buildActorId(\n\t\t\t\tactorId,\n\t\t\t\tthis.#state.initialized.generation,\n\t\t\t);\n\n\t\t\t// Initialize the actor instance with proper metadata\n\t\t\t// This ensures the actor driver knows about this actor\n\t\t\tawait actorDriver.loadActor(actorIdWithGen);\n\n\t\t\treturn this.#state.actor;\n\t\t}\n\n\t\t/** RPC called to get actor metadata without creating it */\n\t\tasync getMetadata(): Promise<\n\t\t\t| {\n\t\t\t\t\tactorId: string;\n\t\t\t\t\tname: string;\n\t\t\t\t\tkey: ActorKey;\n\t\t\t\t\tdestroying: boolean;\n\t\t\t }\n\t\t\t| undefined\n\t\t> {\n\t\t\t// Query the metadata\n\t\t\tconst cursor = this.ctx.storage.sql.exec(\n\t\t\t\t\"SELECT name, key, destroyed, generation FROM _rivetkit_metadata WHERE id = 1\",\n\t\t\t);\n\t\t\tconst result = cursor.raw().next();\n\n\t\t\tif (!result.done && result.value) {\n\t\t\t\tconst name = result.value[0] as string;\n\t\t\t\tconst key = JSON.parse(result.value[1] as string) as ActorKey;\n\t\t\t\tconst destroyed = result.value[2] as number;\n\t\t\t\tconst generation = result.value[3] as number;\n\n\t\t\t\t// Check if destroyed\n\t\t\t\tif (destroyed) {\n\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\tmsg: \"getMetadata: actor is destroyed\",\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tgeneration,\n\t\t\t\t\t});\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\t// Build actor ID with generation\n\t\t\t\tconst doId = this.ctx.id.toString();\n\t\t\t\tconst actorId = buildActorId(doId, generation);\n\t\t\t\tconst destroying =\n\t\t\t\t\tglobalState.getActorState(this.ctx)?.destroying ?? false;\n\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"getMetadata: found actor metadata\",\n\t\t\t\t\tactorId,\n\t\t\t\t\tname,\n\t\t\t\t\tkey,\n\t\t\t\t\tgeneration,\n\t\t\t\t\tdestroying,\n\t\t\t\t});\n\n\t\t\t\treturn { actorId, name, key, destroying };\n\t\t\t}\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getMetadata: no metadata found\",\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\n\t\t/** RPC called by the manager to create a DO. Can optionally allow existing actors. */\n\t\tasync create(req: ActorInitRequest): Promise<ActorInitResponse> {\n\t\t\t// Check if actor exists\n\t\t\tconst checkCursor = this.ctx.storage.sql.exec(\n\t\t\t\t\"SELECT destroyed, generation FROM _rivetkit_metadata WHERE id = 1\",\n\t\t\t);\n\t\t\tconst checkResult = checkCursor.raw().next();\n\n\t\t\tlet created = false;\n\t\t\tlet generation = 0;\n\n\t\t\tif (!checkResult.done && checkResult.value) {\n\t\t\t\tconst destroyed = checkResult.value[0] as number;\n\t\t\t\tgeneration = checkResult.value[1] as number;\n\n\t\t\t\tif (!destroyed) {\n\t\t\t\t\t// Actor exists and is not destroyed\n\t\t\t\t\tif (!req.allowExisting) {\n\t\t\t\t\t\t// Fail if not allowing existing actors\n\t\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\t\tmsg: \"create failed: actor already exists\",\n\t\t\t\t\t\t\tname: req.name,\n\t\t\t\t\t\t\tkey: req.key,\n\t\t\t\t\t\t\tgeneration,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn { error: { actorAlreadyExists: true } };\n\t\t\t\t\t}\n\n\t\t\t\t\t// Return existing actor\n\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\tmsg: \"actor already exists\",\n\t\t\t\t\t\tkey: req.key,\n\t\t\t\t\t\tgeneration,\n\t\t\t\t\t});\n\t\t\t\t\tconst doId = this.ctx.id.toString();\n\t\t\t\t\tconst actorId = buildActorId(doId, generation);\n\t\t\t\t\treturn { success: { actorId, created: false } };\n\t\t\t\t}\n\n\t\t\t\t// Actor exists but is destroyed - resurrect with incremented generation\n\t\t\t\tgeneration = generation + 1;\n\t\t\t\tcreated = true;\n\n\t\t\t\t// Clear stale actor from previous generation\n\t\t\t\t// This is necessary because the DO instance may still be in memory\n\t\t\t\t// with the old #state.actor field from before the destroy\n\t\t\t\tif (this.#state) {\n\t\t\t\t\tthis.#state.actor = undefined;\n\t\t\t\t}\n\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"resurrecting destroyed actor\",\n\t\t\t\t\tkey: req.key,\n\t\t\t\t\toldGeneration: generation - 1,\n\t\t\t\t\tnewGeneration: generation,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// No actor exists - will create with generation 0\n\t\t\t\tgeneration = 0;\n\t\t\t\tcreated = true;\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"creating new actor\",\n\t\t\t\t\tkey: req.key,\n\t\t\t\t\tgeneration,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Perform upsert - either inserts new or updates destroyed actor\n\t\t\tthis.ctx.storage.sql.exec(\n\t\t\t\t`INSERT INTO _rivetkit_metadata (id, name, key, destroyed, generation)\n\t\t\t\tVALUES (1, ?, ?, 0, ?)\n\t\t\t\tON CONFLICT(id) DO UPDATE SET\n\t\t\t\t\tname = excluded.name,\n\t\t\t\t\tkey = excluded.key,\n\t\t\t\t\tdestroyed = 0,\n\t\t\t\t\tgeneration = excluded.generation`,\n\t\t\t\treq.name,\n\t\t\t\tJSON.stringify(req.key),\n\t\t\t\tgeneration,\n\t\t\t);\n\n\t\t\tthis.#state.initialized = {\n\t\t\t\tname: req.name,\n\t\t\t\tkey: req.key,\n\t\t\t\tgeneration,\n\t\t\t};\n\n\t\t\t// Build actor ID with generation\n\t\t\tconst doId = this.ctx.id.toString();\n\t\t\tconst actorId = buildActorId(doId, generation);\n\n\t\t\t// Initialize storage and update KV when created or resurrected\n\t\t\tif (created) {\n\t\t\t\t// Initialize persist data in KV storage\n\t\t\t\tinitializeActorKvStorage(this.ctx.storage.sql, req.input);\n\n\t\t\t\t// Update metadata in the background\n\t\t\t\tconst env = getCloudflareAmbientEnv();\n\t\t\t\tconst actorData = { name: req.name, key: req.key, generation };\n\t\t\t\tthis.ctx.waitUntil(\n\t\t\t\t\tenv.ACTOR_KV.put(\n\t\t\t\t\t\tGLOBAL_KV_KEYS.actorMetadata(actorId),\n\t\t\t\t\t\tJSON.stringify(actorData),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Preemptively load actor so the lifecycle hooks are called\n\t\t\tawait this.#loadActor();\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: created\n\t\t\t\t\t? \"actor created/resurrected\"\n\t\t\t\t\t: \"returning existing actor\",\n\t\t\t\tactorId,\n\t\t\t\tcreated,\n\t\t\t\tgeneration,\n\t\t\t});\n\n\t\t\treturn { success: { actorId, created } };\n\t\t}\n\n\t\tasync fetch(request: Request): Promise<Response> {\n\t\t\tconst { actorRouter, generation } = await this.#loadActor();\n\n\t\t\t// Build actor ID with generation\n\t\t\tconst doId = this.ctx.id.toString();\n\t\t\tconst actorId = buildActorId(doId, generation);\n\n\t\t\treturn await actorRouter.fetch(request, {\n\t\t\t\tactorId,\n\t\t\t});\n\t\t}\n\n\t\tasync alarm(): Promise<void> {\n\t\t\tconst { actorDriver, generation } = await this.#loadActor();\n\n\t\t\t// Build actor ID with generation\n\t\t\tconst doId = this.ctx.id.toString();\n\t\t\tconst actorId = buildActorId(doId, generation);\n\n\t\t\t// Load the actor instance and trigger alarm\n\t\t\tconst actor = await actorDriver.loadActor(actorId);\n\t\t\tawait actor.onAlarm();\n\t\t}\n\t};\n}\n\nfunction initializeActorKvStorage(\n\tsql: SqlStorage,\n\tinput: unknown | undefined,\n): void {\n\tconst initialKvState = getInitialActorKvState(input);\n\tfor (const [key, value] of initialKvState) {\n\t\tkvPut(sql, key, value);\n\t}\n}\n","import invariant from \"invariant\";\nimport type {\n\tActorKey,\n\tActorRouter,\n\tAnyActorInstance as CoreAnyActorInstance,\n\tRegistryConfig,\n\tRunConfig,\n} from \"rivetkit\";\nimport { lookupInRegistry } from \"rivetkit\";\nimport type { Client } from \"rivetkit/client\";\nimport type {\n\tActorDriver,\n\tAnyActorInstance,\n\tManagerDriver,\n} from \"rivetkit/driver-helpers\";\nimport { promiseWithResolvers } from \"rivetkit/utils\";\nimport { parseActorId } from \"./actor-id\";\nimport { kvDelete, kvGet, kvListPrefix, kvPut } from \"./actor-kv\";\nimport { GLOBAL_KV_KEYS } from \"./global-kv\";\nimport { getCloudflareAmbientEnv } from \"./handler\";\n\ninterface DurableObjectGlobalState {\n\tctx: DurableObjectState;\n\tenv: unknown;\n}\n\n/**\n * Cloudflare DO can have multiple DO running within the same global scope.\n *\n * This allows for storing the actor context globally and looking it up by ID in `CloudflareActorsActorDriver`.\n */\nexport class CloudflareDurableObjectGlobalState {\n\t// Map of actor ID -> DO state\n\t#dos: Map<string, DurableObjectGlobalState> = new Map();\n\n\t// WeakMap of DO state -> ActorGlobalState for proper GC\n\t#actors: WeakMap<DurableObjectState, ActorGlobalState> = new WeakMap();\n\n\tgetDOState(doId: string): DurableObjectGlobalState {\n\t\tconst state = this.#dos.get(doId);\n\t\tinvariant(\n\t\t\tstate !== undefined,\n\t\t\t\"durable object state not in global state\",\n\t\t);\n\t\treturn state;\n\t}\n\n\tsetDOState(doId: string, state: DurableObjectGlobalState) {\n\t\tthis.#dos.set(doId, state);\n\t}\n\n\tgetActorState(ctx: DurableObjectState): ActorGlobalState | undefined {\n\t\treturn this.#actors.get(ctx);\n\t}\n\n\tsetActorState(ctx: DurableObjectState, actorState: ActorGlobalState): void {\n\t\tthis.#actors.set(ctx, actorState);\n\t}\n}\n\nexport interface DriverContext {\n\tstate: DurableObjectState;\n}\n\ninterface InitializedData {\n\tname: string;\n\tkey: ActorKey;\n\tgeneration: number;\n}\n\ninterface LoadedActor {\n\tactorRouter: ActorRouter;\n\tactorDriver: ActorDriver;\n\tgeneration: number;\n}\n\n// Actor global state to track running instances\nexport class ActorGlobalState {\n\t// Initialization state\n\tinitialized?: InitializedData;\n\n\t// Loaded actor state\n\tactor?: LoadedActor;\n\tactorInstance?: AnyActorInstance;\n\tactorPromise?: ReturnType<typeof promiseWithResolvers<void>>;\n\n\t/**\n\t * Indicates if `startDestroy` has been called.\n\t *\n\t * This is stored in memory instead of SQLite since the destroy may be cancelled.\n\t *\n\t * See the corresponding `destroyed` property in SQLite metadata.\n\t */\n\tdestroying: boolean = false;\n\n\treset() {\n\t\tthis.initialized = undefined;\n\t\tthis.actor = undefined;\n\t\tthis.actorInstance = undefined;\n\t\tthis.actorPromise = undefined;\n\t\tthis.destroying = false;\n\t}\n}\n\nexport class CloudflareActorsActorDriver implements ActorDriver {\n\t#registryConfig: RegistryConfig;\n\t#runConfig: RunConfig;\n\t#managerDriver: ManagerDriver;\n\t#inlineClient: Client<any>;\n\t#globalState: CloudflareDurableObjectGlobalState;\n\n\tconstructor(\n\t\tregistryConfig: RegistryConfig,\n\t\trunConfig: RunConfig,\n\t\tmanagerDriver: ManagerDriver,\n\t\tinlineClient: Client<any>,\n\t\tglobalState: CloudflareDurableObjectGlobalState,\n\t) {\n\t\tthis.#registryConfig = registryConfig;\n\t\tthis.#runConfig = runConfig;\n\t\tthis.#managerDriver = managerDriver;\n\t\tthis.#inlineClient = inlineClient;\n\t\tthis.#globalState = globalState;\n\t}\n\n\t#getDOCtx(actorId: string) {\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\t\treturn this.#globalState.getDOState(doId).ctx;\n\t}\n\n\tasync loadActor(actorId: string): Promise<AnyActorInstance> {\n\t\t// Parse actor ID to get DO ID and generation\n\t\tconst [doId, expectedGeneration] = parseActorId(actorId);\n\n\t\t// Get the DO state\n\t\tconst doState = this.#globalState.getDOState(doId);\n\n\t\t// Check if actor is already loaded\n\t\tlet actorState = this.#globalState.getActorState(doState.ctx);\n\t\tif (actorState?.actorInstance) {\n\t\t\t// Actor is already loaded, return it\n\t\t\treturn actorState.actorInstance;\n\t\t}\n\n\t\t// Create new actor state if it doesn't exist\n\t\tif (!actorState) {\n\t\t\tactorState = new ActorGlobalState();\n\t\t\tactorState.actorPromise = promiseWithResolvers();\n\t\t\tthis.#globalState.setActorState(doState.ctx, actorState);\n\t\t} else if (actorState.actorPromise) {\n\t\t\t// Another request is already loading this actor, wait for it\n\t\t\tawait actorState.actorPromise.promise;\n\t\t\tif (!actorState.actorInstance) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Actor ${actorId} failed to load in concurrent request`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn actorState.actorInstance;\n\t\t}\n\n\t\t// Load actor metadata\n\t\tconst sql = doState.ctx.storage.sql;\n\t\tconst cursor = sql.exec(\n\t\t\t\"SELECT name, key, destroyed, generation FROM _rivetkit_metadata LIMIT 1\",\n\t\t);\n\t\tconst result = cursor.raw().next();\n\n\t\tif (result.done || !result.value) {\n\t\t\tthrow new Error(\n\t\t\t\t`Actor ${actorId} is not initialized - missing metadata`,\n\t\t\t);\n\t\t}\n\n\t\tconst name = result.value[0] as string;\n\t\tconst key = JSON.parse(result.value[1] as string) as string[];\n\t\tconst destroyed = result.value[2] as number;\n\t\tconst generation = result.value[3] as number;\n\n\t\t// Check if actor is destroyed\n\t\tif (destroyed) {\n\t\t\tthrow new Error(`Actor ${actorId} is destroyed`);\n\t\t}\n\n\t\t// Check if generation matches\n\t\tif (generation !== expectedGeneration) {\n\t\t\tthrow new Error(\n\t\t\t\t`Actor ${actorId} generation mismatch - expected ${expectedGeneration}, got ${generation}`,\n\t\t\t);\n\t\t}\n\n\t\t// Create actor instance\n\t\tconst definition = lookupInRegistry(this.#registryConfig, name);\n\t\tactorState.actorInstance = definition.instantiate();\n\n\t\t// Start actor\n\t\tawait actorState.actorInstance.start(\n\t\t\tthis,\n\t\t\tthis.#inlineClient,\n\t\t\tactorId,\n\t\t\tname,\n\t\t\tkey,\n\t\t\t\"unknown\", // TODO: Support regions in Cloudflare\n\t\t);\n\n\t\t// Finish\n\t\tactorState.actorPromise?.resolve();\n\t\tactorState.actorPromise = undefined;\n\n\t\treturn actorState.actorInstance;\n\t}\n\n\tgetContext(actorId: string): DriverContext {\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\t\tconst state = this.#globalState.getDOState(doId);\n\t\treturn { state: state.ctx };\n\t}\n\n\tasync setAlarm(actor: AnyActorInstance, timestamp: number): Promise<void> {\n\t\tawait this.#getDOCtx(actor.id).storage.setAlarm(timestamp);\n\t}\n\n\tasync getDatabase(actorId: string): Promise<unknown | undefined> {\n\t\treturn this.#getDOCtx(actorId).storage.sql;\n\t}\n\n\t// Batch KV operations\n\tasync kvBatchPut(\n\t\tactorId: string,\n\t\tentries: [Uint8Array, Uint8Array][],\n\t): Promise<void> {\n\t\tconst sql = this.#getDOCtx(actorId).storage.sql;\n\n\t\tfor (const [key, value] of entries) {\n\t\t\tkvPut(sql, key, value);\n\t\t}\n\t}\n\n\tasync kvBatchGet(\n\t\tactorId: string,\n\t\tkeys: Uint8Array[],\n\t): Promise<(Uint8Array | null)[]> {\n\t\tconst sql = this.#getDOCtx(actorId).storage.sql;\n\n\t\tconst results: (Uint8Array | null)[] = [];\n\t\tfor (const key of keys) {\n\t\t\tresults.push(kvGet(sql, key));\n\t\t}\n\n\t\treturn results;\n\t}\n\n\tasync kvBatchDelete(actorId: string, keys: Uint8Array[]): Promise<void> {\n\t\tconst sql = this.#getDOCtx(actorId).storage.sql;\n\n\t\tfor (const key of keys) {\n\t\t\tkvDelete(sql, key);\n\t\t}\n\t}\n\n\tasync kvListPrefix(\n\t\tactorId: string,\n\t\tprefix: Uint8Array,\n\t): Promise<[Uint8Array, Uint8Array][]> {\n\t\tconst sql = this.#getDOCtx(actorId).storage.sql;\n\n\t\treturn kvListPrefix(sql, prefix);\n\t}\n\n\tstartDestroy(actorId: string): void {\n\t\t// Parse actor ID to get DO ID and generation\n\t\tconst [doId, generation] = parseActorId(actorId);\n\n\t\t// Get the DO state\n\t\tconst doState = this.#globalState.getDOState(doId);\n\t\tconst actorState = this.#globalState.getActorState(doState.ctx);\n\n\t\t// Actor not loaded, nothing to destroy\n\t\tif (!actorState?.actorInstance) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if already destroying\n\t\tif (actorState.destroying) {\n\t\t\treturn;\n\t\t}\n\t\tactorState.destroying = true;\n\n\t\t// Spawn onStop in background\n\t\tthis.#callOnStopAsync(actorId, doId, actorState.actorInstance);\n\t}\n\n\tasync #callOnStopAsync(\n\t\tactorId: string,\n\t\tdoId: string,\n\t\tactor: CoreAnyActorInstance,\n\t) {\n\t\t// Stop\n\t\tawait actor.onStop(\"destroy\");\n\n\t\t// Remove state\n\t\tconst doState = this.#globalState.getDOState(doId);\n\t\tconst sql = doState.ctx.storage.sql;\n\t\tsql.exec(\"UPDATE _rivetkit_metadata SET destroyed = 1 WHERE 1=1\");\n\t\tsql.exec(\"DELETE FROM _rivetkit_kv_storage\");\n\n\t\t// Clear any scheduled alarms\n\t\tawait doState.ctx.storage.deleteAlarm();\n\n\t\t// Delete from ACTOR_KV in the background - use full actorId including generation\n\t\tconst env = getCloudflareAmbientEnv();\n\t\tdoState.ctx.waitUntil(\n\t\t\tenv.ACTOR_KV.delete(GLOBAL_KV_KEYS.actorMetadata(actorId)),\n\t\t);\n\n\t\t// Reset global state using the DO context\n\t\tconst actorHandle = this.#globalState.getActorState(doState.ctx);\n\t\tactorHandle?.reset();\n\t}\n}\n\nexport function createCloudflareActorsActorDriverBuilder(\n\tglobalState: CloudflareDurableObjectGlobalState,\n) {\n\treturn (\n\t\tregistryConfig: RegistryConfig,\n\t\trunConfig: RunConfig,\n\t\tmanagerDriver: ManagerDriver,\n\t\tinlineClient: Client<any>,\n\t) => {\n\t\treturn new CloudflareActorsActorDriver(\n\t\t\tregistryConfig,\n\t\t\trunConfig,\n\t\t\tmanagerDriver,\n\t\t\tinlineClient,\n\t\t\tglobalState,\n\t\t);\n\t};\n}\n","/**\n * Actor ID utilities for managing actor IDs with generation tracking.\n *\n * Actor IDs are formatted as: `{doId}:{generation}`\n * This allows tracking actor resurrection and preventing stale references.\n */\n\n/**\n * Build an actor ID from a Durable Object ID and generation number.\n * @param doId The Durable Object ID\n * @param generation The generation number (increments on resurrection)\n * @returns The formatted actor ID\n */\nexport function buildActorId(doId: string, generation: number): string {\n\treturn `${doId}:${generation}`;\n}\n\n/**\n * Parse an actor ID into its components.\n * @param actorId The actor ID to parse\n * @returns A tuple of [doId, generation]\n * @throws Error if the actor ID format is invalid\n */\nexport function parseActorId(actorId: string): [string, number] {\n\tconst parts = actorId.split(\":\");\n\tif (parts.length !== 2) {\n\t\tthrow new Error(`Invalid actor ID format: ${actorId}`);\n\t}\n\n\tconst [doId, generationStr] = parts;\n\tconst generation = parseInt(generationStr, 10);\n\n\tif (Number.isNaN(generation)) {\n\t\tthrow new Error(`Invalid generation number in actor ID: ${actorId}`);\n\t}\n\n\treturn [doId, generation];\n}\n","export function kvGet(sql: SqlStorage, key: Uint8Array): Uint8Array | null {\n\tconst cursor = sql.exec(\n\t\t\"SELECT value FROM _rivetkit_kv_storage WHERE key = ?\",\n\t\tkey,\n\t);\n\tconst result = cursor.raw().next();\n\n\tif (!result.done && result.value) {\n\t\treturn toUint8Array(result.value[0]);\n\t}\n\treturn null;\n}\n\nexport function kvPut(\n\tsql: SqlStorage,\n\tkey: Uint8Array,\n\tvalue: Uint8Array,\n): void {\n\tsql.exec(\n\t\t\"INSERT OR REPLACE INTO _rivetkit_kv_storage (key, value) VALUES (?, ?)\",\n\t\tkey,\n\t\tvalue,\n\t);\n}\n\nexport function kvDelete(sql: SqlStorage, key: Uint8Array): void {\n\tsql.exec(\"DELETE FROM _rivetkit_kv_storage WHERE key = ?\", key);\n}\n\nexport function kvListPrefix(\n\tsql: SqlStorage,\n\tprefix: Uint8Array,\n): [Uint8Array, Uint8Array][] {\n\tconst cursor = sql.exec(\"SELECT key, value FROM _rivetkit_kv_storage\");\n\tconst entries: [Uint8Array, Uint8Array][] = [];\n\n\tfor (const row of cursor.raw()) {\n\t\tconst key = toUint8Array(row[0]);\n\t\tconst value = toUint8Array(row[1]);\n\n\t\t// Check if key starts with prefix\n\t\tif (hasPrefix(key, prefix)) {\n\t\t\tentries.push([key, value]);\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n// Helper function to convert SqlStorageValue to Uint8Array\nfunction toUint8Array(\n\tvalue: string | number | ArrayBuffer | Uint8Array | null,\n): Uint8Array {\n\tif (value instanceof Uint8Array) {\n\t\treturn value;\n\t}\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value);\n\t}\n\tthrow new Error(\n\t\t`Unexpected SQL value type: ${typeof value} (${value?.constructor?.name})`,\n\t);\n}\n\nfunction hasPrefix(arr: Uint8Array, prefix: Uint8Array): boolean {\n\tif (prefix.length > arr.length) return false;\n\tfor (let i = 0; i < prefix.length; i++) {\n\t\tif (arr[i] !== prefix[i]) return false;\n\t}\n\treturn true;\n}\n","/** KV keys for using Workers KV to store actor metadata globally. */\nexport const GLOBAL_KV_KEYS = {\n\tactorMetadata: (actorId: string): string => {\n\t\treturn `actor:${actorId}:metadata`;\n\t},\n};\n","import { env } from \"cloudflare:workers\";\nimport type { Client, Registry, RunConfig } from \"rivetkit\";\nimport {\n\ttype ActorHandlerInterface,\n\tcreateActorDurableObject,\n\ttype DurableObjectConstructor,\n} from \"./actor-handler-do\";\nimport { type Config, ConfigSchema, type InputConfig } from \"./config\";\nimport { CloudflareActorsManagerDriver } from \"./manager-driver\";\nimport { upgradeWebSocket } from \"./websocket\";\n\n/** Cloudflare Workers env */\nexport interface Bindings {\n\tACTOR_KV: KVNamespace;\n\tACTOR_DO: DurableObjectNamespace<ActorHandlerInterface>;\n}\n\n/**\n * Stores the env for the current request. Required since some contexts like the inline client driver does not have access to the Hono context.\n *\n * Use getCloudflareAmbientEnv unless using CF_AMBIENT_ENV.run.\n */\nexport function getCloudflareAmbientEnv(): Bindings {\n\treturn env as unknown as Bindings;\n}\n\nexport interface InlineOutput<A extends Registry<any>> {\n\t/** Client to communicate with the actors. */\n\tclient: Client<A>;\n\n\t/** Fetch handler to manually route requests to the Rivet manager API. */\n\tfetch: (request: Request, ...args: any) => Response | Promise<Response>;\n\n\tconfig: Config;\n\n\tActorHandler: DurableObjectConstructor;\n}\n\nexport interface HandlerOutput {\n\thandler: ExportedHandler<Bindings>;\n\tActorHandler: DurableObjectConstructor;\n}\n\n/**\n * Creates an inline client for accessing Rivet Actors privately without a public manager API.\n *\n * If you want to expose a public manager API, either:\n *\n * - Use `createHandler` to expose the Rivet API on `/rivet`\n * - Forward Rivet API requests to `InlineOutput::fetch`\n */\nexport function createInlineClient<R extends Registry<any>>(\n\tregistry: R,\n\tinputConfig?: InputConfig,\n): InlineOutput<R> {\n\t// HACK: Cloudflare does not support using `crypto.randomUUID()` before start, so we pass a default value\n\t//\n\t// Runner key is not used on Cloudflare\n\tinputConfig = { ...inputConfig, runnerKey: \"\" };\n\n\t// Parse config\n\tconst config = ConfigSchema.parse(inputConfig);\n\n\t// Create config\n\tconst runConfig = {\n\t\t...config,\n\t\tdriver: {\n\t\t\tname: \"cloudflare-workers\",\n\t\t\tmanager: () => new CloudflareActorsManagerDriver(),\n\t\t\t// HACK: We can't build the actor driver until we're inside the Durable Object\n\t\t\tactor: undefined as any,\n\t\t},\n\t\tgetUpgradeWebSocket: () => upgradeWebSocket,\n\t} satisfies RunConfig;\n\n\t// Create Durable Object\n\tconst ActorHandler = createActorDurableObject(registry, runConfig);\n\n\t// Create server\n\tconst { client, fetch } = registry.start(runConfig);\n\n\treturn { client, fetch, config, ActorHandler };\n}\n\n/**\n * Creates a handler to be exported from a Cloudflare Worker.\n *\n * This will automatically expose the Rivet manager API on `/rivet`.\n *\n * This includes a `fetch` handler and `ActorHandler` Durable Object.\n */\nexport function createHandler<R extends Registry<any>>(\n\tregistry: R,\n\tinputConfig?: InputConfig,\n): HandlerOutput {\n\tconst { client, fetch, config, ActorHandler } = createInlineClient(\n\t\tregistry,\n\t\tinputConfig,\n\t);\n\n\t// Create Cloudflare handler\n\tconst handler = {\n\t\tfetch: async (request, cfEnv, ctx) => {\n\t\t\tconst url = new URL(request.url);\n\n\t\t\t// Inject Rivet env\n\t\t\tconst env = Object.assign({ RIVET: client }, cfEnv);\n\n\t\t\t// Mount Rivet manager API\n\t\t\tif (url.pathname.startsWith(config.managerPath)) {\n\t\t\t\tconst strippedPath = url.pathname.substring(\n\t\t\t\t\tconfig.managerPath.length,\n\t\t\t\t);\n\t\t\t\turl.pathname = strippedPath;\n\t\t\t\tconst modifiedRequest = new Request(url.toString(), request);\n\t\t\t\treturn fetch(modifiedRequest, env, ctx);\n\t\t\t}\n\n\t\t\tif (config.fetch) {\n\t\t\t\treturn config.fetch(request, env, ctx);\n\t\t\t} else {\n\t\t\t\treturn new Response(\n\t\t\t\t\t\"This is a RivetKit server.\\n\\nLearn more at https://rivetkit.org\\n\",\n\t\t\t\t\t{ status: 200 },\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t} satisfies ExportedHandler<Bindings>;\n\n\treturn { handler, ActorHandler };\n}\n","import type { Client } from \"rivetkit\";\nimport { RunConfigSchema } from \"rivetkit/driver-helpers\";\nimport { z } from \"zod\";\n\nconst ConfigSchemaBase = RunConfigSchema.removeDefault()\n\t.omit({ driver: true, getUpgradeWebSocket: true })\n\t.extend({\n\t\t/** Path that the Rivet manager API will be mounted. */\n\t\tmanagerPath: z.string().optional().default(\"/rivet\"),\n\n\t\tfetch: z\n\t\t\t.custom<\n\t\t\t\tExportedHandlerFetchHandler<{ RIVET: Client<any> }, unknown>\n\t\t\t>()\n\t\t\t.optional(),\n\t});\nexport const ConfigSchema = ConfigSchemaBase.default(() =>\n\tConfigSchemaBase.parse({}),\n);\nexport type InputConfig = z.input<typeof ConfigSchema>;\nexport type Config = z.infer<typeof ConfigSchema>;\n","import type { Context as HonoContext } from \"hono\";\nimport type { Encoding, UniversalWebSocket } from \"rivetkit\";\nimport {\n\ttype ActorOutput,\n\ttype CreateInput,\n\ttype GetForIdInput,\n\ttype GetOrCreateWithKeyInput,\n\ttype GetWithKeyInput,\n\tgenerateRandomString,\n\ttype ListActorsInput,\n\ttype ManagerDisplayInformation,\n\ttype ManagerDriver,\n\tWS_PROTOCOL_ACTOR,\n\tWS_PROTOCOL_CONN_PARAMS,\n\tWS_PROTOCOL_ENCODING,\n\tWS_PROTOCOL_STANDARD,\n\tWS_PROTOCOL_TARGET,\n} from \"rivetkit/driver-helpers\";\nimport {\n\tActorDuplicateKey,\n\tActorNotFound,\n\tInternalError,\n} from \"rivetkit/errors\";\nimport { assertUnreachable } from \"rivetkit/utils\";\nimport { parseActorId } from \"./actor-id\";\nimport { getCloudflareAmbientEnv } from \"./handler\";\nimport { logger } from \"./log\";\nimport type { Bindings } from \"./mod\";\nimport { serializeNameAndKey } from \"./util\";\n\nconst STANDARD_WEBSOCKET_HEADERS = [\n\t\"connection\",\n\t\"upgrade\",\n\t\"sec-websocket-key\",\n\t\"sec-websocket-version\",\n\t\"sec-websocket-protocol\",\n\t\"sec-websocket-extensions\",\n];\n\nexport class CloudflareActorsManagerDriver implements ManagerDriver {\n\tasync sendRequest(\n\t\tactorId: string,\n\t\tactorRequest: Request,\n\t): Promise<Response> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"sending request to durable object\",\n\t\t\tactorId,\n\t\t\tdoId,\n\t\t\tmethod: actorRequest.method,\n\t\t\turl: actorRequest.url,\n\t\t});\n\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\treturn await stub.fetch(actorRequest);\n\t}\n\n\tasync openWebSocket(\n\t\tpath: string,\n\t\tactorId: string,\n\t\tencoding: Encoding,\n\t\tparams: unknown,\n\t): Promise<UniversalWebSocket> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"opening websocket to durable object\",\n\t\t\tactorId,\n\t\t\tdoId,\n\t\t\tpath,\n\t\t});\n\n\t\t// Make a fetch request to the Durable Object with WebSocket upgrade\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\tconst protocols: string[] = [];\n\t\tprotocols.push(WS_PROTOCOL_STANDARD);\n\t\tprotocols.push(`${WS_PROTOCOL_TARGET}actor`);\n\t\tprotocols.push(`${WS_PROTOCOL_ACTOR}${encodeURIComponent(actorId)}`);\n\t\tprotocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`);\n\t\tif (params) {\n\t\t\tprotocols.push(\n\t\t\t\t`${WS_PROTOCOL_CONN_PARAMS}${encodeURIComponent(JSON.stringify(params))}`,\n\t\t\t);\n\t\t}\n\n\t\tconst headers: Record<string, string> = {\n\t\t\tUpgrade: \"websocket\",\n\t\t\tConnection: \"Upgrade\",\n\t\t\t\"sec-websocket-protocol\": protocols.join(\", \"),\n\t\t};\n\n\t\t// Use the path parameter to determine the URL\n\t\tconst normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n\t\tconst url = `http://actor${normalizedPath}`;\n\n\t\tlogger().debug({ msg: \"rewriting websocket url\", from: path, to: url });\n\n\t\tconst response = await stub.fetch(url, {\n\t\t\theaders,\n\t\t});\n\t\tconst webSocket = response.webSocket;\n\n\t\tif (!webSocket) {\n\t\t\tthrow new InternalError(\n\t\t\t\t`missing websocket connection in response from DO\\n\\nStatus: ${response.status}\\nResponse: ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tlogger().debug({\n\t\t\tmsg: \"durable object websocket connection open\",\n\t\t\tactorId,\n\t\t});\n\n\t\twebSocket.accept();\n\n\t\t// TODO: Is this still needed?\n\t\t// HACK: Cloudflare does not call onopen automatically, so we need\n\t\t// to call this on the next tick\n\t\tsetTimeout(() => {\n\t\t\tconst event = new Event(\"open\");\n\t\t\t(webSocket as any).onopen?.(event);\n\t\t\t(webSocket as any).dispatchEvent(event);\n\t\t}, 0);\n\n\t\treturn webSocket as unknown as UniversalWebSocket;\n\t}\n\n\tasync proxyRequest(\n\t\tc: HonoContext<{ Bindings: Bindings }>,\n\t\tactorRequest: Request,\n\t\tactorId: string,\n\t): Promise<Response> {\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"forwarding request to durable object\",\n\t\t\tactorId,\n\t\t\tdoId,\n\t\t\tmethod: actorRequest.method,\n\t\t\turl: actorRequest.url,\n\t\t});\n\n\t\tconst id = c.env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = c.env.ACTOR_DO.get(id);\n\n\t\treturn await stub.fetch(actorRequest);\n\t}\n\n\tasync proxyWebSocket(\n\t\tc: HonoContext<{ Bindings: Bindings }>,\n\t\tpath: string,\n\t\tactorId: string,\n\t\tencoding: Encoding,\n\t\tparams: unknown,\n\t): Promise<Response> {\n\t\tlogger().debug({\n\t\t\tmsg: \"forwarding websocket to durable object\",\n\t\t\tactorId,\n\t\t\tpath,\n\t\t});\n\n\t\t// Validate upgrade\n\t\tconst upgradeHeader = c.req.header(\"Upgrade\");\n\t\tif (!upgradeHeader || upgradeHeader !== \"websocket\") {\n\t\t\treturn new Response(\"Expected Upgrade: websocket\", {\n\t\t\t\tstatus: 426,\n\t\t\t});\n\t\t}\n\n\t\tconst newUrl = new URL(`http://actor${path}`);\n\t\tconst actorRequest = new Request(newUrl, c.req.raw);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"rewriting websocket url\",\n\t\t\tfrom: c.req.url,\n\t\t\tto: actorRequest.url,\n\t\t});\n\n\t\t// Always build fresh request to prevent forwarding unwanted headers\n\t\t// HACK: Since we can't build a new request, we need to remove\n\t\t// non-standard headers manually\n\t\tconst headerKeys: string[] = [];\n\t\tactorRequest.headers.forEach((v, k) => {\n\t\t\theaderKeys.push(k);\n\t\t});\n\t\tfor (const k of headerKeys) {\n\t\t\tif (!STANDARD_WEBSOCKET_HEADERS.includes(k)) {\n\t\t\t\tactorRequest.headers.delete(k);\n\t\t\t}\n\t\t}\n\n\t\t// Build protocols for WebSocket connection\n\t\tconst protocols: string[] = [];\n\t\tprotocols.push(WS_PROTOCOL_STANDARD);\n\t\tprotocols.push(`${WS_PROTOCOL_TARGET}actor`);\n\t\tprotocols.push(`${WS_PROTOCOL_ACTOR}${encodeURIComponent(actorId)}`);\n\t\tprotocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`);\n\t\tif (params) {\n\t\t\tprotocols.push(\n\t\t\t\t`${WS_PROTOCOL_CONN_PARAMS}${encodeURIComponent(JSON.stringify(params))}`,\n\t\t\t);\n\t\t}\n\t\tactorRequest.headers.set(\n\t\t\t\"sec-websocket-protocol\",\n\t\t\tprotocols.join(\", \"),\n\t\t);\n\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\t\tconst id = c.env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = c.env.ACTOR_DO.get(id);\n\n\t\treturn await stub.fetch(actorRequest);\n\t}\n\n\tasync getForId({\n\t\tc,\n\t\tactorId,\n\t}: GetForIdInput<{ Bindings: Bindings }>): Promise<\n\t\tActorOutput | undefined\n\t> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Parse actor ID to get DO ID and expected generation\n\t\tconst [doId, expectedGeneration] = parseActorId(actorId);\n\n\t\t// Get the Durable Object stub\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\t// Call the DO's getMetadata method\n\t\tconst result = await stub.getMetadata();\n\n\t\tif (!result) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getForId: actor not found\",\n\t\t\t\tactorId,\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Check if the actor IDs match in order to check if the generation matches\n\t\tif (result.actorId !== actorId) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getForId: generation mismatch\",\n\t\t\t\trequestedActorId: actorId,\n\t\t\t\tactualActorId: result.actorId,\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (result.destroying) {\n\t\t\tthrow new ActorNotFound(actorId);\n\t\t}\n\n\t\treturn {\n\t\t\tactorId: result.actorId,\n\t\t\tname: result.name,\n\t\t\tkey: result.key,\n\t\t};\n\t}\n\n\tasync getWithKey({\n\t\tc,\n\t\tname,\n\t\tkey,\n\t}: GetWithKeyInput<{ Bindings: Bindings }>): Promise<\n\t\tActorOutput | undefined\n\t> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\tlogger().debug({ msg: \"getWithKey: searching for actor\", name, key });\n\n\t\t// Generate deterministic ID from the name and key\n\t\tconst nameKeyString = serializeNameAndKey(name, key);\n\t\tconst doId = env.ACTOR_DO.idFromName(nameKeyString).toString();\n\n\t\t// Try to get the Durable Object to see if it exists\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\t// Check if actor exists without creating it\n\t\tconst result = await stub.getMetadata();\n\n\t\tif (result) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getWithKey: found actor with matching name and key\",\n\t\t\t\tactorId: result.actorId,\n\t\t\t\tname: result.name,\n\t\t\t\tkey: result.key,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tactorId: result.actorId,\n\t\t\t\tname: result.name,\n\t\t\t\tkey: result.key,\n\t\t\t};\n\t\t} else {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getWithKey: no actor found with matching name and key\",\n\t\t\t\tname,\n\t\t\t\tkey,\n\t\t\t\tdoId,\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tasync getOrCreateWithKey({\n\t\tc,\n\t\tname,\n\t\tkey,\n\t\tinput,\n\t}: GetOrCreateWithKeyInput<{ Bindings: Bindings }>): Promise<ActorOutput> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Create a deterministic ID from the actor name and key\n\t\t// This ensures that actors with the same name and key will have the same ID\n\t\tconst nameKeyString = serializeNameAndKey(name, key);\n\t\tconst doId = env.ACTOR_DO.idFromName(nameKeyString);\n\n\t\t// Get or create actor using the Durable Object's method\n\t\tconst actor = env.ACTOR_DO.get(doId);\n\t\tconst result = await actor.create({\n\t\t\tname,\n\t\t\tkey,\n\t\t\tinput,\n\t\t\tallowExisting: true,\n\t\t});\n\t\tif (\"success\" in result) {\n\t\t\tconst { actorId, created } = result.success;\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getOrCreateWithKey result\",\n\t\t\t\tactorId,\n\t\t\t\tname,\n\t\t\t\tkey,\n\t\t\t\tcreated,\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tactorId,\n\t\t\t\tname,\n\t\t\t\tkey,\n\t\t\t};\n\t\t} else if (\"error\" in result) {\n\t\t\tthrow new Error(`Error: ${JSON.stringify(result.error)}`);\n\t\t} else {\n\t\t\tassertUnreachable(result);\n\t\t}\n\t}\n\n\tasync createActor({\n\t\tc,\n\t\tname,\n\t\tkey,\n\t\tinput,\n\t}: CreateInput<{ Bindings: Bindings }>): Promise<ActorOutput> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Create a deterministic ID from the actor name and key\n\t\t// This ensures that actors with the same name and key will have the same ID\n\t\tconst nameKeyString = serializeNameAndKey(name, key);\n\t\tconst doId = env.ACTOR_DO.idFromName(nameKeyString);\n\n\t\t// Create actor - this will fail if it already exists\n\t\tconst actor = env.ACTOR_DO.get(doId);\n\t\tconst result = await actor.create({\n\t\t\tname,\n\t\t\tkey,\n\t\t\tinput,\n\t\t\tallowExisting: false,\n\t\t});\n\n\t\tif (\"success\" in result) {\n\t\t\tconst { actorId } = result.success;\n\t\t\treturn {\n\t\t\t\tactorId,\n\t\t\t\tname,\n\t\t\t\tkey,\n\t\t\t};\n\t\t} else if (\"error\" in result) {\n\t\t\tif (result.error.actorAlreadyExists) {\n\t\t\t\tthrow new ActorDuplicateKey(name, key);\n\t\t\t}\n\n\t\t\tthrow new InternalError(\n\t\t\t\t`Unknown error creating actor: ${JSON.stringify(result.error)}`,\n\t\t\t);\n\t\t} else {\n\t\t\tassertUnreachable(result);\n\t\t}\n\t}\n\n\tasync listActors({ c, name }: ListActorsInput): Promise<ActorOutput[]> {\n\t\tlogger().warn({\n\t\t\tmsg: \"listActors not fully implemented for Cloudflare Workers\",\n\t\t\tname,\n\t\t});\n\t\treturn [];\n\t}\n\n\tdisplayInformation(): ManagerDisplayInformation {\n\t\treturn {\n\t\t\tname: \"Cloudflare Workers\",\n\t\t\tproperties: {},\n\t\t};\n\t}\n\n\tgetOrCreateInspectorAccessToken() {\n\t\treturn generateRandomString();\n\t}\n}\n","import { getLogger } from \"rivetkit/log\";\n\nexport function logger() {\n\treturn getLogger(\"driver-cloudflare-workers\");\n}\n","// Constants for key handling\nexport const EMPTY_KEY = \"(none)\";\nexport const KEY_SEPARATOR = \",\";\n\n/**\n * Serializes an array of key strings into a single string for use with idFromName\n *\n * @param name The actor name\n * @param key Array of key strings to serialize\n * @returns A single string containing the serialized name and key\n */\nexport function serializeNameAndKey(name: string, key: string[]): string {\n\t// Escape colons in the name\n\tconst escapedName = name.replace(/:/g, \"\\\\:\");\n\n\t// For empty keys, just return the name and a marker\n\tif (key.length === 0) {\n\t\treturn `${escapedName}:${EMPTY_KEY}`;\n\t}\n\n\t// Serialize the key array\n\tconst serializedKey = serializeKey(key);\n\n\t// Combine name and serialized key\n\treturn `${escapedName}:${serializedKey}`;\n}\n\n/**\n * Serializes an array of key strings into a single string\n *\n * @param key Array of key strings to serialize\n * @returns A single string containing the serialized key\n */\nexport function serializeKey(key: string[]): string {\n\t// Use a special marker for empty key arrays\n\tif (key.length === 0) {\n\t\treturn EMPTY_KEY;\n\t}\n\n\t// Escape each key part to handle the separator and the empty key marker\n\tconst escapedParts = key.map((part) => {\n\t\t// First check if it matches our empty key marker\n\t\tif (part === EMPTY_KEY) {\n\t\t\treturn `\\\\${EMPTY_KEY}`;\n\t\t}\n\n\t\t// Escape backslashes first, then commas\n\t\tlet escaped = part.replace(/\\\\/g, \"\\\\\\\\\");\n\t\tescaped = escaped.replace(/,/g, \"\\\\,\");\n\t\treturn escaped;\n\t});\n\n\treturn escapedParts.join(KEY_SEPARATOR);\n}\n\n/**\n * Deserializes a key string back into an array of key strings\n *\n * @param keyString The serialized key string\n * @returns Array of key strings\n */\nexport function deserializeKey(keyString: string): string[] {\n\t// Handle empty values\n\tif (!keyString) {\n\t\treturn [];\n\t}\n\n\t// Check for special empty key marker\n\tif (keyString === EMPTY_KEY) {\n\t\treturn [];\n\t}\n\n\t// Split by unescaped commas and unescape the escaped characters\n\tconst parts: string[] = [];\n\tlet currentPart = \"\";\n\tlet escaping = false;\n\n\tfor (let i = 0; i < keyString.length; i++) {\n\t\tconst char = keyString[i];\n\n\t\tif (escaping) {\n\t\t\t// This is an escaped character, add it directly\n\t\t\tcurrentPart += char;\n\t\t\tescaping = false;\n\t\t} else if (char === \"\\\\\") {\n\t\t\t// Start of an escape sequence\n\t\t\tescaping = true;\n\t\t} else if (char === KEY_SEPARATOR) {\n\t\t\t// This is a separator\n\t\t\tparts.push(currentPart);\n\t\t\tcurrentPart = \"\";\n\t\t} else {\n\t\t\t// Regular character\n\t\t\tcurrentPart += char;\n\t\t}\n\t}\n\n\t// Add the last part if it exists\n\tif (currentPart || parts.length > 0) {\n\t\tparts.push(currentPart);\n\t}\n\n\treturn parts;\n}\n","// Modified from https://github.com/honojs/hono/blob/40ea0eee58e39b31053a0246c595434f1094ad31/src/adapter/cloudflare-workers/websocket.ts#L17\n//\n// This version calls the open event by default\n\nimport type { UpgradeWebSocket, WSEvents, WSReadyState } from \"hono/ws\";\nimport { defineWebSocketHelper, WSContext } from \"hono/ws\";\nimport { WS_PROTOCOL_STANDARD } from \"rivetkit/driver-helpers\";\n\n// Based on https://github.com/honojs/hono/issues/1153#issuecomment-1767321332\nexport const upgradeWebSocket: UpgradeWebSocket<\n\tWebSocket,\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tany,\n\tWSEvents<WebSocket>\n> = defineWebSocketHelper(async (c, events) => {\n\tconst upgradeHeader = c.req.header(\"Upgrade\");\n\tif (upgradeHeader !== \"websocket\") {\n\t\treturn;\n\t}\n\n\tconst webSocketPair = new WebSocketPair();\n\tconst client: WebSocket = webSocketPair[0];\n\tconst server: WebSocket = webSocketPair[1];\n\n\tconst wsContext = new WSContext<WebSocket>({\n\t\tclose: (code, reason) => server.close(code, reason),\n\t\tget protocol() {\n\t\t\treturn server.protocol;\n\t\t},\n\t\traw: server,\n\t\tget readyState() {\n\t\t\treturn server.readyState as WSReadyState;\n\t\t},\n\t\turl: server.url ? new URL(server.url) : null,\n\t\tsend: (source) => server.send(source),\n\t});\n\n\tif (events.onClose) {\n\t\tserver.addEventListener(\"close\", (evt: CloseEvent) =>\n\t\t\tevents.onClose?.(evt, wsContext),\n\t\t);\n\t}\n\tif (events.onMessage) {\n\t\tserver.addEventListener(\"message\", (evt: MessageEvent) =>\n\t\t\tevents.onMessage?.(evt, wsContext),\n\t\t);\n\t}\n\tif (events.onError) {\n\t\tserver.addEventListener(\"error\", (evt: Event) =>\n\t\t\tevents.onError?.(evt, wsContext),\n\t\t);\n\t}\n\n\tserver.accept?.();\n\n\t// note: cloudflare actors doesn't support 'open' event, so we call it immediately with a fake event\n\t//\n\t// we have to do this after `server.accept() is called`\n\tevents.onOpen?.(new Event(\"open\"), wsContext);\n\n\t// Build response headers\n\tconst headers: Record<string, string> = {};\n\n\t// Set Sec-WebSocket-Protocol if does not exist\n\tconst protocols = c.req.header(\"Sec-WebSocket-Protocol\");\n\tif (\n\t\ttypeof protocols === \"string\" &&\n\t\tprotocols\n\t\t\t.split(\",\")\n\t\t\t.map((x) => x.trim())\n\t\t\t.includes(WS_PROTOCOL_STANDARD)\n\t) {\n\t\theaders[\"Sec-WebSocket-Protocol\"] = WS_PROTOCOL_STANDARD;\n\t}\n\n\treturn new Response(null, {\n\t\tstatus: 101,\n\t\theaders,\n\t\twebSocket: client,\n\t});\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/rivet/rivet/rivetkit-typescript/packages/cloudflare-workers/dist/mod.cjs","../src/actor-handler-do.ts","../src/actor-driver.ts","../src/actor-kv.ts","../src/global-kv.ts","../src/handler.ts","../src/config.ts","../src/manager-driver.ts","../src/actor-id.ts","../src/log.ts","../src/util.ts","../src/websocket.ts"],"names":["env","invariant"],"mappings":"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","file":"/home/runner/work/rivet/rivet/rivetkit-typescript/packages/cloudflare-workers/dist/mod.cjs","sourcesContent":[null,"import { DurableObject, env } from \"cloudflare:workers\";\nimport type { ExecutionContext } from \"hono\";\nimport invariant from \"invariant\";\nimport type { ActorKey, ActorRouter, Registry, RegistryConfig } from \"rivetkit\";\nimport { createActorRouter, createClientWithDriver } from \"rivetkit\";\nimport type { ActorDriver, ManagerDriver } from \"rivetkit/driver-helpers\";\nimport { getInitialActorKvState } from \"rivetkit/driver-helpers\";\nimport type { GetUpgradeWebSocket } from \"rivetkit/utils\";\nimport { stringifyError } from \"rivetkit/utils\";\nimport {\n\tActorGlobalState,\n\tCloudflareDurableObjectGlobalState,\n\tcreateCloudflareActorsActorDriverBuilder,\n} from \"./actor-driver\";\nimport { buildActorId, parseActorId } from \"./actor-id\";\nimport { kvGet, kvPut } from \"./actor-kv\";\nimport { GLOBAL_KV_KEYS } from \"./global-kv\";\nimport type { Bindings } from \"./handler\";\nimport { getCloudflareAmbientEnv } from \"./handler\";\nimport { logger } from \"./log\";\nimport { CloudflareActorsManagerDriver } from \"./manager-driver\";\n\nexport interface ActorHandlerInterface extends DurableObject {\n\tcreate(req: ActorInitRequest): Promise<ActorInitResponse>;\n\tgetMetadata(): Promise<\n\t\t| {\n\t\t\t\tactorId: string;\n\t\t\t\tname: string;\n\t\t\t\tkey: ActorKey;\n\t\t\t\tdestroying: boolean;\n\t\t }\n\t\t| undefined\n\t>;\n\tmanagerKvGet(key: Uint8Array): Promise<Uint8Array | null>;\n}\n\nexport interface ActorInitRequest {\n\tname: string;\n\tkey: ActorKey;\n\tinput?: unknown;\n\tallowExisting: boolean;\n}\nexport type ActorInitResponse =\n\t| { success: { actorId: string; created: boolean } }\n\t| { error: { actorAlreadyExists: true } };\n\nexport type DurableObjectConstructor = new (\n\t...args: ConstructorParameters<typeof DurableObject<Bindings>>\n) => DurableObject<Bindings>;\n\nexport function createActorDurableObject(\n\tregistry: Registry<any>,\n\tgetUpgradeWebSocket: GetUpgradeWebSocket,\n): DurableObjectConstructor {\n\tconst globalState = new CloudflareDurableObjectGlobalState();\n\tconst parsedConfig = registry.parseConfig();\n\n\t/**\n\t * Startup steps:\n\t * 1. If not already created call `initialize`, otherwise check KV to ensure it's initialized\n\t * 2. Load actor\n\t * 3. Start service requests\n\t */\n\treturn class ActorHandler\n\t\textends DurableObject<Bindings>\n\t\timplements ActorHandlerInterface\n\t{\n\t\t/**\n\t\t * This holds a strong reference to ActorGlobalState.\n\t\t * CloudflareDurableObjectGlobalState holds a weak reference so we can\n\t\t * access it elsewhere.\n\t\t **/\n\t\t#state: ActorGlobalState;\n\n\t\tconstructor(\n\t\t\t...args: ConstructorParameters<typeof DurableObject<Bindings>>\n\t\t) {\n\t\t\tsuper(...args);\n\n\t\t\t// Initialize SQL table for key-value storage\n\t\t\t//\n\t\t\t// We do this instead of using the native KV storage so we can store blob keys. The native CF KV API only supports string keys.\n\t\t\tthis.ctx.storage.sql.exec(`\n\t\t\t\tCREATE TABLE IF NOT EXISTS _rivetkit_kv_storage(\n\t\t\t\t\tkey BLOB PRIMARY KEY,\n\t\t\t\t\tvalue BLOB\n\t\t\t\t);\n\t\t\t`);\n\n\t\t\t// Initialize SQL table for actor metadata\n\t\t\t//\n\t\t\t// id always equals 1 in order to ensure that there's always exactly 1 row in this table\n\t\t\tthis.ctx.storage.sql.exec(`\n\t\t\t\tCREATE TABLE IF NOT EXISTS _rivetkit_metadata(\n\t\t\t\t\tid INTEGER PRIMARY KEY CHECK (id = 1),\n\t\t\t\t\tname TEXT NOT NULL,\n\t\t\t\t\tkey TEXT NOT NULL,\n\t\t\t\t\tdestroyed INTEGER DEFAULT 0,\n\t\t\t\t\tgeneration INTEGER DEFAULT 0\n\t\t\t\t);\n\t\t\t`);\n\n\t\t\t// Get or create the actor state from the global WeakMap\n\t\t\tconst state = globalState.getActorState(this.ctx);\n\t\t\tif (state) {\n\t\t\t\tthis.#state = state;\n\t\t\t} else {\n\t\t\t\tthis.#state = new ActorGlobalState();\n\t\t\t\tglobalState.setActorState(this.ctx, this.#state);\n\t\t\t}\n\t\t}\n\n\t\tasync #loadActor() {\n\t\t\tinvariant(this.#state, \"State should be initialized\");\n\n\t\t\t// Check if initialized\n\t\t\tif (!this.#state.initialized) {\n\t\t\t\t// Query SQL for initialization data\n\t\t\t\tconst cursor = this.ctx.storage.sql.exec(\n\t\t\t\t\t\"SELECT name, key, destroyed, generation FROM _rivetkit_metadata WHERE id = 1\",\n\t\t\t\t);\n\t\t\t\tconst result = cursor.raw().next();\n\n\t\t\t\tif (!result.done && result.value) {\n\t\t\t\t\tconst name = result.value[0] as string;\n\t\t\t\t\tconst key = JSON.parse(\n\t\t\t\t\t\tresult.value[1] as string,\n\t\t\t\t\t) as ActorKey;\n\t\t\t\t\tconst destroyed = result.value[2] as number;\n\t\t\t\t\tconst generation = result.value[3] as number;\n\n\t\t\t\t\t// Only initialize if not destroyed\n\t\t\t\t\tif (!destroyed) {\n\t\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\t\tmsg: \"already initialized\",\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\tgeneration,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis.#state.initialized = { name, key, generation };\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger().debug(\"actor is destroyed, cannot load\");\n\t\t\t\t\t\tthrow new Error(\"Actor is destroyed\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlogger().debug(\"not initialized\");\n\t\t\t\t\tthrow new Error(\"Actor is not initialized\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check if already loaded\n\t\t\tif (this.#state.actor) {\n\t\t\t\t// Assert that the cached actor has the correct generation\n\t\t\t\t// This will catch any cases where #state.actor has a stale generation\n\t\t\t\tinvariant(\n\t\t\t\t\t!this.#state.initialized ||\n\t\t\t\t\t\tthis.#state.actor.generation ===\n\t\t\t\t\t\t\tthis.#state.initialized.generation,\n\t\t\t\t\t`Stale actor cached: actor generation ${this.#state.actor.generation} != initialized generation ${this.#state.initialized?.generation}. This should not happen.`,\n\t\t\t\t);\n\t\t\t\treturn this.#state.actor;\n\t\t\t}\n\n\t\t\tif (!this.#state.initialized) throw new Error(\"Not initialized\");\n\n\t\t\t// Register DO with global state first\n\t\t\t// HACK: This leaks the DO context, but DO does not provide a native way\n\t\t\t// of knowing when the DO shuts down. We're making a broad assumption\n\t\t\t// that DO will boot a new isolate frequenlty enough that this is not an issue.\n\t\t\tconst actorId = this.ctx.id.toString();\n\t\t\tglobalState.setDOState(actorId, { ctx: this.ctx, env: env });\n\n\t\t\t// Create manager driver\n\t\t\tconst managerDriver = new CloudflareActorsManagerDriver();\n\n\t\t\t// Create inline client\n\t\t\tconst inlineClient = createClientWithDriver(managerDriver);\n\n\t\t\t// Create actor driver builder\n\t\t\tconst actorDriverBuilder =\n\t\t\t\tcreateCloudflareActorsActorDriverBuilder(globalState);\n\n\t\t\t// Create actor driver\n\t\t\tconst actorDriver = actorDriverBuilder(\n\t\t\t\tparsedConfig,\n\t\t\t\tmanagerDriver,\n\t\t\t\tinlineClient,\n\t\t\t);\n\n\t\t\t// Create actor router\n\t\t\tconst actorRouter = createActorRouter(\n\t\t\t\tparsedConfig,\n\t\t\t\tactorDriver,\n\t\t\t\tgetUpgradeWebSocket,\n\t\t\t\tregistry.config.test?.enabled ?? false,\n\t\t\t);\n\n\t\t\t// Save actor with generation\n\t\t\tthis.#state.actor = {\n\t\t\t\tactorRouter,\n\t\t\t\tactorDriver,\n\t\t\t\tgeneration: this.#state.initialized.generation,\n\t\t\t};\n\n\t\t\t// Build actor ID with generation for loading\n\t\t\tconst actorIdWithGen = buildActorId(\n\t\t\t\tactorId,\n\t\t\t\tthis.#state.initialized.generation,\n\t\t\t);\n\n\t\t\t// Initialize the actor instance with proper metadata\n\t\t\t// This ensures the actor driver knows about this actor\n\t\t\tawait actorDriver.loadActor(actorIdWithGen);\n\n\t\t\treturn this.#state.actor;\n\t\t}\n\n\t\t/** RPC called to get actor metadata without creating it */\n\t\tasync getMetadata(): Promise<\n\t\t\t| {\n\t\t\t\t\tactorId: string;\n\t\t\t\t\tname: string;\n\t\t\t\t\tkey: ActorKey;\n\t\t\t\t\tdestroying: boolean;\n\t\t\t }\n\t\t\t| undefined\n\t\t> {\n\t\t\t// Query the metadata\n\t\t\tconst cursor = this.ctx.storage.sql.exec(\n\t\t\t\t\"SELECT name, key, destroyed, generation FROM _rivetkit_metadata WHERE id = 1\",\n\t\t\t);\n\t\t\tconst result = cursor.raw().next();\n\n\t\t\tif (!result.done && result.value) {\n\t\t\t\tconst name = result.value[0] as string;\n\t\t\t\tconst key = JSON.parse(result.value[1] as string) as ActorKey;\n\t\t\t\tconst destroyed = result.value[2] as number;\n\t\t\t\tconst generation = result.value[3] as number;\n\n\t\t\t\t// Check if destroyed\n\t\t\t\tif (destroyed) {\n\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\tmsg: \"getMetadata: actor is destroyed\",\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tgeneration,\n\t\t\t\t\t});\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\t// Build actor ID with generation\n\t\t\t\tconst doId = this.ctx.id.toString();\n\t\t\t\tconst actorId = buildActorId(doId, generation);\n\t\t\t\tconst destroying =\n\t\t\t\t\tglobalState.getActorState(this.ctx)?.destroying ?? false;\n\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"getMetadata: found actor metadata\",\n\t\t\t\t\tactorId,\n\t\t\t\t\tname,\n\t\t\t\t\tkey,\n\t\t\t\t\tgeneration,\n\t\t\t\t\tdestroying,\n\t\t\t\t});\n\n\t\t\t\treturn { actorId, name, key, destroying };\n\t\t\t}\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getMetadata: no metadata found\",\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\n\t\t/** RPC called by ManagerDriver.kvGet to read from KV. */\n\t\tasync managerKvGet(key: Uint8Array): Promise<Uint8Array | null> {\n\t\t\treturn kvGet(this.ctx.storage.sql, key);\n\t\t}\n\n\t\t/** RPC called by the manager to create a DO. Can optionally allow existing actors. */\n\t\tasync create(req: ActorInitRequest): Promise<ActorInitResponse> {\n\t\t\t// Check if actor exists\n\t\t\tconst checkCursor = this.ctx.storage.sql.exec(\n\t\t\t\t\"SELECT destroyed, generation FROM _rivetkit_metadata WHERE id = 1\",\n\t\t\t);\n\t\t\tconst checkResult = checkCursor.raw().next();\n\n\t\t\tlet created = false;\n\t\t\tlet generation = 0;\n\n\t\t\tif (!checkResult.done && checkResult.value) {\n\t\t\t\tconst destroyed = checkResult.value[0] as number;\n\t\t\t\tgeneration = checkResult.value[1] as number;\n\n\t\t\t\tif (!destroyed) {\n\t\t\t\t\t// Actor exists and is not destroyed\n\t\t\t\t\tif (!req.allowExisting) {\n\t\t\t\t\t\t// Fail if not allowing existing actors\n\t\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\t\tmsg: \"create failed: actor already exists\",\n\t\t\t\t\t\t\tname: req.name,\n\t\t\t\t\t\t\tkey: req.key,\n\t\t\t\t\t\t\tgeneration,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn { error: { actorAlreadyExists: true } };\n\t\t\t\t\t}\n\n\t\t\t\t\t// Return existing actor\n\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\tmsg: \"actor already exists\",\n\t\t\t\t\t\tkey: req.key,\n\t\t\t\t\t\tgeneration,\n\t\t\t\t\t});\n\t\t\t\t\tconst doId = this.ctx.id.toString();\n\t\t\t\t\tconst actorId = buildActorId(doId, generation);\n\t\t\t\t\treturn { success: { actorId, created: false } };\n\t\t\t\t}\n\n\t\t\t\t// Actor exists but is destroyed - resurrect with incremented generation\n\t\t\t\tgeneration = generation + 1;\n\t\t\t\tcreated = true;\n\n\t\t\t\t// Clear stale actor from previous generation\n\t\t\t\t// This is necessary because the DO instance may still be in memory\n\t\t\t\t// with the old #state.actor field from before the destroy\n\t\t\t\tif (this.#state) {\n\t\t\t\t\tthis.#state.actor = undefined;\n\t\t\t\t}\n\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"resurrecting destroyed actor\",\n\t\t\t\t\tkey: req.key,\n\t\t\t\t\toldGeneration: generation - 1,\n\t\t\t\t\tnewGeneration: generation,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// No actor exists - will create with generation 0\n\t\t\t\tgeneration = 0;\n\t\t\t\tcreated = true;\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"creating new actor\",\n\t\t\t\t\tkey: req.key,\n\t\t\t\t\tgeneration,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Perform upsert - either inserts new or updates destroyed actor\n\t\t\tthis.ctx.storage.sql.exec(\n\t\t\t\t`INSERT INTO _rivetkit_metadata (id, name, key, destroyed, generation)\n\t\t\t\tVALUES (1, ?, ?, 0, ?)\n\t\t\t\tON CONFLICT(id) DO UPDATE SET\n\t\t\t\t\tname = excluded.name,\n\t\t\t\t\tkey = excluded.key,\n\t\t\t\t\tdestroyed = 0,\n\t\t\t\t\tgeneration = excluded.generation`,\n\t\t\t\treq.name,\n\t\t\t\tJSON.stringify(req.key),\n\t\t\t\tgeneration,\n\t\t\t);\n\n\t\t\tthis.#state.initialized = {\n\t\t\t\tname: req.name,\n\t\t\t\tkey: req.key,\n\t\t\t\tgeneration,\n\t\t\t};\n\n\t\t\t// Build actor ID with generation\n\t\t\tconst doId = this.ctx.id.toString();\n\t\t\tconst actorId = buildActorId(doId, generation);\n\n\t\t\t// Initialize storage and update KV when created or resurrected\n\t\t\tif (created) {\n\t\t\t\t// Initialize persist data in KV storage\n\t\t\t\tinitializeActorKvStorage(this.ctx.storage.sql, req.input);\n\n\t\t\t\t// Update metadata in the background\n\t\t\t\tconst env = getCloudflareAmbientEnv();\n\t\t\t\tconst actorData = { name: req.name, key: req.key, generation };\n\t\t\t\tthis.ctx.waitUntil(\n\t\t\t\t\tenv.ACTOR_KV.put(\n\t\t\t\t\t\tGLOBAL_KV_KEYS.actorMetadata(actorId),\n\t\t\t\t\t\tJSON.stringify(actorData),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Preemptively load actor so the lifecycle hooks are called\n\t\t\tawait this.#loadActor();\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: created\n\t\t\t\t\t? \"actor created/resurrected\"\n\t\t\t\t\t: \"returning existing actor\",\n\t\t\t\tactorId,\n\t\t\t\tcreated,\n\t\t\t\tgeneration,\n\t\t\t});\n\n\t\t\treturn { success: { actorId, created } };\n\t\t}\n\n\t\tasync fetch(request: Request): Promise<Response> {\n\t\t\tconst { actorRouter, generation } = await this.#loadActor();\n\n\t\t\t// Build actor ID with generation\n\t\t\tconst doId = this.ctx.id.toString();\n\t\t\tconst actorId = buildActorId(doId, generation);\n\n\t\t\treturn await actorRouter.fetch(request, {\n\t\t\t\tactorId,\n\t\t\t});\n\t\t}\n\n\t\tasync alarm(): Promise<void> {\n\t\t\tconst { actorDriver, generation } = await this.#loadActor();\n\n\t\t\t// Build actor ID with generation\n\t\t\tconst doId = this.ctx.id.toString();\n\t\t\tconst actorId = buildActorId(doId, generation);\n\n\t\t\t// Load the actor instance and trigger alarm\n\t\t\tconst actor = await actorDriver.loadActor(actorId);\n\t\t\tawait actor.onAlarm();\n\t\t}\n\t};\n}\n\nfunction initializeActorKvStorage(\n\tsql: SqlStorage,\n\tinput: unknown | undefined,\n): void {\n\tconst initialKvState = getInitialActorKvState(input);\n\tfor (const [key, value] of initialKvState) {\n\t\tkvPut(sql, key, value);\n\t}\n}\n","import invariant from \"invariant\";\nimport type {\n\tActorKey,\n\tActorRouter,\n\tAnyActorInstance as CoreAnyActorInstance,\n\tRegistryConfig,\n} from \"rivetkit\";\nimport { lookupInRegistry } from \"rivetkit\";\nimport type { Client } from \"rivetkit/client\";\nimport type {\n\tActorDriver,\n\tAnyActorInstance,\n\tManagerDriver,\n} from \"rivetkit/driver-helpers\";\nimport { promiseWithResolvers } from \"rivetkit/utils\";\nimport { kvDelete, kvGet, kvListPrefix, kvPut } from \"./actor-kv\";\nimport { GLOBAL_KV_KEYS } from \"./global-kv\";\nimport { getCloudflareAmbientEnv } from \"./handler\";\nimport { parseActorId } from \"./actor-id\";\n\ninterface DurableObjectGlobalState {\n\tctx: DurableObjectState;\n\tenv: unknown;\n}\n\n/**\n * Cloudflare DO can have multiple DO running within the same global scope.\n *\n * This allows for storing the actor context globally and looking it up by ID in `CloudflareActorsActorDriver`.\n */\nexport class CloudflareDurableObjectGlobalState {\n\t// Map of actor ID -> DO state\n\t#dos: Map<string, DurableObjectGlobalState> = new Map();\n\n\t// WeakMap of DO state -> ActorGlobalState for proper GC\n\t#actors: WeakMap<DurableObjectState, ActorGlobalState> = new WeakMap();\n\n\tgetDOState(doId: string): DurableObjectGlobalState {\n\t\tconst state = this.#dos.get(doId);\n\t\tinvariant(\n\t\t\tstate !== undefined,\n\t\t\t\"durable object state not in global state\",\n\t\t);\n\t\treturn state;\n\t}\n\n\tsetDOState(doId: string, state: DurableObjectGlobalState) {\n\t\tthis.#dos.set(doId, state);\n\t}\n\n\tgetActorState(ctx: DurableObjectState): ActorGlobalState | undefined {\n\t\treturn this.#actors.get(ctx);\n\t}\n\n\tsetActorState(ctx: DurableObjectState, actorState: ActorGlobalState): void {\n\t\tthis.#actors.set(ctx, actorState);\n\t}\n}\n\nexport interface DriverContext {\n\tstate: DurableObjectState;\n}\n\ninterface InitializedData {\n\tname: string;\n\tkey: ActorKey;\n\tgeneration: number;\n}\n\ninterface LoadedActor {\n\tactorRouter: ActorRouter;\n\tactorDriver: ActorDriver;\n\tgeneration: number;\n}\n\n// Actor global state to track running instances\nexport class ActorGlobalState {\n\t// Initialization state\n\tinitialized?: InitializedData;\n\n\t// Loaded actor state\n\tactor?: LoadedActor;\n\tactorInstance?: AnyActorInstance;\n\tactorPromise?: ReturnType<typeof promiseWithResolvers<void>>;\n\n\t/**\n\t * Indicates if `startDestroy` has been called.\n\t *\n\t * This is stored in memory instead of SQLite since the destroy may be cancelled.\n\t *\n\t * See the corresponding `destroyed` property in SQLite metadata.\n\t */\n\tdestroying: boolean = false;\n\n\treset() {\n\t\tthis.initialized = undefined;\n\t\tthis.actor = undefined;\n\t\tthis.actorInstance = undefined;\n\t\tthis.actorPromise = undefined;\n\t\tthis.destroying = false;\n\t}\n}\n\nexport class CloudflareActorsActorDriver implements ActorDriver {\n\t#registryConfig: RegistryConfig;\n\t#managerDriver: ManagerDriver;\n\t#inlineClient: Client<any>;\n\t#globalState: CloudflareDurableObjectGlobalState;\n\n\tconstructor(\n\t\tregistryConfig: RegistryConfig,\n\t\tmanagerDriver: ManagerDriver,\n\t\tinlineClient: Client<any>,\n\t\tglobalState: CloudflareDurableObjectGlobalState,\n\t) {\n\t\tthis.#registryConfig = registryConfig;\n\t\tthis.#managerDriver = managerDriver;\n\t\tthis.#inlineClient = inlineClient;\n\t\tthis.#globalState = globalState;\n\t}\n\n\t#getDOCtx(actorId: string) {\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\t\treturn this.#globalState.getDOState(doId).ctx;\n\t}\n\n\tasync loadActor(actorId: string): Promise<AnyActorInstance> {\n\t\t// Parse actor ID to get DO ID and generation\n\t\tconst [doId, expectedGeneration] = parseActorId(actorId);\n\n\t\t// Get the DO state\n\t\tconst doState = this.#globalState.getDOState(doId);\n\n\t\t// Check if actor is already loaded\n\t\tlet actorState = this.#globalState.getActorState(doState.ctx);\n\t\tif (actorState?.actorInstance) {\n\t\t\t// Actor is already loaded, return it\n\t\t\treturn actorState.actorInstance;\n\t\t}\n\n\t\t// Create new actor state if it doesn't exist\n\t\tif (!actorState) {\n\t\t\tactorState = new ActorGlobalState();\n\t\t\tactorState.actorPromise = promiseWithResolvers();\n\t\t\tthis.#globalState.setActorState(doState.ctx, actorState);\n\t\t} else if (actorState.actorPromise) {\n\t\t\t// Another request is already loading this actor, wait for it\n\t\t\tawait actorState.actorPromise.promise;\n\t\t\tif (!actorState.actorInstance) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Actor ${actorId} failed to load in concurrent request`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn actorState.actorInstance;\n\t\t}\n\n\t\t// Load actor metadata\n\t\tconst sql = doState.ctx.storage.sql;\n\t\tconst cursor = sql.exec(\n\t\t\t\"SELECT name, key, destroyed, generation FROM _rivetkit_metadata LIMIT 1\",\n\t\t);\n\t\tconst result = cursor.raw().next();\n\n\t\tif (result.done || !result.value) {\n\t\t\tthrow new Error(\n\t\t\t\t`Actor ${actorId} is not initialized - missing metadata`,\n\t\t\t);\n\t\t}\n\n\t\tconst name = result.value[0] as string;\n\t\tconst key = JSON.parse(result.value[1] as string) as string[];\n\t\tconst destroyed = result.value[2] as number;\n\t\tconst generation = result.value[3] as number;\n\n\t\t// Check if actor is destroyed\n\t\tif (destroyed) {\n\t\t\tthrow new Error(`Actor ${actorId} is destroyed`);\n\t\t}\n\n\t\t// Check if generation matches\n\t\tif (generation !== expectedGeneration) {\n\t\t\tthrow new Error(\n\t\t\t\t`Actor ${actorId} generation mismatch - expected ${expectedGeneration}, got ${generation}`,\n\t\t\t);\n\t\t}\n\n\t\t// Create actor instance\n\t\tconst definition = lookupInRegistry(this.#registryConfig, name);\n\t\tactorState.actorInstance = definition.instantiate();\n\n\t\t// Start actor\n\t\tawait actorState.actorInstance.start(\n\t\t\tthis,\n\t\t\tthis.#inlineClient,\n\t\t\tactorId,\n\t\t\tname,\n\t\t\tkey,\n\t\t\t\"unknown\", // TODO: Support regions in Cloudflare\n\t\t);\n\n\t\t// Finish\n\t\tactorState.actorPromise?.resolve();\n\t\tactorState.actorPromise = undefined;\n\n\t\treturn actorState.actorInstance;\n\t}\n\n\tgetContext(actorId: string): DriverContext {\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\t\tconst state = this.#globalState.getDOState(doId);\n\t\treturn { state: state.ctx };\n\t}\n\n\tasync setAlarm(actor: AnyActorInstance, timestamp: number): Promise<void> {\n\t\tawait this.#getDOCtx(actor.id).storage.setAlarm(timestamp);\n\t}\n\n\tasync getDatabase(actorId: string): Promise<unknown | undefined> {\n\t\treturn this.#getDOCtx(actorId).storage.sql;\n\t}\n\n\t// Batch KV operations\n\tasync kvBatchPut(\n\t\tactorId: string,\n\t\tentries: [Uint8Array, Uint8Array][],\n\t): Promise<void> {\n\t\tconst sql = this.#getDOCtx(actorId).storage.sql;\n\n\t\tfor (const [key, value] of entries) {\n\t\t\tkvPut(sql, key, value);\n\t\t}\n\t}\n\n\tasync kvBatchGet(\n\t\tactorId: string,\n\t\tkeys: Uint8Array[],\n\t): Promise<(Uint8Array | null)[]> {\n\t\tconst sql = this.#getDOCtx(actorId).storage.sql;\n\n\t\tconst results: (Uint8Array | null)[] = [];\n\t\tfor (const key of keys) {\n\t\t\tresults.push(kvGet(sql, key));\n\t\t}\n\n\t\treturn results;\n\t}\n\n\tasync kvBatchDelete(actorId: string, keys: Uint8Array[]): Promise<void> {\n\t\tconst sql = this.#getDOCtx(actorId).storage.sql;\n\n\t\tfor (const key of keys) {\n\t\t\tkvDelete(sql, key);\n\t\t}\n\t}\n\n\tasync kvListPrefix(\n\t\tactorId: string,\n\t\tprefix: Uint8Array,\n\t): Promise<[Uint8Array, Uint8Array][]> {\n\t\tconst sql = this.#getDOCtx(actorId).storage.sql;\n\n\t\treturn kvListPrefix(sql, prefix);\n\t}\n\n\tstartDestroy(actorId: string): void {\n\t\t// Parse actor ID to get DO ID and generation\n\t\tconst [doId, generation] = parseActorId(actorId);\n\n\t\t// Get the DO state\n\t\tconst doState = this.#globalState.getDOState(doId);\n\t\tconst actorState = this.#globalState.getActorState(doState.ctx);\n\n\t\t// Actor not loaded, nothing to destroy\n\t\tif (!actorState?.actorInstance) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if already destroying\n\t\tif (actorState.destroying) {\n\t\t\treturn;\n\t\t}\n\t\tactorState.destroying = true;\n\n\t\t// Spawn onStop in background\n\t\tthis.#callOnStopAsync(actorId, doId, actorState.actorInstance);\n\t}\n\n\tasync #callOnStopAsync(\n\t\tactorId: string,\n\t\tdoId: string,\n\t\tactor: CoreAnyActorInstance,\n\t) {\n\t\t// Stop\n\t\tawait actor.onStop(\"destroy\");\n\n\t\t// Remove state\n\t\tconst doState = this.#globalState.getDOState(doId);\n\t\tconst sql = doState.ctx.storage.sql;\n\t\tsql.exec(\"UPDATE _rivetkit_metadata SET destroyed = 1 WHERE 1=1\");\n\t\tsql.exec(\"DELETE FROM _rivetkit_kv_storage\");\n\n\t\t// Clear any scheduled alarms\n\t\tawait doState.ctx.storage.deleteAlarm();\n\n\t\t// Delete from ACTOR_KV in the background - use full actorId including generation\n\t\tconst env = getCloudflareAmbientEnv();\n\t\tdoState.ctx.waitUntil(\n\t\t\tenv.ACTOR_KV.delete(GLOBAL_KV_KEYS.actorMetadata(actorId)),\n\t\t);\n\n\t\t// Reset global state using the DO context\n\t\tconst actorHandle = this.#globalState.getActorState(doState.ctx);\n\t\tactorHandle?.reset();\n\t}\n}\n\nexport function createCloudflareActorsActorDriverBuilder(\n\tglobalState: CloudflareDurableObjectGlobalState,\n) {\n\treturn (\n\t\tconfig: RegistryConfig,\n\t\tmanagerDriver: ManagerDriver,\n\t\tinlineClient: Client<any>,\n\t) => {\n\t\treturn new CloudflareActorsActorDriver(\n\t\t\tconfig,\n\t\t\tmanagerDriver,\n\t\t\tinlineClient,\n\t\t\tglobalState,\n\t\t);\n\t};\n}\n","export function kvGet(sql: SqlStorage, key: Uint8Array): Uint8Array | null {\n\tconst cursor = sql.exec(\n\t\t\"SELECT value FROM _rivetkit_kv_storage WHERE key = ?\",\n\t\tkey,\n\t);\n\tconst result = cursor.raw().next();\n\n\tif (!result.done && result.value) {\n\t\treturn toUint8Array(result.value[0]);\n\t}\n\treturn null;\n}\n\nexport function kvPut(\n\tsql: SqlStorage,\n\tkey: Uint8Array,\n\tvalue: Uint8Array,\n): void {\n\tsql.exec(\n\t\t\"INSERT OR REPLACE INTO _rivetkit_kv_storage (key, value) VALUES (?, ?)\",\n\t\tkey,\n\t\tvalue,\n\t);\n}\n\nexport function kvDelete(sql: SqlStorage, key: Uint8Array): void {\n\tsql.exec(\"DELETE FROM _rivetkit_kv_storage WHERE key = ?\", key);\n}\n\nexport function kvListPrefix(\n\tsql: SqlStorage,\n\tprefix: Uint8Array,\n): [Uint8Array, Uint8Array][] {\n\tconst cursor = sql.exec(\"SELECT key, value FROM _rivetkit_kv_storage\");\n\tconst entries: [Uint8Array, Uint8Array][] = [];\n\n\tfor (const row of cursor.raw()) {\n\t\tconst key = toUint8Array(row[0]);\n\t\tconst value = toUint8Array(row[1]);\n\n\t\t// Check if key starts with prefix\n\t\tif (hasPrefix(key, prefix)) {\n\t\t\tentries.push([key, value]);\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n// Helper function to convert SqlStorageValue to Uint8Array\nfunction toUint8Array(\n\tvalue: string | number | ArrayBuffer | Uint8Array | null,\n): Uint8Array {\n\tif (value instanceof Uint8Array) {\n\t\treturn value;\n\t}\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value);\n\t}\n\tthrow new Error(\n\t\t`Unexpected SQL value type: ${typeof value} (${value?.constructor?.name})`,\n\t);\n}\n\nfunction hasPrefix(arr: Uint8Array, prefix: Uint8Array): boolean {\n\tif (prefix.length > arr.length) return false;\n\tfor (let i = 0; i < prefix.length; i++) {\n\t\tif (arr[i] !== prefix[i]) return false;\n\t}\n\treturn true;\n}\n","/** KV keys for using Workers KV to store actor metadata globally. */\nexport const GLOBAL_KV_KEYS = {\n\tactorMetadata: (actorId: string): string => {\n\t\treturn `actor:${actorId}:metadata`;\n\t},\n};\n","import { env } from \"cloudflare:workers\";\nimport type { Client, Registry } from \"rivetkit\";\nimport { createClientWithDriver } from \"rivetkit\";\nimport { buildManagerRouter } from \"rivetkit/driver-helpers\";\nimport {\n\ttype ActorHandlerInterface,\n\tcreateActorDurableObject,\n\ttype DurableObjectConstructor,\n} from \"./actor-handler-do\";\nimport { type Config, ConfigSchema, type InputConfig } from \"./config\";\nimport { CloudflareActorsManagerDriver } from \"./manager-driver\";\nimport { upgradeWebSocket } from \"./websocket\";\n\n/** Cloudflare Workers env */\nexport interface Bindings {\n\tACTOR_KV: KVNamespace;\n\tACTOR_DO: DurableObjectNamespace<ActorHandlerInterface>;\n}\n\n/**\n * Stores the env for the current request. Required since some contexts like the inline client driver does not have access to the Hono context.\n *\n * Use getCloudflareAmbientEnv unless using CF_AMBIENT_ENV.run.\n */\nexport function getCloudflareAmbientEnv(): Bindings {\n\treturn env as unknown as Bindings;\n}\n\nexport interface InlineOutput<A extends Registry<any>> {\n\t/** Client to communicate with the actors. */\n\tclient: Client<A>;\n\n\t/** Fetch handler to manually route requests to the Rivet manager API. */\n\tfetch: (request: Request, ...args: any) => Response | Promise<Response>;\n\n\tconfig: Config;\n\n\tActorHandler: DurableObjectConstructor;\n}\n\nexport interface HandlerOutput {\n\thandler: ExportedHandler<Bindings>;\n\tActorHandler: DurableObjectConstructor;\n}\n\n/**\n * Creates an inline client for accessing Rivet Actors privately without a public manager API.\n *\n * If you want to expose a public manager API, either:\n *\n * - Use `createHandler` to expose the Rivet API on `/api/rivet`\n * - Forward Rivet API requests to `InlineOutput::fetch`\n */\nexport function createInlineClient<R extends Registry<any>>(\n\tregistry: R,\n\tinputConfig?: InputConfig,\n): InlineOutput<R> {\n\t// HACK: Cloudflare does not support using `crypto.randomUUID()` before start, so we pass a default value\n\t//\n\t// Runner key is not used on Cloudflare\n\tinputConfig = { ...inputConfig, runnerKey: \"\" };\n\n\t// Parse config\n\tconst config = ConfigSchema.parse(inputConfig);\n\n\t// Create Durable Object\n\tconst ActorHandler = createActorDurableObject(\n\t\tregistry,\n\t\t() => upgradeWebSocket,\n\t);\n\n\t// Configure registry for cloudflare-workers\n\tregistry.config.noWelcome = true;\n\t// Disable inspector since it's not supported on Cloudflare Workers\n\tregistry.config.inspector = {\n\t\tenabled: false,\n\t\ttoken: () => \"\",\n\t};\n\t// Set manager base path to \"/\" since the cloudflare handler strips the /api/rivet prefix\n\tregistry.config.managerBasePath = \"/\";\n\tconst parsedConfig = registry.parseConfig();\n\n\t// Create manager driver\n\tconst managerDriver = new CloudflareActorsManagerDriver();\n\n\t// Build the manager router (has actor management endpoints like /actors)\n\tconst { router } = buildManagerRouter(\n\t\tparsedConfig,\n\t\tmanagerDriver,\n\t\t() => upgradeWebSocket,\n\t);\n\n\t// Create client using the manager driver\n\tconst client = createClientWithDriver<R>(managerDriver);\n\n\treturn { client, fetch: router.fetch.bind(router), config, ActorHandler };\n}\n\n/**\n * Creates a handler to be exported from a Cloudflare Worker.\n *\n * This will automatically expose the Rivet manager API on `/api/rivet`.\n *\n * This includes a `fetch` handler and `ActorHandler` Durable Object.\n */\nexport function createHandler<R extends Registry<any>>(\n\tregistry: R,\n\tinputConfig?: InputConfig,\n): HandlerOutput {\n\tconst { client, fetch, config, ActorHandler } = createInlineClient(\n\t\tregistry,\n\t\tinputConfig,\n\t);\n\n\t// Create Cloudflare handler\n\tconst handler = {\n\t\tfetch: async (request, cfEnv, ctx) => {\n\t\t\tconst url = new URL(request.url);\n\n\t\t\t// Inject Rivet env\n\t\t\tconst env = Object.assign({ RIVET: client }, cfEnv);\n\n\t\t\t// Mount Rivet manager API\n\t\t\tif (url.pathname.startsWith(config.managerPath)) {\n\t\t\t\tconst strippedPath = url.pathname.substring(\n\t\t\t\t\tconfig.managerPath.length,\n\t\t\t\t);\n\t\t\t\turl.pathname = strippedPath;\n\t\t\t\tconst modifiedRequest = new Request(url.toString(), request);\n\t\t\t\treturn fetch(modifiedRequest, env, ctx);\n\t\t\t}\n\n\t\t\tif (config.fetch) {\n\t\t\t\treturn config.fetch(request, env, ctx);\n\t\t\t} else {\n\t\t\t\treturn new Response(\n\t\t\t\t\t\"This is a RivetKit server.\\n\\nLearn more at https://rivet.dev\\n\",\n\t\t\t\t\t{ status: 200 },\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t} satisfies ExportedHandler<Bindings>;\n\n\treturn { handler, ActorHandler };\n}\n","import type { Client } from \"rivetkit\";\nimport { z } from \"zod\";\n\nconst ConfigSchemaBase = z.object({\n\t/** Path that the Rivet manager API will be mounted. */\n\tmanagerPath: z.string().optional().default(\"/api/rivet\"),\n\n\t/** Runner key for authentication. */\n\trunnerKey: z.string().optional(),\n\n\t/** Disable the welcome message. */\n\tnoWelcome: z.boolean().optional().default(false),\n\n\tfetch: z\n\t\t.custom<\n\t\t\tExportedHandlerFetchHandler<{ RIVET: Client<any> }, unknown>\n\t\t>()\n\t\t.optional(),\n});\nexport const ConfigSchema = ConfigSchemaBase.default(() =>\n\tConfigSchemaBase.parse({}),\n);\nexport type InputConfig = z.input<typeof ConfigSchema>;\nexport type Config = z.infer<typeof ConfigSchema>;\n","import type { Hono, Context as HonoContext } from \"hono\";\nimport type { Encoding, RegistryConfig, UniversalWebSocket } from \"rivetkit\";\nimport {\n\ttype ActorOutput,\n\ttype CreateInput,\n\ttype GetForIdInput,\n\ttype GetOrCreateWithKeyInput,\n\ttype GetWithKeyInput,\n\ttype ListActorsInput,\n\ttype ManagerDisplayInformation,\n\ttype ManagerDriver,\n\tWS_PROTOCOL_ACTOR,\n\tWS_PROTOCOL_CONN_PARAMS,\n\tWS_PROTOCOL_ENCODING,\n\tWS_PROTOCOL_STANDARD,\n\tWS_PROTOCOL_TARGET,\n} from \"rivetkit/driver-helpers\";\nimport {\n\tActorDuplicateKey,\n\tActorNotFound,\n\tInternalError,\n} from \"rivetkit/errors\";\nimport { assertUnreachable } from \"rivetkit/utils\";\nimport { parseActorId } from \"./actor-id\";\nimport { getCloudflareAmbientEnv } from \"./handler\";\nimport { logger } from \"./log\";\nimport type { Bindings } from \"./mod\";\nimport { serializeNameAndKey } from \"./util\";\n\nconst STANDARD_WEBSOCKET_HEADERS = [\n\t\"connection\",\n\t\"upgrade\",\n\t\"sec-websocket-key\",\n\t\"sec-websocket-version\",\n\t\"sec-websocket-protocol\",\n\t\"sec-websocket-extensions\",\n];\n\nexport class CloudflareActorsManagerDriver implements ManagerDriver {\n\tasync sendRequest(\n\t\tactorId: string,\n\t\tactorRequest: Request,\n\t): Promise<Response> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"sending request to durable object\",\n\t\t\tactorId,\n\t\t\tdoId,\n\t\t\tmethod: actorRequest.method,\n\t\t\turl: actorRequest.url,\n\t\t});\n\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\treturn await stub.fetch(actorRequest);\n\t}\n\n\tasync openWebSocket(\n\t\tpath: string,\n\t\tactorId: string,\n\t\tencoding: Encoding,\n\t\tparams: unknown,\n\t): Promise<UniversalWebSocket> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"opening websocket to durable object\",\n\t\t\tactorId,\n\t\t\tdoId,\n\t\t\tpath,\n\t\t});\n\n\t\t// Make a fetch request to the Durable Object with WebSocket upgrade\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\tconst protocols: string[] = [];\n\t\tprotocols.push(WS_PROTOCOL_STANDARD);\n\t\tprotocols.push(`${WS_PROTOCOL_TARGET}actor`);\n\t\tprotocols.push(`${WS_PROTOCOL_ACTOR}${encodeURIComponent(actorId)}`);\n\t\tprotocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`);\n\t\tif (params) {\n\t\t\tprotocols.push(\n\t\t\t\t`${WS_PROTOCOL_CONN_PARAMS}${encodeURIComponent(JSON.stringify(params))}`,\n\t\t\t);\n\t\t}\n\n\t\tconst headers: Record<string, string> = {\n\t\t\tUpgrade: \"websocket\",\n\t\t\tConnection: \"Upgrade\",\n\t\t\t\"sec-websocket-protocol\": protocols.join(\", \"),\n\t\t};\n\n\t\t// Use the path parameter to determine the URL\n\t\tconst normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n\t\tconst url = `http://actor${normalizedPath}`;\n\n\t\tlogger().debug({ msg: \"rewriting websocket url\", from: path, to: url });\n\n\t\tconst response = await stub.fetch(url, {\n\t\t\theaders,\n\t\t});\n\t\tconst webSocket = response.webSocket;\n\n\t\tif (!webSocket) {\n\t\t\tthrow new InternalError(\n\t\t\t\t`missing websocket connection in response from DO\\n\\nStatus: ${response.status}\\nResponse: ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tlogger().debug({\n\t\t\tmsg: \"durable object websocket connection open\",\n\t\t\tactorId,\n\t\t});\n\n\t\twebSocket.accept();\n\n\t\t// TODO: Is this still needed?\n\t\t// HACK: Cloudflare does not call onopen automatically, so we need\n\t\t// to call this on the next tick\n\t\tsetTimeout(() => {\n\t\t\tconst event = new Event(\"open\");\n\t\t\t(webSocket as any).onopen?.(event);\n\t\t\t(webSocket as any).dispatchEvent(event);\n\t\t}, 0);\n\n\t\treturn webSocket as unknown as UniversalWebSocket;\n\t}\n\n\tasync proxyRequest(\n\t\tc: HonoContext<{ Bindings: Bindings }>,\n\t\tactorRequest: Request,\n\t\tactorId: string,\n\t): Promise<Response> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"forwarding request to durable object\",\n\t\t\tactorId,\n\t\t\tdoId,\n\t\t\tmethod: actorRequest.method,\n\t\t\turl: actorRequest.url,\n\t\t});\n\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\treturn await stub.fetch(actorRequest);\n\t}\n\n\tasync proxyWebSocket(\n\t\tc: HonoContext<{ Bindings: Bindings }>,\n\t\tpath: string,\n\t\tactorId: string,\n\t\tencoding: Encoding,\n\t\tparams: unknown,\n\t): Promise<Response> {\n\t\tlogger().debug({\n\t\t\tmsg: \"forwarding websocket to durable object\",\n\t\t\tactorId,\n\t\t\tpath,\n\t\t});\n\n\t\t// Validate upgrade\n\t\tconst upgradeHeader = c.req.header(\"Upgrade\");\n\t\tif (!upgradeHeader || upgradeHeader !== \"websocket\") {\n\t\t\treturn new Response(\"Expected Upgrade: websocket\", {\n\t\t\t\tstatus: 426,\n\t\t\t});\n\t\t}\n\n\t\tconst newUrl = new URL(`http://actor${path}`);\n\t\tconst actorRequest = new Request(newUrl, c.req.raw);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"rewriting websocket url\",\n\t\t\tfrom: c.req.url,\n\t\t\tto: actorRequest.url,\n\t\t});\n\n\t\t// Always build fresh request to prevent forwarding unwanted headers\n\t\t// HACK: Since we can't build a new request, we need to remove\n\t\t// non-standard headers manually\n\t\tconst headerKeys: string[] = [];\n\t\tactorRequest.headers.forEach((v, k) => {\n\t\t\theaderKeys.push(k);\n\t\t});\n\t\tfor (const k of headerKeys) {\n\t\t\tif (!STANDARD_WEBSOCKET_HEADERS.includes(k)) {\n\t\t\t\tactorRequest.headers.delete(k);\n\t\t\t}\n\t\t}\n\n\t\t// Build protocols for WebSocket connection\n\t\tconst protocols: string[] = [];\n\t\tprotocols.push(WS_PROTOCOL_STANDARD);\n\t\tprotocols.push(`${WS_PROTOCOL_TARGET}actor`);\n\t\tprotocols.push(`${WS_PROTOCOL_ACTOR}${encodeURIComponent(actorId)}`);\n\t\tprotocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`);\n\t\tif (params) {\n\t\t\tprotocols.push(\n\t\t\t\t`${WS_PROTOCOL_CONN_PARAMS}${encodeURIComponent(JSON.stringify(params))}`,\n\t\t\t);\n\t\t}\n\t\tactorRequest.headers.set(\n\t\t\t\"sec-websocket-protocol\",\n\t\t\tprotocols.join(\", \"),\n\t\t);\n\n\t\t// Parse actor ID to get DO ID\n\t\tconst env = getCloudflareAmbientEnv();\n\t\tconst [doId] = parseActorId(actorId);\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\treturn await stub.fetch(actorRequest);\n\t}\n\n\tasync getForId({\n\t\tc,\n\t\tname,\n\t\tactorId,\n\t}: GetForIdInput<{ Bindings: Bindings }>): Promise<\n\t\tActorOutput | undefined\n\t> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Parse actor ID to get DO ID and expected generation\n\t\tconst [doId, expectedGeneration] = parseActorId(actorId);\n\n\t\t// Get the Durable Object stub\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\t// Call the DO's getMetadata method\n\t\tconst result = await stub.getMetadata();\n\n\t\tif (!result) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getForId: actor not found\",\n\t\t\t\tactorId,\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Check if the actor IDs match in order to check if the generation matches\n\t\tif (result.actorId !== actorId) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getForId: generation mismatch\",\n\t\t\t\trequestedActorId: actorId,\n\t\t\t\tactualActorId: result.actorId,\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (result.destroying) {\n\t\t\tthrow new ActorNotFound(actorId);\n\t\t}\n\n\t\treturn {\n\t\t\tactorId: result.actorId,\n\t\t\tname: result.name,\n\t\t\tkey: result.key,\n\t\t};\n\t}\n\n\tasync getWithKey({\n\t\tc,\n\t\tname,\n\t\tkey,\n\t}: GetWithKeyInput<{ Bindings: Bindings }>): Promise<\n\t\tActorOutput | undefined\n\t> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\tlogger().debug({ msg: \"getWithKey: searching for actor\", name, key });\n\n\t\t// Generate deterministic ID from the name and key\n\t\tconst nameKeyString = serializeNameAndKey(name, key);\n\t\tconst doId = env.ACTOR_DO.idFromName(nameKeyString).toString();\n\n\t\t// Try to get the Durable Object to see if it exists\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\t// Check if actor exists without creating it\n\t\tconst result = await stub.getMetadata();\n\n\t\tif (result) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getWithKey: found actor with matching name and key\",\n\t\t\t\tactorId: result.actorId,\n\t\t\t\tname: result.name,\n\t\t\t\tkey: result.key,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tactorId: result.actorId,\n\t\t\t\tname: result.name,\n\t\t\t\tkey: result.key,\n\t\t\t};\n\t\t} else {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getWithKey: no actor found with matching name and key\",\n\t\t\t\tname,\n\t\t\t\tkey,\n\t\t\t\tdoId,\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tasync getOrCreateWithKey({\n\t\tc,\n\t\tname,\n\t\tkey,\n\t\tinput,\n\t}: GetOrCreateWithKeyInput<{ Bindings: Bindings }>): Promise<ActorOutput> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Create a deterministic ID from the actor name and key\n\t\t// This ensures that actors with the same name and key will have the same ID\n\t\tconst nameKeyString = serializeNameAndKey(name, key);\n\t\tconst doId = env.ACTOR_DO.idFromName(nameKeyString);\n\n\t\t// Get or create actor using the Durable Object's method\n\t\tconst actor = env.ACTOR_DO.get(doId);\n\t\tconst result = await actor.create({\n\t\t\tname,\n\t\t\tkey,\n\t\t\tinput,\n\t\t\tallowExisting: true,\n\t\t});\n\t\tif (\"success\" in result) {\n\t\t\tconst { actorId, created } = result.success;\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getOrCreateWithKey result\",\n\t\t\t\tactorId,\n\t\t\t\tname,\n\t\t\t\tkey,\n\t\t\t\tcreated,\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tactorId,\n\t\t\t\tname,\n\t\t\t\tkey,\n\t\t\t};\n\t\t} else if (\"error\" in result) {\n\t\t\tthrow new Error(`Error: ${JSON.stringify(result.error)}`);\n\t\t} else {\n\t\t\tassertUnreachable(result);\n\t\t}\n\t}\n\n\tasync createActor({\n\t\tc,\n\t\tname,\n\t\tkey,\n\t\tinput,\n\t}: CreateInput<{ Bindings: Bindings }>): Promise<ActorOutput> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Create a deterministic ID from the actor name and key\n\t\t// This ensures that actors with the same name and key will have the same ID\n\t\tconst nameKeyString = serializeNameAndKey(name, key);\n\t\tconst doId = env.ACTOR_DO.idFromName(nameKeyString);\n\n\t\t// Create actor - this will fail if it already exists\n\t\tconst actor = env.ACTOR_DO.get(doId);\n\t\tconst result = await actor.create({\n\t\t\tname,\n\t\t\tkey,\n\t\t\tinput,\n\t\t\tallowExisting: false,\n\t\t});\n\n\t\tif (\"success\" in result) {\n\t\t\tconst { actorId } = result.success;\n\t\t\treturn {\n\t\t\t\tactorId,\n\t\t\t\tname,\n\t\t\t\tkey,\n\t\t\t};\n\t\t} else if (\"error\" in result) {\n\t\t\tif (result.error.actorAlreadyExists) {\n\t\t\t\tthrow new ActorDuplicateKey(name, key);\n\t\t\t}\n\n\t\t\tthrow new InternalError(\n\t\t\t\t`Unknown error creating actor: ${JSON.stringify(result.error)}`,\n\t\t\t);\n\t\t} else {\n\t\t\tassertUnreachable(result);\n\t\t}\n\t}\n\n\tasync listActors({ c, name }: ListActorsInput): Promise<ActorOutput[]> {\n\t\tlogger().warn({\n\t\t\tmsg: \"listActors not fully implemented for Cloudflare Workers\",\n\t\t\tname,\n\t\t});\n\t\treturn [];\n\t}\n\n\tdisplayInformation(): ManagerDisplayInformation {\n\t\treturn {\n\t\t\tproperties: {\n\t\t\t\tDriver: \"Cloudflare Workers\",\n\t\t\t},\n\t\t};\n\t}\n\n\tsetGetUpgradeWebSocket(): void {\n\t\t// No-op for Cloudflare Workers - WebSocket upgrades are handled by the DO\n\t}\n\n\tasync kvGet(actorId: string, key: Uint8Array): Promise<string | null> {\n\t\tconst env = getCloudflareAmbientEnv();\n\n\t\t// Parse actor ID to get DO ID\n\t\tconst [doId] = parseActorId(actorId);\n\n\t\tconst id = env.ACTOR_DO.idFromString(doId);\n\t\tconst stub = env.ACTOR_DO.get(id);\n\n\t\tconst value = await stub.managerKvGet(key);\n\t\treturn value !== null ? new TextDecoder().decode(value) : null;\n\t}\n}\n","/**\n * Actor ID utilities for managing actor IDs with generation tracking.\n *\n * Actor IDs are formatted as: `{doId}:{generation}`\n * This allows tracking actor resurrection and preventing stale references.\n */\n\n/**\n * Build an actor ID from a Durable Object ID and generation number.\n * @param doId The Durable Object ID\n * @param generation The generation number (increments on resurrection)\n * @returns The formatted actor ID\n */\nexport function buildActorId(doId: string, generation: number): string {\n\treturn `${doId}:${generation}`;\n}\n\n/**\n * Parse an actor ID into its components.\n * @param actorId The actor ID to parse\n * @returns A tuple of [doId, generation]\n * @throws Error if the actor ID format is invalid\n */\nexport function parseActorId(actorId: string): [string, number] {\n\tconst parts = actorId.split(\":\");\n\tif (parts.length !== 2) {\n\t\tthrow new Error(`Invalid actor ID format: ${actorId}`);\n\t}\n\n\tconst [doId, generationStr] = parts;\n\tconst generation = parseInt(generationStr, 10);\n\n\tif (Number.isNaN(generation)) {\n\t\tthrow new Error(`Invalid generation number in actor ID: ${actorId}`);\n\t}\n\n\treturn [doId, generation];\n}\n","import { getLogger } from \"rivetkit/log\";\n\nexport function logger() {\n\treturn getLogger(\"driver-cloudflare-workers\");\n}\n","// Constants for key handling\nexport const EMPTY_KEY = \"(none)\";\nexport const KEY_SEPARATOR = \",\";\n\n/**\n * Serializes an array of key strings into a single string for use with idFromName\n *\n * @param name The actor name\n * @param key Array of key strings to serialize\n * @returns A single string containing the serialized name and key\n */\nexport function serializeNameAndKey(name: string, key: string[]): string {\n\t// Escape colons in the name\n\tconst escapedName = name.replace(/:/g, \"\\\\:\");\n\n\t// For empty keys, just return the name and a marker\n\tif (key.length === 0) {\n\t\treturn `${escapedName}:${EMPTY_KEY}`;\n\t}\n\n\t// Serialize the key array\n\tconst serializedKey = serializeKey(key);\n\n\t// Combine name and serialized key\n\treturn `${escapedName}:${serializedKey}`;\n}\n\n/**\n * Serializes an array of key strings into a single string\n *\n * @param key Array of key strings to serialize\n * @returns A single string containing the serialized key\n */\nexport function serializeKey(key: string[]): string {\n\t// Use a special marker for empty key arrays\n\tif (key.length === 0) {\n\t\treturn EMPTY_KEY;\n\t}\n\n\t// Escape each key part to handle the separator and the empty key marker\n\tconst escapedParts = key.map((part) => {\n\t\t// First check if it matches our empty key marker\n\t\tif (part === EMPTY_KEY) {\n\t\t\treturn `\\\\${EMPTY_KEY}`;\n\t\t}\n\n\t\t// Escape backslashes first, then commas\n\t\tlet escaped = part.replace(/\\\\/g, \"\\\\\\\\\");\n\t\tescaped = escaped.replace(/,/g, \"\\\\,\");\n\t\treturn escaped;\n\t});\n\n\treturn escapedParts.join(KEY_SEPARATOR);\n}\n\n/**\n * Deserializes a key string back into an array of key strings\n *\n * @param keyString The serialized key string\n * @returns Array of key strings\n */\nexport function deserializeKey(keyString: string): string[] {\n\t// Handle empty values\n\tif (!keyString) {\n\t\treturn [];\n\t}\n\n\t// Check for special empty key marker\n\tif (keyString === EMPTY_KEY) {\n\t\treturn [];\n\t}\n\n\t// Split by unescaped commas and unescape the escaped characters\n\tconst parts: string[] = [];\n\tlet currentPart = \"\";\n\tlet escaping = false;\n\n\tfor (let i = 0; i < keyString.length; i++) {\n\t\tconst char = keyString[i];\n\n\t\tif (escaping) {\n\t\t\t// This is an escaped character, add it directly\n\t\t\tcurrentPart += char;\n\t\t\tescaping = false;\n\t\t} else if (char === \"\\\\\") {\n\t\t\t// Start of an escape sequence\n\t\t\tescaping = true;\n\t\t} else if (char === KEY_SEPARATOR) {\n\t\t\t// This is a separator\n\t\t\tparts.push(currentPart);\n\t\t\tcurrentPart = \"\";\n\t\t} else {\n\t\t\t// Regular character\n\t\t\tcurrentPart += char;\n\t\t}\n\t}\n\n\t// Add the last part if it exists\n\tif (currentPart || parts.length > 0) {\n\t\tparts.push(currentPart);\n\t}\n\n\treturn parts;\n}\n","// Modified from https://github.com/honojs/hono/blob/40ea0eee58e39b31053a0246c595434f1094ad31/src/adapter/cloudflare-workers/websocket.ts#L17\n//\n// This version calls the open event by default\n\nimport type { UpgradeWebSocket, WSEvents, WSReadyState } from \"hono/ws\";\nimport { defineWebSocketHelper, WSContext } from \"hono/ws\";\nimport { WS_PROTOCOL_STANDARD } from \"rivetkit/driver-helpers\";\n\n// Based on https://github.com/honojs/hono/issues/1153#issuecomment-1767321332\nexport const upgradeWebSocket: UpgradeWebSocket<\n\tWebSocket,\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tany,\n\tWSEvents<WebSocket>\n> = defineWebSocketHelper(async (c, events) => {\n\tconst upgradeHeader = c.req.header(\"Upgrade\");\n\tif (upgradeHeader !== \"websocket\") {\n\t\treturn;\n\t}\n\n\tconst webSocketPair = new WebSocketPair();\n\tconst client: WebSocket = webSocketPair[0];\n\tconst server: WebSocket = webSocketPair[1];\n\n\tconst wsContext = new WSContext<WebSocket>({\n\t\tclose: (code, reason) => server.close(code, reason),\n\t\tget protocol() {\n\t\t\treturn server.protocol;\n\t\t},\n\t\traw: server,\n\t\tget readyState() {\n\t\t\treturn server.readyState as WSReadyState;\n\t\t},\n\t\turl: server.url ? new URL(server.url) : null,\n\t\tsend: (source) => server.send(source),\n\t});\n\n\tif (events.onClose) {\n\t\tserver.addEventListener(\"close\", (evt: CloseEvent) =>\n\t\t\tevents.onClose?.(evt, wsContext),\n\t\t);\n\t}\n\tif (events.onMessage) {\n\t\tserver.addEventListener(\"message\", (evt: MessageEvent) =>\n\t\t\tevents.onMessage?.(evt, wsContext),\n\t\t);\n\t}\n\tif (events.onError) {\n\t\tserver.addEventListener(\"error\", (evt: Event) =>\n\t\t\tevents.onError?.(evt, wsContext),\n\t\t);\n\t}\n\n\tserver.accept?.();\n\n\t// note: cloudflare actors doesn't support 'open' event, so we call it immediately with a fake event\n\t//\n\t// we have to do this after `server.accept() is called`\n\tevents.onOpen?.(new Event(\"open\"), wsContext);\n\n\t// Build response headers\n\tconst headers: Record<string, string> = {};\n\n\t// Set Sec-WebSocket-Protocol if does not exist\n\tconst protocols = c.req.header(\"Sec-WebSocket-Protocol\");\n\tif (\n\t\ttypeof protocols === \"string\" &&\n\t\tprotocols\n\t\t\t.split(\",\")\n\t\t\t.map((x) => x.trim())\n\t\t\t.includes(WS_PROTOCOL_STANDARD)\n\t) {\n\t\theaders[\"Sec-WebSocket-Protocol\"] = WS_PROTOCOL_STANDARD;\n\t}\n\n\treturn new Response(null, {\n\t\tstatus: 101,\n\t\theaders,\n\t\twebSocket: client,\n\t});\n});\n"]}
|