Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 14 additions & 17 deletions site/src/content/docs/actors/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ The `onAuth` hook runs on the HTTP server before clients can access actors. This
import { actor, UserError } from "@rivetkit/actor";

const chatRoom = actor({
onAuth: async (opts) => {
const { req, params, intents } = opts;
onAuth: async (params: { authToken?: string }, { request, intents }) => {

// Extract token from params or headers
const token = params.authToken || req.headers.get("Authorization");
const token = params.authToken || request.headers.get("Authorization");

if (!token) {
throw new UserError("Authentication required");
Expand Down Expand Up @@ -83,8 +82,8 @@ const userProfileActor = actor({
}
},

createConnState: (c, opts) => {
return { userId: opts.params.userId };
createConnState: (c, opts, params: { userId: string }) => {
return { userId: params.userId };
},

actions: {
Expand Down Expand Up @@ -128,9 +127,7 @@ The `onAuth` hook receives an `intents` parameter indicating what the client wan

```typescript
const secureActor = actor({
onAuth: async (opts) => {
const { intents, params } = opts;

onAuth: async (params: { token: string }, { intents }) => {
// Different validation based on intent
if (intents.has("action")) {
// Requires higher privileges for actions
Expand Down Expand Up @@ -162,8 +159,8 @@ Use specific error types for different authentication failures:
import { UserError, Unauthorized, Forbidden } from "@rivetkit/actor/errors";

const protectedActor = actor({
onAuth: async (opts) => {
const token = opts.params.authToken;
onAuth: async (params: { authToken?: string }) => {
const token = params.authToken;

if (!token) {
throw new Unauthorized("Authentication token required");
Expand Down Expand Up @@ -226,9 +223,9 @@ import { actor, UserError } from "@rivetkit/actor";
import jwt from "jsonwebtoken";

const jwtActor = actor({
onAuth: async (opts) => {
const token = opts.params.jwt ||
opts.req.headers.get("Authorization")?.replace("Bearer ", "");
onAuth: async (params: { jwt?: string }, { request }) => {
const token = params.jwt ||
request.headers.get("Authorization")?.replace("Bearer ", "");

if (!token) {
throw new UserError("JWT token required");
Expand Down Expand Up @@ -265,9 +262,9 @@ const jwtActor = actor({

```typescript
const apiActor = actor({
onAuth: async (opts) => {
const apiKey = opts.params.apiKey ||
opts.req.headers.get("X-API-Key");
onAuth: async (params: { apiKey?: string }, { request }) => {
const apiKey = params.apiKey ||
request.headers.get("X-API-Key");

if (!apiKey) {
throw new UserError("API key required");
Expand Down Expand Up @@ -331,7 +328,7 @@ export function requirePermission(permission: string) {

// usage in actor
const forumActor = actor({
onAuth: async (opts) => {
onAuth: async (params: { token: string }) => {
// ... authenticate and return user with role/permissions
},

Expand Down
2 changes: 1 addition & 1 deletion site/src/content/docs/actors/connections.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const gameRoom = actor({
state: {},

// Handle connection setup
createConnState: (c, { params }) => {
createConnState: (c, opts, params: { authToken: string }) => {
// Validate authentication token
const authToken = params.authToken;

Expand Down
10 changes: 8 additions & 2 deletions site/src/content/docs/actors/ephemeral-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ This value will be cloned for every new actor using `structuredClone`.
Create actor state dynamically on each actors' start:

```typescript
import { actor } from "@rivetkit/actor";
import { actor, ActorInitContext } from "@rivetkit/actor";

// Define vars with initialization logic
const counter = actor({
state: { count: 0 },

// Define vars using a creation function
createVars: () => {
createVars: (c: ActorInitContext, driver: any) => {
return {
lastAccessTime: Date.now(),
emitter: createNanoEvents()
Expand All @@ -62,6 +62,12 @@ const counter = actor({
});
```

<Note>
If accepting arguments to `createVars`, you **must** define the types: `createVars(c: ActorInitContext, driver: any)`

Otherwise, the return type will not be inferred and `c.vars` will be of type `unknown`.
</Note>

</Tab>

</Tabs>
Expand Down
4 changes: 2 additions & 2 deletions site/src/content/docs/actors/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const gameRoom = actor({
players: {} as Record<string, {health: number, position: {x: number, y: number}}>
},

createConnState: (c, { params }) => ({
createConnState: (c, opts, params: { playerId: string, role?: string }) => ({
playerId: params.playerId,
role: params.role || "player"
}),
Expand Down Expand Up @@ -86,7 +86,7 @@ const gameRoom = actor({
players: {} as Record<string, {health: number, position: {x: number, y: number}}>
},

createConnState: (c, { params }) => ({
createConnState: (c, opts, params: { playerId: string, role?: string }) => ({
playerId: params.playerId,
role: params.role || "player"
}),
Expand Down
16 changes: 8 additions & 8 deletions site/src/content/docs/actors/external-sql.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Here's a basic example of a user actor that creates a database record on start a

<CodeGroup>
```typescript {{ "title": "registry.ts" }}
import { actor, setup } from "@rivetkit/actor";
import { actor, setup, ActorInitContext } from "@rivetkit/actor";
import { Pool } from "pg";

interface ActorInput {
Expand All @@ -55,10 +55,10 @@ const pool = new Pool({

// Create the user actor
export const userActor = actor({
createState: (opts: { input: ActorInput }) => ({
createState: (c: ActorInitContext, input: ActorInput) => ({
requestCount: 0,
username: opts.input.username,
email: opts.input.email,
username: input.username,
email: input.email,
lastActive: Date.now()
}),

Expand Down Expand Up @@ -140,7 +140,7 @@ Here's the same user actor pattern using Drizzle ORM for more type-safe database

<CodeGroup>
```typescript {{ "title": "registry.ts" }}
import { actor, setup } from "@rivetkit/actor";
import { actor, setup, ActorInitContext } from "@rivetkit/actor";
import { drizzle } from "drizzle-orm/node-postgres";
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { eq } from "drizzle-orm";
Expand Down Expand Up @@ -169,10 +169,10 @@ const db = drizzle(pool);

// Create the user actor
export const userActor = actor({
createState: (opts: { input: ActorInput }) => ({
createState: (c: ActorInitContext, input: ActorInput) => ({
requestCount: 0,
username: opts.input.username,
email: opts.input.email,
username: input.username,
email: input.email,
lastActive: Date.now()
}),

Expand Down
4 changes: 2 additions & 2 deletions site/src/content/docs/actors/helper-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

Rivet provides several TypeScript helper types to make it easier to work with actors in a type-safe way.


## `Context` Types

When working with actors, you often need to access the context object. Rivet provides helper types to extract the context types from actor definitions.
When working with actors, you often need to access the context object outside of the actor's handlers. Rivet provides helper types to extract the context types from actor definitions.

### `ActorContextOf<ActorDefinition>`

Expand Down Expand Up @@ -57,4 +58,3 @@ function processCounterAction(context: ActionContextOf<typeof counter>) {
context.state.count++;
}
```

41 changes: 23 additions & 18 deletions site/src/content/docs/actors/input.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,26 @@ const gameHandle = client.game.getOrCreate(["game-456"], {
Input is available in lifecycle hooks via the `opts.input` parameter:

```typescript
interface ChatRoomInput {
roomName: string,
isPrivate: boolean,
}

const chatRoom = actor({
createState: (c, opts) => ({
name: opts.input?.roomName ?? "Unnamed Room",
isPrivate: opts.input?.isPrivate ?? false,
maxUsers: opts.input?.maxUsers ?? 50,
createState: (c: ActorInitContext, input: ChatRoomInput) => ({
name: input?.roomName ?? "Unnamed Room",
isPrivate: input?.isPrivate ?? false,
maxUsers: input?.maxUsers ?? 50,
users: {},
messages: [],
}),

onCreate: (c, opts) => {
console.log(`Creating room: ${opts.input?.roomName}`);
onCreate: (c, opts, input: ChatRoomInput) => {
console.log(`Creating room: ${input.roomName}`);

// Setup external services based on input
if (opts.input?.isPrivate) {
setupPrivateRoomLogging(opts.input.roomName);
if (input.isPrivate) {
setupPrivateRoomLogging(input.roomName);
}
},

Expand Down Expand Up @@ -76,9 +81,9 @@ const GameInputSchema = z.object({
});

const game = actor({
createState: (c, opts) => {
createState: (c: ActorInitContext, inputRaw: z.infer<typeof GameInputSchema>) => {
// Validate input
const input = GameInputSchema.parse(opts.input);
const input = GameInputSchema.parse(inputRaw);

return {
gameMode: input.gameMode,
Expand Down Expand Up @@ -142,10 +147,10 @@ interface GameInput {
}

const game = actor({
createState: (c, opts: { input?: GameInput }) => ({
gameMode: opts.input?.gameMode ?? "casual",
maxPlayers: opts.input?.maxPlayers ?? 4,
difficulty: opts.input?.difficulty ?? "medium",
createState: (c: ActorInitContext, input: GameInput) => ({
gameMode: input.gameMode,
maxPlayers: input.maxPlayers,
difficulty: input.difficulty ?? "medium",
}),

actions: {
Expand All @@ -160,12 +165,12 @@ If you need to access input data in actions, store it in the actor's state:

```typescript
const game = actor({
createState: (c, opts) => ({
createState: (c: ActorInitContext, input: GameInput) => ({
// Store input configuration in state
config: {
gameMode: opts.input?.gameMode ?? "casual",
maxPlayers: opts.input?.maxPlayers ?? 4,
difficulty: opts.input?.difficulty ?? "medium",
gameMode: input.gameMode,
maxPlayers: input.maxPlayers,
difficulty: input?.difficulty ?? "medium",
},
// Runtime state
players: {},
Expand Down
2 changes: 1 addition & 1 deletion site/src/content/docs/actors/keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Use keys to provide basic actor configuration:

```typescript {{"title":"registry.ts"}}
const userSession = actor({
createState: (c) => ({
createState: () => ({
userId: c.key[0], // Extract user ID from key
loginTime: Date.now(),
preferences: {}
Expand Down
Loading
Loading