@rivetkit/core
Version:
1,664 lines (1,564 loc) • 48.8 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 }; } 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