UNPKG

@rivetkit/core

Version:

1,664 lines (1,564 loc) 48.8 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 }; } var _class; var _class2; var _class3; var _class4; var _chunk4KRNEW7Dcjs = require('./chunk-4KRNEW7D.cjs'); var _chunkHIB3AS73cjs = require('./chunk-HIB3AS73.cjs'); var _chunk53LWTTEXcjs = require('./chunk-53LWTTEX.cjs'); // src/actor/protocol/serde.ts var _cborx = require('cbor-x'); var cbor = _interopRequireWildcard(_cborx); var _zod = require('zod'); // src/actor/log.ts var RUNTIME_LOGGER_NAME = "actor-runtime"; var ACTOR_LOGGER_NAME = "actor"; function logger() { return _chunk4KRNEW7Dcjs.getLogger.call(void 0, RUNTIME_LOGGER_NAME); } function instanceLogger() { return _chunk4KRNEW7Dcjs.getLogger.call(void 0, ACTOR_LOGGER_NAME); } // src/actor/utils.ts function assertUnreachable(x) { logger().error("unreachable", { value: `${x}`, stack: new Error().stack }); throw new (0, _chunk53LWTTEXcjs.Unreachable)(x); } var DeadlineError = class extends Error { constructor() { super("Promise did not complete before deadline."); } }; function deadline(promise, timeout) { const controller = new AbortController(); const signal = controller.signal; const timeoutId = setTimeout(() => controller.abort(), timeout); return Promise.race([ promise, new Promise((_, reject) => { signal.addEventListener("abort", () => reject(new DeadlineError())); }) ]).finally(() => { clearTimeout(timeoutId); }); } var Lock = (_class = class { constructor(_value) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this); this._value = _value; } __init() {this._locked = false} __init2() {this._waiting = []} async lock(fn) { if (this._locked) { await new Promise((resolve) => this._waiting.push(resolve)); } this._locked = true; try { await fn(this._value); } finally { this._locked = false; const next = this._waiting.shift(); if (next) next(); } } }, _class); 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; } // src/actor/protocol/serde.ts var EncodingSchema = _zod.z.enum(["json", "cbor"]); var CachedSerializer = class { #data; #cache = /* @__PURE__ */ new Map(); constructor(data) { this.#data = data; } get rawData() { return this.#data; } serialize(encoding) { const cached = this.#cache.get(encoding); if (cached) { return cached; } else { const serialized = serialize(this.#data, encoding); this.#cache.set(encoding, serialized); return serialized; } } }; 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 { assertUnreachable(encoding); } } async function deserialize(data, encoding) { if (encoding === "json") { if (typeof data !== "string") { logger().warn("received non-string for json parse"); throw new (0, _chunk53LWTTEXcjs.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 { logger().warn("received non-binary type for cbor parse"); throw new (0, _chunk53LWTTEXcjs.MalformedMessage)(); } } else { assertUnreachable(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 { assertUnreachable(message); } } // src/actor/connection.ts function generateConnId() { return crypto.randomUUID(); } function generateConnToken() { return generateSecureToken(32); } var Conn = (_class2 = class { __init3() {this.subscriptions = /* @__PURE__ */ new Set()} #stateEnabled; // TODO: Remove this cyclical reference #actor; /** * The proxied state that notifies of changes automatically. * * Any data that should be stored indefinitely should be held within this object. */ /** * Driver used to manage realtime connection communication. * * @protected */ #driver; get params() { return this.__persist.p; } get auth() { return this.__persist.a; } get _stateEnabled() { return this.#stateEnabled; } /** * Gets the current state of the connection. * * Throws an error if the state is not enabled. */ get state() { this.#validateStateEnabled(); if (!this.__persist.s) throw new Error("state should exists"); return this.__persist.s; } /** * Sets the state of the connection. * * Throws an error if the state is not enabled. */ set state(value) { this.#validateStateEnabled(); this.__persist.s = value; } /** * Unique identifier for the connection. */ get id() { return this.__persist.i; } /** * Token used to authenticate this request. */ get _token() { return this.__persist.t; } /** * Initializes a new instance of the Connection class. * * This should only be constructed by {@link Actor}. * * @protected */ constructor(actor, persist, driver, stateEnabled) {;_class2.prototype.__init3.call(this); this.#actor = actor; this.__persist = persist; this.#driver = driver; this.#stateEnabled = stateEnabled; } #validateStateEnabled() { if (!this.#stateEnabled) { throw new (0, _chunk53LWTTEXcjs.ConnStateNotEnabled)(); } } /** * Sends a WebSocket message to the client. * * @param message - The message to send. * * @protected */ _sendMessage(message) { var _a, _b; (_b = (_a = this.#driver).sendMessage) == null ? void 0 : _b.call(_a, this.#actor, this, this.__persist.ds, message); } /** * Sends an event with arguments to the client. * * @param eventName - The name of the event. * @param args - The arguments for the event. * @see {@link https://rivet.gg/docs/events|Events Documentation} */ send(eventName, ...args) { this.#actor.inspector.emitter.emit("eventFired", { type: "event", eventName, args, connId: this.id }); this._sendMessage( new CachedSerializer({ b: { ev: { n: eventName, a: args } } }) ); } /** * Disconnects the client with an optional reason. * * @param reason - The reason for disconnection. */ async disconnect(reason) { await this.#driver.disconnect(this.#actor, this, this.__persist.ds, reason); } }, _class2); // src/actor/generic-conn-driver.ts var GenericConnGlobalState = (_class3 = class {constructor() { _class3.prototype.__init4.call(this);_class3.prototype.__init5.call(this); } __init4() {this.websockets = /* @__PURE__ */ new Map()} __init5() {this.sseStreams = /* @__PURE__ */ new Map()} }, _class3); 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) { logger().warn("missing ws for sendMessage", { actorId: actor.id, connId: conn.id, totalCount: globalState.websockets.size }); return; } const serialized = message.serialize(state.encoding); logger().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)); logger().debug("converted SharedArrayBuffer to ArrayBuffer", { byteLength: arrayBuffer.byteLength }); ws.send(arrayBuffer); } else { logger().debug("sending ArrayBuffer", { byteLength: buffer.byteLength }); ws.send(buffer); } } else { logger().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) { logger().warn("missing ws for disconnect", { actorId: actor.id, connId: conn.id, totalCount: globalState.websockets.size }); return; } const raw = ws.raw; if (!raw) { logger().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) { logger().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) { logger().warn("missing sse stream for disconnect", { connId: conn.id }); return; } stream.close(); } }; } var CONN_DRIVER_GENERIC_HTTP = "genericHttp"; function createGeneircHttpDriver() { return { disconnect: async () => { } }; } // src/actor/router-endpoints.ts var _streaming = require('hono/streaming'); // src/actor/action.ts 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); } }; // src/actor/protocol/http/action.ts var ActionRequestSchema = _zod.z.object({ // Args a: _zod.z.array(_zod.z.unknown()) }); var ActionResponseSchema = _zod.z.object({ // Output o: _zod.z.unknown() }); // src/actor/protocol/message/mod.ts // src/actor/protocol/message/to-server.ts 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 }) ]) }); // src/actor/protocol/message/mod.ts 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 { assertUnreachable(value); } } async function parseMessage(value, opts) { const length = getValueLength(value); if (length > opts.maxIncomingMessageSize) { throw new (0, _chunk53LWTTEXcjs.MessageTooLong)(); } const deserializedValue = await deserialize(value, opts.encoding); const { data: message, success, error } = ToServerSchema.safeParse(deserializedValue); if (!success) { throw new (0, _chunk53LWTTEXcjs.MalformedMessage)(error); } return message; } async function processMessage(message, actor, conn, handler) { let actionId; let actionName; try { if ("ar" in message.b) { if (handler.onExecuteAction === void 0) { throw new (0, _chunk53LWTTEXcjs.Unsupported)("Action"); } const { i: id, n: name, a: args = [] } = message.b.ar; actionId = id; actionName = name; logger().debug("processing action request", { id, name, argsCount: args.length }); const ctx = new ActionContext( actor.actorContext, conn ); const output = await handler.onExecuteAction(ctx, name, args); logger().debug("sending action response", { id, name, outputType: typeof output, isPromise: output instanceof Promise }); conn._sendMessage( new CachedSerializer({ b: { ar: { i: id, o: output } } }) ); logger().debug("action response sent", { id, name }); } else if ("sr" in message.b) { if (handler.onSubscribe === void 0 || handler.onUnsubscribe === void 0) { throw new (0, _chunk53LWTTEXcjs.Unsupported)("Subscriptions"); } const { e: eventName, s: subscribe } = message.b.sr; logger().debug("processing subscription request", { eventName, subscribe }); if (subscribe) { await handler.onSubscribe(eventName, conn); } else { await handler.onUnsubscribe(eventName, conn); } logger().debug("subscription request completed", { eventName, subscribe }); } else { assertUnreachable(message.b); } } catch (error) { const { code, message: message2, metadata } = _chunkHIB3AS73cjs.deconstructError.call(void 0, error, logger(), { connectionId: conn.id, actionId, actionName }); logger().debug("sending error response", { actionId, actionName, code, message: message2 }); conn._sendMessage( new CachedSerializer({ b: { e: { c: code, m: message2, md: metadata, ai: actionId } } }) ); logger().debug("error response sent", { actionId, actionName }); } } // src/manager/log.ts var LOGGER_NAME = "actor-manager"; function logger2() { return _chunk4KRNEW7Dcjs.getLogger.call(void 0, LOGGER_NAME); } // src/manager/hono-websocket-adapter.ts var HonoWebSocketAdapter = (_class4 = class { // WebSocket readyState values __init6() {this.CONNECTING = 0} __init7() {this.OPEN = 1} __init8() {this.CLOSING = 2} __init9() {this.CLOSED = 3} #ws; #readyState = 1; // Start as OPEN since WSContext is already connected #eventListeners = /* @__PURE__ */ new Map(); #closeCode; #closeReason; constructor(ws) {;_class4.prototype.__init6.call(this);_class4.prototype.__init7.call(this);_class4.prototype.__init8.call(this);_class4.prototype.__init9.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 { logger2().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) => { logger2().error("failed to convert blob to arraybuffer", { error }); this.#fireEvent("error", { type: "error", target: this, error }); }); } else { logger2().warn("unsupported data type, converting to string", { dataType: typeof data, data }); this.#ws.send(String(data)); } } catch (error) { logger2().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) { logger2().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) { logger2().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); } logger2().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) { logger2().error(`error in ${type} event listener`, { error }); } } } switch (type) { case "open": if (this.#onopen) { try { this.#onopen(event); } catch (error) { logger2().error("error in onopen handler", { error }); } } break; case "close": if (this.#onclose) { try { this.#onclose(event); } catch (error) { logger2().error("error in onclose handler", { error }); } } break; case "error": if (this.#onerror) { try { this.#onerror(event); } catch (error) { logger2().error("error in onerror handler", { error }); } } break; case "message": if (this.#onmessage) { try { this.#onmessage(event); } catch (error) { logger2().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; } }, _class4); // src/actor/router-endpoints.ts 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 } = _chunkHIB3AS73cjs.deconstructError.call(void 0, error, logger(), { 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) => { logger().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); logger().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 } = _chunkHIB3AS73cjs.deconstructError.call(void 0, error, logger(), { wsEvent: "open" }, exposeInternalError ); ws.close(1011, code); } })(); }, onMessage: (evt, ws) => { handlersPromise.then(({ conn, actor: actor2 }) => { logger().debug("received message"); const value = evt.data.valueOf(); parseMessage(value, { encoding, maxIncomingMessageSize: runConfig.maxIncomingMessageSize }).then((message) => { actor2.processMessage(message, conn).catch((error) => { const { code } = _chunkHIB3AS73cjs.deconstructError.call(void 0, error, logger(), { wsEvent: "message" }, exposeInternalError ); ws.close(1011, code); }); }).catch((error) => { const { code } = _chunkHIB3AS73cjs.deconstructError.call(void 0, error, logger(), { wsEvent: "message" }, exposeInternalError ); ws.close(1011, code); }); }).catch((error) => { const { code } = _chunkHIB3AS73cjs.deconstructError.call(void 0, error, logger(), { wsEvent: "message" }, exposeInternalError ); ws.close(1011, code); }); }, onClose: (event, ws) => { if (event.wasClean) { logger().info("websocket closed", { code: event.code, reason: event.reason, wasClean: event.wasClean }); } else { logger().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) { logger().info("removing websocket for conn", { totalCount: connGlobalState.websockets.size }); } else { logger().warn("websocket does not exist for conn", { actorId, totalCount: connGlobalState.websockets.size }); } actor2.__removeConn(conn); }).catch((error) => { _chunkHIB3AS73cjs.deconstructError.call(void 0, error, logger(), { wsEvent: "close" }, exposeInternalError ); }); }, onError: (_error) => { try { logger().warn("websocket error"); } catch (error) { _chunkHIB3AS73cjs.deconstructError.call(void 0, error, logger(), { 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); logger().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 { logger().debug("sse shutting down"); if (connId) { actorDriver.getGenericConnGlobalState(actorId).sseStreams.delete(connId); } if (conn && actor) { actor.__removeConn(conn); } abortResolver.resolve(void 0); } catch (error) { logger().error("error closing sse connection", { error }); } }); try { c.executionCtx.waitUntil(abortResolver.promise); } catch (e2) { } await abortResolver.promise; } catch (error) { logger().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); logger().debug("handling action", { actionName, encoding }); let body; if (encoding === "json") { try { body = await c.req.json(); } catch (err) { if (err instanceof _chunk53LWTTEXcjs.InvalidActionRequest) { throw err; } throw new (0, _chunk53LWTTEXcjs.InvalidActionRequest)( `Invalid JSON: ${_chunkHIB3AS73cjs.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, _chunk53LWTTEXcjs.InvalidActionRequest)( `Invalid binary format: ${_chunkHIB3AS73cjs.stringifyError.call(void 0, err)}` ); } } else { return assertUnreachable(encoding); } let actionArgs; try { const result = ActionRequestSchema.safeParse(body); if (!result.success) { throw new (0, _chunk53LWTTEXcjs.InvalidActionRequest)("Invalid action request format"); } actionArgs = result.data.a; } catch (err) { throw new (0, _chunk53LWTTEXcjs.InvalidActionRequest)( `Invalid schema: ${_chunkHIB3AS73cjs.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 assertUnreachable(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, _chunk53LWTTEXcjs.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, _chunk53LWTTEXcjs.InvalidRequest)( `Invalid binary format: ${_chunkHIB3AS73cjs.stringifyError.call(void 0, err)}` ); } } else { return assertUnreachable(encoding); } const actor = await actorDriver.loadActor(actorId); const conn = actor.conns.get(connId); if (!conn) { throw new (0, _chunk53LWTTEXcjs.ConnNotFound)(connId); } if (conn._token !== connToken) { throw new (0, _chunk53LWTTEXcjs.IncorrectConnToken)(); } await actor.processMessage(message, conn); return c.json({}); } async function handleRawWebSocketHandler(c, path, 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(path, "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" }); } logger().debug("rewriting websocket url", { from: path, 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, _chunk53LWTTEXcjs.InvalidEncoding)("undefined"); } const result = EncodingSchema.safeParse(encodingParam); if (!result.success) { throw new (0, _chunk53LWTTEXcjs.InvalidEncoding)(encodingParam); } return result.data; } function getRequestExposeInternalError(req) { const param = req.header(HEADER_EXPOSE_INTERNAL_ERROR); if (!param) { return false; } return param === "true"; } function getRequestQuery(c) { const queryParam = c.req.header(HEADER_ACTOR_QUERY); if (!queryParam) { logger().error("missing query parameter"); throw new (0, _chunk53LWTTEXcjs.InvalidRequest)("missing query"); } try { const parsed = JSON.parse(queryParam); return parsed; } catch (error) { logger().error("invalid query json", { error }); throw new (0, _chunk53LWTTEXcjs.InvalidQueryJSON)(error); } } 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"; var ALLOWED_PUBLIC_HEADERS = [ "Content-Type", "User-Agent", HEADER_ACTOR_QUERY, HEADER_ENCODING, HEADER_CONN_PARAMS, HEADER_ACTOR_ID, HEADER_CONN_ID, HEADER_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, _chunk53LWTTEXcjs.InvalidParams)( `Invalid params JSON: ${_chunkHIB3AS73cjs.stringifyError.call(void 0, err)}` ); } } // src/inspector/protocol/common.ts var _v4 = require('zod/v4'); var _v42 = _interopRequireDefault(_v4); // src/manager/protocol/query.ts 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) }); // src/inspector/protocol/common.ts 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() }); exports.logger = logger; exports.instanceLogger = instanceLogger; exports.assertUnreachable = assertUnreachable; exports.DeadlineError = DeadlineError; exports.deadline = deadline; exports.Lock = Lock; exports.generateRandomString = generateRandomString; exports.EncodingSchema = EncodingSchema; exports.CachedSerializer = CachedSerializer; exports.serialize = serialize; exports.generateConnId = generateConnId; exports.generateConnToken = generateConnToken; exports.Conn = Conn; exports.processMessage = processMessage; exports.logger2 = logger2; exports.GenericConnGlobalState = GenericConnGlobalState; exports.createGenericConnDrivers = createGenericConnDrivers; exports.handleWebSocketConnect = handleWebSocketConnect; exports.handleSseConnect = handleSseConnect; exports.handleAction = handleAction; exports.handleConnectionMessage = handleConnectionMessage; exports.handleRawWebSocketHandler = handleRawWebSocketHandler; exports.getRequestEncoding = getRequestEncoding; exports.getRequestExposeInternalError = getRequestExposeInternalError; exports.getRequestQuery = getRequestQuery; exports.HEADER_ACTOR_QUERY = HEADER_ACTOR_QUERY; exports.HEADER_ENCODING = HEADER_ENCODING; exports.HEADER_EXPOSE_INTERNAL_ERROR = HEADER_EXPOSE_INTERNAL_ERROR; exports.HEADER_CONN_PARAMS = HEADER_CONN_PARAMS; exports.HEADER_AUTH_DATA = HEADER_AUTH_DATA; exports.HEADER_ACTOR_ID = HEADER_ACTOR_ID; exports.HEADER_CONN_ID = HEADER_CONN_ID; exports.HEADER_CONN_TOKEN = HEADER_CONN_TOKEN; exports.ALLOWED_PUBLIC_HEADERS = ALLOWED_PUBLIC_HEADERS; exports.ActorQuerySchema = ActorQuerySchema; exports.ConnectRequestSchema = ConnectRequestSchema; exports.ConnectWebSocketRequestSchema = ConnectWebSocketRequestSchema; exports.ConnMessageRequestSchema = ConnMessageRequestSchema; exports.ResolveRequestSchema = ResolveRequestSchema; exports.ActorId = ActorId; exports.ActorFeature = ActorFeature; exports.ActorLogEntry = ActorLogEntry; exports.ActorSchema = ActorSchema; exports.OperationSchema = OperationSchema; exports.PatchSchema = PatchSchema; exports.ConnectionSchema = ConnectionSchema; exports.RealtimeEventSchema = RealtimeEventSchema; exports.RecordedRealtimeEventSchema = RecordedRealtimeEventSchema; exports.DatabaseQuerySchema = DatabaseQuerySchema; exports.TableSchema = TableSchema; exports.TablesSchema = TablesSchema; exports.ColumnSchema = ColumnSchema; exports.ColumnsSchema = ColumnsSchema; exports.ForeignKeySchema = ForeignKeySchema; exports.ForeignKeysSchema = ForeignKeysSchema; exports.BuildSchema = BuildSchema; exports.BuildsSchema = BuildsSchema; exports.CreateActorSchema = CreateActorSchema; //# sourceMappingURL=chunk-OBXZ7YJ7.cjs.map