rivetkit 2.0.22-rc.1 → 2.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/schemas/actor-persist/v2.ts +259 -0
- package/dist/tsup/{chunk-LCQDY73V.cjs → chunk-2GJILCGQ.cjs} +3 -3
- package/dist/tsup/{chunk-LCQDY73V.cjs.map → chunk-2GJILCGQ.cjs.map} +1 -1
- package/dist/tsup/{chunk-JN6GPVFY.js → chunk-2K2LR56Q.js} +3 -3
- package/dist/tsup/{chunk-EEXX243L.js → chunk-2WVCZCJL.js} +6 -6
- package/dist/tsup/{chunk-FETQGZN4.js → chunk-3BJJSSTM.js} +272 -89
- package/dist/tsup/chunk-3BJJSSTM.js.map +1 -0
- package/dist/tsup/{chunk-ZZYMCYAY.cjs → chunk-3LFMVAJV.cjs} +14 -14
- package/dist/tsup/{chunk-ZZYMCYAY.cjs.map → chunk-3LFMVAJV.cjs.map} +1 -1
- package/dist/tsup/{chunk-NDLOG2JH.js → chunk-6YQKMAMV.js} +2 -2
- package/dist/tsup/{chunk-C2U6KGOG.cjs → chunk-AR4S2QJ7.cjs} +3 -3
- package/dist/tsup/{chunk-C2U6KGOG.cjs.map → chunk-AR4S2QJ7.cjs.map} +1 -1
- package/dist/tsup/{chunk-PELXJCJS.cjs → chunk-B4QZKOMH.cjs} +8 -8
- package/dist/tsup/{chunk-PELXJCJS.cjs.map → chunk-B4QZKOMH.cjs.map} +1 -1
- package/dist/tsup/{chunk-5EB77IQ2.cjs → chunk-CYA35VI3.cjs} +6 -6
- package/dist/tsup/{chunk-5EB77IQ2.cjs.map → chunk-CYA35VI3.cjs.map} +1 -1
- package/dist/tsup/{chunk-UBCUW7HD.js → chunk-D7AA2DK5.js} +2 -2
- package/dist/tsup/{chunk-I7EJWHYV.js → chunk-EBSGEDD3.js} +51 -47
- package/dist/tsup/chunk-EBSGEDD3.js.map +1 -0
- package/dist/tsup/{chunk-R6XOZKMU.cjs → chunk-HSO2H2SB.cjs} +467 -284
- package/dist/tsup/chunk-HSO2H2SB.cjs.map +1 -0
- package/dist/tsup/{chunk-VJLGVVGP.cjs → chunk-HZ4ZM3FL.cjs} +31 -12
- package/dist/tsup/chunk-HZ4ZM3FL.cjs.map +1 -0
- package/dist/tsup/{chunk-7FEMVD3D.cjs → chunk-LMZSOCYD.cjs} +12 -12
- package/dist/tsup/{chunk-7FEMVD3D.cjs.map → chunk-LMZSOCYD.cjs.map} +1 -1
- package/dist/tsup/{chunk-ZVEDMBFT.js → chunk-PBFLG45S.js} +3 -3
- package/dist/tsup/{chunk-GJPOIJHZ.js → chunk-ST6FGRCH.js} +26 -7
- package/dist/tsup/chunk-ST6FGRCH.js.map +1 -0
- package/dist/tsup/{chunk-BIOPK7IB.cjs → chunk-TI72NLP3.cjs} +71 -67
- package/dist/tsup/chunk-TI72NLP3.cjs.map +1 -0
- package/dist/tsup/{chunk-RPI45FGS.js → chunk-TQ4OAC2G.js} +2 -2
- package/dist/tsup/{chunk-4B25D5OW.js → chunk-UB4OHFDW.js} +385 -104
- package/dist/tsup/chunk-UB4OHFDW.js.map +1 -0
- package/dist/tsup/{chunk-6Z3YA6QR.cjs → chunk-V6C34TVH.cjs} +35 -15
- package/dist/tsup/chunk-V6C34TVH.cjs.map +1 -0
- package/dist/tsup/{chunk-OAB7ECAB.cjs → chunk-WVUAO2F7.cjs} +558 -277
- package/dist/tsup/chunk-WVUAO2F7.cjs.map +1 -0
- package/dist/tsup/{chunk-JKNDUKFI.js → chunk-WWAZJHTS.js} +36 -16
- package/dist/tsup/chunk-WWAZJHTS.js.map +1 -0
- package/dist/tsup/client/mod.cjs +9 -9
- package/dist/tsup/client/mod.d.cts +2 -2
- package/dist/tsup/client/mod.d.ts +2 -2
- package/dist/tsup/client/mod.js +8 -8
- package/dist/tsup/common/log.cjs +3 -3
- package/dist/tsup/common/log.js +2 -2
- package/dist/tsup/common/websocket.cjs +4 -4
- package/dist/tsup/common/websocket.js +3 -3
- package/dist/tsup/{conn-Clu655RU.d.ts → conn-BYXlxnh0.d.ts} +111 -102
- package/dist/tsup/{conn-lUvFLo_q.d.cts → conn-BiazosE_.d.cts} +111 -102
- package/dist/tsup/driver-helpers/mod.cjs +5 -5
- package/dist/tsup/driver-helpers/mod.d.cts +1 -1
- package/dist/tsup/driver-helpers/mod.d.ts +1 -1
- package/dist/tsup/driver-helpers/mod.js +4 -4
- package/dist/tsup/driver-test-suite/mod.cjs +71 -71
- package/dist/tsup/driver-test-suite/mod.d.cts +1 -1
- package/dist/tsup/driver-test-suite/mod.d.ts +1 -1
- package/dist/tsup/driver-test-suite/mod.js +11 -11
- package/dist/tsup/inspector/mod.cjs +6 -6
- package/dist/tsup/inspector/mod.d.cts +2 -2
- package/dist/tsup/inspector/mod.d.ts +2 -2
- package/dist/tsup/inspector/mod.js +5 -5
- package/dist/tsup/mod.cjs +10 -10
- package/dist/tsup/mod.d.cts +3 -3
- package/dist/tsup/mod.d.ts +3 -3
- package/dist/tsup/mod.js +9 -9
- package/dist/tsup/test/mod.cjs +11 -11
- package/dist/tsup/test/mod.d.cts +1 -1
- package/dist/tsup/test/mod.d.ts +1 -1
- package/dist/tsup/test/mod.js +10 -10
- package/dist/tsup/utils.cjs +8 -2
- package/dist/tsup/utils.cjs.map +1 -1
- package/dist/tsup/utils.d.cts +8 -1
- package/dist/tsup/utils.d.ts +8 -1
- package/dist/tsup/utils.js +7 -1
- package/package.json +5 -4
- package/src/actor/config.ts +10 -0
- package/src/actor/conn-drivers.ts +43 -1
- package/src/actor/conn-socket.ts +1 -1
- package/src/actor/conn.ts +22 -2
- package/src/actor/context.ts +1 -1
- package/src/actor/driver.ts +13 -2
- package/src/actor/instance.ts +248 -57
- package/src/actor/persisted.ts +7 -0
- package/src/actor/router-endpoints.ts +67 -45
- package/src/actor/router.ts +25 -17
- package/src/client/actor-conn.ts +9 -5
- package/src/common/cors.ts +57 -0
- package/src/common/log.ts +26 -5
- package/src/common/utils.ts +5 -9
- package/src/common/websocket-interface.ts +10 -0
- package/src/driver-helpers/utils.ts +1 -0
- package/src/drivers/engine/actor-driver.ts +261 -14
- package/src/drivers/engine/config.ts +2 -4
- package/src/drivers/file-system/actor.ts +3 -2
- package/src/drivers/file-system/global-state.ts +1 -1
- package/src/drivers/file-system/manager.ts +3 -0
- package/src/engine-process/mod.ts +22 -4
- package/src/inspector/config.ts +0 -45
- package/src/manager/gateway.ts +45 -32
- package/src/manager/hono-websocket-adapter.ts +31 -3
- package/src/manager/router.ts +11 -17
- package/src/registry/run-config.ts +2 -8
- package/src/remote-manager-driver/actor-http-client.ts +5 -8
- package/src/remote-manager-driver/actor-websocket-client.ts +2 -14
- package/src/remote-manager-driver/mod.ts +0 -1
- package/src/schemas/actor-persist/mod.ts +1 -1
- package/src/schemas/actor-persist/versioned.ts +22 -10
- package/src/utils.ts +26 -0
- package/dist/tsup/chunk-4B25D5OW.js.map +0 -1
- package/dist/tsup/chunk-6Z3YA6QR.cjs.map +0 -1
- package/dist/tsup/chunk-BIOPK7IB.cjs.map +0 -1
- package/dist/tsup/chunk-FETQGZN4.js.map +0 -1
- package/dist/tsup/chunk-GJPOIJHZ.js.map +0 -1
- package/dist/tsup/chunk-I7EJWHYV.js.map +0 -1
- package/dist/tsup/chunk-JKNDUKFI.js.map +0 -1
- package/dist/tsup/chunk-OAB7ECAB.cjs.map +0 -1
- package/dist/tsup/chunk-R6XOZKMU.cjs.map +0 -1
- package/dist/tsup/chunk-VJLGVVGP.cjs.map +0 -1
- /package/dist/tsup/{chunk-JN6GPVFY.js.map → chunk-2K2LR56Q.js.map} +0 -0
- /package/dist/tsup/{chunk-EEXX243L.js.map → chunk-2WVCZCJL.js.map} +0 -0
- /package/dist/tsup/{chunk-NDLOG2JH.js.map → chunk-6YQKMAMV.js.map} +0 -0
- /package/dist/tsup/{chunk-UBCUW7HD.js.map → chunk-D7AA2DK5.js.map} +0 -0
- /package/dist/tsup/{chunk-ZVEDMBFT.js.map → chunk-PBFLG45S.js.map} +0 -0
- /package/dist/tsup/{chunk-RPI45FGS.js.map → chunk-TQ4OAC2G.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/rivet/rivet/rivetkit-typescript/packages/rivetkit/dist/tsup/chunk-R6XOZKMU.cjs","../../src/actor/conn.ts","../../src/actor/conn-drivers.ts","../../src/actor/instance.ts","../../src/inspector/actor.ts","../../src/actor/context.ts","../../src/actor/keys.ts","../../src/actor/schedule.ts","../../src/actor/definition.ts","../../src/client/errors.ts","../../src/client/actor-conn.ts","../../src/common/eventsource.ts","../../src/client/actor-query.ts","../../src/client/actor-handle.ts","../../src/client/raw-utils.ts","../../src/client/utils.ts","../../src/client/client.ts","../../src/remote-manager-driver/mod.ts","../../src/remote-manager-driver/log.ts","../../src/remote-manager-driver/api-utils.ts","../../src/remote-manager-driver/actor-http-client.ts","../../src/remote-manager-driver/actor-websocket-client.ts","../../src/remote-manager-driver/api-endpoints.ts","../../src/remote-manager-driver/ws-proxy.ts"],"names":["bareData","InternalError","WebSocket"],"mappings":"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","file":"/home/runner/work/rivet/rivet/rivetkit-typescript/packages/rivetkit/dist/tsup/chunk-R6XOZKMU.cjs","sourcesContent":[null,"import * as cbor from \"cbor-x\";\nimport invariant from \"invariant\";\nimport type * as protocol from \"@/schemas/client-protocol/mod\";\nimport { TO_CLIENT_VERSIONED } from \"@/schemas/client-protocol/versioned\";\nimport { bufferToArrayBuffer } from \"@/utils\";\nimport {\n\tCONN_DRIVERS,\n\tConnDriverKind,\n\ttype ConnDriverState,\n\tConnReadyState,\n\tgetConnDriverKindFromState,\n} from \"./conn-drivers\";\nimport type { ConnSocket } from \"./conn-socket\";\nimport type { AnyDatabaseProvider } from \"./database\";\nimport * as errors from \"./errors\";\nimport type { ActorInstance } from \"./instance\";\nimport type { PersistedConn } from \"./persisted\";\nimport { CachedSerializer } from \"./protocol/serde\";\nimport { generateSecureToken } from \"./utils\";\n\nexport function generateConnId(): string {\n\treturn crypto.randomUUID();\n}\n\nexport function generateConnToken(): string {\n\treturn generateSecureToken(32);\n}\n\nexport function generateConnSocketId(): string {\n\treturn crypto.randomUUID();\n}\n\nexport type ConnId = string;\n\nexport type AnyConn = Conn<any, any, any, any, any, any>;\n\nexport type ConnectionStatus = \"connected\" | \"reconnecting\";\n\n/**\n * Represents a client connection to a actor.\n *\n * Manages connection-specific data and controls the connection lifecycle.\n *\n * @see {@link https://rivet.dev/docs/connections|Connection Documentation}\n */\nexport class Conn<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {\n\tsubscriptions: Set<string> = new Set<string>();\n\n\t// TODO: Remove this cyclical reference\n\t#actor: ActorInstance<S, CP, CS, V, I, DB>;\n\n\t/**\n\t * The proxied state that notifies of changes automatically.\n\t *\n\t * Any data that should be stored indefinitely should be held within this object.\n\t */\n\t__persist: PersistedConn<CP, CS>;\n\n\tget __driverState(): ConnDriverState | undefined {\n\t\treturn this.__socket?.driverState;\n\t}\n\n\t/**\n\t * Socket connected to this connection.\n\t *\n\t * If undefined, then nothing is connected to this.\n\t */\n\t__socket?: ConnSocket;\n\n\tget __status(): ConnectionStatus {\n\t\tif (this.__socket) {\n\t\t\treturn \"connected\";\n\t\t} else {\n\t\t\treturn \"reconnecting\";\n\t\t}\n\t}\n\n\tpublic get params(): CP {\n\t\treturn this.__persist.params;\n\t}\n\n\tpublic get __stateEnabled() {\n\t\treturn this.#actor.connStateEnabled;\n\t}\n\n\t/**\n\t * Gets the current state of the connection.\n\t *\n\t * Throws an error if the state is not enabled.\n\t */\n\tpublic get state(): CS {\n\t\tthis.#validateStateEnabled();\n\t\tif (!this.__persist.state) throw new Error(\"state should exists\");\n\t\treturn this.__persist.state;\n\t}\n\n\t/**\n\t * Sets the state of the connection.\n\t *\n\t * Throws an error if the state is not enabled.\n\t */\n\tpublic set state(value: CS) {\n\t\tthis.#validateStateEnabled();\n\t\tthis.__persist.state = value;\n\t}\n\n\t/**\n\t * Unique identifier for the connection.\n\t */\n\tpublic get id(): ConnId {\n\t\treturn this.__persist.connId;\n\t}\n\n\t/**\n\t * Token used to authenticate this request.\n\t */\n\tpublic get _token(): string {\n\t\treturn this.__persist.token;\n\t}\n\n\t/**\n\t * Status of the connection.\n\t */\n\tpublic get status(): ConnectionStatus {\n\t\treturn this.__status;\n\t}\n\n\t/**\n\t * Timestamp of the last time the connection was seen, i.e. the last time the connection was active and checked for liveness.\n\t */\n\tpublic get lastSeen(): number {\n\t\treturn this.__persist.lastSeen;\n\t}\n\n\t/**\n\t * Initializes a new instance of the Connection class.\n\t *\n\t * This should only be constructed by {@link Actor}.\n\t *\n\t * @protected\n\t */\n\tpublic constructor(\n\t\tactor: ActorInstance<S, CP, CS, V, I, DB>,\n\t\tpersist: PersistedConn<CP, CS>,\n\t) {\n\t\tthis.#actor = actor;\n\t\tthis.__persist = persist;\n\t}\n\n\t#validateStateEnabled() {\n\t\tif (!this.__stateEnabled) {\n\t\t\tthrow new errors.ConnStateNotEnabled();\n\t\t}\n\t}\n\n\t/**\n\t * Sends a WebSocket message to the client.\n\t *\n\t * @param message - The message to send.\n\t *\n\t * @protected\n\t */\n\tpublic _sendMessage(message: CachedSerializer<protocol.ToClient>) {\n\t\tif (this.__driverState) {\n\t\t\tconst driverKind = getConnDriverKindFromState(this.__driverState);\n\t\t\tconst driver = CONN_DRIVERS[driverKind];\n\t\t\tif (driver.sendMessage) {\n\t\t\t\tdriver.sendMessage(\n\t\t\t\t\tthis.#actor,\n\t\t\t\t\tthis,\n\t\t\t\t\t(this.__driverState as any)[driverKind],\n\t\t\t\t\tmessage,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.#actor.rLog.debug({\n\t\t\t\t\tmsg: \"conn driver does not support sending messages\",\n\t\t\t\t\tconn: this.id,\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tthis.#actor.rLog.warn({\n\t\t\t\tmsg: \"missing connection driver state for send message\",\n\t\t\t\tconn: this.id,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Sends an event with arguments to the client.\n\t *\n\t * @param eventName - The name of the event.\n\t * @param args - The arguments for the event.\n\t * @see {@link https://rivet.dev/docs/events|Events Documentation}\n\t */\n\tpublic send(eventName: string, ...args: unknown[]) {\n\t\tthis.#actor.inspector.emitter.emit(\"eventFired\", {\n\t\t\ttype: \"event\",\n\t\t\teventName,\n\t\t\targs,\n\t\t\tconnId: this.id,\n\t\t});\n\t\tthis._sendMessage(\n\t\t\tnew CachedSerializer<protocol.ToClient>(\n\t\t\t\t{\n\t\t\t\t\tbody: {\n\t\t\t\t\t\ttag: \"Event\",\n\t\t\t\t\t\tval: {\n\t\t\t\t\t\t\tname: eventName,\n\t\t\t\t\t\t\targs: bufferToArrayBuffer(cbor.encode(args)),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tTO_CLIENT_VERSIONED,\n\t\t\t),\n\t\t);\n\t}\n\n\t/**\n\t * Disconnects the client with an optional reason.\n\t *\n\t * @param reason - The reason for disconnection.\n\t */\n\tpublic async disconnect(reason?: string) {\n\t\tif (this.__socket && this.__driverState) {\n\t\t\tconst driverKind = getConnDriverKindFromState(this.__driverState);\n\t\t\tconst driver = CONN_DRIVERS[driverKind];\n\t\t\tif (driver.disconnect) {\n\t\t\t\tdriver.disconnect(\n\t\t\t\t\tthis.#actor,\n\t\t\t\t\tthis,\n\t\t\t\t\t(this.__driverState as any)[driverKind],\n\t\t\t\t\treason,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.#actor.rLog.debug({\n\t\t\t\t\tmsg: \"no disconnect handler for conn driver\",\n\t\t\t\t\tconn: this.id,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthis.#actor.__connDisconnected(this, true, this.__socket.socketId);\n\t\t} else {\n\t\t\tthis.#actor.rLog.warn({\n\t\t\t\tmsg: \"missing connection driver state for disconnect\",\n\t\t\t\tconn: this.id,\n\t\t\t});\n\t\t}\n\n\t\tthis.__socket = undefined;\n\t}\n}\n","import type { SSEStreamingApi } from \"hono/streaming\";\nimport type { WSContext } from \"hono/ws\";\nimport type { WebSocket } from \"ws\";\nimport type { AnyConn } from \"@/actor/conn\";\nimport type { AnyActorInstance } from \"@/actor/instance\";\nimport type { CachedSerializer, Encoding } from \"@/actor/protocol/serde\";\nimport { encodeDataToString } from \"@/actor/protocol/serde\";\nimport type * as protocol from \"@/schemas/client-protocol/mod\";\nimport { assertUnreachable, type promiseWithResolvers } from \"@/utils\";\n\nexport enum ConnDriverKind {\n\tWEBSOCKET = 0,\n\tSSE = 1,\n\tHTTP = 2,\n}\n\nexport enum ConnReadyState {\n\tUNKNOWN = -1,\n\tCONNECTING = 0,\n\tOPEN = 1,\n\tCLOSING = 2,\n\tCLOSED = 3,\n}\n\nexport interface ConnDriverWebSocketState {\n\tencoding: Encoding;\n\twebsocket: WSContext;\n\tclosePromise: ReturnType<typeof promiseWithResolvers<void>>;\n}\n\nexport interface ConnDriverSseState {\n\tencoding: Encoding;\n\tstream: SSEStreamingApi;\n}\n\nexport type ConnDriverHttpState = Record<never, never>;\n\nexport type ConnDriverState =\n\t| { [ConnDriverKind.WEBSOCKET]: ConnDriverWebSocketState }\n\t| { [ConnDriverKind.SSE]: ConnDriverSseState }\n\t| { [ConnDriverKind.HTTP]: ConnDriverHttpState };\n\nexport interface ConnDriver<State> {\n\tsendMessage?(\n\t\tactor: AnyActorInstance,\n\t\tconn: AnyConn,\n\t\tstate: State,\n\t\tmessage: CachedSerializer<protocol.ToClient>,\n\t): void;\n\n\t/**\n\t * This returns a promise since we commonly disconnect at the end of a program, and not waiting will cause the socket to not close cleanly.\n\t */\n\tdisconnect(\n\t\tactor: AnyActorInstance,\n\t\tconn: AnyConn,\n\t\tstate: State,\n\t\treason?: string,\n\t): Promise<void>;\n\n\t/**\n\t * Returns the ready state of the connection.\n\t * This is used to determine if the connection is ready to send messages, or if the connection is stale.\n\t */\n\tgetConnectionReadyState(\n\t\tactor: AnyActorInstance,\n\t\tconn: AnyConn,\n\t\tstate: State,\n\t): ConnReadyState | undefined;\n}\n\n// MARK: WebSocket\nconst WEBSOCKET_DRIVER: ConnDriver<ConnDriverWebSocketState> = {\n\tsendMessage: (\n\t\tactor: AnyActorInstance,\n\t\t_conn: AnyConn,\n\t\tstate: ConnDriverWebSocketState,\n\t\tmessage: CachedSerializer<protocol.ToClient>,\n\t) => {\n\t\tconst serialized = message.serialize(state.encoding);\n\n\t\tactor.rLog.debug({\n\t\t\tmsg: \"sending websocket message\",\n\t\t\tencoding: state.encoding,\n\t\t\tdataType: typeof serialized,\n\t\t\tisUint8Array: serialized instanceof Uint8Array,\n\t\t\tisArrayBuffer: serialized instanceof ArrayBuffer,\n\t\t\tdataLength:\n\t\t\t\t(serialized as any).byteLength || (serialized as any).length,\n\t\t});\n\n\t\t// Convert Uint8Array to ArrayBuffer for proper transmission\n\t\tif (serialized instanceof Uint8Array) {\n\t\t\tconst buffer = serialized.buffer.slice(\n\t\t\t\tserialized.byteOffset,\n\t\t\t\tserialized.byteOffset + serialized.byteLength,\n\t\t\t);\n\t\t\t// Handle SharedArrayBuffer case\n\t\t\tif (buffer instanceof SharedArrayBuffer) {\n\t\t\t\tconst arrayBuffer = new ArrayBuffer(buffer.byteLength);\n\t\t\t\tnew Uint8Array(arrayBuffer).set(new Uint8Array(buffer));\n\t\t\t\tactor.rLog.debug({\n\t\t\t\t\tmsg: \"converted SharedArrayBuffer to ArrayBuffer\",\n\t\t\t\t\tbyteLength: arrayBuffer.byteLength,\n\t\t\t\t});\n\t\t\t\tstate.websocket.send(arrayBuffer);\n\t\t\t} else {\n\t\t\t\tactor.rLog.debug({\n\t\t\t\t\tmsg: \"sending ArrayBuffer\",\n\t\t\t\t\tbyteLength: buffer.byteLength,\n\t\t\t\t});\n\t\t\t\tstate.websocket.send(buffer);\n\t\t\t}\n\t\t} else {\n\t\t\tactor.rLog.debug({\n\t\t\t\tmsg: \"sending string data\",\n\t\t\t\tlength: (serialized as string).length,\n\t\t\t});\n\t\t\tstate.websocket.send(serialized);\n\t\t}\n\t},\n\n\tdisconnect: async (\n\t\t_actor: AnyActorInstance,\n\t\t_conn: AnyConn,\n\t\tstate: ConnDriverWebSocketState,\n\t\treason?: string,\n\t) => {\n\t\t// Close socket\n\t\tstate.websocket.close(1000, reason);\n\n\t\t// Create promise to wait for socket to close gracefully\n\t\tawait state.closePromise.promise;\n\t},\n\n\tgetConnectionReadyState: (\n\t\t_actor: AnyActorInstance,\n\t\t_conn: AnyConn,\n\t\tstate: ConnDriverWebSocketState,\n\t): ConnReadyState | undefined => {\n\t\treturn state.websocket.readyState;\n\t},\n};\n\n// MARK: SSE\nconst SSE_DRIVER: ConnDriver<ConnDriverSseState> = {\n\tsendMessage: (\n\t\t_actor: AnyActorInstance,\n\t\t_conn: AnyConn,\n\t\tstate: ConnDriverSseState,\n\t\tmessage: CachedSerializer<protocol.ToClient>,\n\t) => {\n\t\tstate.stream.writeSSE({\n\t\t\tdata: encodeDataToString(message.serialize(state.encoding)),\n\t\t});\n\t},\n\n\tdisconnect: async (\n\t\t_actor: AnyActorInstance,\n\t\t_conn: AnyConn,\n\t\tstate: ConnDriverSseState,\n\t\t_reason?: string,\n\t) => {\n\t\tstate.stream.close();\n\t},\n\n\tgetConnectionReadyState: (\n\t\t_actor: AnyActorInstance,\n\t\t_conn: AnyConn,\n\t\tstate: ConnDriverSseState,\n\t): ConnReadyState | undefined => {\n\t\tif (state.stream.aborted || state.stream.closed) {\n\t\t\treturn ConnReadyState.CLOSED;\n\t\t}\n\n\t\treturn ConnReadyState.OPEN;\n\t},\n};\n\n// MARK: HTTP\nconst HTTP_DRIVER: ConnDriver<ConnDriverHttpState> = {\n\tgetConnectionReadyState(_actor, _conn) {\n\t\t// TODO: This might not be the correct logic\n\t\treturn ConnReadyState.OPEN;\n\t},\n\tdisconnect: async () => {\n\t\t// Noop\n\t\t// TODO: Abort the request\n\t},\n};\n\n/** List of all connection drivers. */\nexport const CONN_DRIVERS: Record<ConnDriverKind, ConnDriver<unknown>> = {\n\t[ConnDriverKind.WEBSOCKET]: WEBSOCKET_DRIVER,\n\t[ConnDriverKind.SSE]: SSE_DRIVER,\n\t[ConnDriverKind.HTTP]: HTTP_DRIVER,\n};\n\nexport function getConnDriverKindFromState(\n\tstate: ConnDriverState,\n): ConnDriverKind {\n\tif (ConnDriverKind.WEBSOCKET in state) return ConnDriverKind.WEBSOCKET;\n\telse if (ConnDriverKind.SSE in state) return ConnDriverKind.SSE;\n\telse if (ConnDriverKind.HTTP in state) return ConnDriverKind.HTTP;\n\telse assertUnreachable(state);\n}\n","import * as cbor from \"cbor-x\";\nimport type { SSEStreamingApi } from \"hono/streaming\";\nimport type { WSContext } from \"hono/ws\";\nimport invariant from \"invariant\";\nimport onChange from \"on-change\";\nimport type { ActorKey, Encoding } from \"@/actor/mod\";\nimport type { Client } from \"@/client/client\";\nimport { getBaseLogger, getIncludeTarget, type Logger } from \"@/common/log\";\nimport { isCborSerializable, stringifyError } from \"@/common/utils\";\nimport type { UniversalWebSocket } from \"@/common/websocket-interface\";\nimport { ActorInspector } from \"@/inspector/actor\";\nimport type { Registry } from \"@/mod\";\nimport type * as bareSchema from \"@/schemas/actor-persist/mod\";\nimport { PERSISTED_ACTOR_VERSIONED } from \"@/schemas/actor-persist/versioned\";\nimport type * as protocol from \"@/schemas/client-protocol/mod\";\nimport { TO_CLIENT_VERSIONED } from \"@/schemas/client-protocol/versioned\";\nimport {\n\tbufferToArrayBuffer,\n\tgetEnvUniversal,\n\tpromiseWithResolvers,\n\tSinglePromiseQueue,\n} from \"@/utils\";\nimport { ActionContext } from \"./action\";\nimport type { ActorConfig, OnConnectOptions } from \"./config\";\nimport {\n\tConn,\n\ttype ConnId,\n\tgenerateConnId,\n\tgenerateConnSocketId,\n\tgenerateConnToken,\n} from \"./conn\";\nimport {\n\tCONN_DRIVERS,\n\ttype ConnDriver,\n\tConnDriverKind,\n\ttype ConnDriverState,\n\tgetConnDriverKindFromState,\n} from \"./conn-drivers\";\nimport type { ConnSocket } from \"./conn-socket\";\nimport { ActorContext } from \"./context\";\nimport type { AnyDatabaseProvider, InferDatabaseClient } from \"./database\";\nimport type { ActorDriver } from \"./driver\";\nimport * as errors from \"./errors\";\nimport { serializeActorKey } from \"./keys\";\nimport type {\n\tPersistedActor,\n\tPersistedConn,\n\tPersistedScheduleEvent,\n} from \"./persisted\";\nimport { processMessage } from \"./protocol/old\";\nimport { CachedSerializer } from \"./protocol/serde\";\nimport { Schedule } from \"./schedule\";\nimport { DeadlineError, deadline } from \"./utils\";\n\n/**\n * Options for the `_saveState` method.\n */\nexport interface SaveStateOptions {\n\t/**\n\t * Forces the state to be saved immediately. This function will return when the state has saved successfully.\n\t */\n\timmediate?: boolean;\n\t/** Bypass ready check for stopping. */\n\tallowStoppingState?: boolean;\n}\n\n/** Actor type alias with all `any` types. Used for `extends` in classes referencing this actor. */\nexport type AnyActorInstance = ActorInstance<\n\t// biome-ignore lint/suspicious/noExplicitAny: Needs to be used in `extends`\n\tany,\n\t// biome-ignore lint/suspicious/noExplicitAny: Needs to be used in `extends`\n\tany,\n\t// biome-ignore lint/suspicious/noExplicitAny: Needs to be used in `extends`\n\tany,\n\t// biome-ignore lint/suspicious/noExplicitAny: Needs to be used in `extends`\n\tany,\n\t// biome-ignore lint/suspicious/noExplicitAny: Needs to be used in `extends`\n\tany,\n\t// biome-ignore lint/suspicious/noExplicitAny: Needs to be used in `extends`\n\tany\n>;\n\nexport type ExtractActorState<A extends AnyActorInstance> =\n\tA extends ActorInstance<\n\t\tinfer State,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany\n\t>\n\t\t? State\n\t\t: never;\n\nexport type ExtractActorConnParams<A extends AnyActorInstance> =\n\tA extends ActorInstance<\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\tinfer ConnParams,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany\n\t>\n\t\t? ConnParams\n\t\t: never;\n\nexport type ExtractActorConnState<A extends AnyActorInstance> =\n\tA extends ActorInstance<\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\tinfer ConnState,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: Must be used for `extends`\n\t\tany\n\t>\n\t\t? ConnState\n\t\t: never;\n\nexport class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {\n\t// Shared actor context for this instance\n\tactorContext: ActorContext<S, CP, CS, V, I, DB>;\n\n\t/** Actor log, intended for the user to call */\n\t#log!: Logger;\n\n\t/** Runtime log, intended for internal actor logs */\n\t#rLog!: Logger;\n\n\t#sleepCalled = false;\n\t#stopCalled = false;\n\n\tget isStopping() {\n\t\treturn this.#stopCalled || this.#sleepCalled;\n\t}\n\n\t#persistChanged = false;\n\t#isInOnStateChange = false;\n\n\t/**\n\t * The proxied state that notifies of changes automatically.\n\t *\n\t * Any data that should be stored indefinitely should be held within this object.\n\t */\n\t#persist!: PersistedActor<S, CP, CS, I>;\n\n\t/** Raw state without the proxy wrapper */\n\t#persistRaw!: PersistedActor<S, CP, CS, I>;\n\n\t#persistWriteQueue = new SinglePromiseQueue();\n\t#alarmWriteQueue = new SinglePromiseQueue();\n\n\t#lastSaveTime = 0;\n\t#pendingSaveTimeout?: NodeJS.Timeout;\n\n\t#vars?: V;\n\n\t#backgroundPromises: Promise<void>[] = [];\n\t#abortController = new AbortController();\n\t#config: ActorConfig<S, CP, CS, V, I, DB>;\n\t#actorDriver!: ActorDriver;\n\t#inlineClient!: Client<Registry<any>>;\n\t#actorId!: string;\n\t#name!: string;\n\t#key!: ActorKey;\n\t#region!: string;\n\t#ready = false;\n\n\t#connections = new Map<ConnId, Conn<S, CP, CS, V, I, DB>>();\n\t#subscriptionIndex = new Map<string, Set<Conn<S, CP, CS, V, I, DB>>>();\n\t#checkConnLivenessInterval?: NodeJS.Timeout;\n\n\t#sleepTimeout?: NodeJS.Timeout;\n\n\t// Track active raw requests so sleep logic can account for them\n\t#activeRawFetchCount = 0;\n\t#activeRawWebSockets = new Set<UniversalWebSocket>();\n\n\t#schedule!: Schedule;\n\t#db!: InferDatabaseClient<DB>;\n\n\t#inspector = new ActorInspector(() => {\n\t\treturn {\n\t\t\tisDbEnabled: async () => {\n\t\t\t\treturn this.#db !== undefined;\n\t\t\t},\n\t\t\tgetDb: async () => {\n\t\t\t\treturn this.db;\n\t\t\t},\n\t\t\tisStateEnabled: async () => {\n\t\t\t\treturn this.stateEnabled;\n\t\t\t},\n\t\t\tgetState: async () => {\n\t\t\t\tthis.#validateStateEnabled();\n\n\t\t\t\t// Must return from `#persistRaw` in order to not return the `onchange` proxy\n\t\t\t\treturn this.#persistRaw.state as Record<string, any> as unknown;\n\t\t\t},\n\t\t\tgetRpcs: async () => {\n\t\t\t\treturn Object.keys(this.#config.actions);\n\t\t\t},\n\t\t\tgetConnections: async () => {\n\t\t\t\treturn Array.from(this.#connections.entries()).map(\n\t\t\t\t\t([id, conn]) => ({\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tstateEnabled: conn.__stateEnabled,\n\t\t\t\t\t\tparams: conn.params as any,\n\t\t\t\t\t\tstate: conn.__stateEnabled ? conn.state : undefined,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t},\n\t\t\tsetState: async (state: unknown) => {\n\t\t\t\tthis.#validateStateEnabled();\n\n\t\t\t\t// Must set on `#persist` instead of `#persistRaw` in order to ensure that the `Proxy` is correctly configured\n\t\t\t\t//\n\t\t\t\t// We have to use `...` so `on-change` recognizes the changes to `state` (i.e. set #persistChanged` to true). This is because:\n\t\t\t\t// 1. In `getState`, we returned the value from `persistRaw`, which does not have the Proxy to monitor state changes\n\t\t\t\t// 2. If we were to assign `state` to `#persist.s`, `on-change` would assume nothing changed since `state` is still === `#persist.s` since we returned a reference in `getState`\n\t\t\t\tthis.#persist.state = { ...(state as S) };\n\t\t\t\tawait this.saveState({ immediate: true });\n\t\t\t},\n\t\t\texecuteAction: async (name, params) => {\n\t\t\t\tconst socketId = generateConnSocketId();\n\t\t\t\tconst conn = await this.createConn(\n\t\t\t\t\t{\n\t\t\t\t\t\tsocketId,\n\t\t\t\t\t\tdriverState: { [ConnDriverKind.HTTP]: {} },\n\t\t\t\t\t},\n\t\t\t\t\tundefined,\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\n\t\t\t\ttry {\n\t\t\t\t\treturn await this.executeAction(\n\t\t\t\t\t\tnew ActionContext(this.actorContext, conn),\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tparams || [],\n\t\t\t\t\t);\n\t\t\t\t} finally {\n\t\t\t\t\tthis.__connDisconnected(conn, true, socketId);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t});\n\n\tget id() {\n\t\treturn this.#actorId;\n\t}\n\n\tget inlineClient(): Client<Registry<any>> {\n\t\treturn this.#inlineClient;\n\t}\n\n\tget inspector() {\n\t\treturn this.#inspector;\n\t}\n\n\tget #sleepingSupported(): boolean {\n\t\treturn this.#actorDriver.sleep !== undefined;\n\t}\n\n\t/**\n\t * This constructor should never be used directly.\n\t *\n\t * Constructed in {@link ActorInstance.start}.\n\t *\n\t * @private\n\t */\n\tconstructor(config: ActorConfig<S, CP, CS, V, I, DB>) {\n\t\tthis.#config = config;\n\t\tthis.actorContext = new ActorContext(this);\n\t}\n\n\tasync start(\n\t\tactorDriver: ActorDriver,\n\t\tinlineClient: Client<Registry<any>>,\n\t\tactorId: string,\n\t\tname: string,\n\t\tkey: ActorKey,\n\t\tregion: string,\n\t) {\n\t\tconst logParams = {\n\t\t\tactor: name,\n\t\t\tkey: serializeActorKey(key),\n\t\t\tactorId,\n\t\t};\n\n\t\tthis.#log = getBaseLogger().child(\n\t\t\tObject.assign(\n\t\t\t\tgetIncludeTarget() ? { target: \"actor\" } : {},\n\t\t\t\tlogParams,\n\t\t\t),\n\t\t);\n\t\tthis.#rLog = getBaseLogger().child(\n\t\t\tObject.assign(\n\t\t\t\tgetIncludeTarget() ? { target: \"actor-runtime\" } : {},\n\t\t\t\tlogParams,\n\t\t\t),\n\t\t);\n\n\t\tthis.#actorDriver = actorDriver;\n\t\tthis.#inlineClient = inlineClient;\n\t\tthis.#actorId = actorId;\n\t\tthis.#name = name;\n\t\tthis.#key = key;\n\t\tthis.#region = region;\n\t\tthis.#schedule = new Schedule(this);\n\n\t\t// Initialize server\n\t\t//\n\t\t// Store the promise so network requests can await initialization\n\t\tawait this.#initialize();\n\n\t\t// TODO: Exit process if this errors\n\t\tif (this.#varsEnabled) {\n\t\t\tlet vars: V | undefined;\n\t\t\tif (\"createVars\" in this.#config) {\n\t\t\t\tconst dataOrPromise = this.#config.createVars(\n\t\t\t\t\tthis.actorContext as unknown as ActorContext<\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tany\n\t\t\t\t\t>,\n\t\t\t\t\tthis.#actorDriver.getContext(this.#actorId),\n\t\t\t\t);\n\t\t\t\tif (dataOrPromise instanceof Promise) {\n\t\t\t\t\tvars = await deadline(\n\t\t\t\t\t\tdataOrPromise,\n\t\t\t\t\t\tthis.#config.options.createVarsTimeout,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tvars = dataOrPromise;\n\t\t\t\t}\n\t\t\t} else if (\"vars\" in this.#config) {\n\t\t\t\tvars = structuredClone(this.#config.vars);\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Could not variables from 'createVars' or 'vars'\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.#vars = vars;\n\t\t}\n\n\t\t// TODO: Exit process if this errors\n\t\tthis.#rLog.info({ msg: \"actor starting\" });\n\t\tif (this.#config.onStart) {\n\t\t\tconst result = this.#config.onStart(this.actorContext);\n\t\t\tif (result instanceof Promise) {\n\t\t\t\tawait result;\n\t\t\t}\n\t\t}\n\n\t\t// Setup Database\n\t\tif (\"db\" in this.#config && this.#config.db) {\n\t\t\tconst client = await this.#config.db.createClient({\n\t\t\t\tgetDatabase: () => actorDriver.getDatabase(this.#actorId),\n\t\t\t});\n\t\t\tthis.#rLog.info({ msg: \"database migration starting\" });\n\t\t\tawait this.#config.db.onMigrate?.(client);\n\t\t\tthis.#rLog.info({ msg: \"database migration complete\" });\n\t\t\tthis.#db = client;\n\t\t}\n\n\t\t// Set alarm for next scheduled event if any exist after finishing initiation sequence\n\t\tif (this.#persist.scheduledEvents.length > 0) {\n\t\t\tawait this.#queueSetAlarm(\n\t\t\t\tthis.#persist.scheduledEvents[0].timestamp,\n\t\t\t);\n\t\t}\n\n\t\tthis.#rLog.info({ msg: \"actor ready\" });\n\t\tthis.#ready = true;\n\n\t\t// Must be called after setting `#ready` or else it will not schedule sleep\n\t\tthis.#resetSleepTimer();\n\n\t\t// Start conn liveness interval\n\t\t//\n\t\t// Check for liveness immediately since we may have connections that\n\t\t// were in `reconnecting` state when the actor went to sleep that we\n\t\t// need to purge.\n\t\t//\n\t\t// We don't use alarms for connection liveness since alarms require\n\t\t// durability & are expensive. Connection liveness is safe to assume\n\t\t// it only needs to be ran while the actor is awake and does not need\n\t\t// to manually wake the actor. The only case this is not true is if the\n\t\t// connection liveness timeout is greater than the actor sleep timeout\n\t\t// OR if the actor is manually put to sleep. In this case, the connections\n\t\t// will be stuck in a `reconnecting` state until the actor is awaken again.\n\t\tthis.#checkConnLivenessInterval = setInterval(\n\t\t\tthis.#checkConnectionsLiveness.bind(this),\n\t\t\tthis.#config.options.connectionLivenessInterval,\n\t\t);\n\t\tthis.#checkConnectionsLiveness();\n\n\t\t// Trigger any pending alarms\n\t\tawait this._onAlarm();\n\t}\n\n\tasync #scheduleEventInner(newEvent: PersistedScheduleEvent) {\n\t\tthis.actorContext.log.info({ msg: \"scheduling event\", ...newEvent });\n\n\t\t// Insert event in to index\n\t\tconst insertIndex = this.#persist.scheduledEvents.findIndex(\n\t\t\t(x) => x.timestamp > newEvent.timestamp,\n\t\t);\n\t\tif (insertIndex === -1) {\n\t\t\tthis.#persist.scheduledEvents.push(newEvent);\n\t\t} else {\n\t\t\tthis.#persist.scheduledEvents.splice(insertIndex, 0, newEvent);\n\t\t}\n\n\t\t// Update alarm if:\n\t\t// - this is the newest event (i.e. at beginning of array) or\n\t\t// - this is the only event (i.e. the only event in the array)\n\t\tif (insertIndex === 0 || this.#persist.scheduledEvents.length === 1) {\n\t\t\tthis.actorContext.log.info({\n\t\t\t\tmsg: \"setting alarm\",\n\t\t\t\ttimestamp: newEvent.timestamp,\n\t\t\t\teventCount: this.#persist.scheduledEvents.length,\n\t\t\t});\n\t\t\tawait this.#queueSetAlarm(newEvent.timestamp);\n\t\t}\n\t}\n\n\t/**\n\t * Triggers any pending alarms.\n\t *\n\t * This method is idempotent. It's called automatically when the actor wakes\n\t * in order to trigger any pending alarms.\n\t */\n\tasync _onAlarm() {\n\t\tconst now = Date.now();\n\t\tthis.actorContext.log.debug({\n\t\t\tmsg: \"alarm triggered\",\n\t\t\tnow,\n\t\t\tevents: this.#persist.scheduledEvents.length,\n\t\t});\n\n\t\t// Update sleep\n\t\t//\n\t\t// Do this before any async logic\n\t\tthis.#resetSleepTimer();\n\n\t\t// Remove events from schedule that we're about to run\n\t\tconst runIndex = this.#persist.scheduledEvents.findIndex(\n\t\t\t(x) => x.timestamp <= now,\n\t\t);\n\t\tif (runIndex === -1) {\n\t\t\t// This method is idempotent, so this will happen in scenarios like `start` and\n\t\t\t// no events are pending.\n\t\t\tthis.#rLog.debug({ msg: \"no events are due yet\" });\n\t\t\tif (this.#persist.scheduledEvents.length > 0) {\n\t\t\t\tconst nextTs = this.#persist.scheduledEvents[0].timestamp;\n\t\t\t\tthis.actorContext.log.debug({\n\t\t\t\t\tmsg: \"alarm fired early, rescheduling for next event\",\n\t\t\t\t\tnow,\n\t\t\t\t\tnextTs,\n\t\t\t\t\tdelta: nextTs - now,\n\t\t\t\t});\n\t\t\t\tawait this.#queueSetAlarm(nextTs);\n\t\t\t}\n\t\t\tthis.actorContext.log.debug({ msg: \"no events to run\", now });\n\t\t\treturn;\n\t\t}\n\t\tconst scheduleEvents = this.#persist.scheduledEvents.splice(\n\t\t\t0,\n\t\t\trunIndex + 1,\n\t\t);\n\t\tthis.actorContext.log.debug({\n\t\t\tmsg: \"running events\",\n\t\t\tcount: scheduleEvents.length,\n\t\t});\n\n\t\t// Set alarm for next event\n\t\tif (this.#persist.scheduledEvents.length > 0) {\n\t\t\tconst nextTs = this.#persist.scheduledEvents[0].timestamp;\n\t\t\tthis.actorContext.log.info({\n\t\t\t\tmsg: \"setting next alarm\",\n\t\t\t\tnextTs,\n\t\t\t\tremainingEvents: this.#persist.scheduledEvents.length,\n\t\t\t});\n\t\t\tawait this.#queueSetAlarm(nextTs);\n\t\t}\n\n\t\t// Iterate by event key in order to ensure we call the events in order\n\t\tfor (const event of scheduleEvents) {\n\t\t\ttry {\n\t\t\t\tthis.actorContext.log.info({\n\t\t\t\t\tmsg: \"running action for event\",\n\t\t\t\t\tevent: event.eventId,\n\t\t\t\t\ttimestamp: event.timestamp,\n\t\t\t\t\taction: event.kind.generic.actionName,\n\t\t\t\t});\n\n\t\t\t\t// Look up function\n\t\t\t\tconst fn: unknown =\n\t\t\t\t\tthis.#config.actions[event.kind.generic.actionName];\n\n\t\t\t\tif (!fn)\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Missing action for alarm ${event.kind.generic.actionName}`,\n\t\t\t\t\t);\n\t\t\t\tif (typeof fn !== \"function\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Alarm function lookup for ${event.kind.generic.actionName} returned ${typeof fn}`,\n\t\t\t\t\t);\n\n\t\t\t\t// Call function\n\t\t\t\ttry {\n\t\t\t\t\tconst args = event.kind.generic.args\n\t\t\t\t\t\t? cbor.decode(new Uint8Array(event.kind.generic.args))\n\t\t\t\t\t\t: [];\n\t\t\t\t\tawait fn.call(undefined, this.actorContext, ...args);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.actorContext.log.error({\n\t\t\t\t\t\tmsg: \"error while running event\",\n\t\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t\t\tevent: event.eventId,\n\t\t\t\t\t\ttimestamp: event.timestamp,\n\t\t\t\t\t\taction: event.kind.generic.actionName,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.actorContext.log.error({\n\t\t\t\t\tmsg: \"internal error while running event\",\n\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t\t...event,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tasync scheduleEvent(\n\t\ttimestamp: number,\n\t\taction: string,\n\t\targs: unknown[],\n\t): Promise<void> {\n\t\treturn this.#scheduleEventInner({\n\t\t\teventId: crypto.randomUUID(),\n\t\t\ttimestamp,\n\t\t\tkind: {\n\t\t\t\tgeneric: {\n\t\t\t\t\tactionName: action,\n\t\t\t\t\targs: bufferToArrayBuffer(cbor.encode(args)),\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t}\n\n\tget stateEnabled() {\n\t\treturn \"createState\" in this.#config || \"state\" in this.#config;\n\t}\n\n\t#validateStateEnabled() {\n\t\tif (!this.stateEnabled) {\n\t\t\tthrow new errors.StateNotEnabled();\n\t\t}\n\t}\n\n\tget connStateEnabled() {\n\t\treturn \"createConnState\" in this.#config || \"connState\" in this.#config;\n\t}\n\n\tget #varsEnabled() {\n\t\treturn \"createVars\" in this.#config || \"vars\" in this.#config;\n\t}\n\n\t#validateVarsEnabled() {\n\t\tif (!this.#varsEnabled) {\n\t\t\tthrow new errors.VarsNotEnabled();\n\t\t}\n\t}\n\n\t/** Promise used to wait for a save to complete. This is required since you cannot await `#saveStateThrottled`. */\n\t#onPersistSavedPromise?: ReturnType<typeof promiseWithResolvers<void>>;\n\n\t/** Throttled save state method. Used to write to KV at a reasonable cadence. */\n\t#savePersistThrottled() {\n\t\tconst now = Date.now();\n\t\tconst timeSinceLastSave = now - this.#lastSaveTime;\n\t\tconst saveInterval = this.#config.options.stateSaveInterval;\n\n\t\t// If we're within the throttle window and not already scheduled, schedule the next save.\n\t\tif (timeSinceLastSave < saveInterval) {\n\t\t\tif (this.#pendingSaveTimeout === undefined) {\n\t\t\t\tthis.#pendingSaveTimeout = setTimeout(() => {\n\t\t\t\t\tthis.#pendingSaveTimeout = undefined;\n\t\t\t\t\tthis.#savePersistInner();\n\t\t\t\t}, saveInterval - timeSinceLastSave);\n\t\t\t}\n\t\t} else {\n\t\t\t// If we're outside the throttle window, save immediately\n\t\t\tthis.#savePersistInner();\n\t\t}\n\t}\n\n\t/** Saves the state to KV. You probably want to use #saveStateThrottled instead except for a few edge cases. */\n\tasync #savePersistInner() {\n\t\ttry {\n\t\t\tthis.#lastSaveTime = Date.now();\n\n\t\t\tif (this.#persistChanged) {\n\t\t\t\tconst finished = this.#persistWriteQueue.enqueue(async () => {\n\t\t\t\t\tthis.#rLog.debug({ msg: \"saving persist\" });\n\n\t\t\t\t\t// There might be more changes while we're writing, so we set this\n\t\t\t\t\t// before writing to KV in order to avoid a race condition.\n\t\t\t\t\tthis.#persistChanged = false;\n\n\t\t\t\t\t// Convert to BARE types and write to KV\n\t\t\t\t\tconst bareData = this.#convertToBarePersisted(\n\t\t\t\t\t\tthis.#persistRaw,\n\t\t\t\t\t);\n\t\t\t\t\tawait this.#actorDriver.writePersistedData(\n\t\t\t\t\t\tthis.#actorId,\n\t\t\t\t\t\tPERSISTED_ACTOR_VERSIONED.serializeWithEmbeddedVersion(\n\t\t\t\t\t\t\tbareData,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tthis.#rLog.debug({ msg: \"persist saved\" });\n\t\t\t\t});\n\n\t\t\t\tawait finished;\n\t\t\t}\n\n\t\t\tthis.#onPersistSavedPromise?.resolve();\n\t\t} catch (error) {\n\t\t\tthis.#onPersistSavedPromise?.reject(error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync #queueSetAlarm(timestamp: number): Promise<void> {\n\t\tawait this.#alarmWriteQueue.enqueue(async () => {\n\t\t\tawait this.#actorDriver.setAlarm(this, timestamp);\n\t\t});\n\t}\n\n\t/**\n\t * Creates proxy for `#persist` that handles automatically flagging when state needs to be updated.\n\t */\n\t#setPersist(target: PersistedActor<S, CP, CS, I>) {\n\t\t// Set raw persist object\n\t\tthis.#persistRaw = target;\n\n\t\t// TODO: Only validate this for conn state\n\t\t// TODO: Allow disabling in production\n\t\t// If this can't be proxied, return raw value\n\t\tif (target === null || typeof target !== \"object\") {\n\t\t\tlet invalidPath = \"\";\n\t\t\tif (\n\t\t\t\t!isCborSerializable(\n\t\t\t\t\ttarget,\n\t\t\t\t\t(path) => {\n\t\t\t\t\t\tinvalidPath = path;\n\t\t\t\t\t},\n\t\t\t\t\t\"\",\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tthrow new errors.InvalidStateType({ path: invalidPath });\n\t\t\t}\n\t\t\treturn target;\n\t\t}\n\n\t\t// Unsubscribe from old state\n\t\tif (this.#persist) {\n\t\t\tonChange.unsubscribe(this.#persist);\n\t\t}\n\n\t\t// Listen for changes to the object in order to automatically write state\n\t\tthis.#persist = onChange(\n\t\t\ttarget,\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: Don't know types in proxy\n\t\t\t(\n\t\t\t\tpath: string,\n\t\t\t\tvalue: any,\n\t\t\t\t_previousValue: any,\n\t\t\t\t_applyData: any,\n\t\t\t) => {\n\t\t\t\tif (path !== \"state\" && !path.startsWith(\"state.\")) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet invalidPath = \"\";\n\t\t\t\tif (\n\t\t\t\t\t!isCborSerializable(\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t(invalidPathPart) => {\n\t\t\t\t\t\t\tinvalidPath = invalidPathPart;\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tthrow new errors.InvalidStateType({\n\t\t\t\t\t\tpath: path + (invalidPath ? `.${invalidPath}` : \"\"),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthis.#persistChanged = true;\n\n\t\t\t\t// Inform the inspector about state changes\n\t\t\t\tthis.inspector.emitter.emit(\n\t\t\t\t\t\"stateUpdated\",\n\t\t\t\t\tthis.#persist.state,\n\t\t\t\t);\n\n\t\t\t\t// Call onStateChange if it exists\n\t\t\t\t// Skip if we're already inside onStateChange to prevent infinite recursion\n\t\t\t\tif (\n\t\t\t\t\tthis.#config.onStateChange &&\n\t\t\t\t\tthis.#ready &&\n\t\t\t\t\t!this.#isInOnStateChange\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.#isInOnStateChange = true;\n\t\t\t\t\t\tthis.#config.onStateChange(\n\t\t\t\t\t\t\tthis.actorContext,\n\t\t\t\t\t\t\tthis.#persistRaw.state,\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthis.#rLog.error({\n\t\t\t\t\t\t\tmsg: \"error in `_onStateChange`\",\n\t\t\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t\t\t});\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tthis.#isInOnStateChange = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// State will be flushed at the end of the action\n\t\t\t},\n\t\t\t{ ignoreDetached: true },\n\t\t);\n\t}\n\n\tasync #initialize() {\n\t\t// Read initial state\n\t\tconst persistDataBuffer = await this.#actorDriver.readPersistedData(\n\t\t\tthis.#actorId,\n\t\t);\n\t\tinvariant(\n\t\t\tpersistDataBuffer !== undefined,\n\t\t\t\"persist data has not been set, it should be set when initialized\",\n\t\t);\n\t\tconst bareData =\n\t\t\tPERSISTED_ACTOR_VERSIONED.deserializeWithEmbeddedVersion(\n\t\t\t\tpersistDataBuffer,\n\t\t\t);\n\t\tconst persistData = this.#convertFromBarePersisted(bareData);\n\n\t\tif (persistData.hasInitiated) {\n\t\t\tthis.#rLog.info({\n\t\t\t\tmsg: \"actor restoring\",\n\t\t\t\tconnections: persistData.connections.length,\n\t\t\t});\n\n\t\t\t// Set initial state\n\t\t\tthis.#setPersist(persistData);\n\n\t\t\t// Load connections\n\t\t\tfor (const connPersist of this.#persist.connections) {\n\t\t\t\t// Create connections\n\t\t\t\tconst conn = new Conn<S, CP, CS, V, I, DB>(this, connPersist);\n\t\t\t\tthis.#connections.set(conn.id, conn);\n\n\t\t\t\t// Register event subscriptions\n\t\t\t\tfor (const sub of connPersist.subscriptions) {\n\t\t\t\t\tthis.#addSubscription(sub.eventName, conn, true);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.#rLog.info({ msg: \"actor creating\" });\n\n\t\t\t// Initialize actor state\n\t\t\tlet stateData: unknown;\n\t\t\tif (this.stateEnabled) {\n\t\t\t\tthis.#rLog.info({ msg: \"actor state initializing\" });\n\n\t\t\t\tif (\"createState\" in this.#config) {\n\t\t\t\t\tthis.#config.createState;\n\n\t\t\t\t\t// Convert state to undefined since state is not defined yet here\n\t\t\t\t\tstateData = await this.#config.createState(\n\t\t\t\t\t\tthis.actorContext as unknown as ActorContext<\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tundefined\n\t\t\t\t\t\t>,\n\t\t\t\t\t\tpersistData.input!,\n\t\t\t\t\t);\n\t\t\t\t} else if (\"state\" in this.#config) {\n\t\t\t\t\tstateData = structuredClone(this.#config.state);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Both 'createState' or 'state' were not defined\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.#rLog.debug({ msg: \"state not enabled\" });\n\t\t\t}\n\n\t\t\t// Save state and mark as initialized\n\t\t\tpersistData.state = stateData as S;\n\t\t\tpersistData.hasInitiated = true;\n\n\t\t\t// Update state\n\t\t\tthis.#rLog.debug({ msg: \"writing state\" });\n\t\t\tconst bareData = this.#convertToBarePersisted(persistData);\n\t\t\tawait this.#actorDriver.writePersistedData(\n\t\t\t\tthis.#actorId,\n\t\t\t\tPERSISTED_ACTOR_VERSIONED.serializeWithEmbeddedVersion(\n\t\t\t\t\tbareData,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tthis.#setPersist(persistData);\n\n\t\t\t// Notify creation\n\t\t\tif (this.#config.onCreate) {\n\t\t\t\tawait this.#config.onCreate(\n\t\t\t\t\tthis.actorContext,\n\t\t\t\t\tpersistData.input!,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t__getConnForId(id: string): Conn<S, CP, CS, V, I, DB> | undefined {\n\t\treturn this.#connections.get(id);\n\t}\n\n\t/**\n\t * Call when conn is disconnected. Used by transports.\n\t *\n\t * If a clean diconnect, will be removed immediately.\n\t *\n\t * If not a clean disconnect, will keep the connection alive for a given interval to wait for reconnect.\n\t */\n\t__connDisconnected(\n\t\tconn: Conn<S, CP, CS, V, I, DB>,\n\t\twasClean: boolean,\n\t\tsocketId: string,\n\t) {\n\t\t// If socket ID is provided, check if it matches the current socket ID\n\t\t// If it doesn't match, this is a stale disconnect event from an old socket\n\t\tif (socketId && conn.__socket && socketId !== conn.__socket.socketId) {\n\t\t\tthis.#rLog.debug({\n\t\t\t\tmsg: \"ignoring stale disconnect event\",\n\t\t\t\tconnId: conn.id,\n\t\t\t\teventSocketId: socketId,\n\t\t\t\tcurrentSocketId: conn.__socket.socketId,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (wasClean) {\n\t\t\t// Disconnected cleanly, remove the conn\n\n\t\t\tthis.#removeConn(conn);\n\t\t} else {\n\t\t\t// Disconnected uncleanly, allow reconnection\n\n\t\t\tif (!conn.__driverState) {\n\t\t\t\tthis.rLog.warn(\"called conn disconnected without driver state\");\n\t\t\t}\n\n\t\t\t// Update last seen so we know when to clean it up\n\t\t\tconn.__persist.lastSeen = Date.now();\n\n\t\t\t// Remove socket\n\t\t\tconn.__socket = undefined;\n\n\t\t\t// Update sleep\n\t\t\tthis.#resetSleepTimer();\n\t\t}\n\t}\n\n\t/**\n\t * Removes a connection and cleans up its resources.\n\t */\n\t#removeConn(conn: Conn<S, CP, CS, V, I, DB>) {\n\t\t// Remove from persist & save immediately\n\t\tconst connIdx = this.#persist.connections.findIndex(\n\t\t\t(c) => c.connId === conn.id,\n\t\t);\n\t\tif (connIdx !== -1) {\n\t\t\tthis.#persist.connections.splice(connIdx, 1);\n\t\t\tthis.saveState({ immediate: true, allowStoppingState: true });\n\t\t} else {\n\t\t\tthis.#rLog.warn({\n\t\t\t\tmsg: \"could not find persisted connection to remove\",\n\t\t\t\tconnId: conn.id,\n\t\t\t});\n\t\t}\n\n\t\t// Remove from state\n\t\tthis.#connections.delete(conn.id);\n\t\tthis.#rLog.debug({ msg: \"removed conn\", connId: conn.id });\n\n\t\t// Remove subscriptions\n\t\tfor (const eventName of [...conn.subscriptions.values()]) {\n\t\t\tthis.#removeSubscription(eventName, conn, true);\n\t\t}\n\n\t\tthis.inspector.emitter.emit(\"connectionUpdated\");\n\t\tif (this.#config.onDisconnect) {\n\t\t\ttry {\n\t\t\t\tconst result = this.#config.onDisconnect(\n\t\t\t\t\tthis.actorContext,\n\t\t\t\t\tconn,\n\t\t\t\t);\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t// Handle promise but don't await it to prevent blocking\n\t\t\t\t\tresult.catch((error) => {\n\t\t\t\t\t\tthis.#rLog.error({\n\t\t\t\t\t\t\tmsg: \"error in `onDisconnect`\",\n\t\t\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.#rLog.error({\n\t\t\t\t\tmsg: \"error in `onDisconnect`\",\n\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Update sleep\n\t\tthis.#resetSleepTimer();\n\t}\n\n\t/**\n\t * Called to create a new connection or reconnect an existing one.\n\t */\n\tasync createConn(\n\t\tsocket: ConnSocket,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: TypeScript bug with ExtractActorConnParams<this>,\n\t\tparams: any,\n\t\trequest?: Request,\n\t\tconnectionId?: string,\n\t\tconnectionToken?: string,\n\t): Promise<Conn<S, CP, CS, V, I, DB>> {\n\t\tthis.#assertReady();\n\n\t\t// If connection ID and token are provided, try to reconnect\n\t\tif (connectionId && connectionToken) {\n\t\t\tthis.rLog.debug({\n\t\t\t\tmsg: \"checking for existing connection\",\n\t\t\t\tconnectionId,\n\t\t\t});\n\t\t\tconst existingConn = this.#connections.get(connectionId);\n\t\t\tif (existingConn && existingConn._token === connectionToken) {\n\t\t\t\t// This is a valid reconnection\n\t\t\t\tthis.rLog.debug({\n\t\t\t\t\tmsg: \"reconnecting existing connection\",\n\t\t\t\t\tconnectionId,\n\t\t\t\t});\n\n\t\t\t\t// If there's an existing driver state, clean it up without marking as clean disconnect\n\t\t\t\tif (existingConn.__driverState) {\n\t\t\t\t\tconst driverKind = getConnDriverKindFromState(\n\t\t\t\t\t\texistingConn.__driverState,\n\t\t\t\t\t);\n\t\t\t\t\tconst driver = CONN_DRIVERS[driverKind];\n\t\t\t\t\tif (driver.disconnect) {\n\t\t\t\t\t\t// Call driver disconnect to clean up directly. Don't use Conn.disconnect since that will remove the connection entirely.\n\t\t\t\t\t\tdriver.disconnect(\n\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\texistingConn,\n\t\t\t\t\t\t\t(existingConn.__driverState as any)[driverKind],\n\t\t\t\t\t\t\t\"Reconnecting with new driver state\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Update with new driver state\n\t\t\t\texistingConn.__socket = socket;\n\t\t\t\texistingConn.__persist.lastSeen = Date.now();\n\n\t\t\t\t// Update sleep timer since connection is now active\n\t\t\t\tthis.#resetSleepTimer();\n\n\t\t\t\tthis.inspector.emitter.emit(\"connectionUpdated\");\n\n\t\t\t\t// Send init message for reconnection\n\t\t\t\texistingConn._sendMessage(\n\t\t\t\t\tnew CachedSerializer<protocol.ToClient>(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\ttag: \"Init\",\n\t\t\t\t\t\t\t\tval: {\n\t\t\t\t\t\t\t\t\tactorId: this.id,\n\t\t\t\t\t\t\t\t\tconnectionId: existingConn.id,\n\t\t\t\t\t\t\t\t\tconnectionToken: existingConn._token,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTO_CLIENT_VERSIONED,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\treturn existingConn;\n\t\t\t}\n\n\t\t\t// If we get here, either connection doesn't exist or token doesn't match\n\t\t\t// Fall through to create new connection with new IDs\n\t\t\tthis.rLog.debug({\n\t\t\t\tmsg: \"connection not found or token mismatch, creating new connection\",\n\t\t\t\tconnectionId,\n\t\t\t});\n\t\t}\n\n\t\t// Generate new connection ID and token if not provided or if reconnection failed\n\t\tconst newConnId = generateConnId();\n\t\tconst newConnToken = generateConnToken();\n\n\t\tif (this.#connections.has(newConnId)) {\n\t\t\tthrow new Error(`Connection already exists: ${newConnId}`);\n\t\t}\n\n\t\t// Prepare connection state\n\t\tlet connState: CS | undefined;\n\n\t\tconst onBeforeConnectOpts = {\n\t\t\trequest,\n\t\t} satisfies OnConnectOptions;\n\n\t\tif (this.#config.onBeforeConnect) {\n\t\t\tawait this.#config.onBeforeConnect(\n\t\t\t\tthis.actorContext,\n\t\t\t\tonBeforeConnectOpts,\n\t\t\t\tparams,\n\t\t\t);\n\t\t}\n\n\t\tif (this.connStateEnabled) {\n\t\t\tif (\"createConnState\" in this.#config) {\n\t\t\t\tconst dataOrPromise = this.#config.createConnState(\n\t\t\t\t\tthis.actorContext as unknown as ActorContext<\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined\n\t\t\t\t\t>,\n\t\t\t\t\tonBeforeConnectOpts,\n\t\t\t\t\tparams,\n\t\t\t\t);\n\t\t\t\tif (dataOrPromise instanceof Promise) {\n\t\t\t\t\tconnState = await deadline(\n\t\t\t\t\t\tdataOrPromise,\n\t\t\t\t\t\tthis.#config.options.createConnStateTimeout,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tconnState = dataOrPromise;\n\t\t\t\t}\n\t\t\t} else if (\"connState\" in this.#config) {\n\t\t\t\tconnState = structuredClone(this.#config.connState);\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Could not create connection state from 'createConnState' or 'connState'\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Create connection\n\t\tconst persist: PersistedConn<CP, CS> = {\n\t\t\tconnId: newConnId,\n\t\t\ttoken: newConnToken,\n\t\t\tparams: params,\n\t\t\tstate: connState as CS,\n\t\t\tlastSeen: Date.now(),\n\t\t\tsubscriptions: [],\n\t\t};\n\t\tconst conn = new Conn<S, CP, CS, V, I, DB>(this, persist);\n\t\tconn.__socket = socket;\n\t\tthis.#connections.set(conn.id, conn);\n\n\t\t// Update sleep\n\t\t//\n\t\t// Do this immediately after adding connection & before any async logic in order to avoid race conditions with sleep timeouts\n\t\tthis.#resetSleepTimer();\n\n\t\t// Add to persistence & save immediately\n\t\tthis.#persist.connections.push(persist);\n\t\tthis.saveState({ immediate: true });\n\n\t\t// Handle connection\n\t\tif (this.#config.onConnect) {\n\t\t\ttry {\n\t\t\t\tconst result = this.#config.onConnect(this.actorContext, conn);\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\tdeadline(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tthis.#config.options.onConnectTimeout,\n\t\t\t\t\t).catch((error) => {\n\t\t\t\t\t\tthis.#rLog.error({\n\t\t\t\t\t\t\tmsg: \"error in `onConnect`, closing socket\",\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconn?.disconnect(\"`onConnect` failed\");\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.#rLog.error({\n\t\t\t\t\tmsg: \"error in `onConnect`\",\n\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t});\n\t\t\t\tconn?.disconnect(\"`onConnect` failed\");\n\t\t\t}\n\t\t}\n\n\t\tthis.inspector.emitter.emit(\"connectionUpdated\");\n\n\t\t// Send init message\n\t\tconn._sendMessage(\n\t\t\tnew CachedSerializer<protocol.ToClient>(\n\t\t\t\t{\n\t\t\t\t\tbody: {\n\t\t\t\t\t\ttag: \"Init\",\n\t\t\t\t\t\tval: {\n\t\t\t\t\t\t\tactorId: this.id,\n\t\t\t\t\t\t\tconnectionId: conn.id,\n\t\t\t\t\t\t\tconnectionToken: conn._token,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tTO_CLIENT_VERSIONED,\n\t\t\t),\n\t\t);\n\n\t\treturn conn;\n\t}\n\n\t// MARK: Messages\n\tasync processMessage(\n\t\tmessage: protocol.ToServer,\n\t\tconn: Conn<S, CP, CS, V, I, DB>,\n\t) {\n\t\tawait processMessage(message, this, conn, {\n\t\t\tonExecuteAction: async (ctx, name, args) => {\n\t\t\t\tthis.inspector.emitter.emit(\"eventFired\", {\n\t\t\t\t\ttype: \"action\",\n\t\t\t\t\tname,\n\t\t\t\t\targs,\n\t\t\t\t\tconnId: conn.id,\n\t\t\t\t});\n\t\t\t\treturn await this.executeAction(ctx, name, args);\n\t\t\t},\n\t\t\tonSubscribe: async (eventName, conn) => {\n\t\t\t\tthis.inspector.emitter.emit(\"eventFired\", {\n\t\t\t\t\ttype: \"subscribe\",\n\t\t\t\t\teventName,\n\t\t\t\t\tconnId: conn.id,\n\t\t\t\t});\n\t\t\t\tthis.#addSubscription(eventName, conn, false);\n\t\t\t},\n\t\t\tonUnsubscribe: async (eventName, conn) => {\n\t\t\t\tthis.inspector.emitter.emit(\"eventFired\", {\n\t\t\t\t\ttype: \"unsubscribe\",\n\t\t\t\t\teventName,\n\t\t\t\t\tconnId: conn.id,\n\t\t\t\t});\n\t\t\t\tthis.#removeSubscription(eventName, conn, false);\n\t\t\t},\n\t\t});\n\t}\n\n\t// MARK: Events\n\t#addSubscription(\n\t\teventName: string,\n\t\tconnection: Conn<S, CP, CS, V, I, DB>,\n\t\tfromPersist: boolean,\n\t) {\n\t\tif (connection.subscriptions.has(eventName)) {\n\t\t\tthis.#rLog.debug({\n\t\t\t\tmsg: \"connection already has subscription\",\n\t\t\t\teventName,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Persist subscriptions & save immediately\n\t\t//\n\t\t// Don't update persistence if already restoring from persistence\n\t\tif (!fromPersist) {\n\t\t\tconnection.__persist.subscriptions.push({ eventName: eventName });\n\t\t\tthis.saveState({ immediate: true });\n\t\t}\n\n\t\t// Update subscriptions\n\t\tconnection.subscriptions.add(eventName);\n\n\t\t// Update subscription index\n\t\tlet subscribers = this.#subscriptionIndex.get(eventName);\n\t\tif (!subscribers) {\n\t\t\tsubscribers = new Set();\n\t\t\tthis.#subscriptionIndex.set(eventName, subscribers);\n\t\t}\n\t\tsubscribers.add(connection);\n\t}\n\n\t#removeSubscription(\n\t\teventName: string,\n\t\tconnection: Conn<S, CP, CS, V, I, DB>,\n\t\tfromRemoveConn: boolean,\n\t) {\n\t\tif (!connection.subscriptions.has(eventName)) {\n\t\t\tthis.#rLog.warn({\n\t\t\t\tmsg: \"connection does not have subscription\",\n\t\t\t\teventName,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Persist subscriptions & save immediately\n\t\t//\n\t\t// Don't update the connection itself if the connection is already being removed\n\t\tif (!fromRemoveConn) {\n\t\t\tconnection.subscriptions.delete(eventName);\n\n\t\t\tconst subIdx = connection.__persist.subscriptions.findIndex(\n\t\t\t\t(s) => s.eventName === eventName,\n\t\t\t);\n\t\t\tif (subIdx !== -1) {\n\t\t\t\tconnection.__persist.subscriptions.splice(subIdx, 1);\n\t\t\t} else {\n\t\t\t\tthis.#rLog.warn({\n\t\t\t\t\tmsg: \"subscription does not exist with name\",\n\t\t\t\t\teventName,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthis.saveState({ immediate: true });\n\t\t}\n\n\t\t// Update scriptions index\n\t\tconst subscribers = this.#subscriptionIndex.get(eventName);\n\t\tif (subscribers) {\n\t\t\tsubscribers.delete(connection);\n\t\t\tif (subscribers.size === 0) {\n\t\t\t\tthis.#subscriptionIndex.delete(eventName);\n\t\t\t}\n\t\t}\n\t}\n\n\t#assertReady(allowStoppingState: boolean = false) {\n\t\tif (!this.#ready) throw new errors.InternalError(\"Actor not ready\");\n\t\tif (!allowStoppingState && this.#sleepCalled)\n\t\t\tthrow new errors.InternalError(\"Actor is going to sleep\");\n\t\tif (!allowStoppingState && this.#stopCalled)\n\t\t\tthrow new errors.InternalError(\"Actor is stopping\");\n\t}\n\n\t/**\n\t * Check the liveness of all connections.\n\t * Sets up a recurring check based on the configured interval.\n\t */\n\t#checkConnectionsLiveness() {\n\t\tthis.#rLog.debug({ msg: \"checking connections liveness\" });\n\n\t\tfor (const conn of this.#connections.values()) {\n\t\t\tif (conn.__status === \"connected\") {\n\t\t\t\tthis.#rLog.debug({\n\t\t\t\t\tmsg: \"connection is alive\",\n\t\t\t\t\tconnId: conn.id,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst lastSeen = conn.__persist.lastSeen;\n\t\t\t\tconst sinceLastSeen = Date.now() - lastSeen;\n\t\t\t\tif (\n\t\t\t\t\tsinceLastSeen <\n\t\t\t\t\tthis.#config.options.connectionLivenessTimeout\n\t\t\t\t) {\n\t\t\t\t\tthis.#rLog.debug({\n\t\t\t\t\t\tmsg: \"connection might be alive, will check later\",\n\t\t\t\t\t\tconnId: conn.id,\n\t\t\t\t\t\tlastSeen,\n\t\t\t\t\t\tsinceLastSeen,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Connection is dead, remove it\n\t\t\t\tthis.#rLog.info({\n\t\t\t\t\tmsg: \"connection is dead, removing\",\n\t\t\t\t\tconnId: conn.id,\n\t\t\t\t\tlastSeen,\n\t\t\t\t});\n\n\t\t\t\t// Assume that the connection is dead here, no need to disconnect anything\n\t\t\t\tthis.#removeConn(conn);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Check if the actor is ready to handle requests.\n\t */\n\tisReady(): boolean {\n\t\treturn this.#ready;\n\t}\n\n\t/**\n\t * Execute an action call from a client.\n\t *\n\t * This method handles:\n\t * 1. Validating the action name\n\t * 2. Executing the action function\n\t * 3. Processing the result through onBeforeActionResponse (if configured)\n\t * 4. Handling timeouts and errors\n\t * 5. Saving state changes\n\t *\n\t * @param ctx The action context\n\t * @param actionName The name of the action being called\n\t * @param args The arguments passed to the action\n\t * @returns The result of the action call\n\t * @throws {ActionNotFound} If the action doesn't exist\n\t * @throws {ActionTimedOut} If the action times out\n\t * @internal\n\t */\n\tasync executeAction(\n\t\tctx: ActionContext<S, CP, CS, V, I, DB>,\n\t\tactionName: string,\n\t\targs: unknown[],\n\t): Promise<unknown> {\n\t\tinvariant(this.#ready, \"executing action before ready\");\n\n\t\t// Prevent calling private or reserved methods\n\t\tif (!(actionName in this.#config.actions)) {\n\t\t\tthis.#rLog.warn({ msg: \"action does not exist\", actionName });\n\t\t\tthrow new errors.ActionNotFound(actionName);\n\t\t}\n\n\t\t// Check if the method exists on this object\n\t\tconst actionFunction = this.#config.actions[actionName];\n\t\tif (typeof actionFunction !== \"function\") {\n\t\t\tthis.#rLog.warn({\n\t\t\t\tmsg: \"action is not a function\",\n\t\t\t\tactionName: actionName,\n\t\t\t\ttype: typeof actionFunction,\n\t\t\t});\n\t\t\tthrow new errors.ActionNotFound(actionName);\n\t\t}\n\n\t\t// TODO: pass abortable to the action to decide when to abort\n\t\t// TODO: Manually call abortable for better error handling\n\t\t// Call the function on this object with those arguments\n\t\ttry {\n\t\t\t// Log when we start executing the action\n\t\t\tthis.#rLog.debug({\n\t\t\t\tmsg: \"executing action\",\n\t\t\t\tactionName: actionName,\n\t\t\t\targs,\n\t\t\t});\n\n\t\t\tconst outputOrPromise = actionFunction.call(\n\t\t\t\tundefined,\n\t\t\t\tctx,\n\t\t\t\t...args,\n\t\t\t);\n\t\t\tlet output: unknown;\n\t\t\tif (outputOrPromise instanceof Promise) {\n\t\t\t\t// Log that we're waiting for an async action\n\t\t\t\tthis.#rLog.debug({\n\t\t\t\t\tmsg: \"awaiting async action\",\n\t\t\t\t\tactionName: actionName,\n\t\t\t\t});\n\n\t\t\t\toutput = await deadline(\n\t\t\t\t\toutputOrPromise,\n\t\t\t\t\tthis.#config.options.actionTimeout,\n\t\t\t\t);\n\n\t\t\t\t// Log that async action completed\n\t\t\t\tthis.#rLog.debug({\n\t\t\t\t\tmsg: \"async action completed\",\n\t\t\t\t\tactionName: actionName,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\toutput = outputOrPromise;\n\t\t\t}\n\n\t\t\t// Process the output through onBeforeActionResponse if configured\n\t\t\tif (this.#config.onBeforeActionResponse) {\n\t\t\t\ttry {\n\t\t\t\t\tconst processedOutput = this.#config.onBeforeActionResponse(\n\t\t\t\t\t\tthis.actorContext,\n\t\t\t\t\t\tactionName,\n\t\t\t\t\t\targs,\n\t\t\t\t\t\toutput,\n\t\t\t\t\t);\n\t\t\t\t\tif (processedOutput instanceof Promise) {\n\t\t\t\t\t\tthis.#rLog.debug({\n\t\t\t\t\t\t\tmsg: \"awaiting onBeforeActionResponse\",\n\t\t\t\t\t\t\tactionName: actionName,\n\t\t\t\t\t\t});\n\t\t\t\t\t\toutput = await processedOutput;\n\t\t\t\t\t\tthis.#rLog.debug({\n\t\t\t\t\t\t\tmsg: \"onBeforeActionResponse completed\",\n\t\t\t\t\t\t\tactionName: actionName,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\toutput = processedOutput;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.#rLog.error({\n\t\t\t\t\t\tmsg: \"error in `onBeforeActionResponse`\",\n\t\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Log the output before returning\n\t\t\tthis.#rLog.debug({\n\t\t\t\tmsg: \"action completed\",\n\t\t\t\tactionName: actionName,\n\t\t\t\toutputType: typeof output,\n\t\t\t\tisPromise: output instanceof Promise,\n\t\t\t});\n\n\t\t\t// This output *might* reference a part of the state (using onChange), but\n\t\t\t// that's OK since this value always gets serialized and sent over the\n\t\t\t// network.\n\t\t\treturn output;\n\t\t} catch (error) {\n\t\t\tif (error instanceof DeadlineError) {\n\t\t\t\tthrow new errors.ActionTimedOut();\n\t\t\t}\n\t\t\tthis.#rLog.error({\n\t\t\t\tmsg: \"action error\",\n\t\t\t\tactionName: actionName,\n\t\t\t\terror: stringifyError(error),\n\t\t\t});\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tthis.#savePersistThrottled();\n\t\t}\n\t}\n\n\t/**\n\t * Returns a list of action methods available on this actor.\n\t */\n\tget actions(): string[] {\n\t\treturn Object.keys(this.#config.actions);\n\t}\n\n\t/**\n\t * Handles raw HTTP requests to the actor.\n\t */\n\tasync handleFetch(\n\t\trequest: Request,\n\t\topts: Record<never, never>,\n\t): Promise<Response> {\n\t\tthis.#assertReady();\n\n\t\tif (!this.#config.onFetch) {\n\t\t\tthrow new errors.FetchHandlerNotDefined();\n\t\t}\n\n\t\t// Track active raw fetch while handler runs\n\t\tthis.#activeRawFetchCount++;\n\t\tthis.#resetSleepTimer();\n\n\t\ttry {\n\t\t\tconst response = await this.#config.onFetch(\n\t\t\t\tthis.actorContext,\n\t\t\t\trequest,\n\t\t\t\topts,\n\t\t\t);\n\t\t\tif (!response) {\n\t\t\t\tthrow new errors.InvalidFetchResponse();\n\t\t\t}\n\t\t\treturn response;\n\t\t} catch (error) {\n\t\t\tthis.#rLog.error({\n\t\t\t\tmsg: \"onFetch error\",\n\t\t\t\terror: stringifyError(error),\n\t\t\t});\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\t// Decrement active raw fetch counter and re-evaluate sleep\n\t\t\tthis.#activeRawFetchCount = Math.max(\n\t\t\t\t0,\n\t\t\t\tthis.#activeRawFetchCount - 1,\n\t\t\t);\n\t\t\tthis.#resetSleepTimer();\n\t\t\tthis.#savePersistThrottled();\n\t\t}\n\t}\n\n\t/**\n\t * Handles raw WebSocket connections to the actor.\n\t */\n\tasync handleWebSocket(\n\t\twebsocket: UniversalWebSocket,\n\t\topts: { request: Request },\n\t): Promise<void> {\n\t\tthis.#assertReady();\n\n\t\tif (!this.#config.onWebSocket) {\n\t\t\tthrow new errors.InternalError(\"onWebSocket handler not defined\");\n\t\t}\n\n\t\ttry {\n\t\t\t// Set up state tracking to detect changes during WebSocket handling\n\t\t\tconst stateBeforeHandler = this.#persistChanged;\n\n\t\t\t// Track active websocket until it fully closes\n\t\t\tthis.#activeRawWebSockets.add(websocket);\n\t\t\tthis.#resetSleepTimer();\n\n\t\t\t// Track socket close\n\t\t\tconst onSocketClosed = () => {\n\t\t\t\t// Remove listener and socket from tracking\n\t\t\t\ttry {\n\t\t\t\t\twebsocket.removeEventListener(\"close\", onSocketClosed);\n\t\t\t\t\twebsocket.removeEventListener(\"error\", onSocketClosed);\n\t\t\t\t} catch {}\n\t\t\t\tthis.#activeRawWebSockets.delete(websocket);\n\t\t\t\tthis.#resetSleepTimer();\n\t\t\t};\n\t\t\ttry {\n\t\t\t\twebsocket.addEventListener(\"close\", onSocketClosed);\n\t\t\t\twebsocket.addEventListener(\"error\", onSocketClosed);\n\t\t\t} catch {}\n\n\t\t\t// Handle WebSocket\n\t\t\tawait this.#config.onWebSocket(this.actorContext, websocket, opts);\n\n\t\t\t// If state changed during the handler, save it\n\t\t\tif (this.#persistChanged && !stateBeforeHandler) {\n\t\t\t\tawait this.saveState({ immediate: true });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.#rLog.error({\n\t\t\t\tmsg: \"onWebSocket error\",\n\t\t\t\terror: stringifyError(error),\n\t\t\t});\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tthis.#savePersistThrottled();\n\t\t}\n\t}\n\n\t// MARK: Lifecycle hooks\n\n\t// MARK: Exposed methods\n\tget log(): Logger {\n\t\tinvariant(this.#log, \"log not configured\");\n\t\treturn this.#log;\n\t}\n\n\tget rLog(): Logger {\n\t\tinvariant(this.#rLog, \"log not configured\");\n\t\treturn this.#rLog;\n\t}\n\n\t/**\n\t * Gets the name.\n\t */\n\tget name(): string {\n\t\treturn this.#name;\n\t}\n\n\t/**\n\t * Gets the key.\n\t */\n\tget key(): ActorKey {\n\t\treturn this.#key;\n\t}\n\n\t/**\n\t * Gets the region.\n\t */\n\tget region(): string {\n\t\treturn this.#region;\n\t}\n\n\t/**\n\t * Gets the scheduler.\n\t */\n\tget schedule(): Schedule {\n\t\treturn this.#schedule;\n\t}\n\n\t/**\n\t * Gets the map of connections.\n\t */\n\tget conns(): Map<ConnId, Conn<S, CP, CS, V, I, DB>> {\n\t\treturn this.#connections;\n\t}\n\n\t/**\n\t * Gets the current state.\n\t *\n\t * Changing properties of this value will automatically be persisted.\n\t */\n\tget state(): S {\n\t\tthis.#validateStateEnabled();\n\t\treturn this.#persist.state;\n\t}\n\n\t/**\n\t * Gets the database.\n\t * @experimental\n\t * @throws {DatabaseNotEnabled} If the database is not enabled.\n\t */\n\tget db(): InferDatabaseClient<DB> {\n\t\tif (!this.#db) {\n\t\t\tthrow new errors.DatabaseNotEnabled();\n\t\t}\n\t\treturn this.#db;\n\t}\n\n\t/**\n\t * Sets the current state.\n\t *\n\t * This property will automatically be persisted.\n\t */\n\tset state(value: S) {\n\t\tthis.#validateStateEnabled();\n\t\tthis.#persist.state = value;\n\t}\n\n\tget vars(): V {\n\t\tthis.#validateVarsEnabled();\n\t\tinvariant(this.#vars !== undefined, \"vars not enabled\");\n\t\treturn this.#vars;\n\t}\n\n\t/**\n\t * Broadcasts an event to all connected clients.\n\t * @param name - The name of the event.\n\t * @param args - The arguments to send with the event.\n\t */\n\t_broadcast<Args extends Array<unknown>>(name: string, ...args: Args) {\n\t\tthis.#assertReady();\n\n\t\tthis.inspector.emitter.emit(\"eventFired\", {\n\t\t\ttype: \"broadcast\",\n\t\t\teventName: name,\n\t\t\targs,\n\t\t});\n\n\t\t// Send to all connected clients\n\t\tconst subscriptions = this.#subscriptionIndex.get(name);\n\t\tif (!subscriptions) return;\n\n\t\tconst toClientSerializer = new CachedSerializer<protocol.ToClient>(\n\t\t\t{\n\t\t\t\tbody: {\n\t\t\t\t\ttag: \"Event\",\n\t\t\t\t\tval: {\n\t\t\t\t\t\tname,\n\t\t\t\t\t\targs: bufferToArrayBuffer(cbor.encode(args)),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTO_CLIENT_VERSIONED,\n\t\t);\n\n\t\t// Send message to clients\n\t\tfor (const connection of subscriptions) {\n\t\t\tconnection._sendMessage(toClientSerializer);\n\t\t}\n\t}\n\n\t/**\n\t * Prevents the actor from sleeping until promise is complete.\n\t *\n\t * This allows the actor runtime to ensure that a promise completes while\n\t * returning from an action request early.\n\t *\n\t * @param promise - The promise to run in the background.\n\t */\n\t_waitUntil(promise: Promise<void>) {\n\t\tthis.#assertReady();\n\n\t\t// TODO: Should we force save the state?\n\t\t// Add logging to promise and make it non-failable\n\t\tconst nonfailablePromise = promise\n\t\t\t.then(() => {\n\t\t\t\tthis.#rLog.debug({ msg: \"wait until promise complete\" });\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.#rLog.error({\n\t\t\t\t\tmsg: \"wait until promise failed\",\n\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t});\n\t\t\t});\n\t\tthis.#backgroundPromises.push(nonfailablePromise);\n\t}\n\n\t/**\n\t * Forces the state to get saved.\n\t *\n\t * This is helpful if running a long task that may fail later or when\n\t * running a background job that updates the state.\n\t *\n\t * @param opts - Options for saving the state.\n\t */\n\tasync saveState(opts: SaveStateOptions) {\n\t\tthis.#assertReady(opts.allowStoppingState);\n\n\t\tif (this.#persistChanged) {\n\t\t\tif (opts.immediate) {\n\t\t\t\t// Save immediately\n\t\t\t\tawait this.#savePersistInner();\n\t\t\t} else {\n\t\t\t\t// Create callback\n\t\t\t\tif (!this.#onPersistSavedPromise) {\n\t\t\t\t\tthis.#onPersistSavedPromise = promiseWithResolvers();\n\t\t\t\t}\n\n\t\t\t\t// Save state throttled\n\t\t\t\tthis.#savePersistThrottled();\n\n\t\t\t\t// Wait for save\n\t\t\t\tawait this.#onPersistSavedPromise.promise;\n\t\t\t}\n\t\t}\n\t}\n\n\t// MARK: Sleep\n\t/**\n\t * Reset timer from the last actor interaction that allows it to be put to sleep.\n\t *\n\t * This should be called any time a sleep-related event happens:\n\t * - Connection opens (will clear timer)\n\t * - Connection closes (will schedule timer if there are no open connections)\n\t * - Alarm triggers (will reset timer)\n\t *\n\t * We don't need to call this on events like individual action calls, since there will always be a connection open for these.\n\t **/\n\t#resetSleepTimer() {\n\t\tif (this.#config.options.noSleep || !this.#sleepingSupported) return;\n\n\t\tconst canSleep = this.#canSleep();\n\n\t\tthis.#rLog.debug({\n\t\t\tmsg: \"resetting sleep timer\",\n\t\t\tcanSleep,\n\t\t\texistingTimeout: !!this.#sleepTimeout,\n\t\t});\n\n\t\tif (this.#sleepTimeout) {\n\t\t\tclearTimeout(this.#sleepTimeout);\n\t\t\tthis.#sleepTimeout = undefined;\n\t\t}\n\n\t\t// Don't set a new timer if already sleeping\n\t\tif (this.#sleepCalled) return;\n\n\t\tif (canSleep) {\n\t\t\tthis.#sleepTimeout = setTimeout(() => {\n\t\t\t\tthis._sleep().catch((error) => {\n\t\t\t\t\tthis.#rLog.error({\n\t\t\t\t\t\tmsg: \"error during sleep\",\n\t\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}, this.#config.options.sleepTimeout);\n\t\t}\n\t}\n\n\t/** If this actor can be put in a sleeping state. */\n\t#canSleep(): boolean {\n\t\tif (!this.#ready) return false;\n\n\t\t// Check for active conns. This will also cover active actions, since all actions have a connection.\n\t\tfor (const conn of this.#connections.values()) {\n\t\t\tif (conn.status === \"connected\") return false;\n\t\t}\n\n\t\t// Do not sleep if raw fetches are in-flight\n\t\tif (this.#activeRawFetchCount > 0) return false;\n\n\t\t// Do not sleep if there are raw websockets open\n\t\tif (this.#activeRawWebSockets.size > 0) return false;\n\n\t\treturn true;\n\t}\n\n\t/** Puts an actor to sleep. This should just start the sleep sequence, most shutdown logic should be in _stop (which is called by the ActorDriver when sleeping). */\n\tasync _sleep() {\n\t\tconst sleep = this.#actorDriver.sleep?.bind(\n\t\t\tthis.#actorDriver,\n\t\t\tthis.#actorId,\n\t\t);\n\t\tinvariant(this.#sleepingSupported, \"sleeping not supported\");\n\t\tinvariant(sleep, \"no sleep on driver\");\n\n\t\tif (this.#sleepCalled) {\n\t\t\tthis.#rLog.warn({ msg: \"already sleeping actor\" });\n\t\t\treturn;\n\t\t}\n\t\tthis.#sleepCalled = true;\n\n\t\tthis.#rLog.info({ msg: \"actor sleeping\" });\n\n\t\t// Schedule sleep to happen on the next tick. This allows for any action that calls _sleep to complete.\n\t\tsetImmediate(async () => {\n\t\t\t// The actor driver should call stop when ready to stop\n\t\t\t//\n\t\t\t// This will call _stop once Pegboard responds with the new status\n\t\t\tawait sleep();\n\t\t});\n\t}\n\n\t// MARK: Stop\n\tasync _stop() {\n\t\tif (this.#stopCalled) {\n\t\t\tthis.#rLog.warn({ msg: \"already stopping actor\" });\n\t\t\treturn;\n\t\t}\n\t\tthis.#stopCalled = true;\n\n\t\tthis.#rLog.info({ msg: \"actor stopping\" });\n\n\t\tif (this.#sleepTimeout) {\n\t\t\tclearTimeout(this.#sleepTimeout);\n\t\t\tthis.#sleepTimeout = undefined;\n\t\t}\n\n\t\t// Abort any listeners waiting for shutdown\n\t\ttry {\n\t\t\tthis.#abortController.abort();\n\t\t} catch {}\n\n\t\t// Call onStop lifecycle hook if defined\n\t\tif (this.#config.onStop) {\n\t\t\ttry {\n\t\t\t\tthis.#rLog.debug({ msg: \"calling onStop\" });\n\t\t\t\tconst result = this.#config.onStop(this.actorContext);\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\tawait deadline(result, this.#config.options.onStopTimeout);\n\t\t\t\t}\n\t\t\t\tthis.#rLog.debug({ msg: \"onStop completed\" });\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof DeadlineError) {\n\t\t\t\t\tthis.#rLog.error({ msg: \"onStop timed out\" });\n\t\t\t\t} else {\n\t\t\t\t\tthis.#rLog.error({\n\t\t\t\t\t\tmsg: \"error in onStop\",\n\t\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Disconnect existing connections\n\t\tconst promises: Promise<unknown>[] = [];\n\t\tfor (const connection of this.#connections.values()) {\n\t\t\tpromises.push(connection.disconnect());\n\n\t\t\t// TODO: Figure out how to abort HTTP requests on shutdown\n\t\t}\n\n\t\t// Wait for any background tasks to finish, with timeout\n\t\tawait this.#waitBackgroundPromises(\n\t\t\tthis.#config.options.waitUntilTimeout,\n\t\t);\n\n\t\t// Clear timeouts\n\t\tif (this.#pendingSaveTimeout) clearTimeout(this.#pendingSaveTimeout);\n\t\tif (this.#sleepTimeout) clearTimeout(this.#sleepTimeout);\n\t\tif (this.#checkConnLivenessInterval)\n\t\t\tclearInterval(this.#checkConnLivenessInterval);\n\n\t\t// Write state\n\t\tawait this.saveState({ immediate: true, allowStoppingState: true });\n\n\t\t// Await all `close` event listeners with 1.5 second timeout\n\t\tconst res = Promise.race([\n\t\t\tPromise.all(promises).then(() => false),\n\t\t\tnew Promise<boolean>((res) =>\n\t\t\t\tglobalThis.setTimeout(() => res(true), 1500),\n\t\t\t),\n\t\t]);\n\n\t\tif (await res) {\n\t\t\tthis.#rLog.warn({\n\t\t\t\tmsg: \"timed out waiting for connections to close, shutting down anyway\",\n\t\t\t});\n\t\t}\n\n\t\t// Wait for queues to finish\n\t\tif (this.#persistWriteQueue.runningDrainLoop)\n\t\t\tawait this.#persistWriteQueue.runningDrainLoop;\n\t\tif (this.#alarmWriteQueue.runningDrainLoop)\n\t\t\tawait this.#alarmWriteQueue.runningDrainLoop;\n\t}\n\n\t/** Abort signal that fires when the actor is stopping. */\n\tget abortSignal(): AbortSignal {\n\t\treturn this.#abortController.signal;\n\t}\n\n\t/** Wait for background waitUntil promises with a timeout. */\n\tasync #waitBackgroundPromises(timeoutMs: number) {\n\t\tconst pending = this.#backgroundPromises;\n\t\tif (pending.length === 0) {\n\t\t\tthis.#rLog.debug({ msg: \"no background promises\" });\n\t\t\treturn;\n\t\t}\n\n\t\t// Race promises with timeout to determine if pending promises settled fast enough\n\t\tconst timedOut = await Promise.race([\n\t\t\tPromise.allSettled(pending).then(() => false),\n\t\t\tnew Promise<true>((resolve) =>\n\t\t\t\tsetTimeout(() => resolve(true), timeoutMs),\n\t\t\t),\n\t\t]);\n\n\t\tif (timedOut) {\n\t\t\tthis.#rLog.error({\n\t\t\t\tmsg: \"timed out waiting for background tasks, background promises may have leaked\",\n\t\t\t\tcount: pending.length,\n\t\t\t\ttimeoutMs,\n\t\t\t});\n\t\t} else {\n\t\t\tthis.#rLog.debug({ msg: \"background promises finished\" });\n\t\t}\n\t}\n\n\t// MARK: BARE Conversion Helpers\n\t#convertToBarePersisted(\n\t\tpersist: PersistedActor<S, CP, CS, I>,\n\t): bareSchema.PersistedActor {\n\t\treturn {\n\t\t\tinput:\n\t\t\t\tpersist.input !== undefined\n\t\t\t\t\t? bufferToArrayBuffer(cbor.encode(persist.input))\n\t\t\t\t\t: null,\n\t\t\thasInitialized: persist.hasInitiated,\n\t\t\tstate: bufferToArrayBuffer(cbor.encode(persist.state)),\n\t\t\tconnections: persist.connections.map((conn) => ({\n\t\t\t\tid: conn.connId,\n\t\t\t\ttoken: conn.token,\n\t\t\t\tparameters: bufferToArrayBuffer(cbor.encode(conn.params || {})),\n\t\t\t\tstate: bufferToArrayBuffer(cbor.encode(conn.state || {})),\n\t\t\t\tsubscriptions: conn.subscriptions.map((sub) => ({\n\t\t\t\t\teventName: sub.eventName,\n\t\t\t\t})),\n\t\t\t\tlastSeen: BigInt(conn.lastSeen),\n\t\t\t})),\n\t\t\tscheduledEvents: persist.scheduledEvents.map((event) => ({\n\t\t\t\teventId: event.eventId,\n\t\t\t\ttimestamp: BigInt(event.timestamp),\n\t\t\t\tkind: {\n\t\t\t\t\ttag: \"GenericPersistedScheduleEvent\" as const,\n\t\t\t\t\tval: {\n\t\t\t\t\t\taction: event.kind.generic.actionName,\n\t\t\t\t\t\targs: event.kind.generic.args ?? null,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})),\n\t\t};\n\t}\n\n\t#convertFromBarePersisted(\n\t\tbareData: bareSchema.PersistedActor,\n\t): PersistedActor<S, CP, CS, I> {\n\t\treturn {\n\t\t\tinput: bareData.input\n\t\t\t\t? cbor.decode(new Uint8Array(bareData.input))\n\t\t\t\t: undefined,\n\t\t\thasInitiated: bareData.hasInitialized,\n\t\t\tstate: cbor.decode(new Uint8Array(bareData.state)),\n\t\t\tconnections: bareData.connections.map((conn) => ({\n\t\t\t\tconnId: conn.id,\n\t\t\t\ttoken: conn.token,\n\t\t\t\tparams: cbor.decode(new Uint8Array(conn.parameters)),\n\t\t\t\tstate: cbor.decode(new Uint8Array(conn.state)),\n\t\t\t\tsubscriptions: conn.subscriptions.map((sub) => ({\n\t\t\t\t\teventName: sub.eventName,\n\t\t\t\t})),\n\t\t\t\tlastSeen: Number(conn.lastSeen),\n\t\t\t})),\n\t\t\tscheduledEvents: bareData.scheduledEvents.map((event) => ({\n\t\t\t\teventId: event.eventId,\n\t\t\t\ttimestamp: Number(event.timestamp),\n\t\t\t\tkind: {\n\t\t\t\t\tgeneric: {\n\t\t\t\t\t\tactionName: event.kind.val.action,\n\t\t\t\t\t\targs: event.kind.val.args,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})),\n\t\t};\n\t}\n}\n","import { sValidator } from \"@hono/standard-validator\";\nimport jsonPatch from \"@rivetkit/fast-json-patch\";\nimport { Hono } from \"hono\";\nimport { streamSSE } from \"hono/streaming\";\nimport { createNanoEvents, type Unsubscribe } from \"nanoevents\";\nimport z from \"zod/v4\";\nimport type {\n\tAnyDatabaseProvider,\n\tInferDatabaseClient,\n} from \"@/actor/database\";\nimport { promiseWithResolvers } from \"@/utils\";\nimport {\n\tColumnsSchema,\n\ttype Connection,\n\tForeignKeysSchema,\n\tPatchSchema,\n\ttype RealtimeEvent,\n\ttype RecordedRealtimeEvent,\n\tTablesSchema,\n} from \"./protocol/common\";\n\nexport type ActorInspectorRouterEnv = {\n\tVariables: {\n\t\tinspector: ActorInspector;\n\t};\n};\n\n/**\n * Create a router for the Actor Inspector.\n * @internal\n */\nexport function createActorInspectorRouter() {\n\treturn new Hono<ActorInspectorRouterEnv>()\n\t\t.get(\"/ping\", (c) => {\n\t\t\treturn c.json({ message: \"pong\" }, 200);\n\t\t})\n\t\t.get(\"/state\", async (c) => {\n\t\t\tif (await c.var.inspector.accessors.isStateEnabled()) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tstate: await c.var.inspector.accessors.getState(),\n\t\t\t\t\t},\n\t\t\t\t\t200,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn c.json({ enabled: false, state: null }, 200);\n\t\t})\n\t\t.patch(\n\t\t\t\"/state\",\n\t\t\tsValidator(\n\t\t\t\t\"json\",\n\t\t\t\tz\n\t\t\t\t\t.object({ patch: PatchSchema })\n\t\t\t\t\t.or(z.object({ replace: z.any() })),\n\t\t\t),\n\t\t\tasync (c) => {\n\t\t\t\tif (!(await c.var.inspector.accessors.isStateEnabled())) {\n\t\t\t\t\treturn c.json({ enabled: false }, 200);\n\t\t\t\t}\n\n\t\t\t\tconst body = c.req.valid(\"json\");\n\t\t\t\tif (\"replace\" in body) {\n\t\t\t\t\tawait c.var.inspector.accessors.setState(body.replace);\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\t\tstate: await c.var.inspector.accessors.getState(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t200,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst state = await c.var.inspector.accessors.getState();\n\n\t\t\t\tconst { newDocument: newState } = jsonPatch.applyPatch(\n\t\t\t\t\tstate,\n\t\t\t\t\tbody.patch,\n\t\t\t\t);\n\t\t\t\tawait c.var.inspector.accessors.setState(newState);\n\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tstate: await c.var.inspector.accessors.getState(),\n\t\t\t\t\t},\n\t\t\t\t\t200,\n\t\t\t\t);\n\t\t\t},\n\t\t)\n\t\t.get(\"/state/stream\", async (c) => {\n\t\t\tif (!(await c.var.inspector.accessors.isStateEnabled())) {\n\t\t\t\treturn c.json({ enabled: false }, 200);\n\t\t\t}\n\n\t\t\tlet id = 0;\n\t\t\tlet unsub: Unsubscribe;\n\t\t\treturn streamSSE(\n\t\t\t\tc,\n\t\t\t\tasync (stream) => {\n\t\t\t\t\tunsub = c.var.inspector.emitter.on(\n\t\t\t\t\t\t\"stateUpdated\",\n\t\t\t\t\t\tasync (state) => {\n\t\t\t\t\t\t\tstream.writeSSE({\n\t\t\t\t\t\t\t\tdata: JSON.stringify(state) || \"\",\n\t\t\t\t\t\t\t\tevent: \"state-update\",\n\t\t\t\t\t\t\t\tid: String(id++),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\tconst { promise } = promiseWithResolvers<void>();\n\n\t\t\t\t\treturn promise;\n\t\t\t\t},\n\t\t\t\tasync () => {\n\t\t\t\t\tunsub?.();\n\t\t\t\t},\n\t\t\t);\n\t\t})\n\t\t.get(\"/connections\", async (c) => {\n\t\t\tconst connections =\n\t\t\t\tawait c.var.inspector.accessors.getConnections();\n\t\t\treturn c.json({ connections }, 200);\n\t\t})\n\t\t.get(\"/connections/stream\", async (c) => {\n\t\t\tlet id = 0;\n\t\t\tlet unsub: Unsubscribe;\n\t\t\treturn streamSSE(\n\t\t\t\tc,\n\t\t\t\tasync (stream) => {\n\t\t\t\t\tunsub = c.var.inspector.emitter.on(\n\t\t\t\t\t\t\"connectionUpdated\",\n\t\t\t\t\t\tasync () => {\n\t\t\t\t\t\t\tstream.writeSSE({\n\t\t\t\t\t\t\t\tdata: JSON.stringify(\n\t\t\t\t\t\t\t\t\tawait c.var.inspector.accessors.getConnections(),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tevent: \"connection-update\",\n\t\t\t\t\t\t\t\tid: String(id++),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\tconst { promise } = promiseWithResolvers<void>();\n\n\t\t\t\t\treturn promise;\n\t\t\t\t},\n\t\t\t\tasync () => {\n\t\t\t\t\tunsub?.();\n\t\t\t\t},\n\t\t\t);\n\t\t})\n\t\t.get(\"/events\", async (c) => {\n\t\t\tconst events = c.var.inspector.lastRealtimeEvents;\n\t\t\treturn c.json({ events }, 200);\n\t\t})\n\t\t.post(\"/events/clear\", async (c) => {\n\t\t\tc.var.inspector.lastRealtimeEvents.length = 0; // Clear the events\n\t\t\treturn c.json({ message: \"Events cleared\" }, 200);\n\t\t})\n\t\t.get(\"/events/stream\", async (c) => {\n\t\t\tlet id = 0;\n\t\t\tlet unsub: Unsubscribe;\n\t\t\treturn streamSSE(\n\t\t\t\tc,\n\t\t\t\tasync (stream) => {\n\t\t\t\t\tunsub = c.var.inspector.emitter.on(\"eventFired\", () => {\n\t\t\t\t\t\tstream.writeSSE({\n\t\t\t\t\t\t\tdata: JSON.stringify(\n\t\t\t\t\t\t\t\tc.var.inspector.lastRealtimeEvents,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tevent: \"realtime-event\",\n\t\t\t\t\t\t\tid: String(id++),\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\n\t\t\t\t\tconst { promise } = promiseWithResolvers<void>();\n\n\t\t\t\t\treturn promise;\n\t\t\t\t},\n\t\t\t\tasync () => {\n\t\t\t\t\tunsub?.();\n\t\t\t\t},\n\t\t\t);\n\t\t})\n\t\t.get(\"/rpcs\", async (c) => {\n\t\t\tconst rpcs = await c.var.inspector.accessors.getRpcs();\n\t\t\treturn c.json({ rpcs }, 200);\n\t\t})\n\t\t.get(\"/db\", async (c) => {\n\t\t\tif (!(await c.var.inspector.accessors.isDbEnabled())) {\n\t\t\t\treturn c.json({ enabled: false, db: null }, 200);\n\t\t\t}\n\n\t\t\t// Access the SQLite database\n\t\t\tconst db = await c.var.inspector.accessors.getDb();\n\n\t\t\t// Get list of tables\n\t\t\tconst rows = await db.execute(`PRAGMA table_list`);\n\t\t\tconst tables = TablesSchema.parse(rows).filter(\n\t\t\t\t(table) =>\n\t\t\t\t\ttable.schema !== \"temp\" &&\n\t\t\t\t\t!table.name.startsWith(\"sqlite_\"),\n\t\t\t);\n\t\t\t// Get columns for each table\n\t\t\tconst tablesInfo = await Promise.all(\n\t\t\t\ttables.map((table) =>\n\t\t\t\t\tdb.execute(`PRAGMA table_info(${table.name})`),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst columns = tablesInfo.map((def) => ColumnsSchema.parse(def));\n\n\t\t\t// Get foreign keys for each table\n\t\t\tconst foreignKeysList = await Promise.all(\n\t\t\t\ttables.map((table) =>\n\t\t\t\t\tdb.execute(`PRAGMA foreign_key_list(${table.name})`),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst foreignKeys = foreignKeysList.map((def) =>\n\t\t\t\tForeignKeysSchema.parse(def),\n\t\t\t);\n\n\t\t\t// Get record counts for each table\n\t\t\tconst countInfo = await Promise.all(\n\t\t\t\ttables.map((table) =>\n\t\t\t\t\tdb.execute(`SELECT COUNT(*) as count FROM ${table.name}`),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst counts = countInfo.map((def) => {\n\t\t\t\treturn def[0].count || 0;\n\t\t\t});\n\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tdb: tablesInfo.map((_, index) => {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttable: tables[index],\n\t\t\t\t\t\t\tcolumns: columns[index],\n\t\t\t\t\t\t\tforeignKeys: foreignKeys[index],\n\t\t\t\t\t\t\trecords: counts[index],\n\t\t\t\t\t\t};\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\t200,\n\t\t\t);\n\t\t})\n\t\t.post(\n\t\t\t\"/db\",\n\t\t\tsValidator(\n\t\t\t\t\"json\",\n\t\t\t\tz.object({\n\t\t\t\t\tquery: z.string(),\n\t\t\t\t\tparams: z.array(z.any()).optional(),\n\t\t\t\t}),\n\t\t\t),\n\t\t\tasync (c) => {\n\t\t\t\tif (!(await c.var.inspector.accessors.isDbEnabled())) {\n\t\t\t\t\treturn c.json({ enabled: false }, 200);\n\t\t\t\t}\n\t\t\t\tconst db = await c.var.inspector.accessors.getDb();\n\n\t\t\t\ttry {\n\t\t\t\t\tconst result = (await db.execute(\n\t\t\t\t\t\tc.req.valid(\"json\").query,\n\t\t\t\t\t\t...(c.req.valid(\"json\").params || []),\n\t\t\t\t\t)) as unknown;\n\t\t\t\t\treturn c.json({ result }, 200);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tc;\n\t\t\t\t\treturn c.json({ error: (error as Error).message }, 500);\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t\t.post(\n\t\t\t\"/action\",\n\t\t\tsValidator(\n\t\t\t\t\"json\",\n\t\t\t\tz.object({\n\t\t\t\t\tname: z.string(),\n\t\t\t\t\tparams: z.array(z.any()).optional(),\n\t\t\t\t}),\n\t\t\t),\n\t\t\tasync (c) => {\n\t\t\t\tconst { name, params } = c.req.valid(\"json\");\n\t\t\t\tconst result = await c.var.inspector.accessors.executeAction(\n\t\t\t\t\tname,\n\t\t\t\t\tparams,\n\t\t\t\t);\n\t\t\t\treturn c.json({ result }, 200);\n\t\t\t},\n\t\t);\n}\n\ninterface ActorInspectorAccessors {\n\tisStateEnabled: () => Promise<boolean>;\n\tgetState: () => Promise<unknown>;\n\tsetState: (state: unknown) => Promise<void>;\n\tisDbEnabled: () => Promise<boolean>;\n\tgetDb: () => Promise<InferDatabaseClient<AnyDatabaseProvider>>;\n\tgetRpcs: () => Promise<string[]>;\n\tgetConnections: () => Promise<Connection[]>;\n\texecuteAction: (name: string, params?: unknown[]) => Promise<unknown>;\n}\n\ninterface ActorInspectorEmitterEvents {\n\tstateUpdated: (state: unknown) => void;\n\tconnectionUpdated: () => void;\n\teventFired: (event: RealtimeEvent) => void;\n}\n\n/**\n * Provides a unified interface for inspecting actor external and internal state.\n */\nexport class ActorInspector {\n\tpublic readonly accessors: ActorInspectorAccessors;\n\tpublic readonly emitter = createNanoEvents<ActorInspectorEmitterEvents>();\n\n\t#lastRealtimeEvents: RecordedRealtimeEvent[] = [];\n\n\tget lastRealtimeEvents() {\n\t\treturn this.#lastRealtimeEvents;\n\t}\n\n\tconstructor(accessors: () => ActorInspectorAccessors) {\n\t\tthis.accessors = accessors();\n\t\tthis.emitter.on(\"eventFired\", (event) => {\n\t\t\tthis.#lastRealtimeEvents.push({\n\t\t\t\tid: crypto.randomUUID(),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t...event,\n\t\t\t});\n\t\t\t// keep the last 100 events\n\t\t\tif (this.#lastRealtimeEvents.length > 100) {\n\t\t\t\tthis.#lastRealtimeEvents = this.#lastRealtimeEvents.slice(-100);\n\t\t\t}\n\t\t});\n\t}\n}\n","import type { ActorKey } from \"@/actor/mod\";\nimport type { Client } from \"@/client/client\";\nimport type { Logger } from \"@/common/log\";\nimport type { Registry } from \"@/registry/mod\";\nimport type { Conn, ConnId } from \"./conn\";\nimport type { AnyDatabaseProvider, InferDatabaseClient } from \"./database\";\nimport type { ActorInstance, SaveStateOptions } from \"./instance\";\nimport type { Schedule } from \"./schedule\";\n\n/**\n * ActorContext class that provides access to actor methods and state\n */\nexport class ActorContext<\n\tTState,\n\tTConnParams,\n\tTConnState,\n\tTVars,\n\tTInput,\n\tTDatabase extends AnyDatabaseProvider,\n> {\n\t#actor: ActorInstance<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase\n\t>;\n\n\tconstructor(\n\t\tactor: ActorInstance<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t) {\n\t\tthis.#actor = actor;\n\t}\n\n\t/**\n\t * Get the actor state\n\t */\n\tget state(): TState {\n\t\treturn this.#actor.state;\n\t}\n\n\t/**\n\t * Get the actor variables\n\t */\n\tget vars(): TVars {\n\t\treturn this.#actor.vars;\n\t}\n\n\t/**\n\t * Broadcasts an event to all connected clients.\n\t * @param name - The name of the event.\n\t * @param args - The arguments to send with the event.\n\t */\n\tbroadcast<Args extends Array<unknown>>(name: string, ...args: Args): void {\n\t\tthis.#actor._broadcast(name, ...args);\n\t\treturn;\n\t}\n\n\t/**\n\t * Gets the logger instance.\n\t */\n\tget log(): Logger {\n\t\treturn this.#actor.log;\n\t}\n\n\t/**\n\t * Gets actor ID.\n\t */\n\tget actorId(): string {\n\t\treturn this.#actor.id;\n\t}\n\n\t/**\n\t * Gets the actor name.\n\t */\n\tget name(): string {\n\t\treturn this.#actor.name;\n\t}\n\n\t/**\n\t * Gets the actor key.\n\t */\n\tget key(): ActorKey {\n\t\treturn this.#actor.key;\n\t}\n\n\t/**\n\t * Gets the region.\n\t */\n\tget region(): string {\n\t\treturn this.#actor.region;\n\t}\n\n\t/**\n\t * Gets the scheduler.\n\t */\n\tget schedule(): Schedule {\n\t\treturn this.#actor.schedule;\n\t}\n\n\t/**\n\t * Gets the map of connections.\n\t */\n\tget conns(): Map<\n\t\tConnId,\n\t\tConn<TState, TConnParams, TConnState, TVars, TInput, TDatabase>\n\t> {\n\t\treturn this.#actor.conns;\n\t}\n\n\t/**\n\t * Returns the client for the given registry.\n\t */\n\tclient<R extends Registry<any>>(): Client<R> {\n\t\treturn this.#actor.inlineClient as Client<R>;\n\t}\n\n\t/**\n\t * Gets the database.\n\t * @experimental\n\t * @throws {DatabaseNotEnabled} If the database is not enabled.\n\t */\n\tget db(): InferDatabaseClient<TDatabase> {\n\t\treturn this.#actor.db;\n\t}\n\n\t/**\n\t * Forces the state to get saved.\n\t *\n\t * @param opts - Options for saving the state.\n\t */\n\tasync saveState(opts: SaveStateOptions): Promise<void> {\n\t\treturn this.#actor.saveState(opts);\n\t}\n\n\t/**\n\t * Prevents the actor from sleeping until promise is complete.\n\t */\n\twaitUntil(promise: Promise<void>): void {\n\t\tthis.#actor._waitUntil(promise);\n\t}\n\n\t/**\n\t * AbortSignal that fires when the actor is stopping.\n\t */\n\tget abortSignal(): AbortSignal {\n\t\treturn this.#actor.abortSignal;\n\t}\n\n\t/**\n\t * Forces the actor to sleep.\n\t *\n\t * Not supported on all drivers.\n\t *\n\t * @experimental\n\t */\n\tsleep() {\n\t\tthis.#actor._sleep();\n\t}\n}\n","import type { ActorKey } from \"@/mod\";\n\nexport const EMPTY_KEY = \"/\";\nexport const KEY_SEPARATOR = \"/\";\n\nexport function serializeActorKey(key: ActorKey): 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// Handle empty strings by using a special marker\n\t\tif (part === \"\") {\n\t\t\treturn \"\\\\0\"; // Use \\0 as a marker for empty strings\n\t\t}\n\n\t\t// Escape backslashes first to avoid conflicts with our markers\n\t\tlet escaped = part.replace(/\\\\/g, \"\\\\\\\\\");\n\n\t\t// Then escape separators\n\t\tescaped = escaped.replace(/\\//g, `\\\\${KEY_SEPARATOR}`);\n\n\t\treturn escaped;\n\t});\n\n\treturn escapedParts.join(KEY_SEPARATOR);\n}\n\nexport function deserializeActorKey(keyString: string | undefined): ActorKey {\n\t// Check for special empty key marker\n\tif (\n\t\tkeyString === undefined ||\n\t\tkeyString === null ||\n\t\tkeyString === EMPTY_KEY\n\t) {\n\t\treturn [];\n\t}\n\n\t// Split by unescaped separators and unescape the escaped characters\n\tconst parts: string[] = [];\n\tlet currentPart = \"\";\n\tlet escaping = false;\n\tlet isEmptyStringMarker = 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// Handle special escape sequences\n\t\t\tif (char === \"0\") {\n\t\t\t\t// \\0 represents an empty string marker\n\t\t\t\tisEmptyStringMarker = true;\n\t\t\t} else {\n\t\t\t\t// This is an escaped character, add it directly\n\t\t\t\tcurrentPart += char;\n\t\t\t}\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\tif (isEmptyStringMarker) {\n\t\t\t\tparts.push(\"\");\n\t\t\t\tisEmptyStringMarker = false;\n\t\t\t} else {\n\t\t\t\tparts.push(currentPart);\n\t\t\t}\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\n\tif (escaping) {\n\t\t// Incomplete escape at the end - treat as literal backslash\n\t\tparts.push(currentPart + \"\\\\\");\n\t} else if (isEmptyStringMarker) {\n\t\tparts.push(\"\");\n\t} else if (currentPart !== \"\" || parts.length > 0) {\n\t\tparts.push(currentPart);\n\t}\n\n\treturn parts;\n}\n","import type { AnyActorInstance } from \"./instance\";\n\nexport class Schedule {\n\t#actor: AnyActorInstance;\n\n\tconstructor(actor: AnyActorInstance) {\n\t\tthis.#actor = actor;\n\t}\n\n\tasync after(duration: number, fn: string, ...args: unknown[]) {\n\t\tawait this.#actor.scheduleEvent(Date.now() + duration, fn, args);\n\t}\n\n\tasync at(timestamp: number, fn: string, ...args: unknown[]) {\n\t\tawait this.#actor.scheduleEvent(timestamp, fn, args);\n\t}\n}\n","import type { RegistryConfig } from \"@/registry/config\";\nimport type { ActionContext } from \"./action\";\nimport type { Actions, ActorConfig } from \"./config\";\nimport type { ActorContext } from \"./context\";\nimport type { AnyDatabaseProvider } from \"./database\";\nimport { ActorInstance } from \"./instance\";\n\nexport type AnyActorDefinition = ActorDefinition<\n\tany,\n\tany,\n\tany,\n\tany,\n\tany,\n\tany,\n\tany\n>;\n\n/**\n * Extracts the context type from an ActorDefinition\n */\nexport type ActorContextOf<AD extends AnyActorDefinition> =\n\tAD extends ActorDefinition<\n\t\tinfer S,\n\t\tinfer CP,\n\t\tinfer CS,\n\t\tinfer V,\n\t\tinfer I,\n\t\tinfer DB,\n\t\tany\n\t>\n\t\t? ActorContext<S, CP, CS, V, I, DB>\n\t\t: never;\n\n/**\n * Extracts the context type from an ActorDefinition\n */\nexport type ActionContextOf<AD extends AnyActorDefinition> =\n\tAD extends ActorDefinition<\n\t\tinfer S,\n\t\tinfer CP,\n\t\tinfer CS,\n\t\tinfer V,\n\t\tinfer I,\n\t\tinfer DB,\n\t\tany\n\t>\n\t\t? ActionContext<S, CP, CS, V, I, DB>\n\t\t: never;\n\nexport class ActorDefinition<\n\tS,\n\tCP,\n\tCS,\n\tV,\n\tI,\n\tDB extends AnyDatabaseProvider,\n\tR extends Actions<S, CP, CS, V, I, DB>,\n> {\n\t#config: ActorConfig<S, CP, CS, V, I, DB>;\n\n\tconstructor(config: ActorConfig<S, CP, CS, V, I, DB>) {\n\t\tthis.#config = config;\n\t}\n\n\tget config(): ActorConfig<S, CP, CS, V, I, DB> {\n\t\treturn this.#config;\n\t}\n\n\tinstantiate(): ActorInstance<S, CP, CS, V, I, DB> {\n\t\treturn new ActorInstance(this.#config);\n\t}\n}\n\nexport function lookupInRegistry(\n\tregistryConfig: RegistryConfig,\n\tname: string,\n): AnyActorDefinition {\n\t// Build actor\n\tconst definition = registryConfig.use[name];\n\tif (!definition) throw new Error(`no actor in registry for name ${name}`);\n\treturn definition;\n}\n","import { MAX_CONN_PARAMS_SIZE } from \"@/common//network\";\n\nexport class ActorClientError extends Error {}\n\nexport class InternalError extends ActorClientError {}\n\nexport class ManagerError extends ActorClientError {\n\tconstructor(error: string, opts?: ErrorOptions) {\n\t\tsuper(`Manager error: ${error}`, opts);\n\t}\n}\n\nexport class MalformedResponseMessage extends ActorClientError {\n\tconstructor(cause?: unknown) {\n\t\tsuper(`Malformed response message: ${cause}`, { cause });\n\t}\n}\n\nexport class ActorError extends ActorClientError {\n\t__type = \"ActorError\";\n\n\tconstructor(\n\t\tpublic readonly group: string,\n\t\tpublic readonly code: string,\n\t\tmessage: string,\n\t\tpublic readonly metadata?: unknown,\n\t) {\n\t\tsuper(message);\n\t}\n}\n\nexport class HttpRequestError extends ActorClientError {\n\tconstructor(message: string, opts?: { cause?: unknown }) {\n\t\tsuper(`HTTP request error: ${message}`, { cause: opts?.cause });\n\t}\n}\n\nexport class ActorConnDisposed extends ActorClientError {\n\tconstructor() {\n\t\tsuper(\"Attempting to interact with a disposed actor connection.\");\n\t}\n}\n","import * as cbor from \"cbor-x\";\nimport invariant from \"invariant\";\nimport pRetry from \"p-retry\";\nimport type { CloseEvent } from \"ws\";\nimport type { AnyActorDefinition } from \"@/actor/definition\";\nimport { inputDataToBuffer } from \"@/actor/protocol/old\";\nimport { type Encoding, jsonStringifyCompat } from \"@/actor/protocol/serde\";\nimport {\n\tHEADER_CONN_ID,\n\tHEADER_CONN_PARAMS,\n\tHEADER_CONN_TOKEN,\n\tHEADER_ENCODING,\n\tPATH_CONNECT_WEBSOCKET,\n} from \"@/common/actor-router-consts\";\nimport { importEventSource } from \"@/common/eventsource\";\nimport type {\n\tUniversalErrorEvent,\n\tUniversalEventSource,\n\tUniversalMessageEvent,\n} from \"@/common/eventsource-interface\";\nimport { assertUnreachable, stringifyError } from \"@/common/utils\";\nimport type { UniversalWebSocket } from \"@/common/websocket-interface\";\nimport type { ManagerDriver } from \"@/driver-helpers/mod\";\nimport type { ActorQuery } from \"@/manager/protocol/query\";\nimport type * as protocol from \"@/schemas/client-protocol/mod\";\nimport {\n\tTO_CLIENT_VERSIONED,\n\tTO_SERVER_VERSIONED,\n} from \"@/schemas/client-protocol/versioned\";\nimport {\n\tdeserializeWithEncoding,\n\tencodingIsBinary,\n\tserializeWithEncoding,\n} from \"@/serde\";\nimport {\n\tbufferToArrayBuffer,\n\tgetEnvUniversal,\n\thttpUserAgent,\n\tpromiseWithResolvers,\n} from \"@/utils\";\nimport type { ActorDefinitionActions } from \"./actor-common\";\nimport { queryActor } from \"./actor-query\";\nimport { ACTOR_CONNS_SYMBOL, type ClientRaw, TRANSPORT_SYMBOL } from \"./client\";\nimport * as errors from \"./errors\";\nimport { logger } from \"./log\";\nimport {\n\ttype WebSocketMessage as ConnMessage,\n\tmessageLength,\n\tsendHttpRequest,\n} from \"./utils\";\n\ninterface ActionInFlight {\n\tname: string;\n\tresolve: (response: protocol.ActionResponse) => void;\n\treject: (error: Error) => void;\n}\n\ninterface EventSubscriptions<Args extends Array<unknown>> {\n\tcallback: (...args: Args) => void;\n\tonce: boolean;\n}\n\n/**\n * A function that unsubscribes from an event.\n *\n * @typedef {Function} EventUnsubscribe\n */\nexport type EventUnsubscribe = () => void;\n\n/**\n * A function that handles connection errors.\n *\n * @typedef {Function} ActorErrorCallback\n */\nexport type ActorErrorCallback = (error: errors.ActorError) => void;\n\nexport interface SendHttpMessageOpts {\n\tephemeral: boolean;\n\tsignal?: AbortSignal;\n}\n\nexport type ConnTransport =\n\t| { websocket: UniversalWebSocket }\n\t| { sse: UniversalEventSource };\n\nexport const CONNECT_SYMBOL = Symbol(\"connect\");\n\n/**\n * Provides underlying functions for {@link ActorConn}. See {@link ActorConn} for using type-safe remote procedure calls.\n *\n * @see {@link ActorConn}\n */\nexport class ActorConnRaw {\n\t#disposed = false;\n\n\t/* Will be aborted on dispose. */\n\t#abortController = new AbortController();\n\n\t/** If attempting to connect. Helpful for knowing if in a retry loop when reconnecting. */\n\t#connecting = false;\n\n\t// Connection info, used for reconnection and HTTP requests\n\t#actorId?: string;\n\t#connectionId?: string;\n\t#connectionToken?: string;\n\n\t#transport?: ConnTransport;\n\n\t#messageQueue: protocol.ToServer[] = [];\n\t#actionsInFlight = new Map<number, ActionInFlight>();\n\n\t// biome-ignore lint/suspicious/noExplicitAny: Unknown subscription type\n\t#eventSubscriptions = new Map<string, Set<EventSubscriptions<any[]>>>();\n\n\t#errorHandlers = new Set<ActorErrorCallback>();\n\n\t#actionIdCounter = 0;\n\n\t/**\n\t * Interval that keeps the NodeJS process alive if this is the only thing running.\n\t *\n\t * See ttps://github.com/nodejs/node/issues/22088\n\t */\n\t#keepNodeAliveInterval: NodeJS.Timeout;\n\n\t/** Promise used to indicate the socket has connected successfully. This will be rejected if the connection fails. */\n\t#onOpenPromise?: ReturnType<typeof promiseWithResolvers<undefined>>;\n\n\t#client: ClientRaw;\n\t#driver: ManagerDriver;\n\t#params: unknown;\n\t#encoding: Encoding;\n\t#actorQuery: ActorQuery;\n\n\t// TODO: ws message queue\n\n\t/**\n\t * Do not call this directly.\n\t *\n\t * Creates an instance of ActorConnRaw.\n\t *\n\t * @protected\n\t */\n\tpublic constructor(\n\t\tclient: ClientRaw,\n\t\tdriver: ManagerDriver,\n\t\tparams: unknown,\n\t\tencoding: Encoding,\n\t\tactorQuery: ActorQuery,\n\t) {\n\t\tthis.#client = client;\n\t\tthis.#driver = driver;\n\t\tthis.#params = params;\n\t\tthis.#encoding = encoding;\n\t\tthis.#actorQuery = actorQuery;\n\n\t\tthis.#keepNodeAliveInterval = setInterval(() => 60_000);\n\t}\n\n\t/**\n\t * Call a raw action connection. See {@link ActorConn} for type-safe action calls.\n\t *\n\t * @see {@link ActorConn}\n\t * @template Args - The type of arguments to pass to the action function.\n\t * @template Response - The type of the response returned by the action function.\n\t * @param {string} name - The name of the action function to call.\n\t * @param {...Args} args - The arguments to pass to the action function.\n\t * @returns {Promise<Response>} - A promise that resolves to the response of the action function.\n\t */\n\tasync action<\n\t\tArgs extends Array<unknown> = unknown[],\n\t\tResponse = unknown,\n\t>(opts: {\n\t\tname: string;\n\t\targs: Args;\n\t\tsignal?: AbortSignal;\n\t}): Promise<Response> {\n\t\tlogger().debug({ msg: \"action\", name: opts.name, args: opts.args });\n\n\t\t// If we have an active connection, use the websockactionId\n\t\tconst actionId = this.#actionIdCounter;\n\t\tthis.#actionIdCounter += 1;\n\n\t\tconst { promise, resolve, reject } =\n\t\t\tpromiseWithResolvers<protocol.ActionResponse>();\n\t\tthis.#actionsInFlight.set(actionId, {\n\t\t\tname: opts.name,\n\t\t\tresolve,\n\t\t\treject,\n\t\t});\n\n\t\tthis.#sendMessage({\n\t\t\tbody: {\n\t\t\t\ttag: \"ActionRequest\",\n\t\t\t\tval: {\n\t\t\t\t\tid: BigInt(actionId),\n\t\t\t\t\tname: opts.name,\n\t\t\t\t\targs: bufferToArrayBuffer(cbor.encode(opts.args)),\n\t\t\t\t},\n\t\t\t},\n\t\t} satisfies protocol.ToServer);\n\n\t\t// TODO: Throw error if disconnect is called\n\n\t\tconst { id: responseId, output } = await promise;\n\t\tif (responseId !== BigInt(actionId))\n\t\t\tthrow new Error(\n\t\t\t\t`Request ID ${actionId} does not match response ID ${responseId}`,\n\t\t\t);\n\n\t\treturn cbor.decode(new Uint8Array(output)) as Response;\n\t}\n\n\t/**\n\t * Do not call this directly.\nenc\n\t * Establishes a connection to the server using the specified endpoint & encoding & driver.\n\t *\n\t * @protected\n\t */\n\tpublic [CONNECT_SYMBOL]() {\n\t\tthis.#connectWithRetry();\n\t}\n\n\tasync #connectWithRetry() {\n\t\tthis.#connecting = true;\n\n\t\t// Attempt to reconnect indefinitely\n\t\ttry {\n\t\t\tawait pRetry(this.#connectAndWait.bind(this), {\n\t\t\t\tforever: true,\n\t\t\t\tminTimeout: 250,\n\t\t\t\tmaxTimeout: 30_000,\n\n\t\t\t\tonFailedAttempt: (error) => {\n\t\t\t\t\tlogger().warn({\n\t\t\t\t\t\tmsg: \"failed to reconnect\",\n\t\t\t\t\t\tattempt: error.attemptNumber,\n\t\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\t// Cancel retry if aborted\n\t\t\t\tsignal: this.#abortController.signal,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tif ((err as Error).name === \"AbortError\") {\n\t\t\t\t// Ignore abortions\n\t\t\t\tlogger().info({ msg: \"connection retry aborted\" });\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\t// Unknown error\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t}\n\n\t\tthis.#connecting = false;\n\t}\n\n\tasync #connectAndWait() {\n\t\ttry {\n\t\t\t// Create promise for open\n\t\t\tif (this.#onOpenPromise)\n\t\t\t\tthrow new Error(\"#onOpenPromise already defined\");\n\t\t\tthis.#onOpenPromise = promiseWithResolvers();\n\n\t\t\t// Connect transport\n\t\t\tif (this.#client[TRANSPORT_SYMBOL] === \"websocket\") {\n\t\t\t\tawait this.#connectWebSocket();\n\t\t\t} else if (this.#client[TRANSPORT_SYMBOL] === \"sse\") {\n\t\t\t\tawait this.#connectSse();\n\t\t\t} else {\n\t\t\t\tassertUnreachable(this.#client[TRANSPORT_SYMBOL]);\n\t\t\t}\n\n\t\t\t// Wait for result\n\t\t\tawait this.#onOpenPromise.promise;\n\t\t} finally {\n\t\t\tthis.#onOpenPromise = undefined;\n\t\t}\n\t}\n\n\tasync #connectWebSocket() {\n\t\tconst { actorId } = await queryActor(\n\t\t\tundefined,\n\t\t\tthis.#actorQuery,\n\t\t\tthis.#driver,\n\t\t);\n\n\t\t// Check if we have connection info for reconnection\n\t\tconst isReconnection = this.#connectionId && this.#connectionToken;\n\t\tif (isReconnection) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"attempting websocket reconnection\",\n\t\t\t\tconnectionId: this.#connectionId,\n\t\t\t});\n\t\t}\n\n\t\tconst ws = await this.#driver.openWebSocket(\n\t\t\tPATH_CONNECT_WEBSOCKET,\n\t\t\tactorId,\n\t\t\tthis.#encoding,\n\t\t\tthis.#params,\n\t\t\t// Pass connection ID and token for reconnection if available\n\t\t\tisReconnection ? this.#connectionId : undefined,\n\t\t\tisReconnection ? this.#connectionToken : undefined,\n\t\t);\n\t\tlogger().debug({\n\t\t\tmsg: \"transport set to new websocket\",\n\t\t\tconnectionId: this.#connectionId,\n\t\t\treadyState: ws.readyState,\n\t\t\tmessageQueueLength: this.#messageQueue.length,\n\t\t});\n\t\tthis.#transport = { websocket: ws };\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"client websocket open\",\n\t\t\t\tconnectionId: this.#connectionId,\n\t\t\t});\n\t\t});\n\t\tws.addEventListener(\"message\", async (ev) => {\n\t\t\ttry {\n\t\t\t\tawait this.#handleOnMessage(ev.data);\n\t\t\t} catch (err) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"error in websocket message handler\",\n\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\tws.addEventListener(\"close\", (ev) => {\n\t\t\ttry {\n\t\t\t\tthis.#handleOnClose(ev);\n\t\t\t} catch (err) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"error in websocket close handler\",\n\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\tws.addEventListener(\"error\", (_ev) => {\n\t\t\ttry {\n\t\t\t\tthis.#handleOnError();\n\t\t\t} catch (err) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"error in websocket error handler\",\n\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tasync #connectSse() {\n\t\tconst EventSource = await importEventSource();\n\n\t\t// Get the actor ID\n\t\tconst { actorId } = await queryActor(\n\t\t\tundefined,\n\t\t\tthis.#actorQuery,\n\t\t\tthis.#driver,\n\t\t);\n\t\tlogger().debug({ msg: \"found actor for sse connection\", actorId });\n\t\tinvariant(actorId, \"Missing actor ID\");\n\n\t\tlogger().debug({\n\t\t\tmsg: \"opening sse connection\",\n\t\t\tactorId,\n\t\t\tencoding: this.#encoding,\n\t\t});\n\n\t\tconst isReconnection = this.#connectionId && this.#connectionToken;\n\n\t\tconst eventSource = new EventSource(\"http://actor/connect/sse\", {\n\t\t\tfetch: (input, init) => {\n\t\t\t\treturn this.#driver.sendRequest(\n\t\t\t\t\tactorId,\n\t\t\t\t\tnew Request(input, {\n\t\t\t\t\t\t...init,\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t...init?.headers,\n\t\t\t\t\t\t\t\"User-Agent\": httpUserAgent(),\n\t\t\t\t\t\t\t[HEADER_ENCODING]: this.#encoding,\n\t\t\t\t\t\t\t...(this.#params !== undefined\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t[HEADER_CONN_PARAMS]: JSON.stringify(\n\t\t\t\t\t\t\t\t\t\t\tthis.#params,\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t...(isReconnection\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t[HEADER_CONN_ID]: this.#connectionId,\n\t\t\t\t\t\t\t\t\t\t[HEADER_CONN_TOKEN]:\n\t\t\t\t\t\t\t\t\t\t\tthis.#connectionToken,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t},\n\t\t}) as UniversalEventSource;\n\n\t\tthis.#transport = { sse: eventSource };\n\n\t\teventSource.addEventListener(\"message\", (ev: UniversalMessageEvent) => {\n\t\t\t// Ignore pings\n\t\t\tif (ev.type === \"ping\") return;\n\n\t\t\tthis.#handleOnMessage(ev.data);\n\t\t});\n\n\t\teventSource.addEventListener(\"error\", (ev: UniversalErrorEvent) => {\n\t\t\tthis.#handleOnError();\n\t\t});\n\t}\n\n\t/** Called by the onopen event from drivers. */\n\t#handleOnOpen() {\n\t\tlogger().debug({\n\t\t\tmsg: \"socket open\",\n\t\t\tmessageQueueLength: this.#messageQueue.length,\n\t\t\tconnectionId: this.#connectionId,\n\t\t});\n\n\t\t// Resolve open promise\n\t\tif (this.#onOpenPromise) {\n\t\t\tthis.#onOpenPromise.resolve(undefined);\n\t\t} else {\n\t\t\tlogger().warn({ msg: \"#onOpenPromise is undefined\" });\n\t\t}\n\n\t\t// Resubscribe to all active events\n\t\tfor (const eventName of this.#eventSubscriptions.keys()) {\n\t\t\tthis.#sendSubscription(eventName, true);\n\t\t}\n\n\t\t// Flush queue\n\t\t//\n\t\t// If the message fails to send, the message will be re-queued\n\t\tconst queue = this.#messageQueue;\n\t\tthis.#messageQueue = [];\n\t\tlogger().debug({\n\t\t\tmsg: \"flushing message queue\",\n\t\t\tqueueLength: queue.length,\n\t\t});\n\t\tfor (const msg of queue) {\n\t\t\tthis.#sendMessage(msg);\n\t\t}\n\t}\n\n\t/** Called by the onmessage event from drivers. */\n\tasync #handleOnMessage(data: any) {\n\t\tlogger().trace({\n\t\t\tmsg: \"received message\",\n\t\t\tdataType: typeof data,\n\t\t\tisBlob: data instanceof Blob,\n\t\t\tisArrayBuffer: data instanceof ArrayBuffer,\n\t\t});\n\n\t\tconst response = await this.#parseMessage(data as ConnMessage);\n\t\tlogger().trace(\n\t\t\tgetEnvUniversal(\"_RIVETKIT_LOG_MESSAGE\")\n\t\t\t\t? {\n\t\t\t\t\t\tmsg: \"parsed message\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\tjsonStringifyCompat(response).substring(0, 100) +\n\t\t\t\t\t\t\t\"...\",\n\t\t\t\t\t}\n\t\t\t\t: { msg: \"parsed message\" },\n\t\t);\n\n\t\tif (response.body.tag === \"Init\") {\n\t\t\t// Store connection info for reconnection\n\t\t\tthis.#actorId = response.body.val.actorId;\n\t\t\tthis.#connectionId = response.body.val.connectionId;\n\t\t\tthis.#connectionToken = response.body.val.connectionToken;\n\t\t\tlogger().trace({\n\t\t\t\tmsg: \"received init message\",\n\t\t\t\tactorId: this.#actorId,\n\t\t\t\tconnectionId: this.#connectionId,\n\t\t\t});\n\t\t\tthis.#handleOnOpen();\n\t\t} else if (response.body.tag === \"Error\") {\n\t\t\t// Connection error\n\t\t\tconst { group, code, message, metadata, actionId } =\n\t\t\t\tresponse.body.val;\n\n\t\t\tif (actionId) {\n\t\t\t\tconst inFlight = this.#takeActionInFlight(Number(actionId));\n\n\t\t\t\tlogger().warn({\n\t\t\t\t\tmsg: \"action error\",\n\t\t\t\t\tactionId: actionId,\n\t\t\t\t\tactionName: inFlight?.name,\n\t\t\t\t\tgroup,\n\t\t\t\t\tcode,\n\t\t\t\t\tmessage,\n\t\t\t\t\tmetadata,\n\t\t\t\t});\n\n\t\t\t\tinFlight.reject(\n\t\t\t\t\tnew errors.ActorError(group, code, message, metadata),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tlogger().warn({\n\t\t\t\t\tmsg: \"connection error\",\n\t\t\t\t\tgroup,\n\t\t\t\t\tcode,\n\t\t\t\t\tmessage,\n\t\t\t\t\tmetadata,\n\t\t\t\t});\n\n\t\t\t\t// Create a connection error\n\t\t\t\tconst actorError = new errors.ActorError(\n\t\t\t\t\tgroup,\n\t\t\t\t\tcode,\n\t\t\t\t\tmessage,\n\t\t\t\t\tmetadata,\n\t\t\t\t);\n\n\t\t\t\t// If we have an onOpenPromise, reject it with the error\n\t\t\t\tif (this.#onOpenPromise) {\n\t\t\t\t\tthis.#onOpenPromise.reject(actorError);\n\t\t\t\t}\n\n\t\t\t\t// Reject any in-flight requests\n\t\t\t\tfor (const [id, inFlight] of this.#actionsInFlight.entries()) {\n\t\t\t\t\tinFlight.reject(actorError);\n\t\t\t\t\tthis.#actionsInFlight.delete(id);\n\t\t\t\t}\n\n\t\t\t\t// Dispatch to error handler if registered\n\t\t\t\tthis.#dispatchActorError(actorError);\n\t\t\t}\n\t\t} else if (response.body.tag === \"ActionResponse\") {\n\t\t\t// Action response OK\n\t\t\tconst { id: actionId } = response.body.val;\n\t\t\tlogger().trace({\n\t\t\t\tmsg: \"received action response\",\n\t\t\t\tactionId,\n\t\t\t});\n\n\t\t\tconst inFlight = this.#takeActionInFlight(Number(actionId));\n\t\t\tlogger().trace({\n\t\t\t\tmsg: \"resolving action promise\",\n\t\t\t\tactionId,\n\t\t\t\tactionName: inFlight?.name,\n\t\t\t});\n\t\t\tinFlight.resolve(response.body.val);\n\t\t} else if (response.body.tag === \"Event\") {\n\t\t\tlogger().trace({\n\t\t\t\tmsg: \"received event\",\n\t\t\t\tname: response.body.val.name,\n\t\t\t});\n\t\t\tthis.#dispatchEvent(response.body.val);\n\t\t} else {\n\t\t\tassertUnreachable(response.body);\n\t\t}\n\t}\n\n\t/** Called by the onclose event from drivers. */\n\t#handleOnClose(event: Event | CloseEvent) {\n\t\t// TODO: Handle queue\n\t\t// TODO: Reconnect with backoff\n\n\t\t// Reject open promise\n\t\tif (this.#onOpenPromise) {\n\t\t\tthis.#onOpenPromise.reject(new Error(\"Closed\"));\n\t\t}\n\n\t\t// We can't use `event instanceof CloseEvent` because it's not defined in NodeJS\n\t\t//\n\t\t// These properties will be undefined\n\t\tconst closeEvent = event as CloseEvent;\n\t\tconst wasClean = closeEvent.wasClean;\n\n\t\tlogger().info({\n\t\t\tmsg: \"socket closed\",\n\t\t\tcode: closeEvent.code,\n\t\t\treason: closeEvent.reason,\n\t\t\twasClean: wasClean,\n\t\t\tconnectionId: this.#connectionId,\n\t\t\tmessageQueueLength: this.#messageQueue.length,\n\t\t\tactionsInFlight: this.#actionsInFlight.size,\n\t\t});\n\n\t\t// Reject all in-flight actions\n\t\tif (this.#actionsInFlight.size > 0) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"rejecting in-flight actions after disconnect\",\n\t\t\t\tcount: this.#actionsInFlight.size,\n\t\t\t\tconnectionId: this.#connectionId,\n\t\t\t\twasClean,\n\t\t\t});\n\n\t\t\tconst disconnectError = new Error(\n\t\t\t\twasClean ? \"Connection closed\" : \"Connection lost\",\n\t\t\t);\n\n\t\t\tfor (const actionInfo of this.#actionsInFlight.values()) {\n\t\t\t\tactionInfo.reject(disconnectError);\n\t\t\t}\n\t\t\tthis.#actionsInFlight.clear();\n\t\t}\n\n\t\tthis.#transport = undefined;\n\n\t\t// Automatically reconnect. Skip if already attempting to connect.\n\t\tif (!this.#disposed && !this.#connecting) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"triggering reconnect\",\n\t\t\t\tconnectionId: this.#connectionId,\n\t\t\t\tmessageQueueLength: this.#messageQueue.length,\n\t\t\t});\n\t\t\t// TODO: Fetch actor to check if it's destroyed\n\t\t\t// TODO: Add backoff for reconnect\n\t\t\t// TODO: Add a way of preserving connection ID for connection state\n\n\t\t\t// Attempt to connect again\n\t\t\tthis.#connectWithRetry();\n\t\t}\n\t}\n\n\t/** Called by the onerror event from drivers. */\n\t#handleOnError() {\n\t\tif (this.#disposed) return;\n\n\t\t// More detailed information will be logged in onclose\n\t\tlogger().warn(\"socket error\");\n\t}\n\n\t#takeActionInFlight(id: number): ActionInFlight {\n\t\tconst inFlight = this.#actionsInFlight.get(id);\n\t\tif (!inFlight) {\n\t\t\tthrow new errors.InternalError(`No in flight response for ${id}`);\n\t\t}\n\t\tthis.#actionsInFlight.delete(id);\n\t\treturn inFlight;\n\t}\n\n\t#dispatchEvent(event: protocol.Event) {\n\t\tconst { name, args: argsRaw } = event;\n\t\tconst args = cbor.decode(new Uint8Array(argsRaw));\n\n\t\tconst listeners = this.#eventSubscriptions.get(name);\n\t\tif (!listeners) return;\n\n\t\t// Create a new array to avoid issues with listeners being removed during iteration\n\t\tfor (const listener of [...listeners]) {\n\t\t\tlistener.callback(...args);\n\n\t\t\t// Remove if this was a one-time listener\n\t\t\tif (listener.once) {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t}\n\t\t}\n\n\t\t// Clean up empty listener sets\n\t\tif (listeners.size === 0) {\n\t\t\tthis.#eventSubscriptions.delete(name);\n\t\t}\n\t}\n\n\t#dispatchActorError(error: errors.ActorError) {\n\t\t// Call all registered error handlers\n\t\tfor (const handler of [...this.#errorHandlers]) {\n\t\t\ttry {\n\t\t\t\thandler(error);\n\t\t\t} catch (err) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"error in connection error handler\",\n\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t#addEventSubscription<Args extends Array<unknown>>(\n\t\teventName: string,\n\t\tcallback: (...args: Args) => void,\n\t\tonce: boolean,\n\t): EventUnsubscribe {\n\t\tconst listener: EventSubscriptions<Args> = {\n\t\t\tcallback,\n\t\t\tonce,\n\t\t};\n\n\t\tlet subscriptionSet = this.#eventSubscriptions.get(eventName);\n\t\tif (subscriptionSet === undefined) {\n\t\t\tsubscriptionSet = new Set();\n\t\t\tthis.#eventSubscriptions.set(eventName, subscriptionSet);\n\t\t\tthis.#sendSubscription(eventName, true);\n\t\t}\n\t\tsubscriptionSet.add(listener);\n\n\t\t// Return unsubscribe function\n\t\treturn () => {\n\t\t\tconst listeners = this.#eventSubscriptions.get(eventName);\n\t\t\tif (listeners) {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t\tif (listeners.size === 0) {\n\t\t\t\t\tthis.#eventSubscriptions.delete(eventName);\n\t\t\t\t\tthis.#sendSubscription(eventName, false);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Subscribes to an event that will happen repeatedly.\n\t *\n\t * @template Args - The type of arguments the event callback will receive.\n\t * @param {string} eventName - The name of the event to subscribe to.\n\t * @param {(...args: Args) => void} callback - The callback function to execute when the event is triggered.\n\t * @returns {EventUnsubscribe} - A function to unsubscribe from the event.\n\t * @see {@link https://rivet.dev/docs/events|Events Documentation}\n\t */\n\ton<Args extends Array<unknown> = unknown[]>(\n\t\teventName: string,\n\t\tcallback: (...args: Args) => void,\n\t): EventUnsubscribe {\n\t\treturn this.#addEventSubscription<Args>(eventName, callback, false);\n\t}\n\n\t/**\n\t * Subscribes to an event that will be triggered only once.\n\t *\n\t * @template Args - The type of arguments the event callback will receive.\n\t * @param {string} eventName - The name of the event to subscribe to.\n\t * @param {(...args: Args) => void} callback - The callback function to execute when the event is triggered.\n\t * @returns {EventUnsubscribe} - A function to unsubscribe from the event.\n\t * @see {@link https://rivet.dev/docs/events|Events Documentation}\n\t */\n\tonce<Args extends Array<unknown> = unknown[]>(\n\t\teventName: string,\n\t\tcallback: (...args: Args) => void,\n\t): EventUnsubscribe {\n\t\treturn this.#addEventSubscription<Args>(eventName, callback, true);\n\t}\n\n\t/**\n\t * Subscribes to connection errors.\n\t *\n\t * @param {ActorErrorCallback} callback - The callback function to execute when a connection error occurs.\n\t * @returns {() => void} - A function to unsubscribe from the error handler.\n\t */\n\tonError(callback: ActorErrorCallback): () => void {\n\t\tthis.#errorHandlers.add(callback);\n\n\t\t// Return unsubscribe function\n\t\treturn () => {\n\t\t\tthis.#errorHandlers.delete(callback);\n\t\t};\n\t}\n\n\t#sendMessage(message: protocol.ToServer, opts?: SendHttpMessageOpts) {\n\t\tif (this.#disposed) {\n\t\t\tthrow new errors.ActorConnDisposed();\n\t\t}\n\n\t\tlet queueMessage = false;\n\t\tif (!this.#transport) {\n\t\t\t// No transport connected yet\n\t\t\tlogger().debug({ msg: \"no transport, queueing message\" });\n\t\t\tqueueMessage = true;\n\t\t} else if (\"websocket\" in this.#transport) {\n\t\t\tconst readyState = this.#transport.websocket.readyState;\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"websocket send attempt\",\n\t\t\t\treadyState,\n\t\t\t\treadyStateString:\n\t\t\t\t\treadyState === 0\n\t\t\t\t\t\t? \"CONNECTING\"\n\t\t\t\t\t\t: readyState === 1\n\t\t\t\t\t\t\t? \"OPEN\"\n\t\t\t\t\t\t\t: readyState === 2\n\t\t\t\t\t\t\t\t? \"CLOSING\"\n\t\t\t\t\t\t\t\t: \"CLOSED\",\n\t\t\t\tconnectionId: this.#connectionId,\n\t\t\t\tmessageType: (message.body as any).tag,\n\t\t\t\tactionName: (message.body as any).val?.name,\n\t\t\t});\n\t\t\tif (readyState === 1) {\n\t\t\t\ttry {\n\t\t\t\t\tconst messageSerialized = serializeWithEncoding(\n\t\t\t\t\t\tthis.#encoding,\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t\tTO_SERVER_VERSIONED,\n\t\t\t\t\t);\n\t\t\t\t\tthis.#transport.websocket.send(messageSerialized);\n\t\t\t\t\tlogger().trace({\n\t\t\t\t\t\tmsg: \"sent websocket message\",\n\t\t\t\t\t\tlen: messageLength(messageSerialized),\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger().warn({\n\t\t\t\t\t\tmsg: \"failed to send message, added to queue\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t\tconnectionId: this.#connectionId,\n\t\t\t\t\t});\n\n\t\t\t\t\t// Assuming the socket is disconnected and will be reconnected soon\n\t\t\t\t\tqueueMessage = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"websocket not open, queueing message\",\n\t\t\t\t\treadyState,\n\t\t\t\t});\n\t\t\t\tqueueMessage = true;\n\t\t\t}\n\t\t} else if (\"sse\" in this.#transport) {\n\t\t\tif (this.#transport.sse.readyState === 1) {\n\t\t\t\t// Spawn in background since #sendMessage cannot be async\n\t\t\t\tthis.#sendHttpMessage(message, opts);\n\t\t\t} else {\n\t\t\t\tqueueMessage = true;\n\t\t\t}\n\t\t} else {\n\t\t\tassertUnreachable(this.#transport);\n\t\t}\n\n\t\tif (!opts?.ephemeral && queueMessage) {\n\t\t\tthis.#messageQueue.push(message);\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"queued connection message\",\n\t\t\t\tqueueLength: this.#messageQueue.length,\n\t\t\t\tconnectionId: this.#connectionId,\n\t\t\t\tmessageType: (message.body as any).tag,\n\t\t\t\tactionName: (message.body as any).val?.name,\n\t\t\t});\n\t\t}\n\t}\n\n\tasync #sendHttpMessage(\n\t\tmessage: protocol.ToServer,\n\t\topts?: SendHttpMessageOpts,\n\t) {\n\t\ttry {\n\t\t\tif (!this.#actorId || !this.#connectionId || !this.#connectionToken)\n\t\t\t\tthrow new errors.InternalError(\n\t\t\t\t\t\"Missing connection ID or token.\",\n\t\t\t\t);\n\n\t\t\tlogger().trace(\n\t\t\t\tgetEnvUniversal(\"_RIVETKIT_LOG_MESSAGE\")\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tmsg: \"sent http message\",\n\t\t\t\t\t\t\tmessage: `${jsonStringifyCompat(message).substring(0, 100)}...`,\n\t\t\t\t\t\t}\n\t\t\t\t\t: { msg: \"sent http message\" },\n\t\t\t);\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"sending http message\",\n\t\t\t\tactorId: this.#actorId,\n\t\t\t\tconnectionId: this.#connectionId,\n\t\t\t});\n\n\t\t\t// Send an HTTP request to the connections endpoint\n\t\t\tawait sendHttpRequest({\n\t\t\t\turl: \"http://actor/connections/message\",\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t[HEADER_ENCODING]: this.#encoding,\n\t\t\t\t\t[HEADER_CONN_ID]: this.#connectionId,\n\t\t\t\t\t[HEADER_CONN_TOKEN]: this.#connectionToken,\n\t\t\t\t},\n\t\t\t\tbody: message,\n\t\t\t\tencoding: this.#encoding,\n\t\t\t\tskipParseResponse: true,\n\t\t\t\tcustomFetch: this.#driver.sendRequest.bind(\n\t\t\t\t\tthis.#driver,\n\t\t\t\t\tthis.#actorId,\n\t\t\t\t),\n\t\t\t\trequestVersionedDataHandler: TO_SERVER_VERSIONED,\n\t\t\t\tresponseVersionedDataHandler: TO_CLIENT_VERSIONED,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\t// TODO: This will not automatically trigger a re-broadcast of HTTP events since SSE is separate from the HTTP action\n\n\t\t\tlogger().warn({\n\t\t\t\tmsg: \"failed to send message, added to queue\",\n\t\t\t\terror,\n\t\t\t});\n\n\t\t\t// Assuming the socket is disconnected and will be reconnected soon\n\t\t\t//\n\t\t\t// Will attempt to resend soon\n\t\t\tif (!opts?.ephemeral) {\n\t\t\t\tthis.#messageQueue.unshift(message);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #parseMessage(data: ConnMessage): Promise<protocol.ToClient> {\n\t\tinvariant(this.#transport, \"transport must be defined\");\n\n\t\t// Decode base64 since SSE sends raw strings\n\t\tif (encodingIsBinary(this.#encoding) && \"sse\" in this.#transport) {\n\t\t\tif (typeof data === \"string\") {\n\t\t\t\tconst binaryString = atob(data);\n\t\t\t\tdata = new Uint8Array(\n\t\t\t\t\t[...binaryString].map((char) => char.charCodeAt(0)),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthrow new errors.InternalError(\n\t\t\t\t\t`Expected data to be a string for SSE, got ${data}.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst buffer = await inputDataToBuffer(data);\n\n\t\treturn deserializeWithEncoding(\n\t\t\tthis.#encoding,\n\t\t\tbuffer,\n\t\t\tTO_CLIENT_VERSIONED,\n\t\t);\n\t}\n\n\t/**\n\t * Get the actor ID (for testing purposes).\n\t * @internal\n\t */\n\tget actorId(): string | undefined {\n\t\treturn this.#actorId;\n\t}\n\n\t/**\n\t * Get the connection ID (for testing purposes).\n\t * @internal\n\t */\n\tget connectionId(): string | undefined {\n\t\treturn this.#connectionId;\n\t}\n\n\t/**\n\t * Disconnects from the actor.\n\t *\n\t * @returns {Promise<void>} A promise that resolves when the socket is gracefully closed.\n\t */\n\tasync dispose(): Promise<void> {\n\t\t// Internally, this \"disposes\" the connection\n\n\t\tif (this.#disposed) {\n\t\t\tlogger().warn({ msg: \"connection already disconnected\" });\n\t\t\treturn;\n\t\t}\n\t\tthis.#disposed = true;\n\n\t\tlogger().debug({ msg: \"disposing actor conn\" });\n\n\t\t// Clear interval so NodeJS process can exit\n\t\tclearInterval(this.#keepNodeAliveInterval);\n\n\t\t// Abort\n\t\tthis.#abortController.abort();\n\n\t\t// Remove from registry\n\t\tthis.#client[ACTOR_CONNS_SYMBOL].delete(this);\n\n\t\t// Disconnect transport cleanly\n\t\tif (!this.#transport) {\n\t\t\t// Nothing to do\n\t\t} else if (\"websocket\" in this.#transport) {\n\t\t\tlogger().debug(\"closing ws\");\n\n\t\t\tconst ws = this.#transport.websocket;\n\t\t\t// Check if WebSocket is already closed or closing\n\t\t\tif (\n\t\t\t\tws.readyState === 2 /* CLOSING */ ||\n\t\t\t\tws.readyState === 3 /* CLOSED */\n\t\t\t) {\n\t\t\t\tlogger().debug({ msg: \"ws already closed or closing\" });\n\t\t\t} else {\n\t\t\t\tconst { promise, resolve } = promiseWithResolvers();\n\t\t\t\tws.addEventListener(\"close\", () => {\n\t\t\t\t\tlogger().debug({ msg: \"ws closed\" });\n\t\t\t\t\tresolve(undefined);\n\t\t\t\t});\n\t\t\t\tws.close(1000, \"Normal closure\");\n\t\t\t\tawait promise;\n\t\t\t}\n\t\t} else if (\"sse\" in this.#transport) {\n\t\t\tlogger().debug(\"closing sse\");\n\n\t\t\t// Send close request to server for SSE connections\n\t\t\tif (this.#connectionId && this.#connectionToken) {\n\t\t\t\ttry {\n\t\t\t\t\tawait sendHttpRequest({\n\t\t\t\t\t\turl: \"http://actor/connections/close\",\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t[HEADER_CONN_ID]: this.#connectionId,\n\t\t\t\t\t\t\t[HEADER_CONN_TOKEN]: this.#connectionToken,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tencoding: this.#encoding,\n\t\t\t\t\t\tskipParseResponse: true,\n\t\t\t\t\t\tcustomFetch: this.#driver.sendRequest.bind(\n\t\t\t\t\t\t\tthis.#driver,\n\t\t\t\t\t\t\tthis.#actorId!,\n\t\t\t\t\t\t),\n\t\t\t\t\t\trequestVersionedDataHandler: TO_SERVER_VERSIONED,\n\t\t\t\t\t\tresponseVersionedDataHandler: TO_CLIENT_VERSIONED,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Ignore errors when closing - connection may already be closed\n\t\t\t\t\tlogger().warn({\n\t\t\t\t\t\tmsg: \"failed to send close request\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.#transport.sse.close();\n\t\t} else {\n\t\t\tassertUnreachable(this.#transport);\n\t\t}\n\t\tthis.#transport = undefined;\n\t}\n\n\t#sendSubscription(eventName: string, subscribe: boolean) {\n\t\tthis.#sendMessage(\n\t\t\t{\n\t\t\t\tbody: {\n\t\t\t\t\ttag: \"SubscriptionRequest\",\n\t\t\t\t\tval: {\n\t\t\t\t\t\teventName,\n\t\t\t\t\t\tsubscribe,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ ephemeral: true },\n\t\t);\n\t}\n}\n\n/**\n * Connection to a actor. Allows calling actor's remote procedure calls with inferred types. See {@link ActorConnRaw} for underlying methods.\n *\n * @example\n * ```\n * const room = client.connect<ChatRoom>(...etc...);\n * // This calls the action named `sendMessage` on the `ChatRoom` actor.\n * await room.sendMessage('Hello, world!');\n * ```\n *\n * Private methods (e.g. those starting with `_`) are automatically excluded.\n *\n * @template AD The actor class that this connection is for.\n * @see {@link ActorConnRaw}\n */\nexport type ActorConn<AD extends AnyActorDefinition> = ActorConnRaw &\n\tActorDefinitionActions<AD>;\n","import type { EventSource } from \"eventsource\";\nimport { logger } from \"@/client/log\";\n\n// Global singleton promise that will be reused for subsequent calls\nlet eventSourcePromise: Promise<typeof EventSource> | null = null;\n\nexport async function importEventSource(): Promise<typeof EventSource> {\n\t// IMPORTANT: Import `eventsource` from the custom `eventsource` library. We need a custom implementation\n\t// since we need to attach our own custom headers to the request.\n\t//\n\t// We can't use the browser-provided EventSource since it does not allow providing custom headers.\n\n\t// Return existing promise if we already started loading\n\tif (eventSourcePromise !== null) {\n\t\treturn eventSourcePromise;\n\t}\n\n\t// Create and store the promise\n\teventSourcePromise = (async () => {\n\t\tlet _EventSource: typeof EventSource;\n\n\t\t// Node.js environment\n\t\ttry {\n\t\t\tconst moduleName = \"eventsource\";\n\t\t\tconst es = await import(/* webpackIgnore: true */ moduleName);\n\t\t\t_EventSource = es.EventSource;\n\t\t\tlogger().debug(\"using eventsource from npm\");\n\t\t} catch (err) {\n\t\t\t// EventSource not available\n\t\t\t_EventSource = class MockEventSource {\n\t\t\t\tconstructor() {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'EventSource support requires installing the \"eventsource\" peer dependency.',\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} as unknown as typeof EventSource;\n\t\t\tlogger().debug(\"using mock eventsource\");\n\t\t}\n\n\t\treturn _EventSource;\n\t})();\n\n\treturn eventSourcePromise;\n}\n","import type { Context as HonoContext } from \"hono\";\nimport * as errors from \"@/actor/errors\";\nimport type { ManagerDriver } from \"@/driver-helpers/mod\";\nimport type { ActorQuery } from \"@/manager/protocol/query\";\nimport { logger } from \"./log\";\n\n/**\n * Query the manager driver to get or create a actor based on the provided query\n */\nexport async function queryActor(\n\tc: HonoContext | undefined,\n\tquery: ActorQuery,\n\tmanagerDriver: ManagerDriver,\n): Promise<{ actorId: string }> {\n\tlogger().debug({ msg: \"querying actor\", query: JSON.stringify(query) });\n\tlet actorOutput: { actorId: string };\n\tif (\"getForId\" in query) {\n\t\tconst output = await managerDriver.getForId({\n\t\t\tc,\n\t\t\tname: query.getForId.name,\n\t\t\tactorId: query.getForId.actorId,\n\t\t});\n\t\tif (!output) throw new errors.ActorNotFound(query.getForId.actorId);\n\t\tactorOutput = output;\n\t} else if (\"getForKey\" in query) {\n\t\tconst existingActor = await managerDriver.getWithKey({\n\t\t\tc,\n\t\t\tname: query.getForKey.name,\n\t\t\tkey: query.getForKey.key,\n\t\t});\n\t\tif (!existingActor) {\n\t\t\tthrow new errors.ActorNotFound(\n\t\t\t\t`${query.getForKey.name}:${JSON.stringify(query.getForKey.key)}`,\n\t\t\t);\n\t\t}\n\t\tactorOutput = existingActor;\n\t} else if (\"getOrCreateForKey\" in query) {\n\t\tconst getOrCreateOutput = await managerDriver.getOrCreateWithKey({\n\t\t\tc,\n\t\t\tname: query.getOrCreateForKey.name,\n\t\t\tkey: query.getOrCreateForKey.key,\n\t\t\tinput: query.getOrCreateForKey.input,\n\t\t\tregion: query.getOrCreateForKey.region,\n\t\t});\n\t\tactorOutput = {\n\t\t\tactorId: getOrCreateOutput.actorId,\n\t\t};\n\t} else if (\"create\" in query) {\n\t\tconst createOutput = await managerDriver.createActor({\n\t\t\tc,\n\t\t\tname: query.create.name,\n\t\t\tkey: query.create.key,\n\t\t\tinput: query.create.input,\n\t\t\tregion: query.create.region,\n\t\t});\n\t\tactorOutput = {\n\t\t\tactorId: createOutput.actorId,\n\t\t};\n\t} else {\n\t\tthrow new errors.InvalidRequest(\"Invalid query format\");\n\t}\n\n\tlogger().debug({ msg: \"actor query result\", actorId: actorOutput.actorId });\n\treturn { actorId: actorOutput.actorId };\n}\n","import * as cbor from \"cbor-x\";\nimport invariant from \"invariant\";\nimport type { AnyActorDefinition } from \"@/actor/definition\";\nimport type { Encoding } from \"@/actor/protocol/serde\";\nimport { assertUnreachable } from \"@/actor/utils\";\nimport { deconstructError } from \"@/common/utils\";\nimport {\n\tHEADER_CONN_PARAMS,\n\tHEADER_ENCODING,\n\ttype ManagerDriver,\n} from \"@/driver-helpers/mod\";\nimport type { ActorQuery } from \"@/manager/protocol/query\";\nimport type * as protocol from \"@/schemas/client-protocol/mod\";\nimport {\n\tHTTP_ACTION_REQUEST_VERSIONED,\n\tHTTP_ACTION_RESPONSE_VERSIONED,\n} from \"@/schemas/client-protocol/versioned\";\nimport { bufferToArrayBuffer } from \"@/utils\";\nimport type { ActorDefinitionActions } from \"./actor-common\";\nimport { type ActorConn, ActorConnRaw } from \"./actor-conn\";\nimport { queryActor } from \"./actor-query\";\nimport { type ClientRaw, CREATE_ACTOR_CONN_PROXY } from \"./client\";\nimport { ActorError } from \"./errors\";\nimport { logger } from \"./log\";\nimport { rawHttpFetch, rawWebSocket } from \"./raw-utils\";\nimport { sendHttpRequest } from \"./utils\";\n\n/**\n * Provides underlying functions for stateless {@link ActorHandle} for action calls.\n * Similar to ActorConnRaw but doesn't maintain a connection.\n *\n * @see {@link ActorHandle}\n */\nexport class ActorHandleRaw {\n\t#client: ClientRaw;\n\t#driver: ManagerDriver;\n\t#encoding: Encoding;\n\t#actorQuery: ActorQuery;\n\t#params: unknown;\n\n\t/**\n\t * Do not call this directly.\n\t *\n\t * Creates an instance of ActorHandleRaw.\n\t *\n\t * @protected\n\t */\n\tpublic constructor(\n\t\tclient: any,\n\t\tdriver: ManagerDriver,\n\t\tparams: unknown,\n\t\tencoding: Encoding,\n\t\tactorQuery: ActorQuery,\n\t) {\n\t\tthis.#client = client;\n\t\tthis.#driver = driver;\n\t\tthis.#encoding = encoding;\n\t\tthis.#actorQuery = actorQuery;\n\t\tthis.#params = params;\n\t}\n\n\t/**\n\t * Call a raw action. This method sends an HTTP request to invoke the named action.\n\t *\n\t * @see {@link ActorHandle}\n\t * @template Args - The type of arguments to pass to the action function.\n\t * @template Response - The type of the response returned by the action function.\n\t */\n\tasync action<\n\t\tArgs extends Array<unknown> = unknown[],\n\t\tResponse = unknown,\n\t>(opts: {\n\t\tname: string;\n\t\targs: Args;\n\t\tsignal?: AbortSignal;\n\t}): Promise<Response> {\n\t\t// return await this.#driver.action<Args, Response>(\n\t\t// \tundefined,\n\t\t// \tthis.#actorQuery,\n\t\t// \tthis.#encodingKind,\n\t\t// \tthis.#params,\n\t\t// \topts.name,\n\t\t// \topts.args,\n\t\t// \t{ signal: opts.signal },\n\t\t// );\n\t\ttry {\n\t\t\t// Get the actor ID\n\t\t\tconst { actorId } = await queryActor(\n\t\t\t\tundefined,\n\t\t\t\tthis.#actorQuery,\n\t\t\t\tthis.#driver,\n\t\t\t);\n\t\t\tlogger().debug({ msg: \"found actor for action\", actorId });\n\t\t\tinvariant(actorId, \"Missing actor ID\");\n\n\t\t\t// Invoke the action\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"handling action\",\n\t\t\t\tname: opts.name,\n\t\t\t\tencoding: this.#encoding,\n\t\t\t});\n\t\t\tconst responseData = await sendHttpRequest<\n\t\t\t\tprotocol.HttpActionRequest,\n\t\t\t\tprotocol.HttpActionResponse\n\t\t\t>({\n\t\t\t\turl: `http://actor/action/${encodeURIComponent(opts.name)}`,\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t[HEADER_ENCODING]: this.#encoding,\n\t\t\t\t\t...(this.#params !== undefined\n\t\t\t\t\t\t? { [HEADER_CONN_PARAMS]: JSON.stringify(this.#params) }\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t\tbody: {\n\t\t\t\t\targs: bufferToArrayBuffer(cbor.encode(opts.args)),\n\t\t\t\t} satisfies protocol.HttpActionRequest,\n\t\t\t\tencoding: this.#encoding,\n\t\t\t\tcustomFetch: this.#driver.sendRequest.bind(\n\t\t\t\t\tthis.#driver,\n\t\t\t\t\tactorId,\n\t\t\t\t),\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\trequestVersionedDataHandler: HTTP_ACTION_REQUEST_VERSIONED,\n\t\t\t\tresponseVersionedDataHandler: HTTP_ACTION_RESPONSE_VERSIONED,\n\t\t\t});\n\n\t\t\treturn cbor.decode(new Uint8Array(responseData.output));\n\t\t} catch (err) {\n\t\t\t// Standardize to ClientActorError instead of the native backend error\n\t\t\tconst { group, code, message, metadata } = deconstructError(\n\t\t\t\terr,\n\t\t\t\tlogger(),\n\t\t\t\t{},\n\t\t\t\ttrue,\n\t\t\t);\n\t\t\tthrow new ActorError(group, code, message, metadata);\n\t\t}\n\t}\n\n\t/**\n\t * Establishes a persistent connection to the actor.\n\t *\n\t * @template AD The actor class that this connection is for.\n\t * @returns {ActorConn<AD>} A connection to the actor.\n\t */\n\tconnect(): ActorConn<AnyActorDefinition> {\n\t\tlogger().debug({\n\t\t\tmsg: \"establishing connection from handle\",\n\t\t\tquery: this.#actorQuery,\n\t\t});\n\n\t\tconst conn = new ActorConnRaw(\n\t\t\tthis.#client,\n\t\t\tthis.#driver,\n\t\t\tthis.#params,\n\t\t\tthis.#encoding,\n\t\t\tthis.#actorQuery,\n\t\t);\n\n\t\treturn this.#client[CREATE_ACTOR_CONN_PROXY](\n\t\t\tconn,\n\t\t) as ActorConn<AnyActorDefinition>;\n\t}\n\n\t/**\n\t * Makes a raw HTTP request to the actor.\n\t *\n\t * @param input - The URL, path, or Request object\n\t * @param init - Standard fetch RequestInit options\n\t * @returns Promise<Response> - The raw HTTP response\n\t */\n\tasync fetch(\n\t\tinput: string | URL | Request,\n\t\tinit?: RequestInit,\n\t): Promise<Response> {\n\t\treturn rawHttpFetch(\n\t\t\tthis.#driver,\n\t\t\tthis.#actorQuery,\n\t\t\tthis.#params,\n\t\t\tinput,\n\t\t\tinit,\n\t\t);\n\t}\n\n\t/**\n\t * Creates a raw WebSocket connection to the actor.\n\t *\n\t * @param path - The path for the WebSocket connection (e.g., \"stream\")\n\t * @param protocols - Optional WebSocket subprotocols\n\t * @returns WebSocket - A raw WebSocket connection\n\t */\n\tasync websocket(\n\t\tpath?: string,\n\t\tprotocols?: string | string[],\n\t): Promise<WebSocket> {\n\t\treturn rawWebSocket(\n\t\t\tthis.#driver,\n\t\t\tthis.#actorQuery,\n\t\t\tthis.#params,\n\t\t\tpath,\n\t\t\tprotocols,\n\t\t);\n\t}\n\n\t/**\n\t * Resolves the actor to get its unique actor ID\n\t *\n\t * @returns {Promise<string>} - A promise that resolves to the actor's ID\n\t */\n\tasync resolve({ signal }: { signal?: AbortSignal } = {}): Promise<string> {\n\t\tif (\n\t\t\t\"getForKey\" in this.#actorQuery ||\n\t\t\t\"getOrCreateForKey\" in this.#actorQuery\n\t\t) {\n\t\t\t// TODO:\n\t\t\tlet name: string;\n\t\t\tif (\"getForKey\" in this.#actorQuery) {\n\t\t\t\tname = this.#actorQuery.getForKey.name;\n\t\t\t} else if (\"getOrCreateForKey\" in this.#actorQuery) {\n\t\t\t\tname = this.#actorQuery.getOrCreateForKey.name;\n\t\t\t} else {\n\t\t\t\tassertUnreachable(this.#actorQuery);\n\t\t\t}\n\n\t\t\tconst { actorId } = await queryActor(\n\t\t\t\tundefined,\n\t\t\t\tthis.#actorQuery,\n\t\t\t\tthis.#driver,\n\t\t\t);\n\n\t\t\tthis.#actorQuery = { getForId: { actorId, name } };\n\n\t\t\treturn actorId;\n\t\t} else if (\"getForId\" in this.#actorQuery) {\n\t\t\t// SKip since it's already resolved\n\t\t\treturn this.#actorQuery.getForId.actorId;\n\t\t} else if (\"create\" in this.#actorQuery) {\n\t\t\t// Cannot create a handle with this query\n\t\t\tinvariant(false, \"actorQuery cannot be create\");\n\t\t} else {\n\t\t\tassertUnreachable(this.#actorQuery);\n\t\t}\n\t}\n}\n\n/**\n * Stateless handle to a actor. Allows calling actor's remote procedure calls with inferred types\n * without establishing a persistent connection.\n *\n * @example\n * ```\n * const room = client.get<ChatRoom>(...etc...);\n * // This calls the action named `sendMessage` on the `ChatRoom` actor without a connection.\n * await room.sendMessage('Hello, world!');\n * ```\n *\n * Private methods (e.g. those starting with `_`) are automatically excluded.\n *\n * @template AD The actor class that this handle is for.\n * @see {@link ActorHandleRaw}\n */\nexport type ActorHandle<AD extends AnyActorDefinition> = Omit<\n\tActorHandleRaw,\n\t\"connect\"\n> & {\n\t// Add typed version of ActorConn (instead of using AnyActorDefinition)\n\tconnect(): ActorConn<AD>;\n\t// Resolve method returns the actor ID\n\tresolve(): Promise<string>;\n} & ActorDefinitionActions<AD>;\n","import invariant from \"invariant\";\nimport { PATH_RAW_WEBSOCKET_PREFIX } from \"@/common/actor-router-consts\";\nimport { deconstructError } from \"@/common/utils\";\nimport { HEADER_CONN_PARAMS, type ManagerDriver } from \"@/driver-helpers/mod\";\nimport type { ActorQuery } from \"@/manager/protocol/query\";\nimport { queryActor } from \"./actor-query\";\nimport { ActorError } from \"./errors\";\nimport { logger } from \"./log\";\n\n/**\n * Shared implementation for raw HTTP fetch requests\n */\nexport async function rawHttpFetch(\n\tdriver: ManagerDriver,\n\tactorQuery: ActorQuery,\n\tparams: unknown,\n\tinput: string | URL | Request,\n\tinit?: RequestInit,\n): Promise<Response> {\n\t// Extract path and merge init options\n\tlet path: string;\n\tlet mergedInit: RequestInit = init || {};\n\n\tif (typeof input === \"string\") {\n\t\tpath = input;\n\t} else if (input instanceof URL) {\n\t\tpath = input.pathname + input.search;\n\t} else if (input instanceof Request) {\n\t\t// Extract path from Request URL\n\t\tconst url = new URL(input.url);\n\t\tpath = url.pathname + url.search;\n\t\t// Merge Request properties with init\n\t\tconst requestHeaders = new Headers(input.headers);\n\t\tconst initHeaders = new Headers(init?.headers || {});\n\n\t\t// Merge headers - init headers override request headers\n\t\tconst mergedHeaders = new Headers(requestHeaders);\n\t\tfor (const [key, value] of initHeaders) {\n\t\t\tmergedHeaders.set(key, value);\n\t\t}\n\n\t\tmergedInit = {\n\t\t\tmethod: input.method,\n\t\t\tbody: input.body,\n\t\t\tmode: input.mode,\n\t\t\tcredentials: input.credentials,\n\t\t\tredirect: input.redirect,\n\t\t\treferrer: input.referrer,\n\t\t\treferrerPolicy: input.referrerPolicy,\n\t\t\tintegrity: input.integrity,\n\t\t\tkeepalive: input.keepalive,\n\t\t\tsignal: input.signal,\n\t\t\t...mergedInit, // init overrides Request properties\n\t\t\theaders: mergedHeaders, // headers must be set after spread to ensure proper merge\n\t\t};\n\t\t// Add duplex if body is present\n\t\tif (mergedInit.body) {\n\t\t\t(mergedInit as any).duplex = \"half\";\n\t\t}\n\t} else {\n\t\tthrow new TypeError(\"Invalid input type for fetch\");\n\t}\n\n\ttry {\n\t\t// Get the actor ID\n\t\tconst { actorId } = await queryActor(undefined, actorQuery, driver);\n\t\tlogger().debug({ msg: \"found actor for raw http\", actorId });\n\t\tinvariant(actorId, \"Missing actor ID\");\n\n\t\t// Build the URL with normalized path\n\t\tconst normalizedPath = path.startsWith(\"/\") ? path.slice(1) : path;\n\t\tconst url = new URL(`http://actor/raw/http/${normalizedPath}`);\n\n\t\t// Forward conn params if provided\n\t\tconst proxyRequestHeaders = new Headers(mergedInit.headers);\n\t\tif (params) {\n\t\t\tproxyRequestHeaders.set(HEADER_CONN_PARAMS, JSON.stringify(params));\n\t\t}\n\n\t\t// Forward the request to the actor\n\t\tconst proxyRequest = new Request(url, {\n\t\t\t...mergedInit,\n\t\t\theaders: proxyRequestHeaders,\n\t\t});\n\n\t\treturn driver.sendRequest(actorId, proxyRequest);\n\t} catch (err) {\n\t\t// Standardize to ClientActorError instead of the native backend error\n\t\tconst { group, code, message, metadata } = deconstructError(\n\t\t\terr,\n\t\t\tlogger(),\n\t\t\t{},\n\t\t\ttrue,\n\t\t);\n\t\tthrow new ActorError(group, code, message, metadata);\n\t}\n}\n\n/**\n * Shared implementation for raw WebSocket connections\n */\nexport async function rawWebSocket(\n\tdriver: ManagerDriver,\n\tactorQuery: ActorQuery,\n\tparams: unknown,\n\tpath?: string,\n\t// TODO: Supportp rotocols\n\tprotocols?: string | string[],\n): Promise<any> {\n\t// TODO: Do we need encoding in rawWebSocket?\n\tconst encoding = \"bare\";\n\n\t// Get the actor ID\n\tconst { actorId } = await queryActor(undefined, actorQuery, driver);\n\tlogger().debug({ msg: \"found actor for action\", actorId });\n\tinvariant(actorId, \"Missing actor ID\");\n\n\t// Parse path and query parameters\n\tlet pathPortion = \"\";\n\tlet queryPortion = \"\";\n\tif (path) {\n\t\tconst queryIndex = path.indexOf(\"?\");\n\t\tif (queryIndex !== -1) {\n\t\t\tpathPortion = path.substring(0, queryIndex);\n\t\t\tqueryPortion = path.substring(queryIndex); // includes the '?'\n\t\t} else {\n\t\t\tpathPortion = path;\n\t\t}\n\t\t// Remove leading slash if present\n\t\tif (pathPortion.startsWith(\"/\")) {\n\t\t\tpathPortion = pathPortion.slice(1);\n\t\t}\n\t}\n\n\tconst fullPath = `${PATH_RAW_WEBSOCKET_PREFIX}${pathPortion}${queryPortion}`;\n\n\tlogger().debug({\n\t\tmsg: \"opening websocket\",\n\t\tactorId,\n\t\tencoding,\n\t\tpath: fullPath,\n\t});\n\n\t// Open WebSocket\n\tconst ws = await driver.openWebSocket(fullPath, actorId, encoding, params);\n\n\t// Node & browser WebSocket types are incompatible\n\treturn ws as any;\n}\n","import * as cbor from \"cbor-x\";\nimport invariant from \"invariant\";\nimport type { Encoding } from \"@/actor/protocol/serde\";\nimport { assertUnreachable } from \"@/common/utils\";\nimport type { VersionedDataHandler } from \"@/common/versioned-data\";\nimport type { HttpResponseError } from \"@/schemas/client-protocol/mod\";\nimport { HTTP_RESPONSE_ERROR_VERSIONED } from \"@/schemas/client-protocol/versioned\";\nimport {\n\tcontentTypeForEncoding,\n\tdeserializeWithEncoding,\n\tencodingIsBinary,\n\tserializeWithEncoding,\n} from \"@/serde\";\nimport { httpUserAgent } from \"@/utils\";\nimport { ActorError, HttpRequestError } from \"./errors\";\nimport { logger } from \"./log\";\n\nexport type WebSocketMessage = string | Blob | ArrayBuffer | Uint8Array;\n\nexport function messageLength(message: WebSocketMessage): number {\n\tif (message instanceof Blob) {\n\t\treturn message.size;\n\t}\n\tif (message instanceof ArrayBuffer) {\n\t\treturn message.byteLength;\n\t}\n\tif (message instanceof Uint8Array) {\n\t\treturn message.byteLength;\n\t}\n\tif (typeof message === \"string\") {\n\t\treturn message.length;\n\t}\n\tassertUnreachable(message);\n}\n\nexport interface HttpRequestOpts<RequestBody, ResponseBody> {\n\tmethod: string;\n\turl: string;\n\theaders: Record<string, string>;\n\tbody?: RequestBody;\n\tencoding: Encoding;\n\tskipParseResponse?: boolean;\n\tsignal?: AbortSignal;\n\tcustomFetch?: (req: Request) => Promise<Response>;\n\trequestVersionedDataHandler: VersionedDataHandler<RequestBody> | undefined;\n\tresponseVersionedDataHandler:\n\t\t| VersionedDataHandler<ResponseBody>\n\t\t| undefined;\n}\n\nexport async function sendHttpRequest<\n\tRequestBody = unknown,\n\tResponseBody = unknown,\n>(opts: HttpRequestOpts<RequestBody, ResponseBody>): Promise<ResponseBody> {\n\tlogger().debug({\n\t\tmsg: \"sending http request\",\n\t\turl: opts.url,\n\t\tencoding: opts.encoding,\n\t});\n\n\t// Serialize body\n\tlet contentType: string | undefined;\n\tlet bodyData: string | Uint8Array | undefined;\n\tif (opts.method === \"POST\" || opts.method === \"PUT\") {\n\t\tinvariant(opts.body !== undefined, \"missing body\");\n\t\tcontentType = contentTypeForEncoding(opts.encoding);\n\t\tbodyData = serializeWithEncoding<RequestBody>(\n\t\t\topts.encoding,\n\t\t\topts.body,\n\t\t\topts.requestVersionedDataHandler,\n\t\t);\n\t}\n\n\t// Send request\n\tlet response: Response;\n\ttry {\n\t\t// Make the HTTP request\n\t\tresponse = await (opts.customFetch ?? fetch)(\n\t\t\tnew Request(opts.url, {\n\t\t\t\tmethod: opts.method,\n\t\t\t\theaders: {\n\t\t\t\t\t...opts.headers,\n\t\t\t\t\t...(contentType\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\"Content-Type\": contentType,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t\"User-Agent\": httpUserAgent(),\n\t\t\t\t},\n\t\t\t\tbody: bodyData,\n\t\t\t\tcredentials: \"include\",\n\t\t\t\tsignal: opts.signal,\n\t\t\t}),\n\t\t);\n\t} catch (error) {\n\t\tthrow new HttpRequestError(`Request failed: ${error}`, {\n\t\t\tcause: error,\n\t\t});\n\t}\n\n\t// Parse response error\n\tif (!response.ok) {\n\t\t// Attempt to parse structured data\n\t\tconst bufferResponse = await response.arrayBuffer();\n\t\tlet responseData: HttpResponseError;\n\t\ttry {\n\t\t\tresponseData = deserializeWithEncoding(\n\t\t\t\topts.encoding,\n\t\t\t\tnew Uint8Array(bufferResponse),\n\t\t\t\tHTTP_RESPONSE_ERROR_VERSIONED,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t//logger().warn(\"failed to cleanly parse error, this is likely because a non-structured response is being served\", {\n\t\t\t//\terror: stringifyError(error),\n\t\t\t//});\n\n\t\t\t// Error is not structured\n\t\t\tconst textResponse = new TextDecoder(\"utf-8\", {\n\t\t\t\tfatal: false,\n\t\t\t}).decode(bufferResponse);\n\n\t\t\tconst rayId = response.headers.get(\"x-rivet-ray-id\");\n\n\t\t\tif (rayId) {\n\t\t\t\tthrow new HttpRequestError(\n\t\t\t\t\t`${response.statusText} (${response.status}) (Ray ID: ${rayId}):\\n${textResponse}`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthrow new HttpRequestError(\n\t\t\t\t\t`${response.statusText} (${response.status}):\\n${textResponse}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Decode metadata based on encoding - only binary encodings have CBOR-encoded metadata\n\t\tlet decodedMetadata: unknown;\n\t\tif (responseData.metadata && encodingIsBinary(opts.encoding)) {\n\t\t\tdecodedMetadata = cbor.decode(\n\t\t\t\tnew Uint8Array(responseData.metadata),\n\t\t\t);\n\t\t}\n\n\t\t// Throw structured error\n\t\tthrow new ActorError(\n\t\t\tresponseData.group,\n\t\t\tresponseData.code,\n\t\t\tresponseData.message,\n\t\t\tdecodedMetadata,\n\t\t);\n\t}\n\n\t// Some requests don't need the success response to be parsed, so this can speed things up\n\tif (opts.skipParseResponse) {\n\t\treturn undefined as ResponseBody;\n\t}\n\n\t// Parse the response based on encoding\n\ttry {\n\t\tconst buffer = new Uint8Array(await response.arrayBuffer());\n\t\treturn deserializeWithEncoding(\n\t\t\topts.encoding,\n\t\t\tbuffer,\n\t\t\topts.responseVersionedDataHandler,\n\t\t);\n\t} catch (error) {\n\t\tthrow new HttpRequestError(`Failed to parse response: ${error}`, {\n\t\t\tcause: error,\n\t\t});\n\t}\n}\n","import type { AnyActorDefinition } from \"@/actor/definition\";\nimport type { Transport } from \"@/actor/protocol/old\";\nimport type { Encoding } from \"@/actor/protocol/serde\";\nimport type { ManagerDriver } from \"@/driver-helpers/mod\";\nimport type { ActorQuery } from \"@/manager/protocol/query\";\nimport type { Registry } from \"@/registry/mod\";\nimport type { ActorActionFunction } from \"./actor-common\";\nimport {\n\ttype ActorConn,\n\ttype ActorConnRaw,\n\tCONNECT_SYMBOL,\n} from \"./actor-conn\";\nimport { type ActorHandle, ActorHandleRaw } from \"./actor-handle\";\nimport { queryActor } from \"./actor-query\";\nimport type { ClientConfig } from \"./config\";\nimport { logger } from \"./log\";\n\nexport type { ClientConfig, ClientConfigInput } from \"./config\";\n\n/** Extract the actor registry from the registry definition. */\nexport type ExtractActorsFromRegistry<A extends Registry<any>> =\n\tA extends Registry<infer Actors> ? Actors : never;\n\n/** Extract the registry definition from the client. */\nexport type ExtractRegistryFromClient<C extends Client<Registry<{}>>> =\n\tC extends Client<infer A> ? A : never;\n\n/**\n * Represents a actor accessor that provides methods to interact with a specific actor.\n */\nexport interface ActorAccessor<AD extends AnyActorDefinition> {\n\t/**\n\t * Gets a stateless handle to a actor by its key, but does not create the actor if it doesn't exist.\n\t * The actor name is automatically injected from the property accessor.\n\t *\n\t * @template AD The actor class that this handle is for.\n\t * @param {string | string[]} [key=[]] - The key to identify the actor. Can be a single string or an array of strings.\n\t * @param {GetWithIdOptions} [opts] - Options for getting the actor.\n\t * @returns {ActorHandle<AD>} - A handle to the actor.\n\t */\n\tget(key?: string | string[], opts?: GetWithIdOptions): ActorHandle<AD>;\n\n\t/**\n\t * Gets a stateless handle to a actor by its key, creating it if necessary.\n\t * The actor name is automatically injected from the property accessor.\n\t *\n\t * @template AD The actor class that this handle is for.\n\t * @param {string | string[]} [key=[]] - The key to identify the actor. Can be a single string or an array of strings.\n\t * @param {GetOptions} [opts] - Options for getting the actor.\n\t * @returns {ActorHandle<AD>} - A handle to the actor.\n\t */\n\tgetOrCreate(\n\t\tkey?: string | string[],\n\t\topts?: GetOrCreateOptions,\n\t): ActorHandle<AD>;\n\n\t/**\n\t * Gets a stateless handle to a actor by its ID.\n\t *\n\t * @template AD The actor class that this handle is for.\n\t * @param {string} actorId - The ID of the actor.\n\t * @param {GetWithIdOptions} [opts] - Options for getting the actor.\n\t * @returns {ActorHandle<AD>} - A handle to the actor.\n\t */\n\tgetForId(actorId: string, opts?: GetWithIdOptions): ActorHandle<AD>;\n\n\t/**\n\t * Creates a new actor with the name automatically injected from the property accessor,\n\t * and returns a stateless handle to it with the actor ID resolved.\n\t *\n\t * @template AD The actor class that this handle is for.\n\t * @param {string | string[]} key - The key to identify the actor. Can be a single string or an array of strings.\n\t * @param {CreateOptions} [opts] - Options for creating the actor (excluding name and key).\n\t * @returns {Promise<ActorHandle<AD>>} - A promise that resolves to a handle to the actor.\n\t */\n\tcreate(\n\t\tkey?: string | string[],\n\t\topts?: CreateOptions,\n\t): Promise<ActorHandle<AD>>;\n}\n\n/**\n * Options for querying actors.\n * @typedef {Object} QueryOptions\n * @property {unknown} [parameters] - Parameters to pass to the connection.\n */\nexport interface QueryOptions {\n\t/** Parameters to pass to the connection. */\n\tparams?: unknown;\n\t/** Signal to abort the request. */\n\tsignal?: AbortSignal;\n}\n\n/**\n * Options for getting a actor by ID.\n * @typedef {QueryOptions} GetWithIdOptions\n */\nexport interface GetWithIdOptions extends QueryOptions {}\n\n/**\n * Options for getting a actor.\n * @typedef {QueryOptions} GetOptions\n */\nexport interface GetOptions extends QueryOptions {}\n\n/**\n * Options for getting or creating a actor.\n * @typedef {QueryOptions} GetOrCreateOptions\n * @property {string} [createInRegion] - Region to create the actor in if it doesn't exist.\n */\nexport interface GetOrCreateOptions extends QueryOptions {\n\t/** Region to create the actor in if it doesn't exist. */\n\tcreateInRegion?: string;\n\t/** Input data to pass to the actor. */\n\tcreateWithInput?: unknown;\n}\n\n/**\n * Options for creating a actor.\n * @typedef {QueryOptions} CreateOptions\n * @property {string} [region] - The region to create the actor in.\n */\nexport interface CreateOptions extends QueryOptions {\n\t/** The region to create the actor in. */\n\tregion?: string;\n\t/** Input data to pass to the actor. */\n\tinput?: unknown;\n}\n\n/**\n * Represents a region to connect to.\n * @typedef {Object} Region\n * @property {string} id - The region ID.\n * @property {string} name - The region name.\n * @see {@link https://rivet.dev/docs/edge|Edge Networking}\n * @see {@link https://rivet.dev/docs/regions|Available Regions}\n */\nexport interface Region {\n\t/**\n\t * The region slug.\n\t */\n\tid: string;\n\n\t/**\n\t * The human-friendly region name.\n\t */\n\tname: string;\n}\n\nexport const ACTOR_CONNS_SYMBOL = Symbol(\"actorConns\");\nexport const CREATE_ACTOR_CONN_PROXY = Symbol(\"createActorConnProxy\");\nexport const TRANSPORT_SYMBOL = Symbol(\"transport\");\n\n/**\n * Client for managing & connecting to actors.\n *\n * @template A The actors map type that defines the available actors.\n * @see {@link https://rivet.dev/docs/manage|Create & Manage Actors}\n */\nexport class ClientRaw {\n\t#disposed = false;\n\n\t[ACTOR_CONNS_SYMBOL] = new Set<ActorConnRaw>();\n\n\t#driver: ManagerDriver;\n\t#encodingKind: Encoding;\n\t[TRANSPORT_SYMBOL]: Transport;\n\n\t/**\n\t * Creates an instance of Client.\n\t */\n\tpublic constructor(driver: ManagerDriver, config: ClientConfig) {\n\t\tthis.#driver = driver;\n\n\t\tthis.#encodingKind = config.encoding ?? \"bare\";\n\t\tthis[TRANSPORT_SYMBOL] = config.transport ?? \"websocket\";\n\t}\n\n\t/**\n\t * Gets a stateless handle to a actor by its ID.\n\t *\n\t * @template AD The actor class that this handle is for.\n\t * @param {string} name - The name of the actor.\n\t * @param {string} actorId - The ID of the actor.\n\t * @param {GetWithIdOptions} [opts] - Options for getting the actor.\n\t * @returns {ActorHandle<AD>} - A handle to the actor.\n\t */\n\tgetForId<AD extends AnyActorDefinition>(\n\t\tname: string,\n\t\tactorId: string,\n\t\topts?: GetWithIdOptions,\n\t): ActorHandle<AD> {\n\t\tlogger().debug({\n\t\t\tmsg: \"get handle to actor with id\",\n\t\t\tname,\n\t\t\tactorId,\n\t\t\tparams: opts?.params,\n\t\t});\n\n\t\tconst actorQuery: ActorQuery = {\n\t\t\tgetForId: {\n\t\t\t\tname,\n\t\t\t\tactorId,\n\t\t\t},\n\t\t};\n\n\t\tconst handle = this.#createHandle(opts?.params, actorQuery);\n\t\treturn createActorProxy(handle) as ActorHandle<AD>;\n\t}\n\n\t/**\n\t * Gets a stateless handle to a actor by its key, but does not create the actor if it doesn't exist.\n\t *\n\t * @template AD The actor class that this handle is for.\n\t * @param {string} name - The name of the actor.\n\t * @param {string | string[]} [key=[]] - The key to identify the actor. Can be a single string or an array of strings.\n\t * @param {GetWithIdOptions} [opts] - Options for getting the actor.\n\t * @returns {ActorHandle<AD>} - A handle to the actor.\n\t */\n\tget<AD extends AnyActorDefinition>(\n\t\tname: string,\n\t\tkey?: string | string[],\n\t\topts?: GetWithIdOptions,\n\t): ActorHandle<AD> {\n\t\t// Convert string to array of strings\n\t\tconst keyArray: string[] = typeof key === \"string\" ? [key] : key || [];\n\n\t\tlogger().debug({\n\t\t\tmsg: \"get handle to actor\",\n\t\t\tname,\n\t\t\tkey: keyArray,\n\t\t\tparameters: opts?.params,\n\t\t});\n\n\t\tconst actorQuery: ActorQuery = {\n\t\t\tgetForKey: {\n\t\t\t\tname,\n\t\t\t\tkey: keyArray,\n\t\t\t},\n\t\t};\n\n\t\tconst handle = this.#createHandle(opts?.params, actorQuery);\n\t\treturn createActorProxy(handle) as ActorHandle<AD>;\n\t}\n\n\t/**\n\t * Gets a stateless handle to a actor by its key, creating it if necessary.\n\t *\n\t * @template AD The actor class that this handle is for.\n\t * @param {string} name - The name of the actor.\n\t * @param {string | string[]} [key=[]] - The key to identify the actor. Can be a single string or an array of strings.\n\t * @param {GetOptions} [opts] - Options for getting the actor.\n\t * @returns {ActorHandle<AD>} - A handle to the actor.\n\t */\n\tgetOrCreate<AD extends AnyActorDefinition>(\n\t\tname: string,\n\t\tkey?: string | string[],\n\t\topts?: GetOrCreateOptions,\n\t): ActorHandle<AD> {\n\t\t// Convert string to array of strings\n\t\tconst keyArray: string[] = typeof key === \"string\" ? [key] : key || [];\n\n\t\tlogger().debug({\n\t\t\tmsg: \"get or create handle to actor\",\n\t\t\tname,\n\t\t\tkey: keyArray,\n\t\t\tparameters: opts?.params,\n\t\t\tcreateInRegion: opts?.createInRegion,\n\t\t});\n\n\t\tconst actorQuery: ActorQuery = {\n\t\t\tgetOrCreateForKey: {\n\t\t\t\tname,\n\t\t\t\tkey: keyArray,\n\t\t\t\tinput: opts?.createWithInput,\n\t\t\t\tregion: opts?.createInRegion,\n\t\t\t},\n\t\t};\n\n\t\tconst handle = this.#createHandle(opts?.params, actorQuery);\n\t\treturn createActorProxy(handle) as ActorHandle<AD>;\n\t}\n\n\t/**\n\t * Creates a new actor with the provided key and returns a stateless handle to it.\n\t * Resolves the actor ID and returns a handle with getForId query.\n\t *\n\t * @template AD The actor class that this handle is for.\n\t * @param {string} name - The name of the actor.\n\t * @param {string | string[]} key - The key to identify the actor. Can be a single string or an array of strings.\n\t * @param {CreateOptions} [opts] - Options for creating the actor (excluding name and key).\n\t * @returns {Promise<ActorHandle<AD>>} - A promise that resolves to a handle to the actor.\n\t */\n\tasync create<AD extends AnyActorDefinition>(\n\t\tname: string,\n\t\tkey?: string | string[],\n\t\topts?: CreateOptions,\n\t): Promise<ActorHandle<AD>> {\n\t\t// Convert string to array of strings\n\t\tconst keyArray: string[] = typeof key === \"string\" ? [key] : key || [];\n\n\t\tconst createQuery = {\n\t\t\tcreate: {\n\t\t\t\t...opts,\n\t\t\t\t// Do these last to override `opts`\n\t\t\t\tname,\n\t\t\t\tkey: keyArray,\n\t\t\t},\n\t\t} satisfies ActorQuery;\n\n\t\tlogger().debug({\n\t\t\tmsg: \"create actor handle\",\n\t\t\tname,\n\t\t\tkey: keyArray,\n\t\t\tparameters: opts?.params,\n\t\t\tcreate: createQuery.create,\n\t\t});\n\n\t\t// Create the actor\n\t\tconst { actorId } = await queryActor(\n\t\t\tundefined,\n\t\t\tcreateQuery,\n\t\t\tthis.#driver,\n\t\t);\n\t\tlogger().debug({\n\t\t\tmsg: \"created actor with ID\",\n\t\t\tname,\n\t\t\tkey: keyArray,\n\t\t\tactorId,\n\t\t});\n\n\t\t// Create handle with actor ID\n\t\tconst getForIdQuery = {\n\t\t\tgetForId: {\n\t\t\t\tname,\n\t\t\t\tactorId,\n\t\t\t},\n\t\t} satisfies ActorQuery;\n\t\tconst handle = this.#createHandle(opts?.params, getForIdQuery);\n\n\t\tconst proxy = createActorProxy(handle) as ActorHandle<AD>;\n\n\t\treturn proxy;\n\t}\n\n\t#createHandle(params: unknown, actorQuery: ActorQuery): ActorHandleRaw {\n\t\treturn new ActorHandleRaw(\n\t\t\tthis,\n\t\t\tthis.#driver,\n\t\t\tparams,\n\t\t\tthis.#encodingKind,\n\t\t\tactorQuery,\n\t\t);\n\t}\n\n\t[CREATE_ACTOR_CONN_PROXY]<AD extends AnyActorDefinition>(\n\t\tconn: ActorConnRaw,\n\t): ActorConn<AD> {\n\t\t// Save to connection list\n\t\tthis[ACTOR_CONNS_SYMBOL].add(conn);\n\n\t\t// Start connection\n\t\tconn[CONNECT_SYMBOL]();\n\n\t\treturn createActorProxy(conn) as ActorConn<AD>;\n\t}\n\n\t/**\n\t * Disconnects from all actors.\n\t *\n\t * @returns {Promise<void>} A promise that resolves when all connections are closed.\n\t */\n\tasync dispose(): Promise<void> {\n\t\tif (this.#disposed) {\n\t\t\tlogger().warn({ msg: \"client already disconnected\" });\n\t\t\treturn;\n\t\t}\n\t\tthis.#disposed = true;\n\n\t\tlogger().debug({ msg: \"disposing client\" });\n\n\t\tconst disposePromises = [];\n\n\t\t// Dispose all connections\n\t\tfor (const conn of this[ACTOR_CONNS_SYMBOL].values()) {\n\t\t\tdisposePromises.push(conn.dispose());\n\t\t}\n\n\t\tawait Promise.all(disposePromises);\n\t}\n}\n\n/**\n * Client type with actor accessors.\n * This adds property accessors for actor names to the ClientRaw base class.\n *\n * @template A The actor registry type.\n */\nexport type Client<A extends Registry<any>> = ClientRaw & {\n\t[K in keyof ExtractActorsFromRegistry<A>]: ActorAccessor<\n\t\tExtractActorsFromRegistry<A>[K]\n\t>;\n};\n\nexport type AnyClient = Client<Registry<any>>;\n\nexport function createClientWithDriver<A extends Registry<any>>(\n\tdriver: ManagerDriver,\n\tconfig: ClientConfig,\n): Client<A> {\n\tconst client = new ClientRaw(driver, config);\n\n\t// Create proxy for accessing actors by name\n\treturn new Proxy(client, {\n\t\tget: (target: ClientRaw, prop: string | symbol, receiver: unknown) => {\n\t\t\t// Get the real property if it exists\n\t\t\tif (typeof prop === \"symbol\" || prop in target) {\n\t\t\t\tconst value = Reflect.get(target, prop, receiver);\n\t\t\t\t// Preserve method binding\n\t\t\t\tif (typeof value === \"function\") {\n\t\t\t\t\treturn value.bind(target);\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t\t// Handle actor accessor for string properties (actor names)\n\t\t\tif (typeof prop === \"string\") {\n\t\t\t\t// Return actor accessor object with methods\n\t\t\t\treturn {\n\t\t\t\t\t// Handle methods (stateless action)\n\t\t\t\t\tget: (\n\t\t\t\t\t\tkey?: string | string[],\n\t\t\t\t\t\topts?: GetWithIdOptions,\n\t\t\t\t\t): ActorHandle<\n\t\t\t\t\t\tExtractActorsFromRegistry<A>[typeof prop]\n\t\t\t\t\t> => {\n\t\t\t\t\t\treturn target.get<\n\t\t\t\t\t\t\tExtractActorsFromRegistry<A>[typeof prop]\n\t\t\t\t\t\t>(prop, key, opts);\n\t\t\t\t\t},\n\t\t\t\t\tgetOrCreate: (\n\t\t\t\t\t\tkey?: string | string[],\n\t\t\t\t\t\topts?: GetOptions,\n\t\t\t\t\t): ActorHandle<\n\t\t\t\t\t\tExtractActorsFromRegistry<A>[typeof prop]\n\t\t\t\t\t> => {\n\t\t\t\t\t\treturn target.getOrCreate<\n\t\t\t\t\t\t\tExtractActorsFromRegistry<A>[typeof prop]\n\t\t\t\t\t\t>(prop, key, opts);\n\t\t\t\t\t},\n\t\t\t\t\tgetForId: (\n\t\t\t\t\t\tactorId: string,\n\t\t\t\t\t\topts?: GetWithIdOptions,\n\t\t\t\t\t): ActorHandle<\n\t\t\t\t\t\tExtractActorsFromRegistry<A>[typeof prop]\n\t\t\t\t\t> => {\n\t\t\t\t\t\treturn target.getForId<\n\t\t\t\t\t\t\tExtractActorsFromRegistry<A>[typeof prop]\n\t\t\t\t\t\t>(prop, actorId, opts);\n\t\t\t\t\t},\n\t\t\t\t\tcreate: async (\n\t\t\t\t\t\tkey: string | string[],\n\t\t\t\t\t\topts: CreateOptions = {},\n\t\t\t\t\t): Promise<\n\t\t\t\t\t\tActorHandle<ExtractActorsFromRegistry<A>[typeof prop]>\n\t\t\t\t\t> => {\n\t\t\t\t\t\treturn await target.create<\n\t\t\t\t\t\t\tExtractActorsFromRegistry<A>[typeof prop]\n\t\t\t\t\t\t>(prop, key, opts);\n\t\t\t\t\t},\n\t\t\t\t} as ActorAccessor<ExtractActorsFromRegistry<A>[typeof prop]>;\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t},\n\t}) as Client<A>;\n}\n\n/**\n * Creates a proxy for a actor that enables calling actions without explicitly using `.action`.\n **/\nfunction createActorProxy<AD extends AnyActorDefinition>(\n\thandle: ActorHandleRaw | ActorConnRaw,\n): ActorHandle<AD> | ActorConn<AD> {\n\t// Stores returned action functions for faster calls\n\tconst methodCache = new Map<string, ActorActionFunction>();\n\treturn new Proxy(handle, {\n\t\tget(target: ActorHandleRaw, prop: string | symbol, receiver: unknown) {\n\t\t\t// Handle built-in Symbol properties\n\t\t\tif (typeof prop === \"symbol\") {\n\t\t\t\treturn Reflect.get(target, prop, receiver);\n\t\t\t}\n\n\t\t\t// Handle built-in Promise methods and existing properties\n\t\t\tif (prop === \"constructor\" || prop in target) {\n\t\t\t\tconst value = Reflect.get(target, prop, target);\n\t\t\t\t// Preserve method binding\n\t\t\t\tif (typeof value === \"function\") {\n\t\t\t\t\treturn value.bind(target);\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t\t// Create action function that preserves 'this' context\n\t\t\tif (typeof prop === \"string\") {\n\t\t\t\t// If JS is attempting to calling this as a promise, ignore it\n\t\t\t\tif (prop === \"then\") return undefined;\n\n\t\t\t\tlet method = methodCache.get(prop);\n\t\t\t\tif (!method) {\n\t\t\t\t\tmethod = (...args: unknown[]) =>\n\t\t\t\t\t\ttarget.action({ name: prop, args });\n\t\t\t\t\tmethodCache.set(prop, method);\n\t\t\t\t}\n\t\t\t\treturn method;\n\t\t\t}\n\t\t},\n\n\t\t// Support for 'in' operator\n\t\thas(target: ActorHandleRaw, prop: string | symbol) {\n\t\t\t// All string properties are potentially action functions\n\t\t\tif (typeof prop === \"string\") {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// For symbols, defer to the target's own has behavior\n\t\t\treturn Reflect.has(target, prop);\n\t\t},\n\n\t\t// Support instanceof checks\n\t\tgetPrototypeOf(target: ActorHandleRaw) {\n\t\t\treturn Reflect.getPrototypeOf(target);\n\t\t},\n\n\t\t// Prevent property enumeration of non-existent action methods\n\t\townKeys(target: ActorHandleRaw) {\n\t\t\treturn Reflect.ownKeys(target);\n\t\t},\n\n\t\t// Support proper property descriptors\n\t\tgetOwnPropertyDescriptor(\n\t\t\ttarget: ActorHandleRaw,\n\t\t\tprop: string | symbol,\n\t\t) {\n\t\t\tconst targetDescriptor = Reflect.getOwnPropertyDescriptor(\n\t\t\t\ttarget,\n\t\t\t\tprop,\n\t\t\t);\n\t\t\tif (targetDescriptor) {\n\t\t\t\treturn targetDescriptor;\n\t\t\t}\n\t\t\tif (typeof prop === \"string\") {\n\t\t\t\t// Make action methods appear non-enumerable\n\t\t\t\treturn {\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\tenumerable: false,\n\t\t\t\t\twritable: false,\n\t\t\t\t\tvalue: (...args: unknown[]) =>\n\t\t\t\t\t\ttarget.action({ name: prop, args }),\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t}) as ActorHandle<AD> | ActorConn<AD>;\n}\n","import * as cbor from \"cbor-x\";\nimport type { Context as HonoContext } from \"hono\";\nimport invariant from \"invariant\";\nimport { deserializeActorKey, serializeActorKey } from \"@/actor/keys\";\nimport { generateRandomString } from \"@/actor/utils\";\nimport type { ClientConfig } from \"@/client/client\";\nimport { noopNext, stringifyError } from \"@/common/utils\";\nimport type {\n\tActorOutput,\n\tCreateInput,\n\tGetForIdInput,\n\tGetOrCreateWithKeyInput,\n\tGetWithKeyInput,\n\tManagerDisplayInformation,\n\tManagerDriver,\n} from \"@/driver-helpers/mod\";\nimport type { Encoding, UniversalWebSocket } from \"@/mod\";\nimport { uint8ArrayToBase64 } from \"@/serde\";\nimport { combineUrlPath, getEnvUniversal } from \"@/utils\";\nimport { sendHttpRequestToActor } from \"./actor-http-client\";\nimport {\n\tbuildWebSocketProtocols,\n\topenWebSocketToActor,\n} from \"./actor-websocket-client\";\nimport {\n\tcreateActor,\n\tdestroyActor,\n\tgetActor,\n\tgetActorByKey,\n\tgetMetadata,\n\tgetOrCreateActor,\n} from \"./api-endpoints\";\nimport { EngineApiError, getEndpoint } from \"./api-utils\";\nimport { logger } from \"./log\";\nimport { createWebSocketProxy } from \"./ws-proxy\";\n\n// TODO:\n// // Lazily import the dynamic imports so we don't have to turn `createClient` in to an async fn\n// const dynamicImports = (async () => {\n// \t// Import dynamic dependencies\n// \tconst [WebSocket, EventSource] = await Promise.all([\n// \t\timportWebSocket(),\n// \t\timportEventSource(),\n// \t]);\n// \treturn {\n// \t\tWebSocket,\n// \t\tEventSource,\n// \t};\n// })();\n\n// Global cache to store metadata check promises for each endpoint\nconst metadataCheckCache = new Map<string, Promise<void>>();\n\nexport class RemoteManagerDriver implements ManagerDriver {\n\t#config: ClientConfig;\n\t#metadataPromise: Promise<void> | undefined;\n\n\tconstructor(runConfig: ClientConfig) {\n\t\t// Disable health check if in Next.js build phase since there is no `/metadata` endpoint\n\t\t//\n\t\t// See https://github.com/vercel/next.js/blob/5e6b008b561caf2710ab7be63320a3d549474a5b/packages/next/shared/lib/constants.ts#L19-L23\n\t\tif (getEnvUniversal(\"NEXT_PHASE\") === \"phase-production-build\") {\n\t\t\tlogger().info(\n\t\t\t\t\"detected next.js build phase, disabling health check\",\n\t\t\t);\n\t\t\trunConfig.disableHealthCheck = true;\n\t\t}\n\n\t\tthis.#config = runConfig;\n\n\t\t// Perform metadata check if enabled\n\t\tif (!runConfig.disableHealthCheck) {\n\t\t\tthis.#metadataPromise = this.#performMetadataCheck(runConfig);\n\t\t\tthis.#metadataPromise.catch((error) => {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"metadata check failed\",\n\t\t\t\t\terror:\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\n\tasync #performMetadataCheck(config: ClientConfig): Promise<void> {\n\t\tconst endpoint = getEndpoint(config);\n\n\t\t// Check if metadata check is already in progress or completed for this endpoint\n\t\tconst existingPromise = metadataCheckCache.get(endpoint);\n\t\tif (existingPromise) {\n\t\t\treturn existingPromise;\n\t\t}\n\n\t\t// Create and store the promise immediately to prevent racing requests\n\t\tconst metadataCheckPromise = (async () => {\n\t\t\ttry {\n\t\t\t\tconst metadataData = await getMetadata(config);\n\n\t\t\t\tif (metadataData.clientEndpoint) {\n\t\t\t\t\tlogger().info({\n\t\t\t\t\t\tmsg: \"received new client endpoint from metadata\",\n\t\t\t\t\t\tendpoint: metadataData.clientEndpoint,\n\t\t\t\t\t});\n\t\t\t\t\tthis.#config.endpoint = metadataData.clientEndpoint;\n\t\t\t\t}\n\n\t\t\t\t// Log successful metadata check with runtime and version info\n\t\t\t\tlogger().info({\n\t\t\t\t\tmsg: \"connected to rivetkit manager\",\n\t\t\t\t\truntime: metadataData.runtime,\n\t\t\t\t\tversion: metadataData.version,\n\t\t\t\t\trunner: metadataData.runner,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"health check failed, validate the Rivet endpoint is configured correctly\",\n\t\t\t\t\tendpoint,\n\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t});\n\t\t\t}\n\t\t})();\n\n\t\tmetadataCheckCache.set(endpoint, metadataCheckPromise);\n\t\treturn metadataCheckPromise;\n\t}\n\n\tasync getForId({\n\t\tc,\n\t\tname,\n\t\tactorId,\n\t}: GetForIdInput): Promise<ActorOutput | undefined> {\n\t\t// Wait for metadata check to complete if in progress\n\t\tif (this.#metadataPromise) {\n\t\t\tawait this.#metadataPromise;\n\t\t}\n\n\t\t// Fetch from API if not in cache\n\t\tconst response = await getActor(this.#config, name, actorId);\n\t\tconst actor = response.actors[0];\n\t\tif (!actor) return undefined;\n\n\t\t// Validate name matches\n\t\tif (actor.name !== name) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"actor name mismatch from api\",\n\t\t\t\tactorId,\n\t\t\t\tapiName: actor.name,\n\t\t\t\trequestedName: name,\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst keyRaw = actor.key;\n\t\tinvariant(keyRaw, `actor ${actorId} should have key`);\n\t\tconst key = deserializeActorKey(keyRaw);\n\n\t\treturn {\n\t\t\tactorId,\n\t\t\tname,\n\t\t\tkey,\n\t\t};\n\t}\n\n\tasync getWithKey({\n\t\tc,\n\t\tname,\n\t\tkey,\n\t}: GetWithKeyInput): Promise<ActorOutput | undefined> {\n\t\t// Wait for metadata check to complete if in progress\n\t\tif (this.#metadataPromise) {\n\t\t\tawait this.#metadataPromise;\n\t\t}\n\n\t\tlogger().debug({ msg: \"getWithKey: searching for actor\", name, key });\n\n\t\t// If not in local cache, fetch by key from API\n\t\ttry {\n\t\t\tconst response = await getActorByKey(this.#config, name, key);\n\t\t\tconst actor = response.actors[0];\n\t\t\tif (!actor) return undefined;\n\n\t\t\tconst actorId = actor.actor_id;\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"getWithKey: found actor via api\",\n\t\t\t\tactorId,\n\t\t\t\tname,\n\t\t\t\tkey,\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} catch (error) {\n\t\t\tif (\n\t\t\t\terror instanceof EngineApiError &&\n\t\t\t\t(error as EngineApiError).group === \"actor\" &&\n\t\t\t\t(error as EngineApiError).code === \"not_found\"\n\t\t\t) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync getOrCreateWithKey(\n\t\tinput: GetOrCreateWithKeyInput,\n\t): Promise<ActorOutput> {\n\t\t// Wait for metadata check to complete if in progress\n\t\tif (this.#metadataPromise) {\n\t\t\tawait this.#metadataPromise;\n\t\t}\n\n\t\tconst { c, name, key, input: actorInput, region } = input;\n\n\t\tlogger().info({\n\t\t\tmsg: \"getOrCreateWithKey: getting or creating actor via engine api\",\n\t\t\tname,\n\t\t\tkey,\n\t\t});\n\n\t\tconst { actor, created } = await getOrCreateActor(this.#config, {\n\t\t\tdatacenter: region,\n\t\t\tname,\n\t\t\tkey: serializeActorKey(key),\n\t\t\trunner_name_selector: this.#config.runnerName,\n\t\t\tinput: actorInput\n\t\t\t\t? uint8ArrayToBase64(cbor.encode(actorInput))\n\t\t\t\t: undefined,\n\t\t\tcrash_policy: \"sleep\",\n\t\t});\n\n\t\tconst actorId = actor.actor_id;\n\n\t\tlogger().info({\n\t\t\tmsg: \"getOrCreateWithKey: actor ready\",\n\t\t\tactorId,\n\t\t\tname,\n\t\t\tkey,\n\t\t\tcreated,\n\t\t});\n\n\t\treturn {\n\t\t\tactorId,\n\t\t\tname,\n\t\t\tkey,\n\t\t};\n\t}\n\n\tasync createActor({\n\t\tc,\n\t\tname,\n\t\tkey,\n\t\tinput,\n\t\tregion,\n\t}: CreateInput): Promise<ActorOutput> {\n\t\t// Wait for metadata check to complete if in progress\n\t\tif (this.#metadataPromise) {\n\t\t\tawait this.#metadataPromise;\n\t\t}\n\n\t\tlogger().info({ msg: \"creating actor via engine api\", name, key });\n\n\t\t// Create actor via engine API\n\t\tconst result = await createActor(this.#config, {\n\t\t\tdatacenter: region,\n\t\t\tname,\n\t\t\trunner_name_selector: this.#config.runnerName,\n\t\t\tkey: serializeActorKey(key),\n\t\t\tinput: input ? uint8ArrayToBase64(cbor.encode(input)) : undefined,\n\t\t\tcrash_policy: \"sleep\",\n\t\t});\n\t\tconst actorId = result.actor.actor_id;\n\n\t\tlogger().info({ msg: \"actor created\", actorId, name, key });\n\n\t\treturn {\n\t\t\tactorId,\n\t\t\tname,\n\t\t\tkey,\n\t\t};\n\t}\n\n\tasync destroyActor(actorId: string): Promise<void> {\n\t\t// Wait for metadata check to complete if in progress\n\t\tif (this.#metadataPromise) {\n\t\t\tawait this.#metadataPromise;\n\t\t}\n\n\t\tlogger().info({ msg: \"destroying actor via engine api\", actorId });\n\n\t\tawait destroyActor(this.#config, actorId);\n\n\t\tlogger().info({ msg: \"actor destroyed\", actorId });\n\t}\n\n\tasync sendRequest(\n\t\tactorId: string,\n\t\tactorRequest: Request,\n\t): Promise<Response> {\n\t\t// Wait for metadata check to complete if in progress\n\t\tif (this.#metadataPromise) {\n\t\t\tawait this.#metadataPromise;\n\t\t}\n\n\t\treturn await sendHttpRequestToActor(\n\t\t\tthis.#config,\n\t\t\tactorId,\n\t\t\tactorRequest,\n\t\t);\n\t}\n\n\tasync openWebSocket(\n\t\tpath: string,\n\t\tactorId: string,\n\t\tencoding: Encoding,\n\t\tparams: unknown,\n\t\tconnId?: string,\n\t\tconnToken?: string,\n\t): Promise<UniversalWebSocket> {\n\t\t// Wait for metadata check to complete if in progress\n\t\tif (this.#metadataPromise) {\n\t\t\tawait this.#metadataPromise;\n\t\t}\n\n\t\treturn await openWebSocketToActor(\n\t\t\tthis.#config,\n\t\t\tpath,\n\t\t\tactorId,\n\t\t\tencoding,\n\t\t\tparams,\n\t\t\tconnId,\n\t\t\tconnToken,\n\t\t);\n\t}\n\n\tasync proxyRequest(\n\t\t_c: HonoContext,\n\t\tactorRequest: Request,\n\t\tactorId: string,\n\t): Promise<Response> {\n\t\t// Wait for metadata check to complete if in progress\n\t\tif (this.#metadataPromise) {\n\t\t\tawait this.#metadataPromise;\n\t\t}\n\n\t\treturn await sendHttpRequestToActor(\n\t\t\tthis.#config,\n\t\t\tactorId,\n\t\t\tactorRequest,\n\t\t);\n\t}\n\n\tasync proxyWebSocket(\n\t\tc: HonoContext,\n\t\tpath: string,\n\t\tactorId: string,\n\t\tencoding: Encoding,\n\t\tparams: unknown,\n\t\tconnId?: string,\n\t\tconnToken?: string,\n\t): Promise<Response> {\n\t\t// Wait for metadata check to complete if in progress\n\t\tif (this.#metadataPromise) {\n\t\t\tawait this.#metadataPromise;\n\t\t}\n\n\t\tconst upgradeWebSocket = this.#config.getUpgradeWebSocket?.();\n\t\tinvariant(upgradeWebSocket, \"missing getUpgradeWebSocket\");\n\n\t\tconst endpoint = getEndpoint(this.#config);\n\t\tconst guardUrl = combineUrlPath(endpoint, path);\n\t\tconst wsGuardUrl = guardUrl.replace(\"http://\", \"ws://\");\n\n\t\tlogger().debug({\n\t\t\tmsg: \"forwarding websocket to actor via guard\",\n\t\t\tactorId,\n\t\t\tpath,\n\t\t\tguardUrl,\n\t\t});\n\n\t\t// Build protocols\n\t\tconst protocols = buildWebSocketProtocols(\n\t\t\tthis.#config,\n\t\t\tactorId,\n\t\t\tencoding,\n\t\t\tparams,\n\t\t\tconnId,\n\t\t\tconnToken,\n\t\t);\n\t\tconst args = await createWebSocketProxy(c, wsGuardUrl, protocols);\n\n\t\treturn await upgradeWebSocket(() => args)(c, noopNext());\n\t}\n\n\tdisplayInformation(): ManagerDisplayInformation {\n\t\treturn { name: \"Remote\", properties: {} };\n\t}\n\n\tgetOrCreateInspectorAccessToken() {\n\t\treturn generateRandomString();\n\t}\n}\n","import { getLogger } from \"@/common//log\";\n\nexport function logger() {\n\treturn getLogger(\"remote-manager-driver\");\n}\n","import type { ClientConfig } from \"@/client/config\";\nimport { sendHttpRequest } from \"@/client/utils\";\nimport { combineUrlPath } from \"@/utils\";\nimport { logger } from \"./log\";\n\n// Error class for Engine API errors\nexport class EngineApiError extends Error {\n\tconstructor(\n\t\tpublic readonly group: string,\n\t\tpublic readonly code: string,\n\t\tmessage?: string,\n\t) {\n\t\tsuper(message || `Engine API error: ${group}/${code}`);\n\t\tthis.name = \"EngineApiError\";\n\t}\n}\n\nexport function getEndpoint(config: ClientConfig) {\n\treturn config.endpoint ?? \"http://127.0.0.1:6420\";\n}\n\n// Helper function for making API calls\nexport async function apiCall<TInput = unknown, TOutput = unknown>(\n\tconfig: ClientConfig,\n\tmethod: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\",\n\tpath: string,\n\tbody?: TInput,\n): Promise<TOutput> {\n\tconst endpoint = getEndpoint(config);\n\tconst url = combineUrlPath(endpoint, path, {\n\t\tnamespace: config.namespace,\n\t});\n\n\tlogger().debug({ msg: \"making api call\", method, url });\n\n\tconst headers: Record<string, string> = {\n\t\t...config.headers,\n\t};\n\n\t// Add Authorization header if token is provided\n\tif (config.token) {\n\t\theaders.Authorization = `Bearer ${config.token}`;\n\t}\n\n\treturn await sendHttpRequest<TInput, TOutput>({\n\t\tmethod,\n\t\turl,\n\t\theaders,\n\t\tbody,\n\t\tencoding: \"json\",\n\t\tskipParseResponse: false,\n\t\trequestVersionedDataHandler: undefined,\n\t\tresponseVersionedDataHandler: undefined,\n\t});\n}\n","import type { ClientConfig } from \"@/client/config\";\nimport {\n\tHEADER_RIVET_ACTOR,\n\tHEADER_RIVET_TARGET,\n\tHEADER_RIVET_TOKEN,\n} from \"@/common/actor-router-consts\";\nimport { combineUrlPath } from \"@/utils\";\nimport { getEndpoint } from \"./api-utils\";\n\nexport async function sendHttpRequestToActor(\n\trunConfig: ClientConfig,\n\tactorId: string,\n\tactorRequest: Request,\n): Promise<Response> {\n\t// Route through guard port\n\tconst url = new URL(actorRequest.url);\n\tconst endpoint = getEndpoint(runConfig);\n\tconst guardUrl = combineUrlPath(endpoint, url.pathname + url.search);\n\n\t// Handle body properly based on method and presence\n\tlet bodyToSend: ArrayBuffer | null = null;\n\tconst guardHeaders = buildGuardHeadersForHttp(\n\t\trunConfig,\n\t\tactorRequest,\n\t\tactorId,\n\t);\n\n\tif (actorRequest.method !== \"GET\" && actorRequest.method !== \"HEAD\") {\n\t\tif (actorRequest.bodyUsed) {\n\t\t\tthrow new Error(\"Request body has already been consumed\");\n\t\t}\n\n\t\t// TODO: This buffers the entire request in memory every time. We\n\t\t// need to properly implement streaming bodies.\n\t\tconst reqBody = await actorRequest.arrayBuffer();\n\n\t\tif (reqBody.byteLength !== 0) {\n\t\t\tbodyToSend = reqBody;\n\n\t\t\t// If this is a streaming request, we need to convert the headers\n\t\t\t// for the basic array buffer\n\t\t\tguardHeaders.delete(\"transfer-encoding\");\n\t\t\tguardHeaders.set(\"content-length\", String(bodyToSend.byteLength));\n\t\t}\n\t}\n\n\tconst guardRequest = new Request(guardUrl, {\n\t\tmethod: actorRequest.method,\n\t\theaders: guardHeaders,\n\t\tbody: bodyToSend,\n\t\tsignal: actorRequest.signal,\n\t});\n\n\treturn mutableResponse(await fetch(guardRequest));\n}\n\nfunction mutableResponse(fetchRes: Response): Response {\n\t// We cannot return the raw response from `fetch` since the response type is not mutable.\n\t//\n\t// In order for middleware to be able to mutate the response, we need to build a new Response object that is mutable.\n\treturn new Response(fetchRes.body, fetchRes);\n}\n\nfunction buildGuardHeadersForHttp(\n\trunConfig: ClientConfig,\n\tactorRequest: Request,\n\tactorId: string,\n): Headers {\n\tconst headers = new Headers();\n\t// Copy all headers from the original request\n\tfor (const [key, value] of actorRequest.headers.entries()) {\n\t\theaders.set(key, value);\n\t}\n\t// Add extra headers from config\n\tfor (const [key, value] of Object.entries(runConfig.headers)) {\n\t\theaders.set(key, value);\n\t}\n\t// Add guard-specific headers\n\theaders.set(HEADER_RIVET_TARGET, \"actor\");\n\theaders.set(HEADER_RIVET_ACTOR, actorId);\n\tif (runConfig.token) {\n\t\theaders.set(HEADER_RIVET_TOKEN, runConfig.token);\n\t}\n\treturn headers;\n}\n","import type { ClientConfig } from \"@/client/config\";\nimport {\n\tHEADER_CONN_PARAMS,\n\tHEADER_ENCODING,\n\tWS_PROTOCOL_ACTOR,\n\tWS_PROTOCOL_CONN_ID,\n\tWS_PROTOCOL_CONN_PARAMS,\n\tWS_PROTOCOL_CONN_TOKEN,\n\tWS_PROTOCOL_ENCODING,\n\tWS_PROTOCOL_STANDARD as WS_PROTOCOL_RIVETKIT,\n\tWS_PROTOCOL_TARGET,\n\tWS_PROTOCOL_TOKEN,\n} from \"@/common/actor-router-consts\";\nimport { importWebSocket } from \"@/common/websocket\";\nimport type { Encoding, UniversalWebSocket } from \"@/mod\";\nimport { combineUrlPath } from \"@/utils\";\nimport { getEndpoint } from \"./api-utils\";\nimport { logger } from \"./log\";\n\nexport async function openWebSocketToActor(\n\trunConfig: ClientConfig,\n\tpath: string,\n\tactorId: string,\n\tencoding: Encoding,\n\tparams: unknown,\n\tconnId?: string,\n\tconnToken?: string,\n): Promise<UniversalWebSocket> {\n\tconst WebSocket = await importWebSocket();\n\n\t// WebSocket connections go through guard\n\tconst endpoint = getEndpoint(runConfig);\n\tconst guardUrl = combineUrlPath(endpoint, path);\n\n\tlogger().debug({\n\t\tmsg: \"opening websocket to actor via guard\",\n\t\tactorId,\n\t\tpath,\n\t\tguardUrl,\n\t});\n\n\t// Create WebSocket connection\n\tconst ws = new WebSocket(\n\t\tguardUrl,\n\t\tbuildWebSocketProtocols(\n\t\t\trunConfig,\n\t\t\tactorId,\n\t\t\tencoding,\n\t\t\tparams,\n\t\t\tconnId,\n\t\t\tconnToken,\n\t\t),\n\t);\n\n\t// Set binary type to arraybuffer for proper encoding support\n\tws.binaryType = \"arraybuffer\";\n\n\tlogger().debug({ msg: \"websocket connection opened\", actorId });\n\n\treturn ws as UniversalWebSocket;\n}\n\nexport function buildWebSocketProtocols(\n\trunConfig: ClientConfig,\n\tactorId: string,\n\tencoding: Encoding,\n\tparams?: unknown,\n\tconnId?: string,\n\tconnToken?: string,\n): string[] {\n\tconst protocols: string[] = [];\n\tprotocols.push(WS_PROTOCOL_RIVETKIT);\n\tprotocols.push(`${WS_PROTOCOL_TARGET}actor`);\n\tprotocols.push(`${WS_PROTOCOL_ACTOR}${actorId}`);\n\tprotocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`);\n\tif (runConfig.token) {\n\t\tprotocols.push(`${WS_PROTOCOL_TOKEN}${runConfig.token}`);\n\t}\n\tif (params) {\n\t\tprotocols.push(\n\t\t\t`${WS_PROTOCOL_CONN_PARAMS}${encodeURIComponent(JSON.stringify(params))}`,\n\t\t);\n\t}\n\tif (connId) {\n\t\tprotocols.push(`${WS_PROTOCOL_CONN_ID}${connId}`);\n\t}\n\tif (connToken) {\n\t\tprotocols.push(`${WS_PROTOCOL_CONN_TOKEN}${connToken}`);\n\t}\n\treturn protocols;\n}\n","import { serializeActorKey } from \"@/actor/keys\";\nimport type { ClientConfig } from \"@/client/client\";\nimport type { MetadataResponse } from \"@/common/router\";\nimport type {\n\tActorsCreateRequest,\n\tActorsCreateResponse,\n\tActorsDeleteResponse,\n\tActorsGetOrCreateRequest,\n\tActorsGetOrCreateResponse,\n\tActorsListResponse,\n} from \"@/manager-api/actors\";\nimport type { RivetId } from \"@/manager-api/common\";\nimport { apiCall } from \"./api-utils\";\n\n// MARK: Get actor\nexport async function getActor(\n\tconfig: ClientConfig,\n\t_: string,\n\tactorId: RivetId,\n): Promise<ActorsListResponse> {\n\treturn apiCall<never, ActorsListResponse>(\n\t\tconfig,\n\t\t\"GET\",\n\t\t`/actors?actor_ids=${encodeURIComponent(actorId)}`,\n\t);\n}\n\n// MARK: Get actor by id\nexport async function getActorByKey(\n\tconfig: ClientConfig,\n\tname: string,\n\tkey: string[],\n): Promise<ActorsListResponse> {\n\tconst serializedKey = serializeActorKey(key);\n\treturn apiCall<never, ActorsListResponse>(\n\t\tconfig,\n\t\t\"GET\",\n\t\t`/actors?name=${encodeURIComponent(name)}&key=${encodeURIComponent(serializedKey)}`,\n\t);\n}\n\n// MARK: Get or create actor by id\nexport async function getOrCreateActor(\n\tconfig: ClientConfig,\n\trequest: ActorsGetOrCreateRequest,\n): Promise<ActorsGetOrCreateResponse> {\n\treturn apiCall<ActorsGetOrCreateRequest, ActorsGetOrCreateResponse>(\n\t\tconfig,\n\t\t\"PUT\",\n\t\t`/actors`,\n\t\trequest,\n\t);\n}\n\n// MARK: Create actor\nexport async function createActor(\n\tconfig: ClientConfig,\n\trequest: ActorsCreateRequest,\n): Promise<ActorsCreateResponse> {\n\treturn apiCall<ActorsCreateRequest, ActorsCreateResponse>(\n\t\tconfig,\n\t\t\"POST\",\n\t\t`/actors`,\n\t\trequest,\n\t);\n}\n\n// MARK: Destroy actor\nexport async function destroyActor(\n\tconfig: ClientConfig,\n\tactorId: RivetId,\n): Promise<ActorsDeleteResponse> {\n\treturn apiCall<never, ActorsDeleteResponse>(\n\t\tconfig,\n\t\t\"DELETE\",\n\t\t`/actors/${encodeURIComponent(actorId)}`,\n\t);\n}\n\n// MARK: Get metadata\nexport async function getMetadata(\n\tconfig: ClientConfig,\n): Promise<MetadataResponse> {\n\treturn apiCall<never, MetadataResponse>(config, \"GET\", `/metadata`);\n}\n\n// MARK: Get datacenters\nexport interface DatacentersResponse {\n\tdatacenters: { name: string }[];\n}\n\nexport async function getDatacenters(\n\tconfig: ClientConfig,\n): Promise<DatacentersResponse> {\n\treturn apiCall<never, DatacentersResponse>(config, \"GET\", `/datacenters`);\n}\n\n// MARK: Update runner config\nexport interface RunnerConfigRequest {\n\tdatacenters: Record<\n\t\tstring,\n\t\t{\n\t\t\tserverless: {\n\t\t\t\turl: string;\n\t\t\t\theaders: Record<string, string>;\n\t\t\t\tmax_runners: number;\n\t\t\t\tmin_runners: number;\n\t\t\t\trequest_lifespan: number;\n\t\t\t\trunners_margin: number;\n\t\t\t\tslots_per_runner: number;\n\t\t\t};\n\t\t}\n\t>;\n}\n\nexport async function updateRunnerConfig(\n\tconfig: ClientConfig,\n\trunnerName: string,\n\trequest: RunnerConfigRequest,\n): Promise<void> {\n\treturn apiCall<RunnerConfigRequest, void>(\n\t\tconfig,\n\t\t\"PUT\",\n\t\t`/runner-configs/${runnerName}`,\n\t\trequest,\n\t);\n}\n","import type { Context as HonoContext } from \"hono\";\nimport type { WSContext } from \"hono/ws\";\nimport { stringifyError } from \"@/common/utils\";\nimport { importWebSocket } from \"@/common/websocket\";\nimport type { UpgradeWebSocketArgs } from \"@/mod\";\nimport { logger } from \"./log\";\n\n/**\n * Returns Hono `upgradeWebSocket` args that will proxy requests from the client to a destination address.\n */\nexport async function createWebSocketProxy(\n\tc: HonoContext,\n\ttargetUrl: string,\n\tprotocols: string[],\n): Promise<UpgradeWebSocketArgs> {\n\tconst WebSocket = await importWebSocket();\n\n\t// WebSocket state\n\tinterface WsState {\n\t\ttargetWs?: WebSocket;\n\t\tconnectPromise?: Promise<void>;\n\t}\n\tconst state: WsState = {};\n\n\treturn {\n\t\tonOpen: async (event: any, clientWs: WSContext) => {\n\t\t\tlogger().debug({ msg: \"client websocket connected\", targetUrl });\n\n\t\t\tif (clientWs.readyState !== 1) {\n\t\t\t\tlogger().warn({\n\t\t\t\t\tmsg: \"client websocket not open on connection\",\n\t\t\t\t\ttargetUrl,\n\t\t\t\t\treadyState: clientWs.readyState,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Create WebSocket\n\t\t\tconst targetWs = new WebSocket(targetUrl, protocols);\n\t\t\tstate.targetWs = targetWs;\n\n\t\t\t// Setup connection promise\n\t\t\tstate.connectPromise = new Promise<void>((resolve, reject) => {\n\t\t\t\ttargetWs.addEventListener(\"open\", () => {\n\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\tmsg: \"target websocket connected\",\n\t\t\t\t\t\ttargetUrl,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (clientWs.readyState !== 1) {\n\t\t\t\t\t\tlogger().warn({\n\t\t\t\t\t\t\tmsg: \"client websocket closed before target connected\",\n\t\t\t\t\t\t\ttargetUrl,\n\t\t\t\t\t\t\tclientReadyState: clientWs.readyState,\n\t\t\t\t\t\t});\n\t\t\t\t\t\ttargetWs.close(1001, \"Client disconnected\");\n\t\t\t\t\t\treject(new Error(\"Client disconnected\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\n\t\t\t\ttargetWs.addEventListener(\"error\", (error) => {\n\t\t\t\t\tlogger().warn({\n\t\t\t\t\t\tmsg: \"target websocket error during connection\",\n\t\t\t\t\t\ttargetUrl,\n\t\t\t\t\t});\n\t\t\t\t\treject(error);\n\t\t\t\t});\n\t\t\t});\n\n\t\t\t// Setup bidirectional forwarding\n\t\t\tstate.targetWs.addEventListener(\"message\", (event) => {\n\t\t\t\tif (\n\t\t\t\t\ttypeof event.data === \"string\" ||\n\t\t\t\t\tevent.data instanceof ArrayBuffer\n\t\t\t\t) {\n\t\t\t\t\tclientWs.send(event.data);\n\t\t\t\t} else if (event.data instanceof Blob) {\n\t\t\t\t\tevent.data.arrayBuffer().then((buffer) => {\n\t\t\t\t\t\tclientWs.send(buffer);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tstate.targetWs.addEventListener(\"close\", (event) => {\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"target websocket closed\",\n\t\t\t\t\ttargetUrl,\n\t\t\t\t\tcode: event.code,\n\t\t\t\t\treason: event.reason,\n\t\t\t\t});\n\t\t\t\tcloseWebSocketIfOpen(clientWs, event.code, event.reason);\n\t\t\t});\n\n\t\t\tstate.targetWs.addEventListener(\"error\", (error) => {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"target websocket error\",\n\t\t\t\t\ttargetUrl,\n\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t});\n\t\t\t\tcloseWebSocketIfOpen(clientWs, 1011, \"Target WebSocket error\");\n\t\t\t});\n\t\t},\n\n\t\tonMessage: async (event: any, clientWs: WSContext) => {\n\t\t\tif (!state.targetWs || !state.connectPromise) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"websocket state not initialized\",\n\t\t\t\t\ttargetUrl,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait state.connectPromise;\n\t\t\t\tif (state.targetWs.readyState === WebSocket.OPEN) {\n\t\t\t\t\tstate.targetWs.send(event.data);\n\t\t\t\t} else {\n\t\t\t\t\tlogger().warn({\n\t\t\t\t\t\tmsg: \"target websocket not open\",\n\t\t\t\t\t\ttargetUrl,\n\t\t\t\t\t\treadyState: state.targetWs.readyState,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"failed to connect to target websocket\",\n\t\t\t\t\ttargetUrl,\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t\tcloseWebSocketIfOpen(\n\t\t\t\t\tclientWs,\n\t\t\t\t\t1011,\n\t\t\t\t\t\"Failed to connect to target\",\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\n\t\tonClose: (event: any, clientWs: WSContext) => {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"client websocket closed\",\n\t\t\t\ttargetUrl,\n\t\t\t\tcode: event.code,\n\t\t\t\treason: event.reason,\n\t\t\t\twasClean: event.wasClean,\n\t\t\t});\n\n\t\t\tif (state.targetWs) {\n\t\t\t\tif (\n\t\t\t\t\tstate.targetWs.readyState === WebSocket.OPEN ||\n\t\t\t\t\tstate.targetWs.readyState === WebSocket.CONNECTING\n\t\t\t\t) {\n\t\t\t\t\tstate.targetWs.close(\n\t\t\t\t\t\t1000,\n\t\t\t\t\t\tevent.reason || \"Client disconnected\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tonError: (event: any, clientWs: WSContext) => {\n\t\t\tlogger().error({ msg: \"client websocket error\", targetUrl, event });\n\n\t\t\tif (state.targetWs) {\n\t\t\t\tif (state.targetWs.readyState === WebSocket.OPEN) {\n\t\t\t\t\tstate.targetWs.close(1011, \"Client WebSocket error\");\n\t\t\t\t} else if (state.targetWs.readyState === WebSocket.CONNECTING) {\n\t\t\t\t\tstate.targetWs.close();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction closeWebSocketIfOpen(\n\tws: WebSocket | WSContext,\n\tcode: number,\n\treason: string,\n): void {\n\tif (ws.readyState === 1) {\n\t\tws.close(code, reason);\n\t} else if (\n\t\t\"close\" in ws &&\n\t\t(ws as WebSocket).readyState === WebSocket.OPEN\n\t) {\n\t\tws.close(code, reason);\n\t}\n}\n"]}
|