Skip to content
This repository was archived by the owner on Oct 22, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions examples/better-auth/src/frontend/components/ChatRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import { createClient, createRivetKit } from "@rivetkit/react";
import { authClient } from "../auth-client";
import type { Registry } from "../../backend/registry";

const client = createClient<Registry>("http://localhost:8080/registry", {
transport: "sse",
});
const client = createClient<Registry>("http://localhost:8080/registry");

const { useActor } = createRivetKit(client);

Expand Down
46 changes: 21 additions & 25 deletions examples/elysia/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
// import { registry } from "./registry";
// import { Elysia } from "elysia";
// import { createMemoryDriver } from "@rivetkit/memory";
//
// // Start RivetKit
// const { client, handler } = registry.run({
// driver: createMemoryDriver(),
// });
//
// // Setup router
// const app = new Elysia()
// // Expose RivetKit to the frontend (optional)
// .mount("/registry", handler)
// // Example HTTP endpoint
// .post("/increment/:name", async ({ params }) => {
// const name = params.name;
//
// const counter = client.counter.getOrCreate(name);
// const newCount = await counter.increment(1);
//
// return `New Count: ${newCount}`;
// })
// .listen(8080);
//
// console.log("Listening at http://localhost:8080");
import { registry } from "./registry";
import { Elysia } from "elysia";

const { client, handler } = registry.createServer();

// Setup router
new Elysia()
// Expose RivetKit to the frontend (optional)
.mount("/registry", handler)
// Example HTTP endpoint
.post("/increment/:name", async ({ params }) => {
const name = params.name;

const counter = client.counter.getOrCreate(name);
const newCount = await counter.increment(1);

return `New Count: ${newCount}`;
})
.listen(8080);

console.log("Listening at http://localhost:8080");
2 changes: 1 addition & 1 deletion examples/express/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { registry } from "./registry";
import express from "express";

// Start RivetKit
const { client, handler } = registry.run();
const { client, handler } = registry.createServer();

// Setup router
const app = express();
Expand Down
57 changes: 24 additions & 33 deletions examples/hono-react/src/backend/server.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
// import { registry } from "./registry";
// import { Hono } from "hono";
// import { serve } from "@hono/node-server";
// import { createMemoryDriver } from "@rivetkit/memory";
//
// // Setup router
// const app = new Hono();
//
// // Start RivetKit
// const { client, hono } = registry.run({
// driver: createMemoryDriver(),
// cors: {
// // IMPORTANT: Configure origins in production
// origin: "*",
// },
// });
//
// // Expose RivetKit to the frontend
// app.route("/registry", hono);
//
// // Example HTTP endpoint
// app.post("/increment/:name", async (c) => {
// const name = c.req.param("name");
//
// const counter = client.counter.getOrCreate(name);
// const newCount = await counter.increment(1);
//
// return c.text(`New Count: ${newCount}`);
// });
//
// serve({ fetch: app.fetch, port: 8080 }, () =>
// console.log("Listening at http://localhost:8080"),
// );
import { registry } from "./registry";
import { Hono } from "hono";

const { client, serve } = registry.createServer({
cors: {
// IMPORTANT: Configure origins in production
origin: "*",
},
});

// Setup router
const app = new Hono();

// Example HTTP endpoint
app.post("/increment/:name", async (c) => {
const name = c.req.param("name");

const counter = client.counter.getOrCreate(name);
const newCount = await counter.increment(1);

return c.text(`New Count: ${newCount}`);
});

