Skip to content
This repository was archived by the owner on Oct 22, 2025. It is now read-only.

Commit d6f0cde

Browse files
committed
refactor: simplify server creation with createServer API (#1018)
1 parent 6515bc5 commit d6f0cde

File tree

26 files changed

+400
-552
lines changed

26 files changed

+400
-552
lines changed

examples/better-auth/src/frontend/components/ChatRoom.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ import { createClient, createRivetKit } from "@rivetkit/react";
33
import { authClient } from "../auth-client";
44
import type { Registry } from "../../backend/registry";
55

6-
const client = createClient<Registry>("http://localhost:8080/registry", {
7-
transport: "sse",
8-
});
6+
const client = createClient<Registry>("http://localhost:8080/registry");
97

108
const { useActor } = createRivetKit(client);
119

examples/elysia/src/server.ts

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
1-
// import { registry } from "./registry";
2-
// import { Elysia } from "elysia";
3-
// import { createMemoryDriver } from "@rivetkit/memory";
4-
//
5-
// // Start RivetKit
6-
// const { client, handler } = registry.run({
7-
// driver: createMemoryDriver(),
8-
// });
9-
//
10-
// // Setup router
11-
// const app = new Elysia()
12-
// // Expose RivetKit to the frontend (optional)
13-
// .mount("/registry", handler)
14-
// // Example HTTP endpoint
15-
// .post("/increment/:name", async ({ params }) => {
16-
// const name = params.name;
17-
//
18-
// const counter = client.counter.getOrCreate(name);
19-
// const newCount = await counter.increment(1);
20-
//
21-
// return `New Count: ${newCount}`;
22-
// })
23-
// .listen(8080);
24-
//
25-
// console.log("Listening at http://localhost:8080");
1+
import { registry } from "./registry";
2+
import { Elysia } from "elysia";
3+
4+
const { client, handler } = registry.createServer();
5+
6+
// Setup router
7+
new Elysia()
8+
// Expose RivetKit to the frontend (optional)
9+
.mount("/registry", handler)
10+
// Example HTTP endpoint
11+
.post("/increment/:name", async ({ params }) => {
12+
const name = params.name;
13+
14+
const counter = client.counter.getOrCreate(name);
15+
const newCount = await counter.increment(1);
16+
17+
return `New Count: ${newCount}`;
18+
})
19+
.listen(8080);
20+
21+
console.log("Listening at http://localhost:8080");

examples/express/src/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { registry } from "./registry";
22
import express from "express";
33

44
// Start RivetKit
5-
const { client, handler } = registry.run();
5+
const { client, handler } = registry.createServer();
66

77
// Setup router
88
const app = express();
Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,24 @@
1-
// import { registry } from "./registry";
2-
// import { Hono } from "hono";
3-
// import { serve } from "@hono/node-server";
4-
// import { createMemoryDriver } from "@rivetkit/memory";
5-
//
6-
// // Setup router
7-
// const app = new Hono();
8-
//
9-
// // Start RivetKit
10-
// const { client, hono } = registry.run({
11-
// driver: createMemoryDriver(),
12-
// cors: {
13-
// // IMPORTANT: Configure origins in production
14-
// origin: "*",
15-
// },
16-
// });
17-
//
18-
// // Expose RivetKit to the frontend
19-
// app.route("/registry", hono);
20-
//
21-
// // Example HTTP endpoint
22-
// app.post("/increment/:name", async (c) => {
23-
// const name = c.req.param("name");
24-
//
25-
// const counter = client.counter.getOrCreate(name);
26-
// const newCount = await counter.increment(1);
27-
//
28-
// return c.text(`New Count: ${newCount}`);
29-
// });
30-
//
31-
// serve({ fetch: app.fetch, port: 8080 }, () =>
32-
// console.log("Listening at http://localhost:8080"),
33-
// );
1+
import { registry } from "./registry";
2+
import { Hono } from "hono";
3+
4+
const { client, serve } = registry.createServer({
5+
cors: {
6+
// IMPORTANT: Configure origins in production
7+
origin: "*",
8+
},
9+
});
10+
11+
// Setup router
12+
const app = new Hono();
13+
14+
// Example HTTP endpoint
15+
app.post("/increment/:name", async (c) => {
16+
const name = c.req.param("name");
17+
18+
const counter = client.counter.getOrCreate(name);
19+
const newCount = await counter.increment(1);
20+
21+
return c.text(`New Count: ${newCount}`);
22+
});
23+
24+
serve(app);
Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,37 @@
1-
// import { useState } from "react";
2-
// import { createClient, createRivetKit } from "@rivetkit/react";
3-
// import type { Registry } from "../backend/registry";
4-
//
5-
// const client = createClient<Registry>("http://localhost:8080/registry", {
6-
// transport: "sse",
7-
// });
8-
// const { useActor } = createRivetKit(client);
9-
//
10-
// function App() {
11-
// const [count, setCount] = useState(0);
12-
// const [counterName, setCounterName] = useState("test-counter");
13-
//
14-
// const counter = useActor({
15-
// name: "counter",
16-
// key: [counterName],
17-
// });
18-
//
19-
// counter.useEvent("newCount", (x: number) => setCount(x));
20-
//
21-
// const increment = async () => {
22-
// await counter.connection?.increment(1);
23-
// };
24-
//
25-
// return (
26-
// <div>
27-
// <h1>Counter: {count}</h1>
28-
// <input
29-
// type="text"
30-
// value={counterName}
31-
// onChange={(e) => setCounterName(e.target.value)}
32-
// placeholder="Counter name"
33-
// />
34-
// <button onClick={increment}>Increment</button>
35-
// </div>
36-
// );
37-
// }
38-
//
39-
// export default App;
1+
import { useState } from "react";
2+
import { createClient, createRivetKit } from "@rivetkit/react";
3+
import type { registry } from "../backend/registry";
4+
5+
const client = createClient<typeof registry>("http://localhost:8080/registry");
6+
const { useActor } = createRivetKit<typeof registry>(client);
7+
8+
function App() {
9+
const [count, setCount] = useState(0);
10+
const [counterName, setCounterName] = useState("test-counter");
11+
12+
const counter = useActor({
13+
name: "counter",
14+
key: [counterName],
15+
});
16+
17+
counter.useEvent("newCount", (x: number) => setCount(x));
18+
19+
const increment = async () => {
20+
await counter.connection?.increment(1);
21+
};
22+
23+
return (
24+
<div>
25+
<h1>Counter: {count}</h1>
26+
<input
27+
type="text"
28+
value={counterName}
29+
onChange={(e) => setCounterName(e.target.value)}
30+
placeholder="Counter name"
31+
/>
32+
<button onClick={increment}>Increment</button>
33+
</div>
34+
);
35+
}
36+
37+
export default App;
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// import React from "react";
2-
// import ReactDOM from "react-dom/client";
3-
// import App from "./App";
4-
//
5-
// ReactDOM.createRoot(document.getElementById("root")!).render(
6-
// <React.StrictMode>
7-
// <App />
8-
// </React.StrictMode>,
9-
// );
1+
import React from "react";
2+
import ReactDOM from "react-dom/client";
3+
import App from "./App";
4+
5+
ReactDOM.createRoot(document.getElementById("root")!).render(
6+
<React.StrictMode>
7+
<App />
8+
</React.StrictMode>,
9+
);
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// import { registry } from "./registry";
2-
// import { serve } from "@rivetkit/nodejs";
3-
//
4-
// serve(registry, {
5-
// cors: {
6-
// // IMPORTANT: Configure origins in production
7-
// origin: "*",
8-
// },
9-
// });
1+
import { registry } from "./registry";
2+
import { serve } from "@rivetkit/nodejs";
3+
4+
serve(registry, {
5+
cors: {
6+
// IMPORTANT: Configure origins in production
7+
origin: "*",
8+
},
9+
});

packages/core/fixtures/driver-test-suite/inline-client.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,38 @@
11
import { actor } from "@rivetkit/core";
2-
import type { Registry } from "./registry";
2+
import type { registry } from "./registry";
33

44
export const inlineClientActor = actor({
55
onAuth: () => {},
66
state: { messages: [] as string[] },
77
actions: {
88
// Action that uses client to call another actor (stateless)
99
callCounterIncrement: async (c, amount: number) => {
10-
const client = c.client<Registry>();
11-
const result = await client.counter.getOrCreate(["inline-test"]).increment(amount);
12-
c.state.messages.push(`Called counter.increment(${amount}), result: ${result}`);
10+
const client = c.client<typeof registry>();
11+
const result = await client.counter
12+
.getOrCreate(["inline-test"])
13+
.increment(amount);
14+
c.state.messages.push(
15+
`Called counter.increment(${amount}), result: ${result}`,
16+
);
1317
return result;
1418
},
1519

1620
// Action that uses client to get counter state (stateless)
1721
getCounterState: async (c) => {
18-
const client = c.client<Registry>();
19-
const count = await client.counter.getOrCreate(["inline-test"]).getCount();
22+
const client = c.client<typeof registry>();
23+
const count = await client.counter
24+
.getOrCreate(["inline-test"])
25+
.getCount();
2026
c.state.messages.push(`Got counter state: ${count}`);
2127
return count;
2228
},
2329

2430
// Action that uses client with .connect() for stateful communication
2531
connectToCounterAndIncrement: async (c, amount: number) => {
26-
const client = c.client<Registry>();
32+
const client = c.client<typeof registry>();
2733
const handle = client.counter.getOrCreate(["inline-test-stateful"]);
2834
const connection = handle.connect();
29-
35+
3036
// Set up event listener
3137
const events: number[] = [];
3238
connection.on("newCount", (count: number) => {
@@ -36,11 +42,13 @@ export const inlineClientActor = actor({
3642
// Perform increments
3743
const result1 = await connection.increment(amount);
3844
const result2 = await connection.increment(amount * 2);
39-
45+
4046
await connection.dispose();
41-
42-
c.state.messages.push(`Connected to counter, incremented by ${amount} and ${amount * 2}, results: ${result1}, ${result2}, events: ${JSON.stringify(events)}`);
43-
47+
48+
c.state.messages.push(
49+
`Connected to counter, incremented by ${amount} and ${amount * 2}, results: ${result1}, ${result2}, events: ${JSON.stringify(events)}`,
50+
);
51+
4452
return { result1, result2, events };
4553
},
4654

packages/core/src/common/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as errors from "@/actor/errors";
22
import { getEnvUniversal } from "@/utils";
33
import type { ContentfulStatusCode } from "hono/utils/http-status";
44
import type { Logger } from "./log";
5+
import { type Next } from "hono";
56

67
export function assertUnreachable(x: never): never {
78
throw new Error(`Unreachable case: ${x}`);
@@ -223,3 +224,8 @@ function getErrorMessage(err: unknown): string {
223224
return String(err);
224225
}
225226
}
227+
228+
/** Generates a `Next` handler to pass to middleware in order to be able to call arbitrary middleware. */
229+
export function noopNext(): Next {
230+
return async () => {};
231+
}

packages/core/src/driver-test-suite/mod.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,21 @@ export async function createTestRuntime(
128128

129129
// Build driver config
130130
let injectWebSocket: NodeWebSocket["injectWebSocket"] | undefined;
131+
let upgradeWebSocket = undefined;
131132
const config: RunConfig = RunConfigSchema.parse({
132133
driver,
133-
getUpgradeWebSocket: (router: any) => {
134-
const webSocket = createNodeWebSocket({ app: router });
135-
injectWebSocket = webSocket.injectWebSocket;
136-
return webSocket.upgradeWebSocket;
137-
},
134+
getUpgradeWebSocket: () => upgradeWebSocket!,
138135
});
139136

140137
// Build topology
141138
const topology =
142139
config.driver.topology === "coordinate"
143140
? new CoordinateTopology(registry.config, config)
144141
: new StandaloneTopology(registry.config, config);
145-
if (!injectWebSocket) throw new Error("injectWebSocket not defined");
142+
143+
// Inject WebSocket
144+
const nodeWebSocket = createNodeWebSocket({ app: topology.router });
145+
upgradeWebSocket = nodeWebSocket.upgradeWebSocket;
146146

147147
// Start server
148148
const port = await getPort();
@@ -152,7 +152,7 @@ export async function createTestRuntime(
152152
port,
153153
});
154154
invariant(injectWebSocket !== undefined, "should have injectWebSocket");
155-
injectWebSocket(server);
155+
nodeWebSocket.injectWebSocket(server);
156156
const endpoint = `http://127.0.0.1:${port}`;
157157

158158
// Cleanup

0 commit comments

Comments
 (0)