### Start Frontend Development Server with Vite Source: https://www.rivet.dev/docs/actors/quickstart/react This command starts the Vite development server for your frontend application. It allows you to see your React application running locally and enables hot module replacement for a faster development experience. ```shell npx vite ``` -------------------------------- ### Install RivetKit Packages for React Source: https://www.rivet.dev/docs/actors/quickstart/react Installs the necessary RivetKit and React-specific packages for your project. These packages enable communication between your React frontend and Rivet Actors. ```shell npm install rivetkit @rivetkit/react ``` -------------------------------- ### Install and Run Vitest for Rivet Testing Source: https://www.rivet.dev/docs/actors/testing Installs Vitest as a development dependency and provides the command to run tests within a Rivet project. This is the initial setup step for testing. ```bash npm install -D vitest npm test ``` -------------------------------- ### Install Rivet Kit for Node.js/Bun Source: https://www.rivet.dev/docs/actors/quickstart/backend Installs the RivetKit npm package, which is the core library for building and interacting with Rivet Actors in Node.js and Bun environments. This command uses npm. ```sh npm install rivetkit ``` -------------------------------- ### Create Next.js App and Navigate Source: https://www.rivet.dev/docs/actors/quickstart/next-js Creates a new Next.js application using `create-next-app` and navigates into the newly created project directory. This is the standard setup for a Next.js project. ```shell npx create-next-app@latest my-app cd my-app ``` -------------------------------- ### Run Rivet Engine with Docker Source: https://www.rivet.dev/docs/self-hosting/install This command starts a Docker container for the Rivet Engine, exposing port 6420. It's a quick way to get the engine running for development or testing. ```bash docker run -p 6420:6420 rivetdev/engine ``` -------------------------------- ### Start Development Server (Command Line) Source: https://www.rivet.dev/docs/actors/quickstart/cloudflare-workers This command initiates the Cloudflare Workers development server, allowing you to test your application locally before deployment. It typically runs on a specified port, and the output will provide the local URL for accessing your service. ```sh wrangler dev ``` -------------------------------- ### Add Rivet Skills Source: https://www.rivet.dev/docs/actors/quickstart/backend Installs the Rivet skills package, which enhances development assistance for AI coding assistants. This command is run via npx. ```sh npx skills add rivet-dev/skills ``` -------------------------------- ### Fan-Out/Fan-In Pattern Client with TypeScript Source: https://www.rivet.dev/docs/actors/design-patterns Demonstrates how to use the fan-out/fan-in pattern client-side using Rivet. It shows creating a client, getting a coordinator handle, starting a job, and retrieving results. Dependencies include 'rivetkit' and 'rivetkit/client'. ```typescript import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; interface Task { id: string; data: string; } interface Result { taskId: string; output: string; } const coordinator = actor({ state: { results: [] as Result[] }, actions: { startJob: async (c, tasks: Task[]) => {}, reportResult: (c, result: Result) => { c.state.results.push(result); }, getResults: (c) => c.state.results, }, }); const worker = actor({ state: {}, actions: { process: async (c, task: Task) => {}, }, }); const registry = setup({ use: { coordinator, worker } }); const client = createClient("http://localhost:8080"); const coordinatorHandle = client.coordinator.getOrCreate(["main"]); // Start a job with multiple tasks await coordinatorHandle.startJob([ { id: "task-1", data: "..." }, { id: "task-2", data: "..." }, { id: "task-3", data: "..." }, ]); // Results are collected as workers report back const results = await coordinatorHandle.getResults(); ``` -------------------------------- ### Setup Rivet API Routes in Next.js Source: https://www.rivet.dev/docs/actors/quickstart/next-js Configures the API routes for Rivet in a Next.js application. It uses `toNextHandler` from `@rivetkit/next-js` to integrate the Rivet registry with Next.js API routes. ```typescript import { toNextHandler } from "@rivetkit/next-js"; import { registry } from "@/rivet/registry"; export const maxDuration = 300; export const { GET, POST, PUT, PATCH, HEAD, OPTIONS } = toNextHandler(registry); ``` -------------------------------- ### Basic RivetKit Registry Setup Source: https://www.rivet.dev/docs/connect/registry-configuration Demonstrates the fundamental setup of a RivetKit registry using the `setup` and `actor` functions. It initializes an actor with empty state and actions, then passes it to the `setup` function to create the registry. ```typescript import { setup, actor } from "rivetkit"; const myActor = actor({ state: {}, actions: {} }); const registry = setup({ use: { myActor }, }); ``` -------------------------------- ### Install Rivet Cloudflare Workers Package Source: https://www.rivet.dev/docs/actors/quickstart/cloudflare-workers Install the Rivetkit and Cloudflare Workers packages using npm. These packages are essential for building Rivet Actors on Cloudflare Workers. ```sh npm install rivetkit @rivetkit/cloudflare-workers ``` -------------------------------- ### Explicit HTTP Server with Hono and @hono/node-server (TypeScript) Source: https://www.rivet.dev/docs/general/http-server This example shows how to explicitly start an HTTP server using Hono with the `@hono/node-server` package. It integrates the RivetKit handler within a Hono app and then uses `serve` to listen on port 3000. Dependencies: 'rivetkit', 'hono', '@hono/node-server'. ```typescript import { Hono } from "hono"; import { serve } from "@hono/node-server"; import { actor, setup } from "rivetkit"; const myActor = actor({ state: {}, actions: {} }); const registry = setup({ use: { myActor } }); const app = new Hono(); app.all("/api/rivet/*", (c) => registry.handler(c.req.raw)); serve({ fetch: app.fetch, port: 3000 }); ``` -------------------------------- ### Build and Run Rivet Engine from Source Source: https://www.rivet.dev/docs/self-hosting/install This snippet shows how to clone the Rivet Engine repository, navigate into the directory, build the release version using Cargo, and then run the compiled executable. This method requires Rust and Cargo to be installed. ```bash git clone https://github.com/rivet-dev/engine.git cd rivet cargo build --release -p rivet-engine ./target/release/rivet-engine ``` -------------------------------- ### Retrieve and Create Rivet Actors (ChatRoom, Game) Source: https://www.rivet.dev/docs/clients/javascript Shows how to get existing actor instances or create new ones using the Rivet client. Examples include getting a chat room, creating a game instance, and retrieving actors by ID. ```typescript import { createClient } from "rivetkit/client"; const client = createClient(); const room = client.chatRoom.getOrCreate(["room-42"]); const existing = client.chatRoom.get(["room-42"]); const created = await client.game.create(["game-1"], { input: { mode: "ranked" }, }); const byId = client.chatRoom.getForId("actor-id"); const resolvedId = await room.resolve(); ``` -------------------------------- ### Install Rivet and Freestyle Dependencies Source: https://www.rivet.dev/docs/actors/ai-and-user-generated-actors Installs the necessary npm packages for interacting with Rivet Engine API and Freestyle Sandboxes. Ensure Node.js 18+ is installed before running this command. ```bash npm install @rivetkit/engine-api-full@^25.7.2 freestyle-sandboxes@^0.0.95 ``` -------------------------------- ### Implement Custom Fetch Handler for Rivet Actors (TypeScript) Source: https://www.rivet.dev/docs/actors/quickstart/cloudflare-workers Implement a custom fetch handler for Rivet Actors on Cloudflare Workers without using a framework like Hono. This example demonstrates handling the `/increment/` route directly within the fetch function. ```typescript import { createHandler } from "@rivetkit/cloudflare-workers"; import { registry } from "./actors"; // The `/api/rivet` endpoint is automatically mounted on this router for external clients const { handler, ActorHandler } = createHandler(registry, { fetch: async (request, env, ctx) => { const url = new URL(request.url); if (url.pathname.startsWith("/increment/")) { const name = url.pathname.split("/")[2]; const client = env.RIVET; const counter = client.counter.getOrCreate([name]); const newCount = await counter.increment(1); return new Response(JSON.stringify({ count: newCount }), { headers: { "Content-Type": "application/json" }, }); } return new Response("Not Found", { status: 404 }); } }); export { handler as default, ActorHandler }; ``` -------------------------------- ### Full Example: Reminder Service with Actor Scheduling (TypeScript) Source: https://www.rivet.dev/docs/actors/schedule Demonstrates a complete example of a reminder service using Rivet's actor scheduling. It includes setting reminders, storing them in state, and scheduling actions to send notifications via connected clients or email. ```typescript import { actor } from "rivetkit"; interface Reminder { userId: string; message: string; scheduledFor: number; } interface ReminderState { reminders: Record; } // Mock email function function sendEmail(to: string, message: string) { console.log(`Sending email to ${to}: ${message}`); } const reminderService = actor({ state: { reminders: {} } as ReminderState, actions: { setReminder: (c, userId: string, message: string, delayMs: number) => { const reminderId = crypto.randomUUID(); // Store the reminder in state c.state.reminders[reminderId] = { userId, message, scheduledFor: Date.now() + delayMs }; // Schedule the sendReminder action to run after the delay c.schedule.after(delayMs, "sendReminder", reminderId); return { reminderId }; }, sendReminder: (c, reminderId: string) => { const reminder = c.state.reminders[reminderId]; if (!reminder) return; // Send reminder notification if (c.conns.size > 0) { // Send the reminder to all connected clients for (const conn of c.conns.values()) { conn.send("reminder", { message: reminder.message, scheduledAt: reminder.scheduledFor }); } } else { // User is offline, send an email notification sendEmail(reminder.userId, reminder.message); } // Clean up the processed reminder delete c.state.reminders[reminderId]; } } }); ``` -------------------------------- ### Create Typed Client (client.ts) Source: https://www.rivet.dev/docs/actors/quickstart/cloudflare-workers This TypeScript code demonstrates how to create a type-safe client for interacting with Rivet actors from a frontend or another service. It uses the `createClient` function from `rivetkit/client`, specifying the deployed application URL and the actor registry type. It shows how to get an actor instance, call actions, and listen to real-time events. ```typescript import { createClient } from "rivetkit/client"; import type { registry } from "./actors"; // Create typed client (use your deployed URL) const client = createClient("https://your-app.workers.dev/api/rivet"); // Use the counter actor directly const counter = client.counter.getOrCreate(["my-counter"]); // Call actions const count = await counter.increment(3); console.log("New count:", count); // Listen to real-time events const connection = counter.connect(); connection.on("newCount", (newCount: number) => { console.log("Count changed:", newCount); }); // Increment through connection await connection.increment(1); ``` -------------------------------- ### Starting RivetKit Registry in Serverless Mode Source: https://www.rivet.dev/docs/connect/registry-configuration Starts the configured RivetKit registry in serverless mode using the `serve()` method. This is suitable for environments where the application runs on demand, such as serverless functions. ```typescript import { actor, setup } from "rivetkit"; const myActor = actor({ state: {}, actions: {} }); const registry = setup({ use: { myActor } }); export default registry.serve(); ``` -------------------------------- ### Production Setup: Rivet Engine with PostgreSQL (Docker) Source: https://www.rivet.dev/docs/self-hosting/docker-container This section outlines a production setup for Rivet Engine with PostgreSQL using Docker. It includes creating a Docker network, running a PostgreSQL container, and then running the Rivet Engine container connected to the same network and configured with the PostgreSQL URL. ```bash # Create network docker network create rivet-net # Run PostgreSQL docker run -d \ --name postgres \ --network rivet-net \ -e POSTGRES_DB=rivet \ -e POSTGRES_USER=rivet \ -e POSTGRES_PASSWORD=rivet_password \ -v postgres-data:/var/lib/postgresql/data \ postgres:15 # Run Rivet Engine docker run -d \ --name rivet-engine \ --network rivet-net \ -p 6420:6420 \ -e RIVET__POSTGRES__URL="postgresql://rivet:rivet_password@postgres:5432/rivet" \ rivetdev/engine ``` -------------------------------- ### Configure RivetKit Setup Options Source: https://www.rivet.dev/docs/actors/limits Demonstrates how to configure soft limits for Rivet Actors by passing options to the `setup` function in RivetKit. This includes setting maximum incoming and outgoing message sizes. ```typescript import { setup } from "rivetkit"; const rivet = setup({ use: { /* ... */ }, maxIncomingMessageSize: 1_048_576, maxOutgoingMessageSize: 10_485_760, // ... }); ``` -------------------------------- ### Production Setup with PostgreSQL and Rivet Engine (Docker Compose) Source: https://www.rivet.dev/docs/self-hosting/docker-compose A production-ready Docker Compose setup including a PostgreSQL database service and the Rivet Engine. It configures PostgreSQL with necessary environment variables and volumes, and sets the RIVET__POSTGRES__URL for the Rivet Engine to connect to it. The services have a dependency defined. ```yaml services: postgres: image: postgres:15 environment: POSTGRES_DB: rivet POSTGRES_USER: rivet POSTGRES_PASSWORD: rivet_password volumes: - postgres-data:/var/lib/postgresql/data restart: unless-stopped rivet-engine: image: rivetdev/engine:latest ports: - "6420:6420" environment: RIVET__POSTGRES__URL: postgresql://rivet:rivet_password@postgres:5432/rivet depends_on: - postgres restart: unless-stopped volumes: postgres-data: ``` -------------------------------- ### Basic Rivet Actor Testing with Vitest Source: https://www.rivet.dev/docs/actors/testing Demonstrates how to set up a basic test for a Rivet actor using `setupTest`. It configures an in-memory environment, interacts with an actor, and asserts its state changes. ```typescript import { test, expect } from "vitest"; import { setupTest } from "rivetkit/test"; import { actor, setup } from "rivetkit"; // Define the actor const myActor = actor({ state: { value: "initial" }, actions: { someAction: (c) => { c.state.value = "updated"; return c.state.value; }, getState: (c) => { return c.state.value; } } }); // Create the registry const registry = setup({ use: { myActor } }); // Test the actor test("my actor test", async (testCtx) => { const { client } = await setupTest(testCtx, registry); // Now you can interact with your actor through the client const myActorHandle = client.myActor.get(["test"]); // Test your actor's functionality await myActorHandle.someAction(); // Make assertions const result = await myActorHandle.getState(); expect(result).toEqual("updated"); }); ``` -------------------------------- ### Get Actor Traces (curl) Source: https://www.rivet.dev/docs/actors/debugging Queries trace spans for an actor in OTLP JSON format. Allows filtering by start and end times and limiting the number of results for performance analysis. ```bash curl "http://localhost:6420/gateway/{actor_id}/inspector/traces?startMs=0&endMs=9999999999999&limit=100" ``` -------------------------------- ### Create Rivet Actor with Input Parameters (TypeScript) Source: https://www.rivet.dev/docs/actors/input Demonstrates how to create a Rivet actor instance using input parameters for initial configuration. It shows the definition of actor state, connection state, and how to pass input during the actor's creation via the client. This example utilizes the 'rivetkit' SDK. ```typescript import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; interface RoomInput { roomName: string; isPrivate: boolean; } const chatRoom = actor({ state: { name: "", isPrivate: false }, createState: (c, input: RoomInput) => ({ name: input.roomName, isPrivate: input.isPrivate }), connState: { userId: "", displayName: "" }, createConnState: (c, params: { userId: string; displayName: string }) => ({ userId: params.userId, displayName: params.displayName, }), actions: {} }); const registry = setup({ use: { chatRoom } }); const client = createClient(); // Actor creation with input const room = await client.chatRoom.create(["room-123"], { input: { roomName: "General Discussion", isPrivate: false, }, }); ``` -------------------------------- ### RivetKitClient Initialization and Actor Handling Source: https://www.rivet.dev/docs/clients/swift Demonstrates how to initialize the RivetKitClient and use compound keys for hierarchical addressing of actors. ```APIDOC ## RivetKitClient Initialization and Actor Handling ### Description This section details the initialization of the `RivetKitClient` and the usage of compound keys for hierarchical actor addressing. It also covers environment variables that can be used for configuration. ### Client Initialization - `RivetKitClient(config:)`: Creates a client instance with the provided configuration. - `ClientConfig`: Used to configure the client, including endpoint, namespace, and token. - `endpoint`: The base URL for the Rivet API. This is a required parameter. - `RIVET_NAMESPACE` (Environment Variable): Specifies the namespace. Can also be included in the endpoint URL. - `RIVET_TOKEN` (Environment Variable): Provides an authentication token. Can also be included in the endpoint URL. - `RIVET_RUNNER` (Environment Variable): The name of the runner, defaults to "default". ### Actor Handling - `client.get()` / `getOrCreate()` / `getForId()` / `create()`: Methods to obtain handles for actors. - `client.dispose()`: Disposes the client and closes all active connections. ### Compound Keys Compound keys (arrays) are recommended for hierarchical addressing to prevent key injection attacks. Avoid string interpolation for keys containing sensitive data. **Example:** ```swift import RivetKitClient let config = try ClientConfig(endpoint: "http://localhost:3000/api/rivet") let client = RivetKitClient(config: config) // Use compound keys for hierarchical addressing let room = client.getOrCreate("chatRoom", ["org-acme", "general"]) let actorId = try await room.resolve() print("Actor ID: \(actorId)") await client.dispose() ``` ### Endpoint Format Endpoints support URL authentication syntax: ``` https://namespace:token@api.rivet.dev ``` Alternatively, provide the endpoint without auth and set `RIVET_NAMESPACE` and `RIVET_TOKEN` environment variables. For serverless deployments, set the endpoint to your app's `/api/rivet` URL. ``` -------------------------------- ### Initialize Actor Resources with onWake Source: https://www.rivet.dev/docs/actors/lifecycle The `onWake` hook is executed when an actor starts, allowing for resource initialization and background task setup. It can be asynchronous and is called before accepting connections. Dependencies include the `rivetkit` library. ```typescript import { actor } from "rivetkit"; const counter = actor({ state: { count: 0 }, vars: { intervalId: null as NodeJS.Timeout | null }, onWake: (c) => { console.log('Actor started with count:', c.state.count); // Set up interval for automatic counting const intervalId = setInterval(() => { c.state.count++; c.broadcast("countChanged", c.state.count); console.log('Auto-increment:', c.state.count); }, 10000); // Store interval ID in vars to clean up later if needed c.vars.intervalId = intervalId; }, actions: { stop: (c) => { if (c.vars.intervalId) { clearInterval(c.vars.intervalId); c.vars.intervalId = null; } } } }); ``` -------------------------------- ### Initialize Actor State with `state` (TypeScript) Source: https://www.rivet.dev/docs/actors/lifecycle Defines the initial state of an actor using the `state` constant. This is a synchronous operation and sets the starting values for the actor's state. It's a fundamental part of actor setup. ```typescript import { actor } from "rivetkit"; const counter = actor({ state: { count: 0 }, actions: { /* ... */ } }); ``` -------------------------------- ### Integrate Rivet Actors with Hono Framework (TypeScript) Source: https://www.rivet.dev/docs/actors/quickstart/cloudflare-workers Integrate Rivet Actors with the Hono web framework on Cloudflare Workers. This example shows how to define a custom route for incrementing the counter actor using Hono. ```typescript import { createHandler, type Client } from "@rivetkit/cloudflare-workers"; import { Hono } from "hono"; import { registry } from "./actors"; const app = new Hono<{ Bindings: { RIVET: Client } }>(); app.post("/increment/:name", async (c) => { const client = c.env.RIVET; const name = c.req.param("name"); // Get or create actor and call action const counter = client.counter.getOrCreate([name]); const newCount = await counter.increment(1); return c.json({ count: newCount }); }); // The `/api/rivet` endpoint is automatically exposed here for external clients const { handler, ActorHandler } = createHandler(registry, { fetch: app.fetch }); export { handler as default, ActorHandler }; ``` -------------------------------- ### Configure Vite for React Development (TypeScript) Source: https://www.rivet.dev/docs/actors/quickstart/react This TypeScript configuration file sets up Vite for a React project. It includes the necessary plugin for React and specifies the development server port. ```typescript import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], server: { port: 5173, }, }) ``` -------------------------------- ### Client Interaction with Setup/Teardown Actor (TypeScript) Source: https://www.rivet.dev/docs/actors/workflows Demonstrates how a client can interact with the `setupRunTeardownActor` to send work and control messages, and retrieve the actor's state. It uses `createClient` from 'rivetkit/client' to establish communication. The client sends messages and then logs the final state of the actor. ```typescript import { createClient } from "rivetkit/client"; import type { registry } from "./actors"; const client = createClient(); const handle = client.setupRunTeardownActor.getOrCreate(["main"]); await handle.send("work", { amount: 5 }); await handle.send("work", { amount: 3 }); await handle.send("control", { type: "stop", reason: "maintenance" }); const state = await handle.getState(); console.log(state.phase, state.total, state.stopReason); ``` -------------------------------- ### Actor with Compound Keys and Client Interaction in TypeScript Source: https://www.rivet.dev/docs/actors This example defines an actor ('chatRoom') that uses compound keys for hierarchical addressing. It demonstrates how to access the key within the actor and how to create a client to interact with actors, including getting or creating instances with compound keys. ```typescript import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; const chatRoom = actor({ state: { messages: [] as string[] }, actions: { getRoomInfo: (c) => ({ org: c.key[0], room: c.key[1] }), }, }); const registry = setup({ use: { chatRoom } }); const client = createClient(); // Compound key: [org, room] client.chatRoom.getOrCreate(["org-acme", "general"]); // Access key inside actor via c.key ``` -------------------------------- ### Handle SQLite Transactions in Rivet Actors (TypeScript) Source: https://www.rivet.dev/docs/actors/sqlite Provides an example of how to manage database transactions within Rivet Actors to ensure atomicity for multiple write operations. It covers starting a transaction with `BEGIN`, committing with `COMMIT` on success, and rolling back with `ROLLBACK` on error. ```typescript await c.db.execute("BEGIN"); try { await c.db.execute("INSERT INTO todos (title) VALUES (?)", title); await c.db.execute( "INSERT INTO comments (todo_id, body) VALUES (last_insert_rowid(), ?)", body, ); await c.db.execute("COMMIT"); } catch (error) { await c.db.execute("ROLLBACK"); throw error; } ``` -------------------------------- ### Create a Rivet Client in TypeScript Source: https://www.rivet.dev/docs/actors/quickstart/backend Creates a Rivet client instance in TypeScript to interact with Rivet Actors. It allows fetching or creating actors, calling their actions, and subscribing to events. This client is typed against the actor registry. ```ts import { createClient } from "rivetkit/client"; import type { registry } from "./actors"; const client = createClient(); // Get or create a counter actor for the key "my-counter" const counter = client.counter.getOrCreate(["my-counter"]); // Call actions const count = await counter.increment(3); console.log("New count:", count); // Listen to realtime events const connection = counter.connect(); connection.on("newCount", (newCount: number) => { console.log("Count changed:", newCount); }); // Increment through connection await connection.increment(1); ``` -------------------------------- ### Explicit HTTP Server with Bun Native Server (TypeScript) Source: https://www.rivet.dev/docs/general/http-server This example shows how to run a RivetKit server using Bun's native `Bun.serve` API. The `fetch` option is configured to use the RivetKit handler, and the server listens on port 3000. Requires Bun runtime. ```typescript import { actor, setup } from "rivetkit"; const myActor = actor({ state: {}, actions: {} }); const registry = setup({ use: { myActor } }); Bun.serve({ port: 3000, fetch: (request: Request) => registry.handler(request), }); ``` -------------------------------- ### Handling New Connections with onConnect in TypeScript Source: https://www.rivet.dev/docs/actors/lifecycle The `onConnect` hook executes after a client has successfully connected to the actor. It can be asynchronous and receives the connection object, allowing for setup tasks like updating user lists or broadcasting join notifications. This example adds a user to a list and broadcasts a 'userJoined' event. ```typescript import { actor } from "rivetkit"; const chatRoom = actor({ state: { users: {} as Record, messages: [] as string[], }, createConnState: (_c, params: { userId?: string }) => ({ userId: params.userId ?? "anonymous", }), onConnect: (c, conn) => { // Add user to the room's user list using connection state const userId = conn.state.userId; c.state.users[userId] = { online: true, lastSeen: Date.now() }; // Broadcast that a user joined c.broadcast("userJoined", { userId, timestamp: Date.now() }); console.log(`User ${userId} connected`); }, actions: { /* ... */ } }); ``` -------------------------------- ### Workflow Loop for Durable Workflows (TypeScript) Source: https://www.rivet.dev/docs/actors The 'workflow' loop pattern is suitable for long-lived, durable workflows. It allows for initialization of resources, processing commands in a loop, and subsequent cleanup. This example defines a worker that processes 'work' messages and can be controlled via 'control' messages, demonstrating setup, a main processing loop, and teardown phases. ```typescript import { actor, queue, setup } from "rivetkit"; import { Loop, workflow } from "rivetkit/workflow"; type WorkMessage = { amount: number }; type ControlMessage = { type: "stop"; reason: string }; const worker = actor({ state: { phase: "idle" as "idle" | "running" | "stopped", processed: 0, total: 0, stopReason: null as string | null, }, queues: { work: queue(), control: queue(), }, run: workflow(async (ctx) => { await ctx.step("setup", async () => { await fetch("https://api.example.com/workers/init", { method: "POST" }); ctx.state.phase = "running"; ctx.state.stopReason = null; }); const stopReason = await ctx.loop("worker-loop", async (loopCtx) => { const message = await loopCtx.queue.next("wait-command", { names: ["work", "control"], }); if (message.name === "work") { await loopCtx.step("apply-work", async () => { await fetch("https://api.example.com/workers/process", { method: "POST", body: JSON.stringify({ amount: message.body.amount }), }); loopCtx.state.processed += 1; loopCtx.state.total += message.body.amount; }); return; } return Loop.break((message.body as ControlMessage).reason); }); await ctx.step("teardown", async () => { await fetch("https://api.example.com/workers/shutdown", { method: "POST" }); ctx.state.phase = "stopped"; ctx.state.stopReason = stopReason; }); }), }); const registry = setup({ use: { worker } }); ``` -------------------------------- ### Download Rivet Engine Kubernetes Manifests Source: https://www.rivet.dev/docs/self-hosting/kubernetes Downloads the Kubernetes manifests for Rivet Engine from the official GitHub repository using npx and giget. This is the first step in setting up Rivet on Kubernetes. ```bash npx "@giget/latest" gh:rivet-dev/rivet/self-host/k8s/engine rivet-k8s cd rivet-k8s ``` -------------------------------- ### RivetKit Client Overview Source: https://www.rivet.dev/docs/clients/javascript This section provides an overview of the RivetKit client, including how to create a client instance and configure engine drivers. ```APIDOC ## RivetKit Client and Engine Driver ### Description This section details the core functionalities of the RivetKit client, including creating a client instance and setting up engine drivers for interacting with Rivet services. ### Methods - **createClient**: Creates a new instance of the Rivet client. - **createEngineDriver**: Initializes an engine driver for managing game server engines. ### Types - **DriverConfig**: Configuration object for the engine driver. - **Client**: Represents the Rivet client object. ``` -------------------------------- ### Listen for Events from Other Actors (TypeScript) Source: https://www.rivet.dev/docs/actors/communicating-between-actors This example illustrates building an event-driven architecture by connecting to and listening for events from multiple actors. It defines interfaces for users, orders, and audit logs. User and order actors broadcast events ('userCreated', 'orderCompleted'), and the audit log actor connects to both to capture these events and store them. The `setup` function registers the actors. ```typescript import { actor, setup } from "rivetkit"; interface User { id: string; name: string; } interface Order { id: string; amount: number; } interface AuditLog { event: string; data: User | Order; timestamp: number; } const userActor = actor({ state: {}, actions: { createUser: (c, name: string) => { const user = { id: crypto.randomUUID(), name }; c.broadcast("userCreated", user); return user; } } }); const orderActor = actor({ state: {}, actions: { completeOrder: (c, amount: number) => { const order = { id: crypto.randomUUID(), amount }; c.broadcast("orderCompleted", order); return order; } } }); const auditLogActor = actor({ state: { logs: [] as AuditLog[] }, actions: { startAuditing: async (c) => { const client = c.client(); // Connect to multiple actors to listen for events const userActorConn = client.userActor.getOrCreate(["main"]).connect(); const orderActorConn = client.orderActor.getOrCreate(["main"]).connect(); // Listen for user events userActorConn.on("userCreated", (user: User) => { c.state.logs.push({ event: "userCreated", data: user, timestamp: Date.now() }); }); // Listen for order events orderActorConn.on("orderCompleted", (order: Order) => { c.state.logs.push({ event: "orderCompleted", data: order, timestamp: Date.now() }); }); return { status: "auditing started" }; } } }); const registry = setup({ use: { userActor, orderActor, auditLogActor } }); ``` -------------------------------- ### Configure Rivet Engine with Mounted Config File (Docker) Source: https://www.rivet.dev/docs/self-hosting/docker-container This example demonstrates configuring Rivet Engine by mounting a JSON configuration file into the container. It first creates a config file and then runs the Docker container, mapping the config file to '/etc/rivet/config.json' in read-only mode. ```bash # Create config file cat < rivet-config.json { "postgres": { "url": "postgresql://postgres:password@localhost:5432/db" } } EOF # Run with mounted config docker run -p 6420:6420 \ -v rivet-data:/data \ -v $(pwd)/rivet-config.json:/etc/rivet/config.json:ro \ rivetdev/engine ``` -------------------------------- ### Starting RivetKit Registry in Runner Mode Source: https://www.rivet.dev/docs/connect/registry-configuration Initializes and starts the RivetKit registry in runner mode using `startRunner()`. This mode is typically used for long-running processes or background tasks. ```typescript import { actor, setup } from "rivetkit"; const myActor = actor({ state: {}, actions: {} }); const registry = setup({ use: { myActor } }); registry.startRunner(); ``` -------------------------------- ### Initialize Railway Project via CLI Source: https://www.rivet.dev/docs/self-hosting/railway This command initializes a new project for deployment on Railway using the command-line interface. It's a prerequisite for manual deployment. ```bash railway init ``` -------------------------------- ### Retrieve and Manage ChatRoom Actors in React Source: https://www.rivet.dev/docs/clients/react This React component and client-side code illustrate how to get, create, or get existing 'chatRoom' actors. It uses `useActor` within a React component for real-time connection status and `createClient` for programmatic access to actor instances like `get`, `getOrCreate`, `create`, and `getForId`. It also shows how to resolve an actor's ID. ```tsx import { createRivetKit } from "@rivetkit/react"; import { createClient } from "rivetkit/client"; const { useActor } = createRivetKit(); function ChatRoom() { const room = useActor({ name: "chatRoom", key: ["room-42"] }); return
{room.connStatus}
; } // For get/getOrCreate/create/getForId, use createClient const client = createClient(); const handle = client.chatRoom.getOrCreate(["room-42"]); const existing = client.chatRoom.get(["room-42"]); const created = await client.game.create(["game-1"], { input: { mode: "ranked" } }); const byId = client.chatRoom.getForId("actor-id"); const resolvedId = await handle.resolve(); ``` -------------------------------- ### Create Inline Client for Rivet Actors (TypeScript) Source: https://www.rivet.dev/docs/actors/quickstart/cloudflare-workers Create an inline client for Rivet Actors on Cloudflare Workers. This approach allows direct interaction with actors within the same worker environment, simplifying client-side logic. ```typescript import { createInlineClient } from "@rivetkit/cloudflare-workers"; import { registry } from "./actors"; const { client, fetch: rivetFetch, ActorHandler, } = createInlineClient(registry); // IMPORTANT: Your Durable Object must be exported here export { ActorHandler }; export default { fetch: async (request, env, ctx) => { const url = new URL(request.url); // Custom request handler if (request.method === "POST" && url.pathname.startsWith("/increment/")) { const name = url.pathname.slice("/increment/".length); const counter = client.counter.getOrCreate([name]); const newCount = await counter.increment(1); return new Response(JSON.stringify({ count: newCount }), { headers: { "Content-Type": "application/json" }, }); } // Optional: Mount /api/rivet path to access actors from external clients if (url.pathname.startsWith("/api/rivet")) { const strippedPath = url.pathname.substring("/api/rivet".length); url.pathname = strippedPath; const modifiedRequest = new Request(url.toString(), request); ``` -------------------------------- ### RivetKit Client Initialization (TypeScript) Source: https://www.rivet.dev/docs/clients/javascript Shows how to create a Rivet client instance using the `createClient` function from the `rivetkit` package. This client is used to interact with Rivet services. It requires configuration details, potentially including endpoint information. ```typescript import { createClient } from "rivetkit"; // Example usage (assuming necessary config is available) const client = createClient({ // ... configuration options ... }); ``` -------------------------------- ### SwiftUI Actor Actions Example Source: https://www.rivet.dev/docs/clients/swiftui Demonstrates how to perform actions on a Rivet Actor and retrieve results in SwiftUI. This example shows fetching a count and renaming an entity via actor actions. ```swift import RivetKitSwiftUI import SwiftUI struct CounterView: View { @Actor("counter", key: ["my-counter"]) private var counter @State private var count = 0 @State private var name = "" var body: some View { VStack { Text("Count: \(count)") Text("Name: \(name)") Button("Fetch") { Task { count = try await counter.action("getCount") name = try await counter.action("rename", "new-name") } } Button("Increment") { counter.send("increment", 1) } } } } ``` -------------------------------- ### Chat Room Client Interaction with Coordinator (TypeScript) Source: https://www.rivet.dev/docs/actors/design-patterns This TypeScript snippet illustrates how a client interacts with the chat room and coordinator actors. It shows how to create a client, get or create a coordinator, create a new chat room, list existing rooms, and send messages to a specific chat room. ```typescript import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; const chatRoom = actor({ state: { messages: [] as { sender: string; text: string }[] }, actions: { sendMessage: (c, sender: string, text: string) => { const message = { sender, text }; c.state.messages.push(message); return message; }, getHistory: (c) => c.state.messages, }, }); const chatRoomList = actor({ state: { chatRoomIds: [] as string[] }, actions: { createChatRoom: async (c, name: string) => "room-id", listChatRooms: (c) => c.state.chatRoomIds, }, }); const registry = setup({ use: { chatRoom, chatRoomList } }); const client = createClient("http://localhost:8080"); // Create a new chat room via coordinator const coordinator = client.chatRoomList.getOrCreate(["main"]); const actorId = await coordinator.createChatRoom("general"); // Get list of all chat rooms const chatRoomIds = await coordinator.listChatRooms(); // Connect to a chat room using its ID const chatRoomHandle = client.chatRoom.getForId(actorId); await chatRoomHandle.sendMessage("alice", "Hello!"); const history = await chatRoomHandle.getHistory(); ``` -------------------------------- ### Automate Rivet and Freestyle Deployment with TypeScript Source: https://www.rivet.dev/docs/actors/ai-and-user-generated-actors A TypeScript script to automate the deployment of actor and frontend code. It handles namespace creation, token generation, Freestyle deployment, and runner configuration. This script requires a Rivet Cloud API token and Freestyle API key for authentication and deployment. ```typescript import { execSync } from "child_process"; import { RivetClient } from "@rivetkit/engine-api-full"; import { FreestyleSandboxes } from "freestyle-sandboxes"; import { prepareDirForDeploymentSync } from "freestyle-sandboxes/utils"; const CLOUD_API_TOKEN = "your-cloud-api-token"; const FREESTYLE_DOMAIN = "your-app.style.dev"; const FREESTYLE_API_KEY = "your-freestyle-api-key"; async function deploy(projectDir: string) { // Step 1: Inspect API token to get project and organization const { project, organization } = await cloudRequest("GET", "/tokens/api/inspect"); // Step 2: Create sandboxed namespace with a unique name const namespaceName = `ns-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`; const { namespace } = await cloudRequest( "POST", `/projects/${project}/namespaces?org=${organization}`, { displayName: namespaceName.substring(0, 16) }, ); const engineNamespaceName = namespace.access.engineNamespaceName; // NOTE: Intentionally different than namespace.name // Step 3: Generate tokens // - Runner token: authenticates the serverless runner to execute actors // - Publishable token: used by frontend clients to connect to actors // - Access token: provides API access for configuring the namespace const { token: runnerToken } = await cloudRequest( "POST", `/projects/${project}/namespaces/${namespace.name}/tokens/secret?org=${organization}`, ); const { token: publishableToken } = await cloudRequest( "POST", `/projects/${project}/namespaces/${namespace.name}/tokens/publishable?org=${organization}`, ); const { token: accessToken } = await cloudRequest( "POST", `/projects/${project}/namespaces/${namespace.name}/tokens/access?org=${organization}`, ); // Step 4: Build the frontend with public environment variables. execSync("npm run build", { cwd: projectDir, env: { ...process.env, VITE_RIVET_ENDPOINT: "https://api.rivet.dev", VITE_RIVET_NAMESPACE: engineNamespaceName, VITE_RIVET_TOKEN: publishableToken, }, stdio: "inherit", }); // Step 5: Deploy actor code and frontend to Freestyle with backend // environment variables. const freestyle = new FreestyleSandboxes({ apiKey: FREESTYLE_API_KEY }); const deploymentSource = prepareDirForDeploymentSync(projectDir); const { deploymentId } = await freestyle.deployWeb(deploymentSource, { envVars: { RIVET_ENDPOINT: "https://api.rivet.dev", RIVET_NAMESPACE: engineNamespaceName, RIVET_TOKEN: runnerToken, }, entrypoint: "src/backend/server.ts", domains: [FREESTYLE_DOMAIN], build: false, }); // Step 6: Configure Rivet to run actors on the Freestyle deployment. const rivet = new RivetClient({ environment: "https://api.rivet.dev", token: accessToken, }); await rivet.runnerConfigsUpsert("default", { datacenters: { "us-west-1": { // Freestyle datacenter is on west coast serverless: { url: `https://${FREESTYLE_DOMAIN}/api/rivet`, headers: {}, runnersMargin: 0, minRunners: 0, maxRunners: 1000, slotsPerRunner: 1, requestLifespan: 60 * 5, }, }, }, namespace: engineNamespaceName, }); console.log("Deployment complete!"); console.log("Frontend:", `https://${FREESTYLE_DOMAIN}`); console.log("Rivet Dashboard:", `https://dashboard.rivet.dev/orgs/${organization}/projects/${project}/ns/${namespace.name}`); console.log("Freestyle Dashboard:", `https://admin.freestyle.sh/dashboard/deployments/${deploymentId}`); } async function cloudRequest(method: string, path: string, body?: any) { const res = await fetch(`https://api-cloud.rivet.dev${path}`, { method, headers: { Authorization: `Bearer ${CLOUD_API_TOKEN}`, ...(body && { "Content-Type": "application/json" }), }, ...(body && { body: JSON.stringify(body) }), }); return res.json(); } ``` -------------------------------- ### Configure Public Endpoint for Clients (TypeScript) Source: https://www.rivet.dev/docs/general/endpoints Configures RivetKit setup for serverless mode, specifying the public endpoint for client connections. This TypeScript code uses the 'serverless.publicEndpoint' option within the 'setup' function. ```typescript import { actor, setup } from "rivetkit"; const myActor = actor({ state: {}, actions: {} }); const registry = setup({ use: { myActor }, serverless: { publicEndpoint: "https://my-namespace:pk_xxxxx@api.rivet.dev", }, }); ```