UNPKG

@rivetkit/redis

Version:

_Lightweight Libraries for Backends_

1,663 lines (1,627 loc) 138 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } var _class; var _class2; var _class3; var _class4; var _class5; var _chunkRIAC4EUGcjs = require('./chunk-RIAC4EUG.cjs'); // ../../core/dist/chunk-IVHL2KCJ.js var _cborx = require('cbor-x'); var cbor = _interopRequireWildcard(_cborx); var cbor2 = _interopRequireWildcard(_cborx); var cbor3 = _interopRequireWildcard(_cborx); var cbor22 = _interopRequireWildcard(_cborx); var cbor4 = _interopRequireWildcard(_cborx); var cbor23 = _interopRequireWildcard(_cborx); var cbor32 = _interopRequireWildcard(_cborx); var cbor5 = _interopRequireWildcard(_cborx); var _zod = require('zod'); var _streaming = require('hono/streaming'); var _v4 = require('zod/v4'); var _v42 = _interopRequireDefault(_v4); var RUNTIME_LOGGER_NAME = "actor-runtime"; function logger2() { return _chunkRIAC4EUGcjs.getLogger.call(void 0, RUNTIME_LOGGER_NAME); } function assertUnreachable2(x) { logger2().error("unreachable", { value: `${x}`, stack: new Error().stack }); throw new (0, _chunkRIAC4EUGcjs.Unreachable)(x); } function generateSecureToken(length = 32) { const array = new Uint8Array(length); crypto.getRandomValues(array); return btoa(String.fromCharCode(...array)); } function generateRandomString(length = 32) { const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; let result = ""; for (let i = 0; i < length; i++) { const randomIndex = Math.floor(Math.random() * characters.length); result += characters[randomIndex]; } return result; } var EncodingSchema = _zod.z.enum(["json", "cbor"]); function serialize(value, encoding) { if (encoding === "json") { return JSON.stringify(value); } else if (encoding === "cbor") { const cleanValue = JSON.parse(JSON.stringify(value)); return cbor.encode(cleanValue); } else { assertUnreachable2(encoding); } } async function deserialize(data, encoding) { if (encoding === "json") { if (typeof data !== "string") { logger2().warn("received non-string for json parse"); throw new (0, _chunkRIAC4EUGcjs.MalformedMessage)(); } else { return JSON.parse(data); } } else if (encoding === "cbor") { if (data instanceof Blob) { const arrayBuffer = await data.arrayBuffer(); return cbor.decode(new Uint8Array(arrayBuffer)); } else if (data instanceof Uint8Array) { return cbor.decode(data); } else if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) { return cbor.decode(new Uint8Array(data)); } else { logger2().warn("received non-binary type for cbor parse"); throw new (0, _chunkRIAC4EUGcjs.MalformedMessage)(); } } else { assertUnreachable2(encoding); } } function base64EncodeUint8Array(uint8Array) { let binary = ""; const len = uint8Array.byteLength; for (let i = 0; i < len; i++) { binary += String.fromCharCode(uint8Array[i]); } return btoa(binary); } function base64EncodeArrayBuffer(arrayBuffer) { const uint8Array = new Uint8Array(arrayBuffer); return base64EncodeUint8Array(uint8Array); } function encodeDataToString(message) { if (typeof message === "string") { return message; } else if (message instanceof ArrayBuffer) { return base64EncodeArrayBuffer(message); } else if (message instanceof Uint8Array) { return base64EncodeUint8Array(message); } else { assertUnreachable2(message); } } function generateConnId() { return crypto.randomUUID(); } function generateConnToken() { return generateSecureToken(32); } var GenericConnGlobalState = (_class = class {constructor() { _class.prototype.__init.call(this);_class.prototype.__init2.call(this); } __init() {this.websockets = /* @__PURE__ */ new Map()} __init2() {this.sseStreams = /* @__PURE__ */ new Map()} }, _class); function createGenericConnDrivers(globalState) { return { [CONN_DRIVER_GENERIC_WEBSOCKET]: createGenericWebSocketDriver(globalState), [CONN_DRIVER_GENERIC_SSE]: createGenericSseDriver(globalState), [CONN_DRIVER_GENERIC_HTTP]: createGeneircHttpDriver() }; } var CONN_DRIVER_GENERIC_WEBSOCKET = "genericWebSocket"; function createGenericWebSocketDriver(globalState) { return { sendMessage: (actor, conn, state, message) => { const ws = globalState.websockets.get(conn.id); if (!ws) { logger2().warn("missing ws for sendMessage", { actorId: actor.id, connId: conn.id, totalCount: globalState.websockets.size }); return; } const serialized = message.serialize(state.encoding); logger2().debug("sending websocket message", { encoding: state.encoding, dataType: typeof serialized, isUint8Array: serialized instanceof Uint8Array, isArrayBuffer: serialized instanceof ArrayBuffer, dataLength: serialized.byteLength || serialized.length }); if (serialized instanceof Uint8Array) { const buffer = serialized.buffer.slice( serialized.byteOffset, serialized.byteOffset + serialized.byteLength ); if (buffer instanceof SharedArrayBuffer) { const arrayBuffer = new ArrayBuffer(buffer.byteLength); new Uint8Array(arrayBuffer).set(new Uint8Array(buffer)); logger2().debug("converted SharedArrayBuffer to ArrayBuffer", { byteLength: arrayBuffer.byteLength }); ws.send(arrayBuffer); } else { logger2().debug("sending ArrayBuffer", { byteLength: buffer.byteLength }); ws.send(buffer); } } else { logger2().debug("sending string data", { length: serialized.length }); ws.send(serialized); } }, disconnect: async (actor, conn, _state, reason) => { const ws = globalState.websockets.get(conn.id); if (!ws) { logger2().warn("missing ws for disconnect", { actorId: actor.id, connId: conn.id, totalCount: globalState.websockets.size }); return; } const raw = ws.raw; if (!raw) { logger2().warn("ws.raw does not exist"); return; } const { promise, resolve } = Promise.withResolvers(); raw.addEventListener("close", () => resolve()); ws.close(1e3, reason); await promise; } }; } var CONN_DRIVER_GENERIC_SSE = "genericSse"; function createGenericSseDriver(globalState) { return { sendMessage: (_actor, conn, state, message) => { const stream = globalState.sseStreams.get(conn.id); if (!stream) { logger2().warn("missing sse stream for sendMessage", { connId: conn.id }); return; } stream.writeSSE({ data: encodeDataToString(message.serialize(state.encoding)) }); }, disconnect: async (_actor, conn, _state, _reason) => { const stream = globalState.sseStreams.get(conn.id); if (!stream) { logger2().warn("missing sse stream for disconnect", { connId: conn.id }); return; } stream.close(); } }; } var CONN_DRIVER_GENERIC_HTTP = "genericHttp"; function createGeneircHttpDriver() { return { disconnect: async () => { } }; } var ActionContext = class { /** * Should not be called directly. * * @param actorContext - The actor context * @param conn - The connection associated with the action */ constructor(actorContext, conn) { this.conn = conn; this.#actorContext = actorContext; } #actorContext; /** * Get the actor state */ get state() { return this.#actorContext.state; } /** * Get the actor variables */ get vars() { return this.#actorContext.vars; } /** * Broadcasts an event to all connected clients. */ broadcast(name, ...args) { this.#actorContext.broadcast(name, ...args); } /** * Gets the logger instance. */ get log() { return this.#actorContext.log; } /** * Gets actor ID. */ get actorId() { return this.#actorContext.actorId; } /** * Gets the actor name. */ get name() { return this.#actorContext.name; } /** * Gets the actor key. */ get key() { return this.#actorContext.key; } /** * Gets the region. */ get region() { return this.#actorContext.region; } /** * Gets the scheduler. */ get schedule() { return this.#actorContext.schedule; } /** * Gets the map of connections. */ get conns() { return this.#actorContext.conns; } /** * Returns the client for the given registry. */ client() { return this.#actorContext.client(); } /** * @experimental */ get db() { return this.#actorContext.db; } /** * Forces the state to get saved. */ async saveState(opts) { return this.#actorContext.saveState(opts); } /** * Runs a promise in the background. */ runInBackground(promise) { this.#actorContext.runInBackground(promise); } }; var ActionRequestSchema = _zod.z.object({ // Args a: _zod.z.array(_zod.z.unknown()) }); var ActionResponseSchema = _zod.z.object({ // Output o: _zod.z.unknown() }); var ActionRequestSchema2 = _zod.z.object({ // ID i: _zod.z.number().int(), // Name n: _zod.z.string(), // Args a: _zod.z.array(_zod.z.unknown()) }); var SubscriptionRequestSchema = _zod.z.object({ // Event name e: _zod.z.string(), // Subscribe s: _zod.z.boolean() }); var ToServerSchema = _zod.z.object({ // Body b: _zod.z.union([ _zod.z.object({ ar: ActionRequestSchema2 }), _zod.z.object({ sr: SubscriptionRequestSchema }) ]) }); var TransportSchema = _zod.z.enum(["websocket", "sse"]); function getValueLength(value) { if (typeof value === "string") { return value.length; } else if (value instanceof Blob) { return value.size; } else if (value instanceof ArrayBuffer || value instanceof SharedArrayBuffer || value instanceof Uint8Array) { return value.byteLength; } else { assertUnreachable2(value); } } async function parseMessage(value, opts) { const length = getValueLength(value); if (length > opts.maxIncomingMessageSize) { throw new (0, _chunkRIAC4EUGcjs.MessageTooLong)(); } const deserializedValue = await deserialize(value, opts.encoding); const { data: message, success, error } = ToServerSchema.safeParse(deserializedValue); if (!success) { throw new (0, _chunkRIAC4EUGcjs.MalformedMessage)(error); } return message; } var LOGGER_NAME = "actor-manager"; function logger22() { return _chunkRIAC4EUGcjs.getLogger.call(void 0, LOGGER_NAME); } var HonoWebSocketAdapter = (_class2 = class { // WebSocket readyState values __init3() {this.CONNECTING = 0} __init4() {this.OPEN = 1} __init5() {this.CLOSING = 2} __init6() {this.CLOSED = 3} #ws; #readyState = 1; // Start as OPEN since WSContext is already connected #eventListeners = /* @__PURE__ */ new Map(); #closeCode; #closeReason; constructor(ws) {;_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this); this.#ws = ws; this.#readyState = this.OPEN; setTimeout(() => { this.#fireEvent("open", { type: "open", target: this }); }, 0); } get readyState() { return this.#readyState; } get binaryType() { return "arraybuffer"; } set binaryType(value) { } get bufferedAmount() { return 0; } get extensions() { return ""; } get protocol() { return ""; } get url() { return ""; } send(data) { if (this.readyState !== this.OPEN) { throw new Error("WebSocket is not open"); } try { logger22().debug("bridge sending data", { dataType: typeof data, isString: typeof data === "string", isArrayBuffer: data instanceof ArrayBuffer, dataStr: typeof data === "string" ? data.substring(0, 100) : "<non-string>" }); if (typeof data === "string") { this.#ws.send(data); } else if (data instanceof ArrayBuffer) { this.#ws.send(data); } else if (ArrayBuffer.isView(data)) { const buffer = data.buffer.slice( data.byteOffset, data.byteOffset + data.byteLength ); if (buffer instanceof SharedArrayBuffer) { const arrayBuffer = new ArrayBuffer(buffer.byteLength); new Uint8Array(arrayBuffer).set(new Uint8Array(buffer)); this.#ws.send(arrayBuffer); } else { this.#ws.send(buffer); } } else if (data instanceof Blob) { data.arrayBuffer().then((buffer) => { this.#ws.send(buffer); }).catch((error) => { logger22().error("failed to convert blob to arraybuffer", { error }); this.#fireEvent("error", { type: "error", target: this, error }); }); } else { logger22().warn("unsupported data type, converting to string", { dataType: typeof data, data }); this.#ws.send(String(data)); } } catch (error) { logger22().error("error sending websocket data", { error }); this.#fireEvent("error", { type: "error", target: this, error }); throw error; } } close(code = 1e3, reason = "") { if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) { return; } this.#readyState = this.CLOSING; this.#closeCode = code; this.#closeReason = reason; try { this.#ws.close(code, reason); this.#readyState = this.CLOSED; this.#fireEvent("close", { type: "close", target: this, code, reason, wasClean: code === 1e3 }); } catch (error) { logger22().error("error closing websocket", { error }); this.#readyState = this.CLOSED; this.#fireEvent("close", { type: "close", target: this, code: 1006, reason: "Abnormal closure", wasClean: false }); } } addEventListener(type, listener) { if (!this.#eventListeners.has(type)) { this.#eventListeners.set(type, /* @__PURE__ */ new Set()); } this.#eventListeners.get(type).add(listener); } removeEventListener(type, listener) { const listeners = this.#eventListeners.get(type); if (listeners) { listeners.delete(listener); } } dispatchEvent(event) { const listeners = this.#eventListeners.get(event.type); if (listeners) { for (const listener of listeners) { try { listener(event); } catch (error) { logger22().error(`error in ${event.type} event listener`, { error }); } } } return true; } // Internal method to handle incoming messages from WSContext _handleMessage(data) { let messageData; if (typeof data === "string") { messageData = data; } else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) { messageData = data; } else if (data && typeof data === "object" && "data" in data) { messageData = data.data; } else { messageData = String(data); } logger22().debug("bridge handling message", { dataType: typeof messageData, isArrayBuffer: messageData instanceof ArrayBuffer, dataStr: typeof messageData === "string" ? messageData : "<binary>" }); this.#fireEvent("message", { type: "message", target: this, data: messageData }); } // Internal method to handle close from WSContext _handleClose(code, reason) { this.#ws.close(1e3, "hack_force_close"); if (this.readyState === this.CLOSED) return; this.#readyState = this.CLOSED; this.#closeCode = code; this.#closeReason = reason; this.#fireEvent("close", { type: "close", target: this, code, reason, wasClean: code === 1e3 }); } // Internal method to handle errors from WSContext _handleError(error) { this.#fireEvent("error", { type: "error", target: this, error }); } #fireEvent(type, event) { const listeners = this.#eventListeners.get(type); if (listeners) { for (const listener of listeners) { try { listener(event); } catch (error) { logger22().error(`error in ${type} event listener`, { error }); } } } switch (type) { case "open": if (this.#onopen) { try { this.#onopen(event); } catch (error) { logger22().error("error in onopen handler", { error }); } } break; case "close": if (this.#onclose) { try { this.#onclose(event); } catch (error) { logger22().error("error in onclose handler", { error }); } } break; case "error": if (this.#onerror) { try { this.#onerror(event); } catch (error) { logger22().error("error in onerror handler", { error }); } } break; case "message": if (this.#onmessage) { try { this.#onmessage(event); } catch (error) { logger22().error("error in onmessage handler", { error }); } } break; } } // Event handler properties with getters/setters #onopen = null; #onclose = null; #onerror = null; #onmessage = null; get onopen() { return this.#onopen; } set onopen(handler) { this.#onopen = handler; } get onclose() { return this.#onclose; } set onclose(handler) { this.#onclose = handler; } get onerror() { return this.#onerror; } set onerror(handler) { this.#onerror = handler; } get onmessage() { return this.#onmessage; } set onmessage(handler) { this.#onmessage = handler; } }, _class2); async function handleWebSocketConnect(c, runConfig, actorDriver, actorId, encoding, parameters, authData) { const exposeInternalError = c ? getRequestExposeInternalError(c.req) : false; const { promise: handlersPromise, resolve: handlersResolve, reject: handlersReject } = Promise.withResolvers(); let actor; try { actor = await actorDriver.loadActor(actorId); } catch (error) { return { onOpen: (_evt, ws) => { const { code } = _chunkRIAC4EUGcjs.deconstructError.call(void 0, error, logger2(), { wsEvent: "open" }, exposeInternalError ); ws.close(1011, code); }, onMessage: (_evt, ws) => { ws.close(1011, "Actor not loaded"); }, onClose: (_event, _ws) => { }, onError: (_error) => { } }; } return { onOpen: (_evt, ws) => { logger2().debug("websocket open"); (async () => { try { const connId = generateConnId(); const connToken = generateConnToken(); const connState = await actor.prepareConn(parameters, c == null ? void 0 : c.req.raw); const connGlobalState = actorDriver.getGenericConnGlobalState(actorId); connGlobalState.websockets.set(connId, ws); logger2().debug("registered websocket for conn", { actorId, totalCount: connGlobalState.websockets.size }); const conn = await actor.createConn( connId, connToken, parameters, connState, CONN_DRIVER_GENERIC_WEBSOCKET, { encoding }, authData ); handlersResolve({ conn, actor, connId }); } catch (error) { handlersReject(error); const { code } = _chunkRIAC4EUGcjs.deconstructError.call(void 0, error, logger2(), { wsEvent: "open" }, exposeInternalError ); ws.close(1011, code); } })(); }, onMessage: (evt, ws) => { handlersPromise.then(({ conn, actor: actor2 }) => { logger2().debug("received message"); const value = evt.data.valueOf(); parseMessage(value, { encoding, maxIncomingMessageSize: runConfig.maxIncomingMessageSize }).then((message) => { actor2.processMessage(message, conn).catch((error) => { const { code } = _chunkRIAC4EUGcjs.deconstructError.call(void 0, error, logger2(), { wsEvent: "message" }, exposeInternalError ); ws.close(1011, code); }); }).catch((error) => { const { code } = _chunkRIAC4EUGcjs.deconstructError.call(void 0, error, logger2(), { wsEvent: "message" }, exposeInternalError ); ws.close(1011, code); }); }).catch((error) => { const { code } = _chunkRIAC4EUGcjs.deconstructError.call(void 0, error, logger2(), { wsEvent: "message" }, exposeInternalError ); ws.close(1011, code); }); }, onClose: (event, ws) => { if (event.wasClean) { logger2().info("websocket closed", { code: event.code, reason: event.reason, wasClean: event.wasClean }); } else { logger2().warn("websocket closed", { code: event.code, reason: event.reason, wasClean: event.wasClean }); } ws.close(1e3, "hack_force_close"); handlersPromise.then(({ conn, actor: actor2, connId }) => { const connGlobalState = actorDriver.getGenericConnGlobalState(actorId); const didDelete = connGlobalState.websockets.delete(connId); if (didDelete) { logger2().info("removing websocket for conn", { totalCount: connGlobalState.websockets.size }); } else { logger2().warn("websocket does not exist for conn", { actorId, totalCount: connGlobalState.websockets.size }); } actor2.__removeConn(conn); }).catch((error) => { _chunkRIAC4EUGcjs.deconstructError.call(void 0, error, logger2(), { wsEvent: "close" }, exposeInternalError ); }); }, onError: (_error) => { try { logger2().warn("websocket error"); } catch (error) { _chunkRIAC4EUGcjs.deconstructError.call(void 0, error, logger2(), { wsEvent: "error" }, exposeInternalError ); } } }; } async function handleSseConnect(c, runConfig, actorDriver, actorId, authData) { const encoding = getRequestEncoding(c.req); const parameters = getRequestConnParams(c.req); return _streaming.streamSSE.call(void 0, c, async (stream) => { let actor; let connId; let connToken; let connState; let conn; try { actor = await actorDriver.loadActor(actorId); connId = generateConnId(); connToken = generateConnToken(); connState = await actor.prepareConn(parameters, c.req.raw); logger2().debug("sse open"); actorDriver.getGenericConnGlobalState(actorId).sseStreams.set(connId, stream); conn = await actor.createConn( connId, connToken, parameters, connState, CONN_DRIVER_GENERIC_SSE, { encoding }, authData ); stream.onAbort(() => { }); const abortResolver = Promise.withResolvers(); c.req.raw.signal.addEventListener("abort", async () => { try { logger2().debug("sse shutting down"); if (connId) { actorDriver.getGenericConnGlobalState(actorId).sseStreams.delete(connId); } if (conn && actor) { actor.__removeConn(conn); } abortResolver.resolve(void 0); } catch (error) { logger2().error("error closing sse connection", { error }); } }); try { c.executionCtx.waitUntil(abortResolver.promise); } catch (e2) { } await abortResolver.promise; } catch (error) { logger2().error("error in sse connection", { error }); if (connId !== void 0) { actorDriver.getGenericConnGlobalState(actorId).sseStreams.delete(connId); } if (conn && actor !== void 0) { actor.__removeConn(conn); } stream.close(); } }); } async function handleAction(c, runConfig, actorDriver, actionName, actorId, authData) { const encoding = getRequestEncoding(c.req); const parameters = getRequestConnParams(c.req); logger2().debug("handling action", { actionName, encoding }); let body; if (encoding === "json") { try { body = await c.req.json(); } catch (err) { if (err instanceof _chunkRIAC4EUGcjs.InvalidActionRequest) { throw err; } throw new (0, _chunkRIAC4EUGcjs.InvalidActionRequest)( `Invalid JSON: ${_chunkRIAC4EUGcjs.stringifyError.call(void 0, err)}` ); } } else if (encoding === "cbor") { try { const value = await c.req.arrayBuffer(); const uint8Array = new Uint8Array(value); body = await deserialize(uint8Array, encoding); } catch (err) { throw new (0, _chunkRIAC4EUGcjs.InvalidActionRequest)( `Invalid binary format: ${_chunkRIAC4EUGcjs.stringifyError.call(void 0, err)}` ); } } else { return assertUnreachable2(encoding); } let actionArgs; try { const result = ActionRequestSchema.safeParse(body); if (!result.success) { throw new (0, _chunkRIAC4EUGcjs.InvalidActionRequest)("Invalid action request format"); } actionArgs = result.data.a; } catch (err) { throw new (0, _chunkRIAC4EUGcjs.InvalidActionRequest)( `Invalid schema: ${_chunkRIAC4EUGcjs.stringifyError.call(void 0, err)}` ); } let actor; let conn; let output; try { actor = await actorDriver.loadActor(actorId); const connState = await actor.prepareConn(parameters, c.req.raw); conn = await actor.createConn( generateConnId(), generateConnToken(), parameters, connState, CONN_DRIVER_GENERIC_HTTP, {}, authData ); const ctx = new ActionContext(actor.actorContext, conn); output = await actor.executeAction(ctx, actionName, actionArgs); } finally { if (conn) { actor == null ? void 0 : actor.__removeConn(conn); } } if (encoding === "json") { const responseData = { o: output // Use the format expected by ResponseOkSchema }; return c.json(responseData); } else if (encoding === "cbor") { const responseData = { o: output // Use the format expected by ResponseOkSchema }; const serialized = serialize(responseData, encoding); return c.body(serialized, 200, { "Content-Type": "application/octet-stream" }); } else { return assertUnreachable2(encoding); } } async function handleConnectionMessage(c, runConfig, actorDriver, connId, connToken, actorId) { const encoding = getRequestEncoding(c.req); let message; if (encoding === "json") { try { message = await c.req.json(); } catch (_err) { throw new (0, _chunkRIAC4EUGcjs.InvalidRequest)("Invalid JSON"); } } else if (encoding === "cbor") { try { const value = await c.req.arrayBuffer(); const uint8Array = new Uint8Array(value); message = await parseMessage(uint8Array, { encoding, maxIncomingMessageSize: runConfig.maxIncomingMessageSize }); } catch (err) { throw new (0, _chunkRIAC4EUGcjs.InvalidRequest)( `Invalid binary format: ${_chunkRIAC4EUGcjs.stringifyError.call(void 0, err)}` ); } } else { return assertUnreachable2(encoding); } const actor = await actorDriver.loadActor(actorId); const conn = actor.conns.get(connId); if (!conn) { throw new (0, _chunkRIAC4EUGcjs.ConnNotFound)(connId); } if (conn._token !== connToken) { throw new (0, _chunkRIAC4EUGcjs.IncorrectConnToken)(); } await actor.processMessage(message, conn); return c.json({}); } async function handleRawWebSocketHandler(c, path3, actorDriver, actorId, authData) { const actor = await actorDriver.loadActor(actorId); return { onOpen: (_evt, ws) => { const adapter = new HonoWebSocketAdapter(ws); ws.__adapter = adapter; const url = new URL(path3, "http://actor"); const pathname = url.pathname.replace(/^\/raw\/websocket/, "") || "/"; const normalizedPath = pathname + url.search; let newRequest; if (c) { newRequest = new Request(`http://actor${normalizedPath}`, c.req.raw); } else { newRequest = new Request(`http://actor${normalizedPath}`, { method: "GET" }); } logger2().debug("rewriting websocket url", { from: path3, to: newRequest.url }); actor.handleWebSocket(adapter, { request: newRequest, auth: authData }); }, onMessage: (event, ws) => { const adapter = ws.__adapter; if (adapter) { adapter._handleMessage(event); } }, onClose: (evt, ws) => { const adapter = ws.__adapter; if (adapter) { adapter._handleClose((evt == null ? void 0 : evt.code) || 1006, (evt == null ? void 0 : evt.reason) || ""); } }, onError: (error, ws) => { const adapter = ws.__adapter; if (adapter) { adapter._handleError(error); } } }; } function getRequestEncoding(req) { const encodingParam = req.header(HEADER_ENCODING); if (!encodingParam) { throw new (0, _chunkRIAC4EUGcjs.InvalidEncoding)("undefined"); } const result = EncodingSchema.safeParse(encodingParam); if (!result.success) { throw new (0, _chunkRIAC4EUGcjs.InvalidEncoding)(encodingParam); } return result.data; } function getRequestExposeInternalError(req) { const param = req.header(HEADER_EXPOSE_INTERNAL_ERROR); if (!param) { return false; } return param === "true"; } var HEADER_ACTOR_QUERY = "X-RivetKit-Query"; var HEADER_ENCODING = "X-RivetKit-Encoding"; var HEADER_EXPOSE_INTERNAL_ERROR = "X-RivetKit-Expose-Internal-Error"; var HEADER_CONN_PARAMS = "X-RivetKit-Conn-Params"; var HEADER_AUTH_DATA = "X-RivetKit-Auth-Data"; var HEADER_ACTOR_ID = "X-RivetKit-Actor"; var HEADER_CONN_ID = "X-RivetKit-Conn"; var HEADER_CONN_TOKEN = "X-RivetKit-Conn-Token"; function getRequestConnParams(req) { const paramsParam = req.header(HEADER_CONN_PARAMS); if (!paramsParam) { return null; } try { return JSON.parse(paramsParam); } catch (err) { throw new (0, _chunkRIAC4EUGcjs.InvalidParams)( `Invalid params JSON: ${_chunkRIAC4EUGcjs.stringifyError.call(void 0, err)}` ); } } var MAX_ACTOR_KEY_SIZE = 128; var ActorKeySchema = _zod.z.array(_zod.z.string().max(MAX_ACTOR_KEY_SIZE)); var CreateRequestSchema = _zod.z.object({ name: _zod.z.string(), key: ActorKeySchema, input: _zod.z.unknown().optional(), region: _zod.z.string().optional() }); var GetForKeyRequestSchema = _zod.z.object({ name: _zod.z.string(), key: ActorKeySchema }); var GetOrCreateRequestSchema = _zod.z.object({ name: _zod.z.string(), key: ActorKeySchema, input: _zod.z.unknown().optional(), region: _zod.z.string().optional() }); var ActorQuerySchema = _zod.z.union([ _zod.z.object({ getForId: _zod.z.object({ actorId: _zod.z.string() }) }), _zod.z.object({ getForKey: GetForKeyRequestSchema }), _zod.z.object({ getOrCreateForKey: GetOrCreateRequestSchema }), _zod.z.object({ create: CreateRequestSchema }) ]); var ConnectRequestSchema = _zod.z.object({ query: ActorQuerySchema.describe(HEADER_ACTOR_QUERY), encoding: EncodingSchema.describe(HEADER_ENCODING), connParams: _zod.z.string().optional().describe(HEADER_CONN_PARAMS) }); var ConnectWebSocketRequestSchema = _zod.z.object({ query: ActorQuerySchema.describe("query"), encoding: EncodingSchema.describe("encoding"), connParams: _zod.z.unknown().optional().describe("conn_params") }); var ConnMessageRequestSchema = _zod.z.object({ actorId: _zod.z.string().describe(HEADER_ACTOR_ID), connId: _zod.z.string().describe(HEADER_CONN_ID), encoding: EncodingSchema.describe(HEADER_ENCODING), connToken: _zod.z.string().describe(HEADER_CONN_TOKEN) }); var ResolveRequestSchema = _zod.z.object({ query: ActorQuerySchema.describe(HEADER_ACTOR_QUERY), connParams: _zod.z.string().optional().describe(HEADER_CONN_PARAMS) }); var ActorId = _v42.default.string().brand("ActorId"); var ActorFeature = /* @__PURE__ */ ((ActorFeature2) => { ActorFeature2["Logs"] = "logs"; ActorFeature2["Config"] = "config"; ActorFeature2["Connections"] = "connections"; ActorFeature2["State"] = "state"; ActorFeature2["Console"] = "console"; ActorFeature2["Runtime"] = "runtime"; ActorFeature2["Metrics"] = "metrics"; ActorFeature2["EventsMonitoring"] = "events-monitoring"; ActorFeature2["Database"] = "database"; return ActorFeature2; })(ActorFeature || {}); var ActorLogEntry = _v42.default.object({ level: _v42.default.string(), message: _v42.default.string(), timestamp: _v42.default.string(), metadata: _v42.default.record(_v42.default.string(), _v42.default.any()).optional() }); var ActorSchema = _v42.default.object({ id: ActorId, name: _v42.default.string(), key: _v42.default.array(_v42.default.string()), tags: _v42.default.record(_v42.default.string(), _v42.default.string()).optional(), region: _v42.default.string().optional(), createdAt: _v42.default.string().optional(), startedAt: _v42.default.string().optional(), destroyedAt: _v42.default.string().optional(), features: _v42.default.array(_v42.default.enum(ActorFeature)).optional() }); var OperationSchema = _v42.default.discriminatedUnion("op", [ _v42.default.object({ op: _v42.default.literal("remove"), path: _v42.default.string() }), _v42.default.object({ op: _v42.default.literal("add"), path: _v42.default.string(), value: _v42.default.unknown() }), _v42.default.object({ op: _v42.default.literal("replace"), path: _v42.default.string(), value: _v42.default.unknown() }), _v42.default.object({ op: _v42.default.literal("move"), path: _v42.default.string(), from: _v42.default.string() }), _v42.default.object({ op: _v42.default.literal("copy"), path: _v42.default.string(), from: _v42.default.string() }), _v42.default.object({ op: _v42.default.literal("test"), path: _v42.default.string(), value: _v42.default.unknown() }) ]); var PatchSchema = _v42.default.array(OperationSchema); var ConnectionSchema = _v42.default.object({ params: _v42.default.record(_v42.default.string(), _v42.default.any()).optional(), id: _v42.default.string(), stateEnabled: _v42.default.boolean().optional(), state: _v42.default.any().optional(), auth: _v42.default.record(_v42.default.string(), _v42.default.any()).optional() }); var RealtimeEventSchema = _v42.default.discriminatedUnion("type", [ _v42.default.object({ type: _v42.default.literal("action"), name: _v42.default.string(), args: _v42.default.array(_v42.default.any()), connId: _v42.default.string() }), _v42.default.object({ type: _v42.default.literal("broadcast"), eventName: _v42.default.string(), args: _v42.default.array(_v42.default.any()) }), _v42.default.object({ type: _v42.default.literal("subscribe"), eventName: _v42.default.string(), connId: _v42.default.string() }), _v42.default.object({ type: _v42.default.literal("unsubscribe"), eventName: _v42.default.string(), connId: _v42.default.string() }), _v42.default.object({ type: _v42.default.literal("event"), eventName: _v42.default.string(), args: _v42.default.array(_v42.default.any()), connId: _v42.default.string() }) ]); var RecordedRealtimeEventSchema = RealtimeEventSchema.and( _v42.default.object({ id: _v42.default.string(), timestamp: _v42.default.number() }) ); var DatabaseQuerySchema = _v42.default.object({ sql: _v42.default.string(), args: _v42.default.array(_v42.default.string().or(_v42.default.number())) }); var TableSchema = _v42.default.object({ schema: _v42.default.string(), name: _v42.default.string(), type: _v42.default.enum(["table", "view"]) }); var TablesSchema = _v42.default.array(TableSchema); var ColumnSchema = _v42.default.object({ cid: _v42.default.number(), name: _v42.default.string(), type: _v42.default.string().toLowerCase().transform((val) => { return _v42.default.enum(["integer", "text", "real", "blob", "numeric", "serial"]).parse(val); }), notnull: _v42.default.coerce.boolean(), dflt_value: _v42.default.string().nullable(), pk: _v42.default.coerce.boolean().nullable() }); var ColumnsSchema = _v42.default.array(ColumnSchema); var ForeignKeySchema = _v42.default.object({ id: _v42.default.number(), table: _v42.default.string(), from: _v42.default.string(), to: _v42.default.string() }); var ForeignKeysSchema = _v42.default.array(ForeignKeySchema); var BuildSchema = _v42.default.object({ name: _v42.default.string(), createdAt: _v42.default.string().optional(), tags: _v42.default.record(_v42.default.string(), _v42.default.string()).optional() }); var BuildsSchema = _v42.default.array(BuildSchema); var CreateActorSchema = _v42.default.object({ name: _v42.default.string(), // FIXME: Replace with ActorKeySchema when ready key: _v42.default.array(_v42.default.string().max(MAX_ACTOR_KEY_SIZE)), input: _v42.default.any() }); // ../../core/dist/chunk-EKNB2QDI.js var LOGGER_NAME2 = "actor-client"; function logger3() { return _chunkRIAC4EUGcjs.getLogger.call(void 0, LOGGER_NAME2); } // ../../core/dist/chunk-KFDEBHI5.js var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant); var _onchange = require('on-change'); var _onchange2 = _interopRequireDefault(_onchange); var _standardvalidator = require('@hono/standard-validator'); var _fastjsonpatch = require('@rivetkit/fast-json-patch'); var _fastjsonpatch2 = _interopRequireDefault(_fastjsonpatch); var _hono = require('hono'); var _nanoevents = require('nanoevents'); var _pretry = require('p-retry'); var _pretry2 = _interopRequireDefault(_pretry); function createActorInspectorRouter() { return new (0, _hono.Hono)().get("/ping", (c) => { return c.json({ message: "pong" }, 200); }).get("/state", async (c) => { if (await c.var.inspector.accessors.isStateEnabled()) { return c.json( { enabled: true, state: await c.var.inspector.accessors.getState() }, 200 ); } return c.json({ enabled: false, state: null }, 200); }).patch( "/state", _standardvalidator.sValidator.call(void 0, "json", _v42.default.object({ patch: PatchSchema }).or(_v42.default.object({ replace: _v42.default.any() })) ), async (c) => { if (!await c.var.inspector.accessors.isStateEnabled()) { return c.json({ enabled: false }, 200); } const body = c.req.valid("json"); if ("replace" in body) { await c.var.inspector.accessors.setState(body.replace); return c.json( { enabled: true, state: await c.var.inspector.accessors.getState() }, 200 ); } const state = await c.var.inspector.accessors.getState(); const { newDocument: newState } = _fastjsonpatch2.default.applyPatch( state, body.patch ); await c.var.inspector.accessors.setState(newState); return c.json( { enabled: true, state: await c.var.inspector.accessors.getState() }, 200 ); } ).get("/state/stream", async (c) => { if (!await c.var.inspector.accessors.isStateEnabled()) { return c.json({ enabled: false }, 200); } let id = 0; let unsub; return _streaming.streamSSE.call(void 0, c, async (stream) => { unsub = c.var.inspector.emitter.on("stateUpdated", async (state) => { stream.writeSSE({ data: JSON.stringify(state) || "", event: "state-update", id: String(id++) }); }); const { promise } = Promise.withResolvers(); return promise; }, async () => { unsub == null ? void 0 : unsub(); } ); }).get("/connections", async (c) => { const connections = await c.var.inspector.accessors.getConnections(); return c.json({ connections }, 200); }).get("/connections/stream", async (c) => { let id = 0; let unsub; return _streaming.streamSSE.call(void 0, c, async (stream) => { unsub = c.var.inspector.emitter.on("connectionUpdated", async () => { stream.writeSSE({ data: JSON.stringify( await c.var.inspector.accessors.getConnections() ), event: "connection-update", id: String(id++) }); }); const { promise } = Promise.withResolvers(); return promise; }, async () => { unsub == null ? void 0 : unsub(); } ); }).get("/events", async (c) => { const events = c.var.inspector.lastRealtimeEvents; return c.json({ events }, 200); }).post("/events/clear", async (c) => { c.var.inspector.lastRealtimeEvents.length = 0; return c.json({ message: "Events cleared" }, 200); }).get("/events/stream", async (c) => { let id = 0; let unsub; return _streaming.streamSSE.call(void 0, c, async (stream) => { unsub = c.var.inspector.emitter.on("eventFired", () => { stream.writeSSE({ data: JSON.stringify(c.var.inspector.lastRealtimeEvents), event: "realtime-event", id: String(id++) }); }); const { promise } = Promise.withResolvers(); return promise; }, async () => { unsub == null ? void 0 : unsub(); } ); }).get("/rpcs", async (c) => { const rpcs = await c.var.inspector.accessors.getRpcs(); return c.json({ rpcs }, 200); }).get("/db", async (c) => { if (!await c.var.inspector.accessors.isDbEnabled()) { return c.json({ enabled: false, db: null }, 200); } const db = await c.var.inspector.accessors.getDb(); const rows = await db.execute(`PRAGMA table_list`); const tables = TablesSchema.parse(rows).filter( (table) => table.schema !== "temp" && !table.name.startsWith("sqlite_") ); const tablesInfo = await Promise.all( tables.map((table) => db.execute(`PRAGMA table_info(${table.name})`)) ); const columns = tablesInfo.map((def) => ColumnsSchema.parse(def)); const foreignKeysList = await Promise.all( tables.map( (table) => db.execute(`PRAGMA foreign_key_list(${table.name})`) ) ); const foreignKeys = foreignKeysList.map( (def) => ForeignKeysSchema.parse(def) ); const countInfo = await Promise.all( tables.map( (table) => db.execute(`SELECT COUNT(*) as count FROM ${table.name}`) ) ); const counts = countInfo.map((def) => { return def[0].count || 0; }); return c.json( { enabled: true, db: tablesInfo.map((_, index) => { return { table: tables[index], columns: columns[index], foreignKeys: foreignKeys[index], records: counts[index] }; }) }, 200 ); }).post( "/db", _standardvalidator.sValidator.call(void 0, "json", _v42.default.object({ query: _v42.default.string(), params: _v42.default.array(_v42.default.any()).optional() }) ), async (c) => { if (!await c.var.inspector.accessors.isDbEnabled()) { return c.json({ enabled: false }, 200); } const db = await c.var.inspector.accessors.getDb(); try { const result = await db.execute( c.req.valid("json").query, ...c.req.valid("json").params || [] ); return c.json({ result }, 200); } catch (error) { c; return c.json({ error: error.message }, 500); } } ); } function lookupInRegistry(registryConfig, name) { const definition = registryConfig.use[name]; if (!definition) throw new Error(`no actor in registry for name ${name}`); return definition; } var ActorClientError = class extends Error { }; var InternalError2 = class extends ActorClientError { }; var ActorError = (_class3 = class extends ActorClientError { constructor(code, message, metadata) { super(message);_class3.prototype.__init7.call(this);; this.code = code; this.metadata = metadata; } __init7() {this.__type = "ActorError"} }, _class3); var HttpRequestError = class extends ActorClientError { constructor(message, opts) { super(`HTTP request error: ${message}`, { cause: opts == null ? void 0 : opts.cause }); } }; var ActorConnDisposed = class extends ActorClientError { constructor() { super("Attempting to interact with a disposed actor connection."); } }; async function rawHttpFetch(driver, actorQuery, params, input, init) { let path3; let mergedInit = init || {}; if (typeof input === "string") { path3 = input; } else if (input instanceof URL) { path3 = input.pathname + input.search; } else if (input instanceof Request) { const url = new URL(input.url); path3 = url.pathname + url.search; const requestHeaders = new Headers(input.headers); const initHeaders = new Headers((init == null ? void 0 : init.headers) || {}); const mergedHeaders = new Headers(requestHeaders); for (const [key, value] of initHeaders) { mergedHeaders.set(key, value); } mergedInit = { method: input.method, body: input.body, mode: input.mode, credentials: input.credentials, redirect: input.redirect, referrer: input.referrer, referrerPolicy: input.referrerPolicy, integrity: input.integrity, keepalive: input.keepalive, signal: input.signal, ...mergedInit, // init overrides Request properties headers: mergedHeaders // headers must be set after spread to ensure proper merge }; if (mergedInit.body) { mergedInit.duplex = "half"; } } else { throw new TypeError("Invalid input type for fetch"); } return await driver.rawHttpRequest( void 0, actorQuery, // Force JSON so it's readable by the user "json", params, path3, mergedInit, void 0 ); } async function rawWebSocket(driver, actorQuery, params, path3, protocols) { return await driver.rawWebSocket( void 0, actorQuery, // Force JSON so it's readable by the user "json", params, path3 || "", protocols, void 0 ); } var ActorHandleRaw = class { #client; #driver; #encodingKind; #actorQuery; #params; /** * Do not call this directly. * * Creates an instance of ActorHandleRaw. * * @protected */ constructor(client, driver, params, encodingKind, actorQuery) { this.#client = client; this.#driver = driver; this.#encodingKind = encodingKind; this.#actorQuery = actorQuery; this.#params = params; } /** * Call a raw action. This method sends an HTTP request to invoke the named action. * * @see {@link ActorHandle} * @template Args - The type of arguments to pass to the action function. * @template Response - The type of the response returned by the action function. */ async action(opts) { return await this.#driver.action( void 0, this.#actorQuery, this.#encodingKind, this.#params, opts.name, opts.args, { signal: opts.signal } ); } /** * Establishes a persistent connection to the actor. * * @template AD The actor class that this connection is for. * @returns {ActorConn<AD>} A connection to the actor. */ connect() { logger3().debug("establishing connection from handle", { query: this.#actorQuery }); const conn = new ActorConnRaw( this.#client, this.#driver, this.#params, this.#encodingKind, this.#actorQuery ); return this.#client[CREATE_ACTOR_CONN_PROXY]( conn ); } /** * Makes a raw HTTP request to the actor. * * @param input - The URL, path, or Request object * @param init - Standard fetch RequestInit options * @returns Promise<Response> - The raw HTTP response */ async fetch(input, init) { return rawHttpFetch( this.#driver, this.#actorQuery, this.#params, input, init ); } /** * Creates a raw WebSocket connection to the actor. * * @param path - The path for the WebSocket connection (e.g., "stream") * @param protocols - Optional WebSocket subprotocols * @returns WebSocket - A raw WebSocket connection */ async websocket(path3, protocols) { return rawWebSocket(