serve(app);
76 changes: 37 additions & 39 deletions examples/hono-react/src/frontend/App.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,37 @@
// import { useState } from "react";
// import { createClient, createRivetKit } from "@rivetkit/react";
// import type { Registry } from "../backend/registry";
//
// const client = createClient<Registry>("http://localhost:8080/registry", {
// transport: "sse",
// });
// const { useActor } = createRivetKit(client);
//
// function App() {
// const [count, setCount] = useState(0);
// const [counterName, setCounterName] = useState("test-counter");
//
// const counter = useActor({
// name: "counter",
// key: [counterName],
// });
//
// counter.useEvent("newCount", (x: number) => setCount(x));
//
// const increment = async () => {
// await counter.connection?.increment(1);
// };
//
// return (
// <div>
// <h1>Counter: {count}</h1>
// <input
// type="text"
// value={counterName}
// onChange={(e) => setCounterName(e.target.value)}
// placeholder="Counter name"
// />
// <button onClick={increment}>Increment</button>
// </div>
// );
// }
//
// export default App;
import { useState } from "react";
import { createClient, createRivetKit } from "@rivetkit/react";
import type { registry } from "../backend/registry";

const client = createClient<typeof registry>("http://localhost:8080/registry");
const { useActor } = createRivetKit<typeof registry>(client);

function App() {
const [count, setCount] = useState(0);
const [counterName, setCounterName] = useState("test-counter");

const counter = useActor({
name: "counter",
key: [counterName],
});

counter.useEvent("newCount", (x: number) => setCount(x));

const increment = async () => {
await counter.connection?.increment(1);
};

return (
<div>
<h1>Counter: {count}</h1>
<input
type="text"
value={counterName}
onChange={(e) => setCounterName(e.target.value)}
placeholder="Counter name"
/>
<button onClick={increment}>Increment</button>
</div>
);
}

export default App;
18 changes: 9 additions & 9 deletions examples/hono-react/src/frontend/main.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// import React from "react";
// import ReactDOM from "react-dom/client";
// import App from "./App";
//
// ReactDOM.createRoot(document.getElementById("root")!).render(
// <React.StrictMode>
// <App />
// </React.StrictMode>,
// );
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
18 changes: 9 additions & 9 deletions examples/react/src/backend/server.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// import { registry } from "./registry";
// import { serve } from "@rivetkit/nodejs";
//
// serve(registry, {
// cors: {
// // IMPORTANT: Configure origins in production
// origin: "*",
// },
// });
import { registry } from "./registry";
import { serve } from "@rivetkit/nodejs";

serve(registry, {
cors: {
// IMPORTANT: Configure origins in production
origin: "*",
},
});
32 changes: 20 additions & 12 deletions packages/core/fixtures/driver-test-suite/inline-client.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
import { actor } from "@rivetkit/core";
import type { Registry } from "./registry";
import type { registry } from "./registry";

