diff --git a/examples/better-auth/README.md b/examples/better-auth/README.md
new file mode 100644
index 000000000..7f2594758
--- /dev/null
+++ b/examples/better-auth/README.md
@@ -0,0 +1,55 @@
+# Better Auth Integration for RivetKit
+
+Example project demonstrating authentication integration with [RivetKit](https://rivetkit.org) using Better Auth.
+
+[Learn More →](https://github.com/rivet-gg/rivetkit)
+
+[Discord](https://rivet.gg/discord) — [Documentation](https://rivetkit.org) — [Issues](https://github.com/rivet-gg/rivetkit/issues)
+
+## Getting Started
+
+### Prerequisites
+
+- Node.js 18+
+- npm or pnpm
+
+### Installation
+
+```sh
+git clone https://github.com/rivet-gg/rivetkit
+cd rivetkit/examples/better-auth
+npm install
+```
+
+### Development
+
+```sh
+npm run dev
+```
+
+Open your browser to `http://localhost:5173` to see the frontend and the backend will be running on `http://localhost:6420`.
+
+## Features
+
+- **Authentication**: Email/password authentication using Better Auth
+- **Protected Workers**: RivetKit workers with authentication via `onAuth` hook
+- **Real-time Chat**: Authenticated chat room with real-time messaging
+- **SQLite Database**: Persistent user data and session storage
+
+## How It Works
+
+1. **Better Auth Setup**: Configured with SQLite adapter for user storage
+2. **Protected Worker**: The `chatRoom` worker uses the `onAuth` hook to verify user sessions
+3. **Frontend Integration**: React components handle authentication flow and chat interface
+4. **Session Management**: Better Auth handles session creation, validation, and cleanup
+
+## Key Files
+
+- `src/backend/auth.ts` - Better Auth configuration with SQLite
+- `src/backend/registry.ts` - RivetKit worker with authentication
+- `src/frontend/components/AuthForm.tsx` - Login/signup form
+- `src/frontend/components/ChatRoom.tsx` - Authenticated chat interface
+
+## License
+
+Apache 2.0
\ No newline at end of file
diff --git a/examples/better-auth/package.json b/examples/better-auth/package.json
new file mode 100644
index 000000000..eb6572e16
--- /dev/null
+++ b/examples/better-auth/package.json
@@ -0,0 +1,41 @@
+{
+ "name": "example-better-auth",
+ "version": "0.9.0-rc.1",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "concurrently \"npm run dev:backend\" \"npm run dev:frontend\"",
+ "dev:backend": "tsx --watch src/backend/server.ts",
+ "dev:frontend": "vite",
+ "build": "vite build",
+ "check-types": "tsc --noEmit",
+ "test": "vitest run"
+ },
+ "devDependencies": {
+ "@types/node": "^22.13.9",
+ "@types/react": "^18.2.0",
+ "@types/react-dom": "^18.2.0",
+ "@vitejs/plugin-react": "^4.2.0",
+ "concurrently": "^8.2.2",
+ "rivetkit": "workspace:*",
+ "tsx": "^3.12.7",
+ "typescript": "^5.5.2",
+ "vite": "^5.0.0",
+ "vitest": "^3.1.1"
+ },
+ "dependencies": {
+ "@hono/node-server": "^1.14.4",
+ "@rivetkit/memory": "workspace:0.9.0-rc.1",
+ "@rivetkit/react": "workspace:0.9.0-rc.1",
+ "better-auth": "^1.0.1",
+ "hono": "^4.7.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "example": {
+ "platforms": [
+ "*"
+ ]
+ },
+ "stableVersion": "0.8.0"
+}
diff --git a/examples/better-auth/src/backend/auth.ts b/examples/better-auth/src/backend/auth.ts
new file mode 100644
index 000000000..c735ba539
--- /dev/null
+++ b/examples/better-auth/src/backend/auth.ts
@@ -0,0 +1,20 @@
+import { betterAuth } from "better-auth";
+import { sqliteAdapter } from "@better-auth/sqlite";
+import Database from "better-sqlite3";
+
+const db = new Database("./auth.db");
+
+export const auth = betterAuth({
+ database: sqliteAdapter(db),
+ emailAndPassword: {
+ enabled: true,
+ },
+ session: {
+ expiresIn: 60 * 60 * 24 * 7, // 7 days
+ updateAge: 60 * 60 * 24, // 1 day (every day the session expiry is updated)
+ },
+ plugins: [],
+});
+
+export type Session = typeof auth.$Infer.Session;
+export type User = typeof auth.$Infer.User;
\ No newline at end of file
diff --git a/examples/better-auth/src/backend/registry.ts b/examples/better-auth/src/backend/registry.ts
new file mode 100644
index 000000000..7043bf599
--- /dev/null
+++ b/examples/better-auth/src/backend/registry.ts
@@ -0,0 +1,48 @@
+import { worker, setup } from "rivetkit";
+import { auth, type Session, type User } from "./auth";
+
+export const chatRoom = worker({
+ onAuth: async (c) => {
+ const authResult = await auth.api.getSession({
+ headers: c.req.headers,
+ });
+
+ if (!authResult?.session || !authResult?.user) {
+ throw new Error("Unauthorized");
+ }
+
+ return {
+ userId: authResult.user.id,
+ user: authResult.user,
+ session: authResult.session,
+ };
+ },
+ state: {
+ messages: [] as Array<{ id: string; userId: string; username: string; message: string; timestamp: number }>
+ },
+ actions: {
+ sendMessage: (c, message: string) => {
+ const newMessage = {
+ id: crypto.randomUUID(),
+ userId: c.auth.userId,
+ username: c.auth.user.email,
+ message,
+ timestamp: Date.now(),
+ };
+
+ c.state.messages.push(newMessage);
+ c.broadcast("newMessage", newMessage);
+
+ return newMessage;
+ },
+ getMessages: (c) => {
+ return c.state.messages;
+ },
+ },
+});
+
+export const registry = setup({
+ workers: { chatRoom },
+});
+
+export type Registry = typeof registry;
\ No newline at end of file
diff --git a/examples/better-auth/src/backend/server.ts b/examples/better-auth/src/backend/server.ts
new file mode 100644
index 000000000..241bf8472
--- /dev/null
+++ b/examples/better-auth/src/backend/server.ts
@@ -0,0 +1,55 @@
+import { registry } from "./registry";
+import { auth } from "./auth";
+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: "*",
+ },
+});
+
+// Mount Better Auth routes
+app.on(["GET", "POST"], "/api/auth/**", (c) => auth.handler(c.req.raw));
+
+// Expose RivetKit to the frontend
+app.route("/registry", hono);
+
+// Example HTTP endpoint to join chat room
+app.post("/api/join-room/:roomId", async (c) => {
+ const roomId = c.req.param("roomId");
+
+ // Verify authentication
+ const authResult = await auth.api.getSession({
+ headers: c.req.header(),
+ });
+
+ if (!authResult?.session || !authResult?.user) {
+ return c.json({ error: "Unauthorized" }, 401);
+ }
+
+ try {
+ const room = client.chatRoom.getOrCreate(roomId);
+ const messages = await room.getMessages();
+
+ return c.json({
+ success: true,
+ roomId,
+ messages,
+ user: authResult.user
+ });
+ } catch (error) {
+ return c.json({ error: "Failed to join room" }, 500);
+ }
+});
+
+serve({ fetch: app.fetch, port: 6420 }, () =>
+ console.log("Listening at http://localhost:6420"),
+);
\ No newline at end of file
diff --git a/examples/better-auth/src/frontend/App.tsx b/examples/better-auth/src/frontend/App.tsx
new file mode 100644
index 000000000..30549a0e3
--- /dev/null
+++ b/examples/better-auth/src/frontend/App.tsx
@@ -0,0 +1,73 @@
+import { useState, useEffect } from "react";
+import { authClient } from "./auth-client";
+import { AuthForm } from "./components/AuthForm";
+import { ChatRoom } from "./components/ChatRoom";
+
+function App() {
+ const [user, setUser] = useState<{ id: string; email: string } | null>(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ // Check if user is already authenticated
+ const checkAuth = async () => {
+ try {
+ const session = await authClient.getSession();
+ if (session.data?.user) {
+ setUser(session.data.user);
+ }
+ } catch (error) {
+ console.error("Auth check failed:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ checkAuth();
+ }, []);
+
+ const handleAuthSuccess = async () => {
+ try {
+ const session = await authClient.getSession();
+ if (session.data?.user) {
+ setUser(session.data.user);
+ }
+ } catch (error) {
+ console.error("Failed to get user after auth:", error);
+ }
+ };
+
+ const handleSignOut = () => {
+ setUser(null);
+ };
+
+ if (loading) {
+ return (
+
+ Loading...
+
+ );
+ }
+
+ return (
+
+
+
+ RivetKit with Better Auth
+
+
+ {user ? (
+
+ ) : (
+
+ )}
+
+
+ );
+}
+
+export default App;
\ No newline at end of file
diff --git a/examples/better-auth/src/frontend/auth-client.ts b/examples/better-auth/src/frontend/auth-client.ts
new file mode 100644
index 000000000..793a44e51
--- /dev/null
+++ b/examples/better-auth/src/frontend/auth-client.ts
@@ -0,0 +1,5 @@
+import { createAuthClient } from "better-auth/react";
+
+export const authClient = createAuthClient({
+ baseURL: "http://localhost:6420",
+});
\ No newline at end of file
diff --git a/examples/better-auth/src/frontend/components/AuthForm.tsx b/examples/better-auth/src/frontend/components/AuthForm.tsx
new file mode 100644
index 000000000..005e89696
--- /dev/null
+++ b/examples/better-auth/src/frontend/components/AuthForm.tsx
@@ -0,0 +1,106 @@
+import { useState } from "react";
+import { authClient } from "../auth-client";
+
+interface AuthFormProps {
+ onAuthSuccess: () => void;
+}
+
+export function AuthForm({ onAuthSuccess }: AuthFormProps) {
+ const [isLogin, setIsLogin] = useState(true);
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const [error, setError] = useState("");
+ const [loading, setLoading] = useState(false);
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setError("");
+ setLoading(true);
+
+ try {
+ if (isLogin) {
+ await authClient.signIn.email({
+ email,
+ password,
+ });
+ } else {
+ await authClient.signUp.email({
+ email,
+ password,
+ });
+ }
+ onAuthSuccess();
+ } catch (err) {
+ setError(err instanceof Error ? err.message : "Authentication failed");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
{isLogin ? "Sign In" : "Sign Up"}
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/examples/better-auth/src/frontend/components/ChatRoom.tsx b/examples/better-auth/src/frontend/components/ChatRoom.tsx
new file mode 100644
index 000000000..dcd0f86dc
--- /dev/null
+++ b/examples/better-auth/src/frontend/components/ChatRoom.tsx
@@ -0,0 +1,159 @@
+import { useState, useEffect } from "react";
+import { createClient, createRivetKit } from "@rivetkit/react";
+import { authClient } from "../auth-client";
+import type { Registry } from "../../backend/registry";
+
+const client = createClient("http://localhost:6420/registry", {
+ transport: "sse",
+});
+
+const { useWorker } = createRivetKit(client);
+
+interface ChatRoomProps {
+ user: { id: string; email: string };
+ onSignOut: () => void;
+}
+
+export function ChatRoom({ user, onSignOut }: ChatRoomProps) {
+ const [message, setMessage] = useState("");
+ const [messages, setMessages] = useState>([]);
+ const [roomId] = useState("general");
+
+ const chatRoom = useWorker({
+ name: "chatRoom",
+ key: [roomId],
+ });
+
+ // Listen for new messages
+ chatRoom.useEvent("newMessage", (newMessage) => {
+ setMessages(prev => [...prev, newMessage]);
+ });
+
+ // Load initial messages when connected
+ useEffect(() => {
+ if (chatRoom.connection) {
+ chatRoom.connection.getMessages().then(initialMessages => {
+ setMessages(initialMessages);
+ });
+ }
+ }, [chatRoom.connection]);
+
+ const handleSendMessage = async (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!message.trim() || !chatRoom.connection) return;
+
+ try {
+ await chatRoom.connection.sendMessage(message.trim());
+ setMessage("");
+ } catch (error) {
+ console.error("Failed to send message:", error);
+ }
+ };
+
+ const handleSignOut = async () => {
+ await authClient.signOut();
+ onSignOut();
+ };
+
+ return (
+
+
+
+
Chat Room: {roomId}
+
Logged in as: {user.email}
+
+
+
+
+
+ {messages.length === 0 ? (
+
No messages yet. Start the conversation!
+ ) : (
+ messages.map((msg) => (
+
+
+ {msg.username} • {new Date(msg.timestamp).toLocaleTimeString()}
+
+
{msg.message}
+
+ ))
+ )}
+
+
+
+
+
+ Connection Status: {chatRoom.connection ? "Connected" : "Connecting..."}
+
+
+ );
+}
\ No newline at end of file
diff --git a/examples/better-auth/src/frontend/index.html b/examples/better-auth/src/frontend/index.html
new file mode 100644
index 000000000..c8973df5d
--- /dev/null
+++ b/examples/better-auth/src/frontend/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ RivetKit + Better Auth
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/better-auth/src/frontend/main.tsx b/examples/better-auth/src/frontend/main.tsx
new file mode 100644
index 000000000..f5871ecc7
--- /dev/null
+++ b/examples/better-auth/src/frontend/main.tsx
@@ -0,0 +1,9 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+
+
+ ,
+);
\ No newline at end of file
diff --git a/examples/better-auth/tsconfig.json b/examples/better-auth/tsconfig.json
new file mode 100644
index 000000000..c8e9f28f2
--- /dev/null
+++ b/examples/better-auth/tsconfig.json
@@ -0,0 +1,43 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+ /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ "target": "esnext",
+ /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ "lib": ["esnext", "dom"],
+ /* Specify what JSX code is generated. */
+ "jsx": "react-jsx",
+
+ /* Specify what module code is generated. */
+ "module": "esnext",
+ /* Specify how TypeScript looks up a file from a given module specifier. */
+ "moduleResolution": "bundler",
+ /* Specify type package names to be included without being referenced in a source file. */
+ "types": ["node"],
+ /* Enable importing .json files */
+ "resolveJsonModule": true,
+
+ /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
+ "allowJs": true,
+ /* Enable error reporting in type-checked JavaScript files. */
+ "checkJs": false,
+
+ /* Disable emitting files from a compilation. */
+ "noEmit": true,
+
+ /* Ensure that each file can be safely transpiled without relying on other imports. */
+ "isolatedModules": true,
+ /* Allow 'import x from y' when a module doesn't have a default export. */
+ "allowSyntheticDefaultImports": true,
+ /* Ensure that casing is correct in imports. */
+ "forceConsistentCasingInFileNames": true,
+
+ /* Enable all strict type-checking options. */
+ "strict": true,
+
+ /* Skip type checking all .d.ts files. */
+ "skipLibCheck": true
+ },
+ "include": ["src/**/*"]
+}
\ No newline at end of file
diff --git a/examples/better-auth/vite.config.ts b/examples/better-auth/vite.config.ts
new file mode 100644
index 000000000..315f881dc
--- /dev/null
+++ b/examples/better-auth/vite.config.ts
@@ -0,0 +1,13 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+export default defineConfig({
+ plugins: [react()],
+ root: "src/frontend",
+ build: {
+ outDir: "../../dist",
+ },
+ server: {
+ host: "0.0.0.0",
+ },
+});
\ No newline at end of file
diff --git a/examples/cloudflare-workers/README.md b/examples/cloudflare-workers/README.md
new file mode 100644
index 000000000..d05f1f95d
--- /dev/null
+++ b/examples/cloudflare-workers/README.md
@@ -0,0 +1,57 @@
+# Cloudflare Workers for RivetKit
+
+Example project demonstrating Cloudflare Workers deployment with [RivetKit](https://rivetkit.org).
+
+[Learn More →](https://github.com/rivet-gg/rivetkit)
+
+[Discord](https://rivet.gg/discord) — [Documentation](https://rivetkit.org) — [Issues](https://github.com/rivet-gg/rivetkit/issues)
+
+## Getting Started
+
+### Prerequisites
+
+- Node.js
+- Cloudflare account with Workers enabled
+- Wrangler CLI installed globally (`npm install -g wrangler`)
+
+### Installation
+
+```sh
+git clone https://github.com/rivet-gg/rivetkit
+cd rivetkit/examples/cloudflare-workers
+npm install
+```
+
+### Development
+
+```sh
+npm run dev
+```
+
+This will start the Cloudflare Workers development server locally at http://localhost:8787.
+
+### Testing the Client
+
+In a separate terminal, run the client script to interact with your workers:
+
+```sh
+npm run client
+```
+
+### Deploy to Cloudflare
+
+First, authenticate with Cloudflare:
+
+```sh
+wrangler login
+```
+
+Then deploy:
+
+```sh
+npm run deploy
+```
+
+## License
+
+Apache 2.0
\ No newline at end of file
diff --git a/examples/cloudflare-workers/package.json b/examples/cloudflare-workers/package.json
new file mode 100644
index 000000000..a7f34ace0
--- /dev/null
+++ b/examples/cloudflare-workers/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "example-cloudflare-workers",
+ "version": "0.9.0-rc.1",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "wrangler dev",
+ "deploy": "wrangler deploy",
+ "check-types": "tsc --noEmit",
+ "client": "tsx scripts/client.ts"
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "^4.20250129.0",
+ "@types/node": "^22.13.9",
+ "rivetkit": "workspace:*",
+ "tsx": "^3.12.7",
+ "typescript": "^5.5.2",
+ "wrangler": "^3.0.0"
+ },
+ "dependencies": {
+ "@rivetkit/cloudflare-workers": "workspace:*"
+ },
+ "example": {
+ "platforms": [
+ "cloudflare-workers"
+ ]
+ },
+ "stableVersion": "0.8.0"
+}
diff --git a/examples/cloudflare-workers/scripts/client.ts b/examples/cloudflare-workers/scripts/client.ts
new file mode 100644
index 000000000..5c7cec651
--- /dev/null
+++ b/examples/cloudflare-workers/scripts/client.ts
@@ -0,0 +1,37 @@
+import { createClient } from "rivetkit/client";
+import type { Registry } from "../src/registry.js";
+
+// Create RivetKit client
+const client = createClient("http://localhost:8787");
+
+async function main() {
+ console.log("🚀 Cloudflare Workers Client Demo");
+
+ try {
+ // Create counter instance
+ const counter = client.counter.getOrCreate("demo");
+
+ // Increment counter
+ console.log("Incrementing counter 'demo'...");
+ const result1 = await counter.increment(1);
+ console.log("New count:", result1);
+
+ // Increment again with larger value
+ console.log("Incrementing counter 'demo' by 5...");
+ const result2 = await counter.increment(5);
+ console.log("New count:", result2);
+
+ // Create another counter
+ const counter2 = client.counter.getOrCreate("another");
+ console.log("Incrementing counter 'another' by 10...");
+ const result3 = await counter2.increment(10);
+ console.log("New count:", result3);
+
+ console.log("✅ Demo completed!");
+ } catch (error) {
+ console.error("❌ Error:", error);
+ process.exit(1);
+ }
+}
+
+main().catch(console.error);
diff --git a/examples/cloudflare-workers/src/index.ts b/examples/cloudflare-workers/src/index.ts
new file mode 100644
index 000000000..341b3fff9
--- /dev/null
+++ b/examples/cloudflare-workers/src/index.ts
@@ -0,0 +1,6 @@
+import { createHandler } from "@rivetkit/cloudflare-workers";
+import { registry } from "./registry";
+
+const { handler, WorkerHandler } = createHandler(registry);
+
+export { handler as default, WorkerHandler };
diff --git a/examples/cloudflare-workers/src/registry.ts b/examples/cloudflare-workers/src/registry.ts
new file mode 100644
index 000000000..11f62e9b9
--- /dev/null
+++ b/examples/cloudflare-workers/src/registry.ts
@@ -0,0 +1,20 @@
+import { worker, setup } from "rivetkit";
+
+export const counter = worker({
+ onAuth: () => {
+ // Configure auth here
+ },
+ state: { count: 0 },
+ actions: {
+ increment: (c, x: number) => {
+ c.state.count += x;
+ return c.state.count;
+ },
+ },
+});
+
+export const registry = setup({
+ workers: { counter },
+});
+
+export type Registry = typeof registry;
\ No newline at end of file
diff --git a/packages/platforms/bun/public/tsconfig.json b/examples/cloudflare-workers/tsconfig.json
similarity index 93%
rename from packages/platforms/bun/public/tsconfig.json
rename to examples/cloudflare-workers/tsconfig.json
index 7578b052c..681844dd9 100644
--- a/packages/platforms/bun/public/tsconfig.json
+++ b/examples/cloudflare-workers/tsconfig.json
@@ -1,5 +1,4 @@
{
- "$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
@@ -15,7 +14,7 @@
/* Specify how TypeScript looks up a file from a given module specifier. */
"moduleResolution": "bundler",
/* Specify type package names to be included without being referenced in a source file. */
- "types": ["bun"],
+ "types": ["@cloudflare/workers-types"],
/* Enable importing .json files */
"resolveJsonModule": true,
@@ -40,5 +39,5 @@
/* Skip type checking all .d.ts files. */
"skipLibCheck": true
},
- "include": ["**/*.ts"]
-}
+ "include": ["src/**/*"]
+}
\ No newline at end of file
diff --git a/examples/cloudflare-workers/wrangler.json b/examples/cloudflare-workers/wrangler.json
new file mode 100644
index 000000000..8791c7de9
--- /dev/null
+++ b/examples/cloudflare-workers/wrangler.json
@@ -0,0 +1,30 @@
+{
+ "name": "rivetkit-cloudflare-workers-example",
+ "main": "src/index.ts",
+ "compatibility_date": "2025-01-20",
+ "compatibility_flags": ["nodejs_compat"],
+ "migrations": [
+ {
+ "tag": "v1",
+ "new_classes": ["WorkerHandler"]
+ }
+ ],
+ "durable_objects": {
+ "bindings": [
+ {
+ "name": "WORKER_DO",
+ "class_name": "WorkerHandler"
+ }
+ ]
+ },
+ "kv_namespaces": [
+ {
+ "binding": "WORKER_KV",
+ "id": "example_namespace",
+ "preview_id": "example_namespace_preview"
+ }
+ ],
+ "observability": {
+ "enabled": true
+ }
+}
\ No newline at end of file
diff --git a/examples/rivet/.dockerignore b/examples/rivet/.dockerignore
new file mode 100644
index 000000000..de4d1f007
--- /dev/null
+++ b/examples/rivet/.dockerignore
@@ -0,0 +1,2 @@
+dist
+node_modules
diff --git a/examples/rivet/Dockerfile b/examples/rivet/Dockerfile
new file mode 100644
index 000000000..643968a74
--- /dev/null
+++ b/examples/rivet/Dockerfile
@@ -0,0 +1,39 @@
+FROM node:22-alpine AS builder
+
+RUN npm i -g corepack && corepack enable
+
+WORKDIR /app
+
+COPY package.json ./
+
+RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
+ pnpm install
+
+COPY . .
+
+RUN pnpm build
+
+COPY . .
+
+# ===
+
+FROM node:22-alpine AS runtime
+
+RUN npm i -g corepack && corepack enable
+
+RUN addgroup -g 1001 -S rivet && \
+ adduser -S rivet -u 1001 -G rivet
+
+WORKDIR /app
+
+COPY --from=builder --chown=rivet:rivet /app/package.json ./
+
+RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
+ pnpm install --prod
+
+COPY --from=builder --chown=rivet:rivet /app/dist ./dist
+
+USER rivet
+
+CMD ["node", "dist/server.js"]
+
diff --git a/examples/rivet/README.md b/examples/rivet/README.md
new file mode 100644
index 000000000..62a27648f
--- /dev/null
+++ b/examples/rivet/README.md
@@ -0,0 +1,64 @@
+# Rivet Platform for RivetKit
+
+Example project demonstrating Rivet cloud platform deployment with [RivetKit](https://rivetkit.org).
+
+[Learn More →](https://github.com/rivet-gg/rivetkit)
+
+[Discord](https://rivet.gg/discord) — [Documentation](https://rivetkit.org) — [Issues](https://github.com/rivet-gg/rivetkit/issues)
+
+## Getting Started
+
+### Prerequisites
+
+- Node.js
+- Rivet CLI (`npm install -g @rivet-gg/cli`)
+- Rivet Cloud account
+
+### Installation
+
+```sh
+git clone https://github.com/rivet-gg/rivetkit
+cd rivetkit/examples/rivet
+npm install
+```
+
+### Configuration
+
+Set up your environment variables:
+
+```sh
+export RIVET_ENDPOINT=https://api.rivet.gg
+export RIVET_SERVICE_TOKEN=your_service_token
+export RIVET_PROJECT=your_project_id
+export RIVET_ENVIRONMENT=your_environment
+```
+
+### Development
+
+```sh
+npm run dev
+```
+
+This will start the RivetKit server locally at http://localhost:6420.
+
+### Testing the Client
+
+In a separate terminal, run the client script to interact with your workers:
+
+```sh
+npm run client
+```
+
+### Deployment
+
+Deploy to Rivet Cloud:
+
+```sh
+rivet deploy
+```
+
+Your RivetKit workers will be deployed as Rivet actors with automatic scaling and management.
+
+## License
+
+Apache 2.0
diff --git a/examples/rivet/package.json b/examples/rivet/package.json
new file mode 100644
index 000000000..0cd0e06b4
--- /dev/null
+++ b/examples/rivet/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "example-rivet",
+ "version": "0.9.0-rc.1",
+ "private": true,
+ "scripts": {
+ "dev": "tsx --watch src/server.ts",
+ "check-types": "tsc --noEmit",
+ "build": "tsc",
+ "client": "tsx scripts/client.ts"
+ },
+ "devDependencies": {
+ "@types/node": "^22.13.9",
+ "tsx": "^3.12.7",
+ "typescript": "^5.5.2"
+ },
+ "dependencies": {
+ "rivetkit": "https://pkg.pr.new/rivet-gg/rivetkit@65c3659",
+ "@rivetkit/rivet": "https://pkg.pr.new/rivet-gg/rivetkit/@rivetkit/rivet@65c3659"
+ },
+ "example": {
+ "platforms": [
+ "*"
+ ]
+ },
+ "stableVersion": "0.8.0"
+}
diff --git a/examples/rivet/rivet.json b/examples/rivet/rivet.json
new file mode 100644
index 000000000..b821d3b1c
--- /dev/null
+++ b/examples/rivet/rivet.json
@@ -0,0 +1,6 @@
+{
+ "rivetkit": {
+ "registry": "./src/registry.ts",
+ "dockerfile": "Dockerfile"
+ }
+}
diff --git a/examples/rivet/scripts/client.ts b/examples/rivet/scripts/client.ts
new file mode 100644
index 000000000..a8d79bf05
--- /dev/null
+++ b/examples/rivet/scripts/client.ts
@@ -0,0 +1,42 @@
+import { createClient } from "rivetkit/client";
+import { execSync } from "node:child_process";
+import type { Registry } from "../src/registry.js";
+
+// Get endpoint from rivet kit
+const endpoint = execSync("rivet kit endpoint", { encoding: "utf8" }).trim();
+console.log("🔗 Using endpoint:", endpoint);
+
+// Create RivetKit client
+const client = createClient(endpoint);
+
+async function main() {
+ console.log("🚀 Rivet Client Demo");
+
+ try {
+ // Create counter instance
+ const counter = client.counter.getOrCreate("demo");
+
+ // Increment counter
+ console.log("Incrementing counter 'demo'...");
+ const result1 = await counter.increment(1);
+ console.log("New count:", result1);
+
+ // Increment again with larger value
+ console.log("Incrementing counter 'demo' by 5...");
+ const result2 = await counter.increment(5);
+ console.log("New count:", result2);
+
+ // Create another counter
+ const counter2 = client.counter.getOrCreate("another");
+ console.log("Incrementing counter 'another' by 10...");
+ const result3 = await counter2.increment(10);
+ console.log("New count:", result3);
+
+ console.log("✅ Demo completed!");
+ } catch (error) {
+ console.error("❌ Error:", error);
+ process.exit(1);
+ }
+}
+
+main().catch(console.error);
\ No newline at end of file
diff --git a/examples/rivet/src/registry.ts b/examples/rivet/src/registry.ts
new file mode 100644
index 000000000..ce4f8a995
--- /dev/null
+++ b/examples/rivet/src/registry.ts
@@ -0,0 +1,20 @@
+import { worker, setup } from "rivetkit";
+
+export const counter = worker({
+ onAuth: () => {
+ // Configure auth here
+ },
+ state: { count: 0 },
+ actions: {
+ increment: (c, x: number) => {
+ c.state.count += x;
+ return c.state.count;
+ },
+ },
+});
+
+export const registry = setup({
+ workers: { counter },
+});
+
+export type Registry = typeof registry;
diff --git a/examples/rivet/src/server.ts b/examples/rivet/src/server.ts
new file mode 100644
index 000000000..a2cbb7f78
--- /dev/null
+++ b/examples/rivet/src/server.ts
@@ -0,0 +1,4 @@
+import { startManager } from "@rivetkit/rivet/manager";
+import { registry } from "./registry";
+
+startManager(registry);
diff --git a/examples/rivet/tsconfig.json b/examples/rivet/tsconfig.json
new file mode 100644
index 000000000..755f4644c
--- /dev/null
+++ b/examples/rivet/tsconfig.json
@@ -0,0 +1,41 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+ /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ "target": "esnext",
+ /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ "lib": ["esnext"],
+ /* Specify what JSX code is generated. */
+ "jsx": "react-jsx",
+
+ /* Specify what module code is generated. */
+ "module": "nodenext",
+ /* Specify how TypeScript looks up a file from a given module specifier. */
+ "moduleResolution": "nodenext",
+ /* Specify type package names to be included without being referenced in a source file. */
+ "types": ["node"],
+ /* Enable importing .json files */
+ "resolveJsonModule": true,
+
+ /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
+ "allowJs": true,
+ /* Enable error reporting in type-checked JavaScript files. */
+ "checkJs": false,
+
+ /* Ensure that each file can be safely transpiled without relying on other imports. */
+ "isolatedModules": true,
+ /* Allow 'import x from y' when a module doesn't have a default export. */
+ "allowSyntheticDefaultImports": true,
+ /* Ensure that casing is correct in imports. */
+ "forceConsistentCasingInFileNames": true,
+
+ /* Enable all strict type-checking options. */
+ "strict": true,
+
+ /* Skip type checking all .d.ts files. */
+ "skipLibCheck": true,
+ "outDir": "dist"
+ },
+ "include": ["src/**/*"]
+}
diff --git a/packages/drivers/file-system/README.md b/packages/drivers/file-system/README.md
deleted file mode 100644
index 2f27893c3..000000000
--- a/packages/drivers/file-system/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# RivetKit File System Driver
-
-_Lightweight Libraries for Backends_
-
-[Learn More →](https://github.com/rivet-gg/rivetkit)
-
-[Discord](https://rivet.gg/discord) — [Documentation](https://rivetkit.org) — [Issues](https://github.com/rivet-gg/rivetkit/issues)
-
-## License
-
-Apache 2.0
\ No newline at end of file
diff --git a/packages/platforms/bun/README.md b/packages/platforms/bun/README.md
deleted file mode 100644
index 5fd4b42c9..000000000
--- a/packages/platforms/bun/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# RivetKit Bun Adapter
-
-_Lightweight Libraries for Backends_
-
-[Learn More →](https://github.com/rivet-gg/rivetkit)
-
-[Discord](https://rivet.gg/discord) — [Documentation](https://rivetkit.org) — [Issues](https://github.com/rivet-gg/rivetkit/issues)
-
-## License
-
-Apache 2.0
\ No newline at end of file
diff --git a/packages/platforms/bun/package.json b/packages/platforms/bun/package.json
deleted file mode 100644
index 295b7fca7..000000000
--- a/packages/platforms/bun/package.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "name": "@rivetkit/bun",
- "version": "0.9.0-rc.1",
- "keywords": ["rivetkit", "bun", "platform", "runtime", "fast"],
- "files": [
- "src",
- "dist",
- "package.json"
- ],
- "type": "module",
- "exports": {
- ".": {
- "import": {
- "types": "./dist/mod.d.ts",
- "default": "./dist/mod.js"
- },
- "require": {
- "types": "./dist/mod.d.cts",
- "default": "./dist/mod.cjs"
- }
- },
- "./tsconfig": "./dist/tsconfig.json"
- },
- "sideEffects": false,
- "scripts": {
- "build": "tsup src/mod.ts",
- "check-types": "tsc --noEmit"
- },
- "peerDependencies": {
- "@rivetkit/file-system": "*",
- "@rivetkit/memory": "*",
- "rivetkit": "*"
- },
- "devDependencies": {
- "@rivetkit/file-system": "workspace:^",
- "@rivetkit/memory": "workspace:*",
- "@types/bun": "^1.2.2",
- "hono": "^4.7.0",
- "rivetkit": "workspace:*",
- "tsup": "^8.4.0",
- "typescript": "^5.5.2"
- },
- "dependencies": {
- "dedent": "^1.5.3",
- "zod": "^3.24.2"
- },
- "stableVersion": "0.8.0"
-}
diff --git a/packages/platforms/bun/src/config.ts b/packages/platforms/bun/src/config.ts
deleted file mode 100644
index 55b30fe8f..000000000
--- a/packages/platforms/bun/src/config.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { DriverConfigSchema } from "rivetkit/driver-helpers";
-import { z } from "zod";
-
-export const ConfigSchema = DriverConfigSchema.extend({
- mode: z.enum(["file-system", "memory"]).optional().default("file-system"),
- hostname: z
- .string()
- .optional()
- .default(process.env.HOSTNAME ?? "127.0.0.1"),
- port: z
- .number()
- .optional()
- .default(Number.parseInt(process.env.PORT ?? "6420")),
-}).default({});
-export type InputConfig = z.input;
diff --git a/packages/platforms/bun/src/log.ts b/packages/platforms/bun/src/log.ts
deleted file mode 100644
index c58352cda..000000000
--- a/packages/platforms/bun/src/log.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { getLogger } from "rivetkit/log";
-
-export const LOGGER_NAME = "bun";
-
-export function logger() {
- return getLogger(LOGGER_NAME);
-}
diff --git a/packages/platforms/bun/src/mod.ts b/packages/platforms/bun/src/mod.ts
deleted file mode 100644
index 552c92af7..000000000
--- a/packages/platforms/bun/src/mod.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-import type { Serve, Server, ServerWebSocket, WebSocketHandler } from "bun";
-import { assertUnreachable } from "rivetkit/utils";
-import { CoordinateTopology } from "rivetkit/topologies/coordinate";
-import { ConfigSchema, type InputConfig } from "./config";
-import { logger } from "./log";
-import { createBunWebSocket } from "hono/bun";
-import type { Hono } from "hono";
-import { type Registry, StandaloneTopology } from "rivetkit";
-import {
- MemoryGlobalState,
- MemoryManagerDriver,
- MemoryWorkerDriver,
-} from "@rivetkit/memory";
-import { FileSystemWorkerDriver, FileSystemGlobalState, FileSystemManagerDriver } from "@rivetkit/file-system";
-
-export { InputConfig as Config } from "./config";
-
-export function createRouter(
- registry: Registry,
- inputConfig?: InputConfig,
-): {
- router: Hono;
- webSocketHandler: WebSocketHandler;
-} {
- const config = ConfigSchema.parse(inputConfig);
-
- // Setup WebSocket routing for Bun
- const webSocket = createBunWebSocket();
- if (!config.getUpgradeWebSocket) {
- config.getUpgradeWebSocket = () => webSocket.upgradeWebSocket;
- }
-
- // HACK: Hono BunWebSocketHandler type is not compatible with Bun's
- const webSocketHandler = webSocket.websocket as unknown as WebSocketHandler;
-
- // Configure default configuration
- if (!config.topology) config.topology = "standalone";
- if (!config.driver.manager || !config.driver.worker) {
- if (config.mode === "file-system") {
- const fsState = new FileSystemGlobalState();
- if (!config.driver.manager) {
- config.driver.manager = new FileSystemManagerDriver(registry, fsState);
- }
- if (!config.driver.worker) {
- config.driver.worker = new FileSystemWorkerDriver(fsState);
- }
- } else if (config.mode === "memory") {
- const memoryState = new MemoryGlobalState();
- if (!config.driver.manager) {
- config.driver.manager = new MemoryManagerDriver(registry, memoryState);
- }
- if (!config.driver.worker) {
- config.driver.worker = new MemoryWorkerDriver(memoryState);
- }
- } else {
- assertUnreachable(config.mode);
- }
- }
-
- // Setup topology
- if (config.topology === "standalone") {
- const topology = new StandaloneTopology(registry.config, config);
- return { router: topology.router, webSocketHandler };
- } else if (config.topology === "partition") {
- throw new Error("Bun only supports standalone & coordinate topology.");
- } else if (config.topology === "coordinate") {
- const topology = new CoordinateTopology(registry.config, config);
- return { router: topology.router, webSocketHandler };
- } else {
- assertUnreachable(config.topology);
- }
-}
-
-export function createHandler(
- registry: Registry,
- inputConfig?: InputConfig,
-): Serve {
- const config = ConfigSchema.parse(inputConfig);
-
- const { router, webSocketHandler } = createRouter(registry, config);
-
- return {
- hostname: config.hostname,
- port: config.port,
- fetch: router.fetch,
- websocket: webSocketHandler,
- };
-}
-
-export function serve(
- registry: Registry,
- inputConfig: InputConfig,
-): Server {
- const config = ConfigSchema.parse(inputConfig);
-
- const handler = createHandler(registry, config);
- const server = Bun.serve(handler);
-
- logger().info("rivetkit started", {
- hostname: config.hostname,
- port: config.port,
- });
-
- return server;
-}
diff --git a/packages/platforms/bun/tsconfig.json b/packages/platforms/bun/tsconfig.json
deleted file mode 100644
index 828128ae2..000000000
--- a/packages/platforms/bun/tsconfig.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "extends": "../../../tsconfig.base.json",
- "compilerOptions": {
- "types": ["bun"],
- "paths": {
- "@/*": ["./src/*"]
- }
- },
- "include": ["src/**/*"]
-}
diff --git a/packages/platforms/bun/tsup.config.ts b/packages/platforms/bun/tsup.config.ts
deleted file mode 100644
index 677cffb7b..000000000
--- a/packages/platforms/bun/tsup.config.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import defaultConfig from "../../../tsup.base.ts";
-import { defineConfig } from "tsup";
-
-export default defineConfig(defaultConfig);
diff --git a/packages/platforms/bun/turbo.json b/packages/platforms/bun/turbo.json
deleted file mode 100644
index 95960709b..000000000
--- a/packages/platforms/bun/turbo.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "$schema": "https://turbo.build/schema.json",
- "extends": ["//"]
-}
diff --git a/packages/platforms/cloudflare-workers/src/config.ts b/packages/platforms/cloudflare-workers/src/config.ts
index 31cab579f..3ad481223 100644
--- a/packages/platforms/cloudflare-workers/src/config.ts
+++ b/packages/platforms/cloudflare-workers/src/config.ts
@@ -1,6 +1,6 @@
-import { DriverConfigSchema } from "rivetkit/driver-helpers";
+import { RunConfigSchema } from "rivetkit/driver-helpers";
import { z } from "zod";
-export const ConfigSchema = DriverConfigSchema.default({});
+export const ConfigSchema = RunConfigSchema.omit({ driver: true, getUpgradeWebSocket: true }).default({});
export type InputConfig = z.input;
export type Config = z.infer;
diff --git a/packages/platforms/cloudflare-workers/src/handler.ts b/packages/platforms/cloudflare-workers/src/handler.ts
index 753071fbf..920127f28 100644
--- a/packages/platforms/cloudflare-workers/src/handler.ts
+++ b/packages/platforms/cloudflare-workers/src/handler.ts
@@ -15,7 +15,7 @@ import type { Hono } from "hono";
import { PartitionTopologyManager } from "rivetkit/topologies/partition";
import { logger } from "./log";
import { CloudflareWorkersManagerDriver } from "./manager-driver";
-import { Encoding, Registry } from "rivetkit";
+import { Encoding, Registry, RunConfig } from "rivetkit";
import { upgradeWebSocket } from "./websocket";
import invariant from "invariant";
import { AsyncLocalStorage } from "node:async_hooks";
@@ -76,178 +76,155 @@ export function createRouter(
router: Hono<{ Bindings: Bindings }>;
WorkerHandler: DurableObjectConstructor;
} {
- const driverConfig = ConfigSchema.parse(inputConfig);
-
- // Configure drivers
- //
- // Worker driver will get set in `WorkerHandler`
- if (!driverConfig.driver.manager)
- driverConfig.driver.manager = new CloudflareWorkersManagerDriver();
-
- // Setup WebSockets
- if (!driverConfig.getUpgradeWebSocket)
- driverConfig.getUpgradeWebSocket = () => upgradeWebSocket;
+ const config = ConfigSchema.parse(inputConfig);
+ const runConfig = {
+ driver: {
+ topology: "partition",
+ manager: new CloudflareWorkersManagerDriver(),
+ // HACK: We can't build the worker driver until we're inside the Druable Object
+ worker: undefined as any,
+ },
+ getUpgradeWebSocket: () => upgradeWebSocket,
+ ...config,
+ } satisfies RunConfig;
// Create Durable Object
- const WorkerHandler = createWorkerDurableObject(registry, driverConfig);
-
- driverConfig.topology = driverConfig.topology ?? "partition";
- if (driverConfig.topology === "partition") {
- const managerTopology = new PartitionTopologyManager(
- registry.config,
- driverConfig,
- {
- sendRequest: async (workerId, workerRequest): Promise => {
- const env = getCloudflareAmbientEnv();
-
- logger().debug("sending request to durable object", {
- workerId,
- method: workerRequest.method,
- url: workerRequest.url,
- });
+ const WorkerHandler = createWorkerDurableObject(registry, runConfig);
- const id = env.WORKER_DO.idFromString(workerId);
- const stub = env.WORKER_DO.get(id);
+ const managerTopology = new PartitionTopologyManager(
+ registry.config,
+ runConfig,
+ {
+ sendRequest: async (workerId, workerRequest): Promise => {
+ const env = getCloudflareAmbientEnv();
- return await stub.fetch(workerRequest);
- },
-
- openWebSocket: async (
+ logger().debug("sending request to durable object", {
workerId,
- encodingKind: Encoding,
- params: unknown,
- ): Promise => {
- const env = getCloudflareAmbientEnv();
-
- logger().debug("opening websocket to durable object", { workerId });
-
- // Make a fetch request to the Durable Object with WebSocket upgrade
- const id = env.WORKER_DO.idFromString(workerId);
- const stub = env.WORKER_DO.get(id);
-
- const headers: Record = {
- Upgrade: "websocket",
- Connection: "Upgrade",
- [HEADER_EXPOSE_INTERNAL_ERROR]: "true",
- [HEADER_ENCODING]: encodingKind,
- };
- if (params) {
- headers[HEADER_CONN_PARAMS] = JSON.stringify(params);
- }
- // HACK: See packages/platforms/cloudflare-workers/src/websocket.ts
- headers["sec-websocket-protocol"] = "rivetkit";
-
- const response = await stub.fetch("http://worker/connect/websocket", {
- headers,
- });
- const webSocket = response.webSocket;
-
- if (!webSocket) {
- throw new InternalError(
- "missing websocket connection in response from DO",
- );
- }
+ method: workerRequest.method,
+ url: workerRequest.url,
+ });
- logger().debug("durable object websocket connection open", {
- workerId,
- });
+ const id = env.WORKER_DO.idFromString(workerId);
+ const stub = env.WORKER_DO.get(id);
- webSocket.accept();
+ return await stub.fetch(workerRequest);
+ },
- // TODO: Is this still needed?
- // HACK: Cloudflare does not call onopen automatically, so we need
- // to call this on the next tick
- setTimeout(() => {
- (webSocket as any).onopen?.(new Event("open"));
- }, 0);
+ openWebSocket: async (
+ workerId,
+ encodingKind: Encoding,
+ params: unknown,
+ ): Promise => {
+ const env = getCloudflareAmbientEnv();
+
+ logger().debug("opening websocket to durable object", { workerId });
+
+ // Make a fetch request to the Durable Object with WebSocket upgrade
+ const id = env.WORKER_DO.idFromString(workerId);
+ const stub = env.WORKER_DO.get(id);
+
+ const headers: Record = {
+ Upgrade: "websocket",
+ Connection: "Upgrade",
+ [HEADER_EXPOSE_INTERNAL_ERROR]: "true",
+ [HEADER_ENCODING]: encodingKind,
+ };
+ if (params) {
+ headers[HEADER_CONN_PARAMS] = JSON.stringify(params);
+ }
+ // HACK: See packages/platforms/cloudflare-workers/src/websocket.ts
+ headers["sec-websocket-protocol"] = "rivetkit";
+
+ const response = await stub.fetch("http://worker/connect/websocket", {
+ headers,
+ });
+ const webSocket = response.webSocket;
+
+ if (!webSocket) {
+ throw new InternalError(
+ "missing websocket connection in response from DO",
+ );
+ }
+
+ logger().debug("durable object websocket connection open", {
+ workerId,
+ });
- return webSocket as unknown as WebSocket;
- },
+ webSocket.accept();
- proxyRequest: async (c, workerRequest, workerId): Promise => {
- logger().debug("forwarding request to durable object", {
- workerId,
- method: workerRequest.method,
- url: workerRequest.url,
- });
+ // TODO: Is this still needed?
+ // HACK: Cloudflare does not call onopen automatically, so we need
+ // to call this on the next tick
+ setTimeout(() => {
+ (webSocket as any).onopen?.(new Event("open"));
+ }, 0);
- const id = c.env.WORKER_DO.idFromString(workerId);
- const stub = c.env.WORKER_DO.get(id);
+ return webSocket as unknown as WebSocket;
+ },
- return await stub.fetch(workerRequest);
- },
- proxyWebSocket: async (
- c,
- path,
+ proxyRequest: async (c, workerRequest, workerId): Promise => {
+ logger().debug("forwarding request to durable object", {
workerId,
- encoding,
- params,
- authData,
- ) => {
- logger().debug("forwarding websocket to durable object", {
- workerId,
- path,
- });
+ method: workerRequest.method,
+ url: workerRequest.url,
+ });
- // Validate upgrade
- const upgradeHeader = c.req.header("Upgrade");
- if (!upgradeHeader || upgradeHeader !== "websocket") {
- return new Response("Expected Upgrade: websocket", {
- status: 426,
- });
- }
+ const id = c.env.WORKER_DO.idFromString(workerId);
+ const stub = c.env.WORKER_DO.get(id);
- // TODO: strip headers
- const newUrl = new URL(`http://worker${path}`);
- const workerRequest = new Request(newUrl, c.req.raw);
-
- // Always build fresh request to prevent forwarding unwanted headers
- // HACK: Since we can't build a new request, we need to remove
- // non-standard headers manually
- const headerKeys: string[] = [];
- workerRequest.headers.forEach((v, k) => headerKeys.push(k));
- for (const k of headerKeys) {
- if (!STANDARD_WEBSOCKET_HEADERS.includes(k)) {
- workerRequest.headers.delete(k);
- }
- }
+ return await stub.fetch(workerRequest);
+ },
+ proxyWebSocket: async (c, path, workerId, encoding, params, authData) => {
+ logger().debug("forwarding websocket to durable object", {
+ workerId,
+ path,
+ });
- // Add RivetKit headers
- workerRequest.headers.set(HEADER_EXPOSE_INTERNAL_ERROR, "true");
- workerRequest.headers.set(HEADER_ENCODING, encoding);
- if (params) {
- workerRequest.headers.set(
- HEADER_CONN_PARAMS,
- JSON.stringify(params),
- );
- }
- if (authData) {
- workerRequest.headers.set(
- HEADER_AUTH_DATA,
- JSON.stringify(authData),
- );
+ // Validate upgrade
+ const upgradeHeader = c.req.header("Upgrade");
+ if (!upgradeHeader || upgradeHeader !== "websocket") {
+ return new Response("Expected Upgrade: websocket", {
+ status: 426,
+ });
+ }
+
+ // TODO: strip headers
+ const newUrl = new URL(`http://worker${path}`);
+ const workerRequest = new Request(newUrl, c.req.raw);
+
+ // Always build fresh request to prevent forwarding unwanted headers
+ // HACK: Since we can't build a new request, we need to remove
+ // non-standard headers manually
+ const headerKeys: string[] = [];
+ workerRequest.headers.forEach((v, k) => headerKeys.push(k));
+ for (const k of headerKeys) {
+ if (!STANDARD_WEBSOCKET_HEADERS.includes(k)) {
+ workerRequest.headers.delete(k);
}
+ }
+
+ // Add RivetKit headers
+ workerRequest.headers.set(HEADER_EXPOSE_INTERNAL_ERROR, "true");
+ workerRequest.headers.set(HEADER_ENCODING, encoding);
+ if (params) {
+ workerRequest.headers.set(HEADER_CONN_PARAMS, JSON.stringify(params));
+ }
+ if (authData) {
+ workerRequest.headers.set(HEADER_AUTH_DATA, JSON.stringify(authData));
+ }
+
+ const id = c.env.WORKER_DO.idFromString(workerId);
+ const stub = c.env.WORKER_DO.get(id);
+
+ return await stub.fetch(workerRequest);
+ },
+ },
+ );
- const id = c.env.WORKER_DO.idFromString(workerId);
- const stub = c.env.WORKER_DO.get(id);
+ // Force the router to have access to the Cloudflare bindings
+ const router = managerTopology.router as unknown as Hono<{
+ Bindings: Bindings;
+ }>;
- return await stub.fetch(workerRequest);
- },
- },
- );
-
- // Force the router to have access to the Cloudflare bindings
- const router = managerTopology.router as unknown as Hono<{
- Bindings: Bindings;
- }>;
-
- return { router, WorkerHandler };
- } else if (
- driverConfig.topology === "standalone" ||
- driverConfig.topology === "coordinate"
- ) {
- throw new Error("Cloudflare only supports partition topology.");
- } else {
- assertUnreachable(driverConfig.topology);
- }
+ return { router, WorkerHandler };
}
diff --git a/packages/platforms/cloudflare-workers/src/worker-handler-do.ts b/packages/platforms/cloudflare-workers/src/worker-handler-do.ts
index 954b1b20f..3767aaca6 100644
--- a/packages/platforms/cloudflare-workers/src/worker-handler-do.ts
+++ b/packages/platforms/cloudflare-workers/src/worker-handler-do.ts
@@ -1,7 +1,6 @@
import { DurableObject } from "cloudflare:workers";
-import type { Registry, WorkerKey } from "rivetkit";
+import type { Registry, RunConfig, WorkerKey } from "rivetkit";
import { logger } from "./log";
-import type { Config } from "./config";
import { PartitionTopologyWorker } from "rivetkit/topologies/partition";
import {
CloudflareDurableObjectGlobalState,
@@ -43,7 +42,7 @@ interface LoadedWorker {
export function createWorkerDurableObject(
registry: Registry,
- config: Config,
+ runConfig: RunConfig,
): DurableObjectConstructor {
const globalState = new CloudflareDurableObjectGlobalState();
@@ -100,12 +99,13 @@ export function createWorkerDurableObject(
if (!this.#initialized) throw new Error("Not initialized");
- // Create topology
- if (!config.drivers) config.drivers = {};
- if (!config.driver.worker) {
- config.driver.worker = new CloudflareWorkersWorkerDriver(globalState);
- }
- const workerTopology = new PartitionTopologyWorker(registry.config, config);
+ // Configure worker driver
+ runConfig.driver.worker = new CloudflareWorkersWorkerDriver(globalState);
+
+ const workerTopology = new PartitionTopologyWorker(
+ registry.config,
+ runConfig,
+ );
// Register DO with global state
// HACK: This leaks the DO context, but DO does not provide a native way
diff --git a/packages/platforms/rivet/src/config.ts b/packages/platforms/rivet/src/config.ts
index 31cab579f..c98a03918 100644
--- a/packages/platforms/rivet/src/config.ts
+++ b/packages/platforms/rivet/src/config.ts
@@ -1,6 +1,9 @@
-import { DriverConfigSchema } from "rivetkit/driver-helpers";
+import { RunConfigSchema } from "rivetkit/driver-helpers";
import { z } from "zod";
-export const ConfigSchema = DriverConfigSchema.default({});
+export const ConfigSchema = RunConfigSchema.omit({
+ driver: true,
+ getUpgradeWebSocket: true,
+}).default({});
export type InputConfig = z.input;
export type Config = z.infer;
diff --git a/packages/platforms/rivet/src/manager-driver.ts b/packages/platforms/rivet/src/manager-driver.ts
index 3b5f36995..33dae4fef 100644
--- a/packages/platforms/rivet/src/manager-driver.ts
+++ b/packages/platforms/rivet/src/manager-driver.ts
@@ -123,11 +123,13 @@ export class RivetManagerDriver implements ManagerDriver {
},
},
runtime: {
- environment: workerLogLevel
- ? {
- _LOG_LEVEL: workerLogLevel,
- }
- : {},
+ environment: {
+ RIVET_ENDPOINT: this.#clientConfig.endpoint,
+ RIVET_SERVICE_TOKEN: this.#clientConfig.token,
+ RIVET_PROJECT: this.#clientConfig.project,
+ RIVET_ENVIRONMENT: this.#clientConfig.environment,
+ ...(workerLogLevel ? { _LOG_LEVEL: workerLogLevel } : {}),
+ },
},
lifecycle: {
durable: true,
diff --git a/packages/platforms/rivet/src/manager.ts b/packages/platforms/rivet/src/manager.ts
index 454027dd0..8c0014b31 100644
--- a/packages/platforms/rivet/src/manager.ts
+++ b/packages/platforms/rivet/src/manager.ts
@@ -8,7 +8,7 @@ import { PartitionTopologyManager } from "rivetkit/topologies/partition";
import { proxy } from "hono/proxy";
import invariant from "invariant";
import { ConfigSchema, InputConfig } from "./config";
-import type { Registry } from "rivetkit";
+import type { Registry, RunConfig } from "rivetkit";
import { createWebSocketProxy } from "./ws-proxy";
import { flushCache, getWorkerMeta } from "./worker-meta";
import {
@@ -18,6 +18,7 @@ import {
HEADER_EXPOSE_INTERNAL_ERROR,
} from "rivetkit/driver-helpers";
import { importWebSocket } from "rivetkit/driver-helpers/websocket";
+import { RivetWorkerDriver } from "./worker-driver";
export async function startManager(
registry: Registry,
@@ -25,8 +26,6 @@ export async function startManager(
): Promise {
setupLogging();
- const driverConfig = ConfigSchema.parse(inputConfig);
-
const portStr = process.env.PORT_HTTP;
if (!portStr) {
throw "Missing port";
@@ -36,8 +35,8 @@ export async function startManager(
throw "Invalid port";
}
- const endpoint = process.env.RIVET_API_ENDPOINT;
- if (!endpoint) throw new Error("missing RIVET_API_ENDPOINT");
+ const endpoint = process.env.RIVET_ENDPOINT;
+ if (!endpoint) throw new Error("missing RIVET_ENDPOINT");
const token = process.env.RIVET_SERVICE_TOKEN;
if (!token) throw new Error("missing RIVET_SERVICE_TOKEN");
const project = process.env.RIVET_PROJECT;
@@ -52,6 +51,26 @@ export async function startManager(
environment,
};
+ const config = ConfigSchema.parse(inputConfig);
+ let injectWebSocket: NodeWebSocket["injectWebSocket"] | undefined;
+ const runConfig = {
+ driver: {
+ topology: "partition",
+ manager: new RivetManagerDriver(clientConfig),
+ // HACK: We can't build the worker driver until we're inside the worker
+ worker: undefined as any,
+ },
+ // Setup WebSocket routing for Node
+ //
+ // Save `injectWebSocket` for after server is created
+ getUpgradeWebSocket: (app) => {
+ const webSocket = createNodeWebSocket({ app });
+ injectWebSocket = webSocket.injectWebSocket;
+ return webSocket.upgradeWebSocket;
+ },
+ ...config,
+ } satisfies RunConfig;
+
//// Force disable inspector
//driverConfig.registry.config.inspector = {
// enabled: false,
@@ -80,29 +99,10 @@ export async function startManager(
// },
//};
- // Setup manager driver
- if (!driverConfig.drivers) driverConfig.drivers = {};
- if (!driverConfig.driver.manager) {
- driverConfig.driver.manager = new RivetManagerDriver(clientConfig);
- }
-
- // Setup WebSocket routing for Node
- //
- // Save `injectWebSocket` for after server is created
- let injectWebSocket: NodeWebSocket["injectWebSocket"] | undefined;
- if (!driverConfig.getUpgradeWebSocket) {
- driverConfig.getUpgradeWebSocket = (app) => {
- const webSocket = createNodeWebSocket({ app });
- injectWebSocket = webSocket.injectWebSocket;
- return webSocket.upgradeWebSocket;
- };
- }
-
// Create manager topology
- driverConfig.topology = driverConfig.topology ?? "partition";
const managerTopology = new PartitionTopologyManager(
registry.config,
- driverConfig,
+ runConfig,
{
sendRequest: async (workerId, workerRequest) => {
const meta = await getWorkerMeta(clientConfig, workerId);
@@ -200,10 +200,12 @@ export async function startManager(
);
// HACK: Expose endpoint for tests to flush cache
- managerTopology.router.post("/.test/rivet/flush-cache", (c) => {
- flushCache();
- return c.text("ok");
- });
+ if (registry.config.test.enabled) {
+ managerTopology.router.post("/.test/rivet/flush-cache", (c) => {
+ flushCache();
+ return c.text("ok");
+ });
+ }
// Start server with ambient env wrapper
logger().info("server running", { port });
diff --git a/packages/platforms/rivet/src/worker.ts b/packages/platforms/rivet/src/worker.ts
index b792cd08e..d53317fde 100644
--- a/packages/platforms/rivet/src/worker.ts
+++ b/packages/platforms/rivet/src/worker.ts
@@ -6,17 +6,19 @@ import { PartitionTopologyWorker } from "rivetkit/topologies/partition";
import { RivetWorkerDriver } from "./worker-driver";
import invariant from "invariant";
import type { ActorContext } from "@rivet-gg/actor-core";
-import { Registry } from "rivetkit";
+import { Registry, RunConfig } from "rivetkit";
import { type Config, ConfigSchema, type InputConfig } from "./config";
import { stringifyError } from "rivetkit/utils";
+import { RivetManagerDriver } from "./manager-driver";
+import { RivetClientConfig } from "./rivet-client";
export function createWorkerHandler(
registry: Registry,
inputConfig?: InputConfig,
): RivetHandler {
- let driverConfig: Config;
+ let config: Config;
try {
- driverConfig = ConfigSchema.parse(inputConfig);
+ config = ConfigSchema.parse(inputConfig);
} catch (error) {
logger().error("failed to start manager", { error: stringifyError(error) });
Deno.exit(1);
@@ -26,7 +28,7 @@ export function createWorkerHandler(
async start(ctx: ActorContext) {
const role = ctx.metadata.actor.tags.role;
if (role === "worker") {
- await startWorker(ctx, registry, driverConfig);
+ await startWorker(ctx, registry, config);
} else {
throw new Error(`Unexpected role (must be worker): ${role}`);
}
@@ -37,7 +39,7 @@ export function createWorkerHandler(
async function startWorker(
ctx: ActorContext,
registry: Registry,
- driverConfig: Config,
+ config: Config,
): Promise {
setupLogging();
@@ -50,26 +52,42 @@ async function startWorker(
throw "Invalid port";
}
- const endpoint = Deno.env.get("RIVET_API_ENDPOINT");
- if (!endpoint) throw new Error("missing RIVET_API_ENDPOINT");
+ const endpoint = Deno.env.get("RIVET_ENDPOINT");
+ if (!endpoint) throw new Error("missing RIVET_ENDPOINT");
+ const token = Deno.env.get("RIVET_SERVICE_TOKEN");
+ if (!token) throw new Error("missing RIVET_SERVICE_TOKEN");
+ const project = Deno.env.get("RIVET_PROJECT");
+ if (!project) throw new Error("missing RIVET_PROJECT");
+ const environment = Deno.env.get("RIVET_ENVIRONMENT");
+ if (!environment) throw new Error("missing RIVET_ENVIRONMENT");
+
+ const clientConfig: RivetClientConfig = {
+ endpoint,
+ token,
+ project,
+ environment,
+ };
+
+ const runConfig = {
+ driver: {
+ topology: "partition",
+ manager: new RivetManagerDriver(clientConfig),
+ worker: new RivetWorkerDriver(ctx),
+ },
+ getUpgradeWebSocket: () => upgradeWebSocket,
+ ...config,
+ } satisfies RunConfig;
// Initialization promise
+ //
+ // Resolve immediately if already initialized
+ //
+ // Otherwise, will wait for `POST /initialize` request
const initializedPromise = Promise.withResolvers();
if ((await ctx.kv.get(["rivetkit", "initialized"])) === true) {
initializedPromise.resolve(undefined);
}
- // Setup worker driver
- if (!driverConfig.drivers) driverConfig.drivers = {};
- if (!driverConfig.driver.worker) {
- driverConfig.driver.worker = new RivetWorkerDriver(ctx);
- }
-
- // Setup WebSocket upgrader
- if (!driverConfig.getUpgradeWebSocket) {
- driverConfig.getUpgradeWebSocket = () => upgradeWebSocket;
- }
-
//registry.config.inspector = {
// enabled: true,
// onRequest: async (c) => {
@@ -117,8 +135,10 @@ async function startWorker(
//};
// Create worker topology
- driverConfig.topology = driverConfig.topology ?? "partition";
- const workerTopology = new PartitionTopologyWorker(registry.config, driverConfig);
+ const workerTopology = new PartitionTopologyWorker(
+ registry.config,
+ runConfig,
+ );
// Set a catch-all route
const router = workerTopology.router;
diff --git a/packages/platforms/rivet/src/ws-proxy.ts b/packages/platforms/rivet/src/ws-proxy.ts
index 7bba7eeed..12b75d094 100644
--- a/packages/platforms/rivet/src/ws-proxy.ts
+++ b/packages/platforms/rivet/src/ws-proxy.ts
@@ -17,7 +17,7 @@ export async function createWebSocketProxy(
) {
const WebSocket = await importWebSocket();
- let targetWs: WebSocket | undefined = undefined;
+ let targetWs: any | undefined = undefined; // WS not compatible between Node & browser
const messageQueue: any[] = [];
return {
@@ -39,11 +39,11 @@ export async function createWebSocketProxy(
}
};
- targetWs.onmessage = (event) => {
+ targetWs.onmessage = (event: any) => {
wsContext.send(event.data as any);
};
- targetWs.onclose = (event) => {
+ targetWs.onclose = (event: any) => {
logger().debug("target websocket closed", {
code: event.code,
reason: event.reason,
@@ -55,7 +55,7 @@ export async function createWebSocketProxy(
}
};
- targetWs.onerror = (event) => {
+ targetWs.onerror = () => {
logger().warn("target websocket error");
if (wsContext.readyState === WebSocket.OPEN) {
diff --git a/packages/platforms/rivet/tests/rivet-deploy.ts b/packages/platforms/rivet/tests/rivet-deploy.ts
index fb4d8cb30..37f7e4b83 100644
--- a/packages/platforms/rivet/tests/rivet-deploy.ts
+++ b/packages/platforms/rivet/tests/rivet-deploy.ts
@@ -127,7 +127,7 @@ export async function deployToRivet(projectPath: string) {
dockerfile: "Dockerfile",
runtime: {
environment: {
- RIVET_API_ENDPOINT: apiEndpoint,
+ RIVET_ENDPOINT: apiEndpoint,
RIVET_SERVICE_TOKEN: rivetCloudToken, // TODO: This should be a service token, but both work
RIVET_PROJECT: project,
RIVET_ENVIRONMENT: environment,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b79583929..6900a7393 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -49,6 +49,61 @@ importers:
specifier: ^8.3.2
version: 8.5.5
+ examples/better-auth:
+ dependencies:
+ '@hono/node-server':
+ specifier: ^1.14.4
+ version: 1.14.4(hono@4.8.0)
+ '@rivetkit/memory':
+ specifier: workspace:0.9.0-rc.1
+ version: link:../../packages/drivers/memory
+ '@rivetkit/react':
+ specifier: workspace:0.9.0-rc.1
+ version: link:../../packages/frameworks/react
+ better-auth:
+ specifier: ^1.0.1
+ version: 1.2.10
+ hono:
+ specifier: ^4.7.0
+ version: 4.8.0
+ react:
+ specifier: ^18.3
+ version: 18.3.1
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.2.0(react@18.3.1)
+ devDependencies:
+ '@types/node':
+ specifier: ^22.13.9
+ version: 22.15.32
+ '@types/react':
+ specifier: ^18.2.0
+ version: 18.3.23
+ '@types/react-dom':
+ specifier: ^18.2.0
+ version: 18.3.7(@types/react@18.3.23)
+ '@vitejs/plugin-react':
+ specifier: ^4.2.0
+ version: 4.5.2(vite@5.4.19(@types/node@22.15.32))
+ concurrently:
+ specifier: ^8.2.2
+ version: 8.2.2
+ rivetkit:
+ specifier: workspace:*
+ version: link:../../packages/core
+ tsx:
+ specifier: ^3.12.7
+ version: 3.14.0
+ typescript:
+ specifier: ^5.5.2
+ version: 5.8.3
+ vite:
+ specifier: ^5.0.0
+ version: 5.4.19(@types/node@22.15.32)
+ vitest:
+ specifier: ^3.1.1
+ version: 3.2.4(@types/node@22.15.32)(tsx@3.14.0)(yaml@2.8.0)
+
examples/chat-room:
dependencies:
'@rivetkit/nodejs':
@@ -77,6 +132,31 @@ importers:
specifier: ^3.1.1
version: 3.2.4(@types/node@22.15.32)(tsx@3.14.0)(yaml@2.8.0)
+ examples/cloudflare-workers:
+ dependencies:
+ '@rivetkit/cloudflare-workers':
+ specifier: workspace:*
+ version: link:../../packages/platforms/cloudflare-workers
+ devDependencies:
+ '@cloudflare/workers-types':
+ specifier: ^4.20250129.0
+ version: 4.20250619.0
+ '@types/node':
+ specifier: ^22.13.9
+ version: 22.15.32
+ rivetkit:
+ specifier: workspace:*
+ version: link:../../packages/core
+ tsx:
+ specifier: ^3.12.7
+ version: 3.14.0
+ typescript:
+ specifier: ^5.5.2
+ version: 5.8.3
+ wrangler:
+ specifier: ^3.0.0
+ version: 3.114.9(@cloudflare/workers-types@4.20250619.0)
+
examples/counter:
dependencies:
'@rivetkit/nodejs':
@@ -309,6 +389,25 @@ importers:
specifier: ^3.1.1
version: 3.2.4(@types/node@22.15.32)(tsx@3.14.0)(yaml@2.8.0)
+ examples/rivet:
+ dependencies:
+ '@rivetkit/rivet':
+ specifier: https://pkg.pr.new/rivet-gg/rivetkit/@rivetkit/rivet@65c3659
+ version: https://pkg.pr.new/rivet-gg/rivetkit/@rivetkit/rivet@65c3659(rivetkit@https://pkg.pr.new/rivet-gg/rivetkit@65c3659(@hono/node-server@1.14.4(hono@4.8.0))(@hono/node-ws@1.1.7(@hono/node-server@1.14.4(hono@4.8.0))(hono@4.8.0))(eventsource@3.0.7)(ws@8.18.2))
+ rivetkit:
+ specifier: https://pkg.pr.new/rivet-gg/rivetkit@65c3659
+ version: https://pkg.pr.new/rivet-gg/rivetkit@65c3659(@hono/node-server@1.14.4(hono@4.8.0))(@hono/node-ws@1.1.7(@hono/node-server@1.14.4(hono@4.8.0))(hono@4.8.0))(eventsource@3.0.7)(ws@8.18.2)
+ devDependencies:
+ '@types/node':
+ specifier: ^22.13.9
+ version: 22.15.32
+ tsx:
+ specifier: ^3.12.7
+ version: 3.14.0
+ typescript:
+ specifier: ^5.5.2
+ version: 5.8.3
+
examples/trpc:
dependencies:
'@rivetkit/memory':
@@ -563,37 +662,6 @@ importers:
specifier: ^3.101.0
version: 3.114.9(@cloudflare/workers-types@4.20250619.0)
- packages/platforms/bun:
- dependencies:
- dedent:
- specifier: ^1.5.3
- version: 1.6.0
- zod:
- specifier: ^3.24.2
- version: 3.25.67
- devDependencies:
- '@rivetkit/file-system':
- specifier: workspace:^
- version: link:../../drivers/file-system
- '@rivetkit/memory':
- specifier: workspace:*
- version: link:../../drivers/memory
- '@types/bun':
- specifier: ^1.2.2
- version: 1.2.17
- hono:
- specifier: ^4.7.0
- version: 4.8.0
- rivetkit:
- specifier: workspace:*
- version: link:../../core
- tsup:
- specifier: ^8.4.0
- version: 8.5.0(@microsoft/api-extractor@7.52.8(@types/node@24.0.3))(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.0)
- typescript:
- specifier: ^5.5.2
- version: 5.8.3
-
packages/platforms/cloudflare-workers:
dependencies:
hono:
@@ -805,6 +873,12 @@ packages:
resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
engines: {node: '>=6.9.0'}
+ '@better-auth/utils@0.2.5':
+ resolution: {integrity: sha512-uI2+/8h/zVsH8RrYdG8eUErbuGBk16rZKQfz8CjxQOyCE6v7BqFYEbFwvOkvl1KbUdxhqOnXp78+uE5h8qVEgQ==}
+
+ '@better-fetch/fetch@1.1.18':
+ resolution: {integrity: sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==}
+
'@biomejs/biome@1.9.4':
resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==}
engines: {node: '>=14.21.3'}
@@ -1544,6 +1618,9 @@ packages:
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
engines: {node: '>=14'}
+ '@hexagon/base64@1.1.28':
+ resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==}
+
'@hono/node-server@1.14.4':
resolution: {integrity: sha512-DnxpshhYewr2q9ZN8ez/M5mmc3sucr8CT1sIgIy1bkeUXut9XWDkqHoFHRhWIQgkYnKpVRxunyhK7WzpJeJ6qQ==}
engines: {node: '>=18.14.1'}
@@ -1703,6 +1780,9 @@ packages:
'@jridgewell/trace-mapping@0.3.9':
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+ '@levischuck/tiny-cbor@0.2.11':
+ resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==}
+
'@microsoft/api-extractor-model@7.30.6':
resolution: {integrity: sha512-znmFn69wf/AIrwHya3fxX6uB5etSIn6vg4Q4RB/tb5VDDs1rqREc+AvMC/p19MUN13CZ7+V/8pkYPTj7q8tftg==}
@@ -1716,6 +1796,13 @@ packages:
'@microsoft/tsdoc@0.15.1':
resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==}
+ '@noble/ciphers@0.6.0':
+ resolution: {integrity: sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ==}
+
+ '@noble/hashes@1.8.0':
+ resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
+ engines: {node: ^14.21.3 || >=16}
+
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -1728,6 +1815,21 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
+ '@peculiar/asn1-android@2.3.16':
+ resolution: {integrity: sha512-a1viIv3bIahXNssrOIkXZIlI2ePpZaNmR30d4aBL99mu2rO+mT9D6zBsp7H6eROWGtmwv0Ionp5olJurIo09dw==}
+
+ '@peculiar/asn1-ecc@2.3.15':
+ resolution: {integrity: sha512-/HtR91dvgog7z/WhCVdxZJ/jitJuIu8iTqiyWVgRE9Ac5imt2sT/E4obqIVGKQw7PIy+X6i8lVBoT6wC73XUgA==}
+
+ '@peculiar/asn1-rsa@2.3.15':
+ resolution: {integrity: sha512-p6hsanvPhexRtYSOHihLvUUgrJ8y0FtOM97N5UEpC+VifFYyZa0iZ5cXjTkZoDwxJ/TTJ1IJo3HVTB2JJTpXvg==}
+
+ '@peculiar/asn1-schema@2.3.15':
+ resolution: {integrity: sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==}
+
+ '@peculiar/asn1-x509@2.3.15':
+ resolution: {integrity: sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg==}
+
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@@ -1741,6 +1843,12 @@ packages:
'@rivet-gg/api@25.4.2':
resolution: {integrity: sha512-VmQ+1dfwWoDamF+49A+cB5htnjJbD4LzmQiaiycBS4ICqAiC3b9rW6l1UAyUfG32x02cSRRJ80yApBl54CdlqQ==}
+ '@rivetkit/rivet@https://pkg.pr.new/rivet-gg/rivetkit/@rivetkit/rivet@65c3659':
+ resolution: {tarball: https://pkg.pr.new/rivet-gg/rivetkit/@rivetkit/rivet@65c3659}
+ version: 0.9.0-rc.1
+ peerDependencies:
+ rivetkit: '*'
+
'@rolldown/pluginutils@1.0.0-beta.11':
resolution: {integrity: sha512-L/gAA/hyCSuzTF1ftlzUSI/IKr2POHsv1Dd78GfqkR83KMNuswWD61JxGV2L7nRwBBBSDr6R1gCkdTmoN7W4ag==}
@@ -1875,6 +1983,13 @@ packages:
'@rushstack/ts-command-line@5.0.1':
resolution: {integrity: sha512-bsbUucn41UXrQK7wgM8CNM/jagBytEyJqXw/umtI8d68vFm1Jwxh1OtLrlW7uGZgjCWiiPH6ooUNa1aVsuVr3Q==}
+ '@simplewebauthn/browser@13.1.0':
+ resolution: {integrity: sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==}
+
+ '@simplewebauthn/server@13.1.1':
+ resolution: {integrity: sha512-1hsLpRHfSuMB9ee2aAdh0Htza/X3f4djhYISrggqGe3xopNjOcePiSDkDDoPzDYaaMCrbqGP1H2TYU7bgL9PmA==}
+ engines: {node: '>=20.0.0'}
+
'@sinclair/typebox@0.34.35':
resolution: {integrity: sha512-C6ypdODf2VZkgRT6sFM8E1F8vR+HcffniX0Kp8MsU8PIfrlXbNCBz0jzj17GjdmjTx1OtZzdH8+iALL21UjF5A==}
@@ -1923,9 +2038,6 @@ packages:
'@types/body-parser@1.19.6':
resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
- '@types/bun@1.2.17':
- resolution: {integrity: sha512-l/BYs/JYt+cXA/0+wUhulYJB6a6p//GTPiJ7nV+QHa8iiId4HZmnu/3J/SowP5g0rTiERY2kfGKXEK5Ehltx4Q==}
-
'@types/chai@5.2.2':
resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==}
@@ -2167,6 +2279,10 @@ packages:
as-table@1.0.55:
resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==}
+ asn1js@3.0.6:
+ resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==}
+ engines: {node: '>=12.0.0'}
+
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
@@ -2180,6 +2296,12 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ better-auth@1.2.10:
+ resolution: {integrity: sha512-nEj1RG4DdLUuJiV5CR93ORyPCptGRBwksaPPCkUtGo9ka+UIlTpaiKoTaTqVLLYlqwX4bOj9tJ32oBNdf2G3Kg==}
+
+ better-call@1.0.9:
+ resolution: {integrity: sha512-Qfm0gjk0XQz0oI7qvTK1hbqTsBY4xV2hsHAxF8LZfUYl3RaECCIifXuVqtPpZJWvlCCMlQSvkvhhyuApGUba6g==}
+
birpc@0.2.14:
resolution: {integrity: sha512-37FHE8rqsYM5JEKCnXFyHpBCzvgHEExwVVTq+nUmloInU7l8ezD1TpOhKpS8oe1DTYFqEK27rFZVKG43oTqXRA==}
@@ -2211,9 +2333,6 @@ packages:
buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
- bun-types@1.2.17:
- resolution: {integrity: sha512-ElC7ItwT3SCQwYZDYoAH+q6KT4Fxjl8DtZ6qDulUFBmXA8YB4xo+l54J9ZJN+k2pphfn9vk7kfubeSd5QfTVJQ==}
-
bundle-require@5.1.0:
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -2798,6 +2917,9 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
+ jose@5.10.0:
+ resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==}
+
joycon@3.1.1:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
@@ -2834,6 +2956,10 @@ packages:
kolorist@1.8.0:
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
+ kysely@0.28.2:
+ resolution: {integrity: sha512-4YAVLoF0Sf0UTqlhgQMFU9iQECdah7n+13ANkiuVfRvlK+uI0Etbgd7bVP36dKlG+NXWbhGua8vnGt+sdhvT7A==}
+ engines: {node: '>=18.0.0'}
+
lefthook-darwin-arm64@1.11.14:
resolution: {integrity: sha512-YPbUK6kGytY5W6aNUrzK7Vod3ynLVvj5JQiBh0DjlxCHMgIQPpFkDfwQzGw1E8CySyC95HXO83En5Ule8umS7g==}
cpu: [arm64]
@@ -3031,6 +3157,10 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ nanostores@0.11.4:
+ resolution: {integrity: sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+
negotiator@1.0.0:
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
engines: {node: '>= 0.6'}
@@ -3207,6 +3337,13 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
+ pvtsutils@1.3.6:
+ resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==}
+
+ pvutils@1.1.3:
+ resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==}
+ engines: {node: '>=6.0.0'}
+
qs@6.14.0:
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
engines: {node: '>=0.6'}
@@ -3291,6 +3428,25 @@ packages:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ rivetkit@https://pkg.pr.new/rivet-gg/rivetkit@65c3659:
+ resolution: {tarball: https://pkg.pr.new/rivet-gg/rivetkit@65c3659}
+ version: 0.9.0-rc.1
+ engines: {node: '>=22.0.0'}
+ peerDependencies:
+ '@hono/node-server': ^1.14.0
+ '@hono/node-ws': ^1.1.1
+ eventsource: ^3.0.5
+ ws: ^8.0.0
+ peerDependenciesMeta:
+ '@hono/node-server':
+ optional: true
+ '@hono/node-ws':
+ optional: true
+ eventsource:
+ optional: true
+ ws:
+ optional: true
+
rollup-plugin-inject@3.0.2:
resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==}
deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.
@@ -3306,6 +3462,9 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
+ rou3@0.5.1:
+ resolution: {integrity: sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==}
+
router@2.2.0:
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
engines: {node: '>= 18'}
@@ -3350,6 +3509,9 @@ packages:
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
engines: {node: '>= 18'}
+ set-cookie-parser@2.7.1:
+ resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
+
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
@@ -3659,6 +3821,9 @@ packages:
resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==}
engines: {node: '>=18'}
+ uncrypto@0.1.3:
+ resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
+
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
@@ -4093,6 +4258,13 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
+ '@better-auth/utils@0.2.5':
+ dependencies:
+ typescript: 5.8.3
+ uncrypto: 0.1.3
+
+ '@better-fetch/fetch@1.1.18': {}
+
'@biomejs/biome@1.9.4':
optionalDependencies:
'@biomejs/cli-darwin-arm64': 1.9.4
@@ -4503,6 +4675,8 @@ snapshots:
'@fastify/busboy@2.1.1': {}
+ '@hexagon/base64@1.1.28': {}
+
'@hono/node-server@1.14.4(hono@4.8.0)':
dependencies:
hono: 4.8.0
@@ -4636,6 +4810,8 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
+ '@levischuck/tiny-cbor@0.2.11': {}
+
'@microsoft/api-extractor-model@7.30.6(@types/node@22.15.32)':
dependencies:
'@microsoft/tsdoc': 0.15.1
@@ -4699,6 +4875,10 @@ snapshots:
'@microsoft/tsdoc@0.15.1': {}
+ '@noble/ciphers@0.6.0': {}
+
+ '@noble/hashes@1.8.0': {}
+
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -4711,6 +4891,39 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
+ '@peculiar/asn1-android@2.3.16':
+ dependencies:
+ '@peculiar/asn1-schema': 2.3.15
+ asn1js: 3.0.6
+ tslib: 2.8.1
+
+ '@peculiar/asn1-ecc@2.3.15':
+ dependencies:
+ '@peculiar/asn1-schema': 2.3.15
+ '@peculiar/asn1-x509': 2.3.15
+ asn1js: 3.0.6
+ tslib: 2.8.1
+
+ '@peculiar/asn1-rsa@2.3.15':
+ dependencies:
+ '@peculiar/asn1-schema': 2.3.15
+ '@peculiar/asn1-x509': 2.3.15
+ asn1js: 3.0.6
+ tslib: 2.8.1
+
+ '@peculiar/asn1-schema@2.3.15':
+ dependencies:
+ asn1js: 3.0.6
+ pvtsutils: 1.3.6
+ tslib: 2.8.1
+
+ '@peculiar/asn1-x509@2.3.15':
+ dependencies:
+ '@peculiar/asn1-schema': 2.3.15
+ asn1js: 3.0.6
+ pvtsutils: 1.3.6
+ tslib: 2.8.1
+
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -4731,6 +4944,18 @@ snapshots:
transitivePeerDependencies:
- encoding
+ '@rivetkit/rivet@https://pkg.pr.new/rivet-gg/rivetkit/@rivetkit/rivet@65c3659(rivetkit@https://pkg.pr.new/rivet-gg/rivetkit@65c3659(@hono/node-server@1.14.4(hono@4.8.0))(@hono/node-ws@1.1.7(@hono/node-server@1.14.4(hono@4.8.0))(hono@4.8.0))(eventsource@3.0.7)(ws@8.18.2))':
+ dependencies:
+ '@hono/node-server': 1.14.4(hono@4.8.0)
+ '@hono/node-ws': 1.1.7(@hono/node-server@1.14.4(hono@4.8.0))(hono@4.8.0)
+ hono: 4.8.0
+ invariant: 2.2.4
+ rivetkit: https://pkg.pr.new/rivet-gg/rivetkit@65c3659(@hono/node-server@1.14.4(hono@4.8.0))(@hono/node-ws@1.1.7(@hono/node-server@1.14.4(hono@4.8.0))(hono@4.8.0))(eventsource@3.0.7)(ws@8.18.2)
+ zod: 3.25.67
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+
'@rolldown/pluginutils@1.0.0-beta.11': {}
'@rollup/pluginutils@5.2.0(rollup@4.44.0)':
@@ -4867,6 +5092,18 @@ snapshots:
transitivePeerDependencies:
- '@types/node'
+ '@simplewebauthn/browser@13.1.0': {}
+
+ '@simplewebauthn/server@13.1.1':
+ dependencies:
+ '@hexagon/base64': 1.1.28
+ '@levischuck/tiny-cbor': 0.2.11
+ '@peculiar/asn1-android': 2.3.16
+ '@peculiar/asn1-ecc': 2.3.15
+ '@peculiar/asn1-rsa': 2.3.15
+ '@peculiar/asn1-schema': 2.3.15
+ '@peculiar/asn1-x509': 2.3.15
+
'@sinclair/typebox@0.34.35':
optional: true
@@ -4926,10 +5163,6 @@ snapshots:
'@types/connect': 3.4.38
'@types/node': 22.15.32
- '@types/bun@1.2.17':
- dependencies:
- bun-types: 1.2.17
-
'@types/chai@5.2.2':
dependencies:
'@types/deep-eql': 4.0.2
@@ -5056,6 +5289,14 @@ snapshots:
chai: 5.2.0
tinyrainbow: 2.0.0
+ '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.15.32)(tsx@3.14.0)(yaml@2.8.0))':
+ dependencies:
+ '@vitest/spy': 3.2.4
+ estree-walker: 3.0.3
+ magic-string: 0.30.17
+ optionalDependencies:
+ vite: 6.3.5(@types/node@22.15.32)(tsx@3.14.0)(yaml@2.8.0)
+
'@vitest/mocker@3.2.4(vite@6.3.5(@types/node@24.0.3)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
'@vitest/spy': 3.2.4
@@ -5215,6 +5456,12 @@ snapshots:
dependencies:
printable-characters: 1.0.42
+ asn1js@3.0.6:
+ dependencies:
+ pvtsutils: 1.3.6
+ pvutils: 1.1.3
+ tslib: 2.8.1
+
assertion-error@2.0.1: {}
asynckit@0.4.0: {}
@@ -5223,6 +5470,28 @@ snapshots:
base64-js@1.5.1: {}
+ better-auth@1.2.10:
+ dependencies:
+ '@better-auth/utils': 0.2.5
+ '@better-fetch/fetch': 1.1.18
+ '@noble/ciphers': 0.6.0
+ '@noble/hashes': 1.8.0
+ '@simplewebauthn/browser': 13.1.0
+ '@simplewebauthn/server': 13.1.1
+ better-call: 1.0.9
+ defu: 6.1.4
+ jose: 5.10.0
+ kysely: 0.28.2
+ nanostores: 0.11.4
+ zod: 3.25.67
+
+ better-call@1.0.9:
+ dependencies:
+ '@better-fetch/fetch': 1.1.18
+ rou3: 0.5.1
+ set-cookie-parser: 2.7.1
+ uncrypto: 0.1.3
+
birpc@0.2.14: {}
blake3-wasm@2.1.5: {}
@@ -5268,10 +5537,6 @@ snapshots:
base64-js: 1.5.1
ieee754: 1.2.1
- bun-types@1.2.17:
- dependencies:
- '@types/node': 22.15.32
-
bundle-require@5.1.0(esbuild@0.25.5):
dependencies:
esbuild: 0.25.5
@@ -5925,6 +6190,8 @@ snapshots:
jju@1.4.0: {}
+ jose@5.10.0: {}
+
joycon@3.1.1: {}
js-base64@3.7.7: {}
@@ -5949,6 +6216,8 @@ snapshots:
kolorist@1.8.0: {}
+ kysely@0.28.2: {}
+
lefthook-darwin-arm64@1.11.14:
optional: true
@@ -6134,6 +6403,8 @@ snapshots:
nanoid@3.3.11: {}
+ nanostores@0.11.4: {}
+
negotiator@1.0.0: {}
node-domexception@1.0.0: {}
@@ -6271,6 +6542,12 @@ snapshots:
punycode@2.3.1: {}
+ pvtsutils@1.3.6:
+ dependencies:
+ tslib: 2.8.1
+
+ pvutils@1.1.3: {}
+
qs@6.14.0:
dependencies:
side-channel: 1.1.0
@@ -6341,6 +6618,21 @@ snapshots:
reusify@1.1.0: {}
+ rivetkit@https://pkg.pr.new/rivet-gg/rivetkit@65c3659(@hono/node-server@1.14.4(hono@4.8.0))(@hono/node-ws@1.1.7(@hono/node-server@1.14.4(hono@4.8.0))(hono@4.8.0))(eventsource@3.0.7)(ws@8.18.2):
+ dependencies:
+ '@hono/zod-openapi': 0.19.8(hono@4.8.0)(zod@3.25.67)
+ cbor-x: 1.6.0
+ hono: 4.8.0
+ invariant: 2.2.4
+ on-change: 5.0.1
+ p-retry: 6.2.1
+ zod: 3.25.67
+ optionalDependencies:
+ '@hono/node-server': 1.14.4(hono@4.8.0)
+ '@hono/node-ws': 1.1.7(@hono/node-server@1.14.4(hono@4.8.0))(hono@4.8.0)
+ eventsource: 3.0.7
+ ws: 8.18.2
+
rollup-plugin-inject@3.0.2:
dependencies:
estree-walker: 0.6.1
@@ -6381,6 +6673,8 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.44.0
fsevents: 2.3.3
+ rou3@0.5.1: {}
+
router@2.2.0:
dependencies:
debug: 4.4.1
@@ -6442,6 +6736,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ set-cookie-parser@2.7.1: {}
+
setprototypeof@1.2.0: {}
sharp@0.33.5:
@@ -6790,6 +7086,8 @@ snapshots:
uint8array-extras@1.4.0: {}
+ uncrypto@0.1.3: {}
+
undici-types@5.26.5: {}
undici-types@6.21.0: {}
@@ -7017,7 +7315,7 @@ snapshots:
dependencies:
'@types/chai': 5.2.2
'@vitest/expect': 3.2.4
- '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@24.0.3)(tsx@4.20.3)(yaml@2.8.0))
+ '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.15.32)(tsx@3.14.0)(yaml@2.8.0))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4