diff --git a/packages/rivetkit/scripts/dump-openapi.ts b/packages/rivetkit/scripts/dump-openapi.ts index b582e50d6..4022e0729 100644 --- a/packages/rivetkit/scripts/dump-openapi.ts +++ b/packages/rivetkit/scripts/dump-openapi.ts @@ -16,6 +16,9 @@ function main() { const driverConfig: RunConfig = RunConfigSchema.parse({ driver: createFileSystemOrMemoryDriver(false), getUpgradeWebSocket: () => () => unimplemented(), + inspector: { + enabled: false, + }, }); const managerDriver: ManagerDriver = { diff --git a/packages/rivetkit/src/actor/router.ts b/packages/rivetkit/src/actor/router.ts index 3802215f8..53025ba59 100644 --- a/packages/rivetkit/src/actor/router.ts +++ b/packages/rivetkit/src/actor/router.ts @@ -1,4 +1,5 @@ import { Hono, type Context as HonoContext } from "hono"; +import { cors } from "hono/cors"; import invariant from "invariant"; import { EncodingSchema } from "@/actor/protocol/serde"; import { @@ -241,14 +242,18 @@ export function createActorRouter( router.route( "/inspect", new Hono() - .use(secureInspector(runConfig), async (c, next) => { - const inspector = (await actorDriver.loadActor(c.env.actorId)) - .inspector; - invariant(inspector, "inspector not supported on this platform"); - - c.set("inspector", inspector); - await next(); - }) + .use( + cors(runConfig.inspector.cors), + secureInspector(runConfig), + async (c, next) => { + const inspector = (await actorDriver.loadActor(c.env.actorId)) + .inspector; + invariant(inspector, "inspector not supported on this platform"); + + c.set("inspector", inspector); + return next(); + }, + ) .route("/", createActorInspectorRouter()), ); } diff --git a/packages/rivetkit/src/inspector/config.ts b/packages/rivetkit/src/inspector/config.ts index 88cd99cf5..c612f498d 100644 --- a/packages/rivetkit/src/inspector/config.ts +++ b/packages/rivetkit/src/inspector/config.ts @@ -24,6 +24,7 @@ const defaultEnabled = () => { const defaultInspectorOrigins = [ "http://localhost:43708", + "http://localhost:43709", "https://studio.rivet.gg", ]; @@ -40,10 +41,13 @@ const defaultCors: CorsOptions = { }, allowMethods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"], allowHeaders: [ - "Content-Type", "Authorization", - HEADER_ACTOR_QUERY, - "last-event-id", + "Content-Type", + "User-Agent", + "baggage", + "sentry-trace", + "x-rivet-actor", + "x-rivet-target", ], maxAge: 3600, credentials: true, diff --git a/packages/rivetkit/src/manager/router.ts b/packages/rivetkit/src/manager/router.ts index 4abc76876..87697f74d 100644 --- a/packages/rivetkit/src/manager/router.ts +++ b/packages/rivetkit/src/manager/router.ts @@ -1,14 +1,14 @@ import { createRoute, OpenAPIHono } from "@hono/zod-openapi"; import * as cbor from "cbor-x"; -import type { Hono } from "hono"; -import { cors } from "hono/cors"; +import { Hono } from "hono"; +import { cors as corsMiddleware } from "hono/cors"; +import { createMiddleware } from "hono/factory"; import { z } from "zod"; import { - ActorError, ActorNotFound, FeatureNotImplemented, MissingActorHeader, - RouteNotFound, + Unsupported, WebSocketsNotEnabled, } from "@/actor/errors"; import { @@ -16,6 +16,8 @@ import { handleRouteNotFound, loggerMiddleware, } from "@/common/router"; +import { createManagerInspectorRouter } from "@/inspector/manager"; +import { secureInspector } from "@/inspector/utils"; import { type ActorsCreateRequest, ActorsCreateRequestSchema, @@ -68,12 +70,12 @@ export function createManagerRouter( router.use("*", loggerMiddleware(logger())); - if (runConfig.cors) { - router.use("*", cors(runConfig.cors)); - } + const cors = runConfig.cors + ? corsMiddleware(runConfig.cors) + : createMiddleware((_c, next) => next()); // Actor proxy middleware - intercept requests with x-rivet-target=actor - router.use("*", async (c, next) => { + router.use("*", cors, async (c, next) => { const target = c.req.header("x-rivet-target"); const actorId = c.req.header("x-rivet-actor"); @@ -98,9 +100,16 @@ export function createManagerRouter( // For WebSocket, use the driver's proxyWebSocket method // Extract any additional headers that might be needed - const encoding = c.req.header("x-rivet-encoding") || "json"; - const connParams = c.req.header("x-rivet-conn-params"); - const authData = c.req.header("x-rivet-auth-data"); + const encoding = + c.req.header("X-RivetKit-Encoding") || + c.req.header("x-rivet-encoding") || + "json"; + const connParams = + c.req.header("X-RivetKit-Conn-Params") || + c.req.header("x-rivet-conn-params"); + const authData = + c.req.header("X-RivetKit-Auth-Data") || + c.req.header("x-rivet-auth-data"); return await managerDriver.proxyWebSocket( c, @@ -135,7 +144,7 @@ export function createManagerRouter( }); // GET / - router.get("/", (c) => { + router.get("/", cors, (c) => { return c.text( "This is a RivetKit server.\n\nLearn more at https://rivetkit.org", ); @@ -144,6 +153,7 @@ export function createManagerRouter( // GET /actors/by-id { const route = createRoute({ + middleware: [cors], method: "get", path: "/actors/by-id", request: { @@ -177,6 +187,7 @@ export function createManagerRouter( // PUT /actors/by-id { const route = createRoute({ + cors: [cors], method: "put", path: "/actors/by-id", request: { @@ -241,6 +252,7 @@ export function createManagerRouter( // GET /actors/{actor_id} { const route = createRoute({ + middleware: [cors], method: "get", path: "/actors/{actor_id}", request: { @@ -287,6 +299,7 @@ export function createManagerRouter( // POST /actors { const route = createRoute({ + middleware: [cors], method: "post", path: "/actors", request: { @@ -346,6 +359,7 @@ export function createManagerRouter( // DELETE /actors/{actor_id} { const route = createRoute({ + middleware: [cors], method: "delete", path: "/actors/{actor_id}", request: { @@ -370,6 +384,23 @@ export function createManagerRouter( }); } + if (runConfig.inspector?.enabled) { + if (!managerDriver.inspector) { + throw new Unsupported("inspector"); + } + router.route( + "/inspect", + new Hono<{ Variables: { inspector: any } }>() + .use(corsMiddleware(runConfig.inspector.cors)) + .use(secureInspector(runConfig)) + .use((c, next) => { + c.set("inspector", managerDriver.inspector!); + return next(); + }) + .route("/", createManagerInspectorRouter()), + ); + } + // Error handling router.notFound(handleRouteNotFound); router.onError(handleRouteError); diff --git a/packages/rivetkit/src/registry/mod.ts b/packages/rivetkit/src/registry/mod.ts index 895c61157..6ee7f1375 100644 --- a/packages/rivetkit/src/registry/mod.ts +++ b/packages/rivetkit/src/registry/mod.ts @@ -1,10 +1,6 @@ import type { Hono } from "hono"; import { type Client, createClientWithDriver } from "@/client/client"; -import { - configureBaseLogger, - configureDefaultLogger, - getPinoLevel, -} from "@/common/log"; +import { configureBaseLogger, configureDefaultLogger } from "@/common/log"; import { chooseDefaultDriver } from "@/drivers/default"; import { getInspectorUrl } from "@/inspector/utils"; import { createManagerRouter } from "@/manager/router"; @@ -86,7 +82,7 @@ export class Registry { definitions: Object.keys(this.#config.use).length, ...driverLog, }); - if (config.inspector?.enabled) { + if (config.inspector?.enabled && managerDriver.inspector) { logger().info({ msg: "inspector ready", url: getInspectorUrl(config) }); } @@ -100,7 +96,7 @@ export class Registry { const padding = " ".repeat(Math.max(0, 13 - k.length)); console.log(` - ${k}:${padding}${v}`); } - if (config.inspector?.enabled) { + if (config.inspector?.enabled && managerDriver.inspector) { console.log(` - Inspector: ${getInspectorUrl(config)}`); } console.log(); diff --git a/packages/rivetkit/src/remote-manager-driver/actor-websocket-client.ts b/packages/rivetkit/src/remote-manager-driver/actor-websocket-client.ts index abb7e9db0..3a08593cb 100644 --- a/packages/rivetkit/src/remote-manager-driver/actor-websocket-client.ts +++ b/packages/rivetkit/src/remote-manager-driver/actor-websocket-client.ts @@ -34,6 +34,9 @@ export async function openWebSocketToActor( headers: buildGuardHeadersForWebSocket(actorId, encoding, params), }); + // Set binary type to arraybuffer for proper encoding support + ws.binaryType = "arraybuffer"; + logger().debug({ msg: "websocket connection opened", actorId }); return ws as UniversalWebSocket;