export const inlineClientActor = actor({
onAuth: () => {},
state: { messages: [] as string[] },
actions: {
// Action that uses client to call another actor (stateless)
callCounterIncrement: async (c, amount: number) => {
const client = c.client<Registry>();
const result = await client.counter.getOrCreate(["inline-test"]).increment(amount);
c.state.messages.push(`Called counter.increment(${amount}), result: ${result}`);
const client = c.client<typeof registry>();
const result = await client.counter
.getOrCreate(["inline-test"])
.increment(amount);
c.state.messages.push(
`Called counter.increment(${amount}), result: ${result}`,
);
return result;
},

// Action that uses client to get counter state (stateless)
getCounterState: async (c) => {
const client = c.client<Registry>();
const count = await client.counter.getOrCreate(["inline-test"]).getCount();
const client = c.client<typeof registry>();
const count = await client.counter
.getOrCreate(["inline-test"])
.getCount();
c.state.messages.push(`Got counter state: ${count}`);
return count;
},

// Action that uses client with .connect() for stateful communication
connectToCounterAndIncrement: async (c, amount: number) => {
const client = c.client<Registry>();
const client = c.client<typeof registry>();
const handle = client.counter.getOrCreate(["inline-test-stateful"]);
const connection = handle.connect();

// Set up event listener
const events: number[] = [];
connection.on("newCount", (count: number) => {
Expand All @@ -36,11 +42,13 @@ export const inlineClientActor = actor({
// Perform increments
const result1 = await connection.increment(amount);
const result2 = await connection.increment(amount * 2);

await connection.dispose();

c.state.messages.push(`Connected to counter, incremented by ${amount} and ${amount * 2}, results: ${result1}, ${result2}, events: ${JSON.stringify(events)}`);


c.state.messages.push(
`Connected to counter, incremented by ${amount} and ${amount * 2}, results: ${result1}, ${result2}, events: ${JSON.stringify(events)}`,
);

return { result1, result2, events };
},

Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as errors from "@/actor/errors";
import { getEnvUniversal } from "@/utils";
import type { ContentfulStatusCode } from "hono/utils/http-status";
import type { Logger } from "./log";
import { type Next } from "hono";

export function assertUnreachable(x: never): never {
throw new Error(`Unreachable case: ${x}`);
Expand Down Expand Up @@ -223,3 +224,8 @@ function getErrorMessage(err: unknown): string {
return String(err);
}
}

/** Generates a `Next` handler to pass to middleware in order to be able to call arbitrary middleware. */
export function noopNext(): Next {
return async () => {};
}
14 changes: 7 additions & 7 deletions packages/core/src/driver-test-suite/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,21 +128,21 @@ export async function createTestRuntime(

// Build driver config
let injectWebSocket: NodeWebSocket["injectWebSocket"] | undefined;
let upgradeWebSocket = undefined;
const config: RunConfig = RunConfigSchema.parse({
driver,
getUpgradeWebSocket: (router: any) => {
const webSocket = createNodeWebSocket({ app: router });
injectWebSocket = webSocket.injectWebSocket;
return webSocket.upgradeWebSocket;
},
getUpgradeWebSocket: () => upgradeWebSocket!,
});

// Build topology
const topology =
config.driver.topology === "coordinate"
? new CoordinateTopology(registry.config, config)
: new StandaloneTopology(registry.config, config);
if (!injectWebSocket) throw new Error("injectWebSocket not defined");

// Inject WebSocket
const nodeWebSocket = createNodeWebSocket({ app: topology.router });
upgradeWebSocket = nodeWebSocket.upgradeWebSocket;

// Start server
const port = await getPort();
Expand All @@ -152,7 +152,7 @@ export async function createTestRuntime(
port,
});
invariant(injectWebSocket !== undefined, "should have injectWebSocket");
injectWebSocket(server);
nodeWebSocket.injectWebSocket(server);
const endpoint = `http://127.0.0.1:${port}`;

// Cleanup
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/driver-test-suite/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { assertUnreachable } from "@/actor/utils";
import { createClientWithDriver } from "@/client/client";
import { type Client, createClient } from "@/client/mod";
import { type TestContext, vi } from "vitest";
import type { Registry } from "../../fixtures/driver-test-suite/registry";
import type { registry } from "../../fixtures/driver-test-suite/registry";
import type { DriverTestConfig } from "./mod";
import { createTestInlineClientDriver } from "./test-inline-client-driver";

Expand All @@ -12,7 +12,7 @@ export async function setupDriverTest(
c: TestContext,
driverTestConfig: DriverTestConfig,
): Promise<{
client: Client<Registry>;
client: Client<typeof registry>;
}> {
if (!driverTestConfig.useRealTimers) {
vi.useFakeTimers();
Expand All @@ -23,10 +23,10 @@ export async function setupDriverTest(
const { endpoint, cleanup } = await driverTestConfig.start(projectPath);
c.onTestFinished(cleanup);

let client: Client<Registry>;
let client: Client<typeof registry>;
if (driverTestConfig.clientType === "http") {
// Create client
client = createClient<Registry>(endpoint, {
client = createClient<typeof registry>(endpoint, {
transport: driverTestConfig.transport,
});
} else if (driverTestConfig.clientType === "inline") {
Expand Down
Loading
Loading