@rivetkit/redis
Version:
_Lightweight Libraries for Backends_
1,663 lines (1,627 loc) • 138 kB
JavaScript
"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(