From b716026a11e363d204f553c09dc54b5c998bc834 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Tue, 23 Dec 2025 00:03:52 -0700 Subject: [PATCH] chore(rivetkit): specialize context types for better compiler errors --- .../packages/rivetkit/src/actor/config.ts | 71 ++++++++--------- .../rivetkit/src/actor/contexts/action.ts | 18 ++++- .../src/actor/contexts/{ => base}/actor.ts | 50 +++++++++--- .../actor/contexts/{ => base}/conn-init.ts | 25 +++++- .../src/actor/contexts/{ => base}/conn.ts | 22 +++++- .../actor/contexts/before-action-response.ts | 35 +++++++++ .../src/actor/contexts/before-connect.ts | 26 +++++++ .../rivetkit/src/actor/contexts/connect.ts | 35 +++++++++ .../src/actor/contexts/create-conn-state.ts | 16 +++- .../src/actor/contexts/create-vars.ts | 26 +++++++ .../rivetkit/src/actor/contexts/create.ts | 26 +++++++ .../rivetkit/src/actor/contexts/destroy.ts | 36 +++++++++ .../rivetkit/src/actor/contexts/disconnect.ts | 37 +++++++++ .../rivetkit/src/actor/contexts/index.ts | 32 ++++++++ .../src/actor/contexts/on-before-connect.ts | 13 ---- .../rivetkit/src/actor/contexts/on-connect.ts | 22 ------ .../rivetkit/src/actor/contexts/request.ts | 17 +++- .../rivetkit/src/actor/contexts/sleep.ts | 36 +++++++++ .../src/actor/contexts/state-change.ts | 36 +++++++++ .../rivetkit/src/actor/contexts/wake.ts | 36 +++++++++ .../rivetkit/src/actor/contexts/websocket.ts | 17 +++- .../packages/rivetkit/src/actor/definition.ts | 35 +-------- .../src/actor/instance/connection-manager.ts | 12 +-- .../rivetkit/src/actor/instance/mod.ts | 19 +++-- .../packages/rivetkit/src/actor/mod.ts | 17 +--- .../rivetkit/src/actor/protocol/old.ts | 2 +- .../rivetkit/src/actor/router-endpoints.ts | 2 +- .../packages/rivetkit/src/mod.ts | 1 + website/src/content/docs/actors/actions.mdx | 2 +- .../content/docs/actors/authentication.mdx | 4 +- .../src/content/docs/actors/connections.mdx | 8 +- .../docs/actors/ephemeral-variables.mdx | 16 ++-- .../src/content/docs/actors/external-sql.mdx | 8 +- .../src/content/docs/actors/helper-types.mdx | 72 +---------------- website/src/content/docs/actors/input.mdx | 8 +- website/src/content/docs/actors/lifecycle.mdx | 10 +-- website/src/content/docs/actors/state.mdx | 10 +-- website/src/content/docs/actors/types.mdx | 77 +++++++++++++++++++ .../docs/connect/cloudflare-workers.mdx | 6 +- website/src/sitemap/mod.ts | 4 +- 40 files changed, 681 insertions(+), 264 deletions(-) rename rivetkit-typescript/packages/rivetkit/src/actor/contexts/{ => base}/actor.ts (68%) rename rivetkit-typescript/packages/rivetkit/src/actor/contexts/{ => base}/conn-init.ts (56%) rename rivetkit-typescript/packages/rivetkit/src/actor/contexts/{ => base}/conn.ts (58%) create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/before-action-response.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/before-connect.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/connect.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/create-vars.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/create.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/destroy.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/disconnect.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/index.ts delete mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/on-before-connect.ts delete mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/on-connect.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/sleep.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/state-change.ts create mode 100644 rivetkit-typescript/packages/rivetkit/src/actor/contexts/wake.ts create mode 100644 website/src/content/docs/actors/types.mdx diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/config.ts b/rivetkit-typescript/packages/rivetkit/src/actor/config.ts index 360cf05832..7ab8fcf99f 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/config.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/config.ts @@ -1,24 +1,25 @@ import { z } from "zod"; import type { UniversalWebSocket } from "@/common/websocket-interface"; import type { Conn } from "./conn/mod"; -import type { ActionContext } from "./contexts/action"; -import type { ActorContext } from "./contexts/actor"; -import type { CreateConnStateContext } from "./contexts/create-conn-state"; -import type { OnBeforeConnectContext } from "./contexts/on-before-connect"; -import type { OnConnectContext } from "./contexts/on-connect"; -import type { RequestContext } from "./contexts/request"; -import type { WebSocketContext } from "./contexts/websocket"; +import type { + ActionContext, + ActorContext, + BeforeActionResponseContext, + BeforeConnectContext, + ConnectContext, + CreateConnStateContext, + CreateContext, + CreateVarsContext, + DestroyContext, + DisconnectContext, + RequestContext, + SleepContext, + StateChangeContext, + WakeContext, + WebSocketContext, +} from "./contexts"; import type { AnyDatabaseProvider } from "./database"; -export type InitContext = ActorContext< - undefined, - undefined, - undefined, - undefined, - undefined, - undefined ->; - export interface ActorTypes< TState, TConnParams, @@ -134,7 +135,7 @@ type CreateState = | { state: TState } | { createState: ( - c: InitContext, + c: CreateContext, input: TInput, ) => TState | Promise; } @@ -168,7 +169,14 @@ type CreateConnState< /** * @experimental */ -type CreateVars = +type CreateVars< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, +> = | { /** * @experimental @@ -180,7 +188,7 @@ type CreateVars = * @experimental */ createVars: ( - c: InitContext, + c: CreateVarsContext, driverCtx: any, ) => TVars | Promise; } @@ -240,14 +248,7 @@ interface BaseActorConfig< * This is called before any other lifecycle hooks. */ onCreate?: ( - c: ActorContext< - TState, - TConnParams, - TConnState, - TVars, - TInput, - TDatabase - >, + c: CreateContext, input: TInput, ) => void | Promise; @@ -255,7 +256,7 @@ interface BaseActorConfig< * Called when the actor is destroyed. */ onDestroy?: ( - c: ActorContext< + c: DestroyContext< TState, TConnParams, TConnState, @@ -274,7 +275,7 @@ interface BaseActorConfig< * @returns Void or a Promise that resolves when startup is complete */ onWake?: ( - c: ActorContext< + c: WakeContext< TState, TConnParams, TConnState, @@ -295,7 +296,7 @@ interface BaseActorConfig< * @returns Void or a Promise that resolves when shutdown is complete */ onSleep?: ( - c: ActorContext< + c: SleepContext< TState, TConnParams, TConnState, @@ -317,7 +318,7 @@ interface BaseActorConfig< * @param newState The updated state */ onStateChange?: ( - c: ActorContext< + c: StateChangeContext< TState, TConnParams, TConnState, @@ -339,7 +340,7 @@ interface BaseActorConfig< * @throws Throw an error to reject the connection */ onBeforeConnect?: ( - c: OnBeforeConnectContext, + c: BeforeConnectContext, params: TConnParams, ) => void | Promise; @@ -353,7 +354,7 @@ interface BaseActorConfig< * @returns Void or a Promise that resolves when connection handling is complete */ onConnect?: ( - c: OnConnectContext< + c: ConnectContext< TState, TConnParams, TConnState, @@ -374,7 +375,7 @@ interface BaseActorConfig< * @returns Void or a Promise that resolves when disconnect handling is complete */ onDisconnect?: ( - c: ActorContext< + c: DisconnectContext< TState, TConnParams, TConnState, @@ -398,7 +399,7 @@ interface BaseActorConfig< * @returns The modified output to send to the client */ onBeforeActionResponse?: ( - c: ActorContext< + c: BeforeActionResponseContext< TState, TConnParams, TConnState, diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/action.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/action.ts index 9e99862a69..5c1cccc022 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/action.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/action.ts @@ -1,7 +1,8 @@ import type { Conn } from "../conn/mod"; import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; import type { ActorInstance } from "../instance/mod"; -import { ConnContext } from "./conn"; +import { ConnContext } from "./base/conn"; /** * Context for a remote procedure call. @@ -21,3 +22,18 @@ export class ActionContext< TInput, TDatabase > {} + +/** + * Extracts the ActionContext type from an ActorDefinition. + */ +export type ActionContextOf = AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any +> + ? ActionContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/actor.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/base/actor.ts similarity index 68% rename from rivetkit-typescript/packages/rivetkit/src/actor/contexts/actor.ts rename to rivetkit-typescript/packages/rivetkit/src/actor/contexts/base/actor.ts index 195971cbf8..96eb7edd2f 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/actor.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/base/actor.ts @@ -2,10 +2,14 @@ import type { ActorKey } from "@/actor/mod"; import type { Client } from "@/client/client"; import type { Logger } from "@/common/log"; import type { Registry } from "@/registry/mod"; -import type { Conn, ConnId } from "../conn/mod"; -import type { AnyDatabaseProvider, InferDatabaseClient } from "../database"; -import type { ActorInstance, SaveStateOptions } from "../instance/mod"; -import type { Schedule } from "../schedule"; +import type { Conn, ConnId } from "../../conn/mod"; +import type { AnyDatabaseProvider, InferDatabaseClient } from "../../database"; +import type { + ActorDefinition, + AnyActorDefinition, +} from "../../definition"; +import type { ActorInstance, SaveStateOptions } from "../../instance/mod"; +import type { Schedule } from "../../schedule"; /** * ActorContext class that provides access to actor methods and state @@ -42,16 +46,23 @@ export class ActorContext< /** * Get the actor state + * + * @remarks + * This property is not available in `createState` since the state hasn't been created yet. */ - get state(): TState { - return this.#actor.state; + get state(): TState extends never ? never : TState { + return this.#actor.state as TState extends never ? never : TState; } /** * Get the actor variables + * + * @remarks + * This property is not available in `createVars` since the variables haven't been created yet. + * Variables are only available if you define `vars` or `createVars` in your actor config. */ - get vars(): TVars { - return this.#actor.vars; + get vars(): TVars extends never ? never : TVars { + return this.#actor.vars as TVars extends never ? never : TVars; } /** @@ -125,11 +136,18 @@ export class ActorContext< /** * Gets the database. + * * @experimental + * @remarks + * This property is only available if you define a `db` provider in your actor config. * @throws {DatabaseNotEnabled} If the database is not enabled. */ - get db(): InferDatabaseClient { - return this.#actor.db; + get db(): TDatabase extends never + ? never + : InferDatabaseClient { + return this.#actor.db as TDatabase extends never + ? never + : InferDatabaseClient; } /** @@ -177,3 +195,15 @@ export class ActorContext< this.#actor.startDestroy(); } } + +export type ActorContextOf = AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any +> + ? ActorContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/conn-init.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/base/conn-init.ts similarity index 56% rename from rivetkit-typescript/packages/rivetkit/src/actor/contexts/conn-init.ts rename to rivetkit-typescript/packages/rivetkit/src/actor/contexts/base/conn-init.ts index 801bd86046..a5f5b002df 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/conn-init.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/base/conn-init.ts @@ -1,5 +1,9 @@ -import type { AnyDatabaseProvider } from "../database"; -import type { ActorInstance } from "../instance/mod"; +import type { AnyDatabaseProvider } from "../../database"; +import type { + ActorDefinition, + AnyActorDefinition, +} from "../../definition"; +import type { ActorInstance } from "../../instance/mod"; import { ActorContext } from "./actor"; /** @@ -11,7 +15,7 @@ export abstract class ConnInitContext< TVars, TInput, TDatabase extends AnyDatabaseProvider, -> extends ActorContext { +> extends ActorContext { /** * The incoming request that initiated the connection. * May be undefined for connections initiated without a direct HTTP request. @@ -25,7 +29,20 @@ export abstract class ConnInitContext< actor: ActorInstance, request: Request | undefined, ) { - super(actor); + super(actor as any); this.request = request; } } + +export type ConnInitContextOf = + AD extends ActorDefinition< + infer S, + any, + any, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? ConnInitContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/conn.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/base/conn.ts similarity index 58% rename from rivetkit-typescript/packages/rivetkit/src/actor/contexts/conn.ts rename to rivetkit-typescript/packages/rivetkit/src/actor/contexts/base/conn.ts index 725d40b418..06be2482c3 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/conn.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/base/conn.ts @@ -1,6 +1,10 @@ -import type { Conn } from "../conn/mod"; -import type { AnyDatabaseProvider } from "../database"; -import type { ActorInstance } from "../instance/mod"; +import type { Conn } from "../../conn/mod"; +import type { AnyDatabaseProvider } from "../../database"; +import type { + ActorDefinition, + AnyActorDefinition, +} from "../../definition"; +import type { ActorInstance } from "../../instance/mod"; import { ActorContext } from "./actor"; /** @@ -46,3 +50,15 @@ export abstract class ConnContext< super(actor); } } + +export type ConnContextOf = AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any +> + ? ConnContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/before-action-response.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/before-action-response.ts new file mode 100644 index 0000000000..309ba14bdb --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/before-action-response.ts @@ -0,0 +1,35 @@ +import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ActorContext } from "./base/actor"; + +/** + * Context for the onBeforeActionResponse lifecycle hook. + */ +export class BeforeActionResponseContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase +> {} + +export type BeforeActionResponseContextOf = + AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? BeforeActionResponseContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/before-connect.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/before-connect.ts new file mode 100644 index 0000000000..4a54b761f2 --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/before-connect.ts @@ -0,0 +1,26 @@ +import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ConnInitContext } from "./base/conn-init"; + +/** + * Context for the onBeforeConnect lifecycle hook. + */ +export class BeforeConnectContext< + TState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ConnInitContext {} + +export type BeforeConnectContextOf = + AD extends ActorDefinition< + infer S, + any, + any, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? BeforeConnectContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/connect.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/connect.ts new file mode 100644 index 0000000000..2c1472ac92 --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/connect.ts @@ -0,0 +1,35 @@ +import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ConnContext } from "./base/conn"; + +/** + * Context for the onConnect lifecycle hook. + */ +export class ConnectContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ConnContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase +> {} + +export type ConnectContextOf = + AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? ConnectContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create-conn-state.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create-conn-state.ts index 78e9c78e6c..9953be1470 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create-conn-state.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create-conn-state.ts @@ -1,5 +1,6 @@ import type { AnyDatabaseProvider } from "../database"; -import { ConnInitContext } from "./conn-init"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ConnInitContext } from "./base/conn-init"; /** * Context for the createConnState lifecycle hook. @@ -11,3 +12,16 @@ export class CreateConnStateContext< TInput, TDatabase extends AnyDatabaseProvider, > extends ConnInitContext {} + +export type CreateConnStateContextOf = + AD extends ActorDefinition< + infer S, + any, + any, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? CreateConnStateContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create-vars.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create-vars.ts new file mode 100644 index 0000000000..ef611cefb6 --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create-vars.ts @@ -0,0 +1,26 @@ +import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ActorContext } from "./base/actor"; + +/** + * Context for the createVars lifecycle hook. + */ +export class CreateVarsContext< + TState, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ActorContext {} + + +export type CreateVarsContextOf = + AD extends ActorDefinition< + infer S, + any, + any, + any, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? CreateVarsContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create.ts new file mode 100644 index 0000000000..17f860781d --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/create.ts @@ -0,0 +1,26 @@ +import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ActorContext } from "./base/actor"; + +/** + * Context for the onCreate lifecycle hook. + */ +export class CreateContext< + TState, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ActorContext {} + + +export type CreateContextOf = + AD extends ActorDefinition< + infer S, + any, + any, + any, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? CreateContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/destroy.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/destroy.ts new file mode 100644 index 0000000000..c6304e1a84 --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/destroy.ts @@ -0,0 +1,36 @@ +import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ActorContext } from "./base/actor"; + +/** + * Context for the onDestroy lifecycle hook. + */ +export class DestroyContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase +> {} + + +export type DestroyContextOf = + AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? DestroyContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/disconnect.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/disconnect.ts new file mode 100644 index 0000000000..42743546f6 --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/disconnect.ts @@ -0,0 +1,37 @@ +import type { Conn } from "../conn/mod"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import type { AnyDatabaseProvider } from "../database"; +import { ActorContext } from "./base/actor"; + +/** + * Context for the onDisconnect lifecycle hook. + */ +export class DisconnectContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase +> {} + + +export type DisconnectContextOf = + AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? DisconnectContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/index.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/index.ts new file mode 100644 index 0000000000..ff11968672 --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/index.ts @@ -0,0 +1,32 @@ +// Base contexts +export { ActorContext, type ActorContextOf } from "./base/actor"; +export { ConnContext, type ConnContextOf } from "./base/conn"; +export { ConnInitContext, type ConnInitContextOf } from "./base/conn-init"; + +// Lifecycle contexts +export { ActionContext, type ActionContextOf } from "./action"; +export { + BeforeActionResponseContext, + type BeforeActionResponseContextOf, +} from "./before-action-response"; +export { + BeforeConnectContext, + type BeforeConnectContextOf, +} from "./before-connect"; +export { ConnectContext, type ConnectContextOf } from "./connect"; +export { CreateContext, type CreateContextOf } from "./create"; +export { + CreateConnStateContext, + type CreateConnStateContextOf, +} from "./create-conn-state"; +export { CreateVarsContext, type CreateVarsContextOf } from "./create-vars"; +export { DestroyContext, type DestroyContextOf } from "./destroy"; +export { DisconnectContext, type DisconnectContextOf } from "./disconnect"; +export { RequestContext, type RequestContextOf } from "./request"; +export { SleepContext, type SleepContextOf } from "./sleep"; +export { + StateChangeContext, + type StateChangeContextOf, +} from "./state-change"; +export { WakeContext, type WakeContextOf } from "./wake"; +export { WebSocketContext, type WebSocketContextOf } from "./websocket"; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/on-before-connect.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/on-before-connect.ts deleted file mode 100644 index 759c210052..0000000000 --- a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/on-before-connect.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { AnyDatabaseProvider } from "../database"; -import { ConnInitContext } from "./conn-init"; - -/** - * Context for the onBeforeConnect lifecycle hook. - * Called before a connection is established, allowing for validation and early rejection. - */ -export class OnBeforeConnectContext< - TState, - TVars, - TInput, - TDatabase extends AnyDatabaseProvider, -> extends ConnInitContext {} diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/on-connect.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/on-connect.ts deleted file mode 100644 index 14493f3c08..0000000000 --- a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/on-connect.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { AnyDatabaseProvider } from "../database"; -import { ConnContext } from "./conn"; - -/** - * Context for the onConnect lifecycle hook. - * Called when a connection is successfully established. - */ -export class OnConnectContext< - TState, - TConnParams, - TConnState, - TVars, - TInput, - TDatabase extends AnyDatabaseProvider, -> extends ConnContext< - TState, - TConnParams, - TConnState, - TVars, - TInput, - TDatabase -> {} diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/request.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/request.ts index 1615687f61..632da2407c 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/request.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/request.ts @@ -1,7 +1,8 @@ import type { Conn } from "../conn/mod"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; import type { AnyDatabaseProvider } from "../database"; import type { ActorInstance } from "../instance/mod"; -import { ConnContext } from "./conn"; +import { ConnContext } from "./base/conn"; /** * Context for raw HTTP request handlers (onRequest). @@ -46,3 +47,17 @@ export class RequestContext< this.request = request; } } + + +export type RequestContextOf = + AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? RequestContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/sleep.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/sleep.ts new file mode 100644 index 0000000000..1614d1927c --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/sleep.ts @@ -0,0 +1,36 @@ +import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ActorContext } from "./base/actor"; + +/** + * Context for the onSleep lifecycle hook. + */ +export class SleepContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase +> {} + + +export type SleepContextOf = + AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? SleepContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/state-change.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/state-change.ts new file mode 100644 index 0000000000..d323c25839 --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/state-change.ts @@ -0,0 +1,36 @@ +import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ActorContext } from "./base/actor"; + +/** + * Context for the onStateChange lifecycle hook. + */ +export class StateChangeContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase +> {} + + +export type StateChangeContextOf = + AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? StateChangeContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/wake.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/wake.ts new file mode 100644 index 0000000000..b2c4402a2e --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/wake.ts @@ -0,0 +1,36 @@ +import type { AnyDatabaseProvider } from "../database"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; +import { ActorContext } from "./base/actor"; + +/** + * Context for the onWake lifecycle hook. + */ +export class WakeContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, +> extends ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase +> {} + + +export type WakeContextOf = + AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? WakeContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/websocket.ts b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/websocket.ts index f368330971..b274953cd9 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/contexts/websocket.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/contexts/websocket.ts @@ -1,7 +1,8 @@ import type { Conn } from "../conn/mod"; +import type { ActorDefinition, AnyActorDefinition } from "../definition"; import type { AnyDatabaseProvider } from "../database"; import type { ActorInstance } from "../instance/mod"; -import { ConnContext } from "./conn"; +import { ConnContext } from "./base/conn"; /** * Context for raw WebSocket handlers (onWebSocket). @@ -46,3 +47,17 @@ export class WebSocketContext< this.request = request; } } + + +export type WebSocketContextOf = + AD extends ActorDefinition< + infer S, + infer CP, + infer CS, + infer V, + infer I, + infer DB extends AnyDatabaseProvider, + any + > + ? WebSocketContext + : never; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/definition.ts b/rivetkit-typescript/packages/rivetkit/src/actor/definition.ts index 2111791e97..32d48982e1 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/definition.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/definition.ts @@ -1,7 +1,6 @@ import type { RegistryConfig } from "@/registry/config"; import type { Actions, ActorConfig } from "./config"; -import type { ActionContext } from "./contexts/action"; -import type { ActorContext } from "./contexts/actor"; +import type { ActionContextOf, ActorContext } from "./contexts"; import type { AnyDatabaseProvider } from "./database"; import { ActorInstance } from "./instance/mod"; @@ -15,38 +14,6 @@ export type AnyActorDefinition = ActorDefinition< any >; -/** - * Extracts the context type from an ActorDefinition - */ -export type ActorContextOf = - AD extends ActorDefinition< - infer S, - infer CP, - infer CS, - infer V, - infer I, - infer DB, - any - > - ? ActorContext - : never; - -/** - * Extracts the context type from an ActorDefinition - */ -export type ActionContextOf = - AD extends ActorDefinition< - infer S, - infer CP, - infer CS, - infer V, - infer I, - infer DB, - any - > - ? ActionContext - : never; - export class ActorDefinition< S, CP, diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/instance/connection-manager.ts b/rivetkit-typescript/packages/rivetkit/src/actor/instance/connection-manager.ts index 6ec99ec25a..1213beb497 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/instance/connection-manager.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/instance/connection-manager.ts @@ -23,9 +23,11 @@ import { type PersistedConn, } from "../conn/persisted"; import type { ConnDataInput } from "../conn/state-manager"; -import { CreateConnStateContext } from "../contexts/create-conn-state"; -import { OnBeforeConnectContext } from "../contexts/on-before-connect"; -import { OnConnectContext } from "../contexts/on-connect"; +import { + BeforeConnectContext, + ConnectContext, + CreateConnStateContext, +} from "../contexts"; import type { AnyDatabaseProvider } from "../database"; import { CachedSerializer } from "../protocol/serde"; import { deadline } from "../utils"; @@ -115,7 +117,7 @@ export class ConnectionManager< // Create new connection if (this.#actor.config.onBeforeConnect) { - const ctx = new OnBeforeConnectContext(this.#actor, request); + const ctx = new BeforeConnectContext(this.#actor, request); await this.#actor.config.onBeforeConnect(ctx, params); } @@ -443,7 +445,7 @@ export class ConnectionManager< #callOnConnect(conn: Conn) { if (this.#actor.config.onConnect) { try { - const ctx = new OnConnectContext(this.#actor, conn); + const ctx = new ConnectContext(this.#actor, conn); const result = this.#actor.config.onConnect(ctx, conn); if (result instanceof Promise) { deadline( diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/instance/mod.ts b/rivetkit-typescript/packages/rivetkit/src/actor/instance/mod.ts index c40b7ffaa4..6cb89ec855 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/instance/mod.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/instance/mod.ts @@ -15,7 +15,7 @@ import type * as protocol from "@/schemas/client-protocol/mod"; import { TO_CLIENT_VERSIONED } from "@/schemas/client-protocol/versioned"; import { ToClientSchema } from "@/schemas/client-protocol-zod/mod"; import { EXTRA_ERROR_LOG } from "@/utils"; -import type { ActorConfig, InitContext } from "../config"; +import type { ActorConfig } from "../config"; import type { ConnDriver } from "../conn/driver"; import { createHttpDriver } from "../conn/drivers/http"; import { @@ -28,10 +28,12 @@ import { convertConnFromBarePersistedConn, type PersistedConn, } from "../conn/persisted"; -import { ActionContext } from "../contexts/action"; -import { ActorContext } from "../contexts/actor"; -import { RequestContext } from "../contexts/request"; -import { WebSocketContext } from "../contexts/websocket"; +import { + ActionContext, + ActorContext, + RequestContext, + WebSocketContext, +} from "../contexts"; import type { AnyDatabaseProvider, InferDatabaseClient } from "../database"; import type { ActorDriver } from "../driver"; import * as errors from "../errors"; @@ -826,7 +828,10 @@ export class ActorInstance { // Call onCreate lifecycle if (this.#config.onCreate) { - await this.#config.onCreate(this.actorContext, persistData.input!); + await this.#config.onCreate( + this.actorContext as any, + persistData.input!, + ); } } @@ -892,7 +897,7 @@ export class ActorInstance { let vars: V | undefined; if ("createVars" in this.#config) { const dataOrPromise = this.#config.createVars( - this.actorContext as unknown as InitContext, + this.actorContext as any, this.driver.getContext(this.#actorId), ); if (dataOrPromise instanceof Promise) { diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/mod.ts b/rivetkit-typescript/packages/rivetkit/src/actor/mod.ts index a3ddeee0d1..f2c9df9302 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/mod.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/mod.ts @@ -72,23 +72,8 @@ export type { } from "@/common/websocket-interface"; export type { ActorKey } from "@/manager/protocol/query"; export type * from "./config"; -export type { InitContext } from "./config"; export type { AnyConn, Conn } from "./conn/mod"; -export type { ActionContext } from "./contexts/action"; -export type { ActorContext } from "./contexts/actor"; -export type { ConnContext } from "./contexts/conn"; -export type { ConnInitContext } from "./contexts/conn-init"; -export type { CreateConnStateContext } from "./contexts/create-conn-state"; -export type { OnBeforeConnectContext } from "./contexts/on-before-connect"; -export type { OnConnectContext } from "./contexts/on-connect"; -export type { RequestContext } from "./contexts/request"; -export type { WebSocketContext } from "./contexts/websocket"; -export type { - ActionContextOf, - ActorContextOf, - ActorDefinition, - AnyActorDefinition, -} from "./definition"; +export type { ActorDefinition, AnyActorDefinition } from "./definition"; export { lookupInRegistry } from "./definition"; export { UserError, type UserErrorOptions } from "./errors"; export type { AnyActorInstance } from "./instance/mod"; diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/protocol/old.ts b/rivetkit-typescript/packages/rivetkit/src/actor/protocol/old.ts index 8b9c20d2d7..e9dfa5a5f1 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/protocol/old.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/protocol/old.ts @@ -23,7 +23,7 @@ import { import { deserializeWithEncoding } from "@/serde"; import { assertUnreachable, bufferToArrayBuffer } from "../../utils"; import { CONN_SEND_MESSAGE_SYMBOL, type Conn } from "../conn/mod"; -import { ActionContext } from "../contexts/action"; +import { ActionContext } from "../contexts"; import type { ActorInstance } from "../instance/mod"; interface MessageEventOpts { diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/router-endpoints.ts b/rivetkit-typescript/packages/rivetkit/src/actor/router-endpoints.ts index 53ee19aa50..467cf52e69 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/router-endpoints.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/router-endpoints.ts @@ -1,7 +1,7 @@ import * as cbor from "cbor-x"; import type { Context as HonoContext, HonoRequest } from "hono"; import type { AnyConn } from "@/actor/conn/mod"; -import { ActionContext } from "@/actor/contexts/action"; +import { ActionContext } from "@/actor/contexts"; import * as errors from "@/actor/errors"; import type { AnyActorInstance } from "@/actor/instance/mod"; import { type Encoding, EncodingSchema } from "@/actor/protocol/serde"; diff --git a/rivetkit-typescript/packages/rivetkit/src/mod.ts b/rivetkit-typescript/packages/rivetkit/src/mod.ts index 324d375bdd..28a2dabd3d 100644 --- a/rivetkit-typescript/packages/rivetkit/src/mod.ts +++ b/rivetkit-typescript/packages/rivetkit/src/mod.ts @@ -1,4 +1,5 @@ export * from "@/actor/mod"; +export type * from "@/actor/contexts"; export { type AnyClient, type Client, diff --git a/website/src/content/docs/actors/actions.mdx b/website/src/content/docs/actors/actions.mdx index bb519ff5c4..e439307df3 100644 --- a/website/src/content/docs/actors/actions.mdx +++ b/website/src/content/docs/actors/actions.mdx @@ -270,7 +270,7 @@ function incrementCount(c: ActionContextOf) { } ``` -See [helper types](/docs/actors/helper-types) for more details on using `ActionContextOf` and other utility types. +See [types](/docs/actors/types) for more details on using `ActionContextOf` and other utility types. ## API Reference diff --git a/website/src/content/docs/actors/authentication.mdx b/website/src/content/docs/actors/authentication.mdx index 303ef3a7c8..0f373b831d 100644 --- a/website/src/content/docs/actors/authentication.mdx +++ b/website/src/content/docs/actors/authentication.mdx @@ -483,6 +483,6 @@ const cachedAuthActor = actor({ ## API Reference - [`AuthIntent`](/typedoc/types/rivetkit.mod.AuthIntent.html) - Authentication intent type -- [`OnBeforeConnectContext`](/typedoc/interfaces/rivetkit.mod.OnBeforeConnectContext.html) - Context for auth checks -- [`OnConnectContext`](/typedoc/interfaces/rivetkit.mod.OnConnectContext.html) - Context after connection +- [`BeforeConnectContext`](/typedoc/interfaces/rivetkit.mod.BeforeConnectContext.html) - Context for auth checks +- [`ConnectContext`](/typedoc/interfaces/rivetkit.mod.ConnectContext.html) - Context after connection diff --git a/website/src/content/docs/actors/connections.mdx b/website/src/content/docs/actors/connections.mdx index 5ec3bdb822..f5986a8cfb 100644 --- a/website/src/content/docs/actors/connections.mdx +++ b/website/src/content/docs/actors/connections.mdx @@ -157,7 +157,7 @@ There are two ways to define the initial state for connections: ### `onBeforeConnect` -[API Reference](/typedoc/interfaces/rivetkit.mod.OnBeforeConnectContext.html) +[API Reference](/typedoc/interfaces/rivetkit.mod.BeforeConnectContext.html) The `onBeforeConnect` hook is called whenever a new client connects to the actor. Can be async. Clients can pass parameters when connecting, accessible via `params`. This hook is used for connection validation and can throw errors to reject connections. @@ -204,7 +204,7 @@ Connections cannot interact with the actor until this method completes successfu ### `onConnect` -[API Reference](/typedoc/interfaces/rivetkit.mod.OnConnectContext.html) +[API Reference](/typedoc/interfaces/rivetkit.mod.ConnectContext.html) Executed after the client has successfully connected. Can be async. Receives the connection object as a second parameter. @@ -336,6 +336,6 @@ This ensures the underlying network connections close cleanly before continuing. - [`Conn`](/typedoc/interfaces/rivetkit.mod.Conn.html) - Connection interface - [`ConnInitContext`](/typedoc/interfaces/rivetkit.mod.ConnInitContext.html) - Connection initialization context - [`CreateConnStateContext`](/typedoc/interfaces/rivetkit.mod.CreateConnStateContext.html) - Context for creating connection state -- [`OnBeforeConnectContext`](/typedoc/interfaces/rivetkit.mod.OnBeforeConnectContext.html) - Pre-connection lifecycle hook context -- [`OnConnectContext`](/typedoc/interfaces/rivetkit.mod.OnConnectContext.html) - Post-connection lifecycle hook context +- [`BeforeConnectContext`](/typedoc/interfaces/rivetkit.mod.BeforeConnectContext.html) - Pre-connection lifecycle hook context +- [`ConnectContext`](/typedoc/interfaces/rivetkit.mod.ConnectContext.html) - Post-connection lifecycle hook context - [`ActorConn`](/typedoc/types/rivetkit.client_mod.ActorConn.html) - Typed connection from client side diff --git a/website/src/content/docs/actors/ephemeral-variables.mdx b/website/src/content/docs/actors/ephemeral-variables.mdx index 6abcb84404..d16e2403a2 100644 --- a/website/src/content/docs/actors/ephemeral-variables.mdx +++ b/website/src/content/docs/actors/ephemeral-variables.mdx @@ -42,15 +42,15 @@ This value will be cloned for every new actor using `structuredClone`. Create actor state dynamically on each actors' start: ```typescript -import { actor, InitContext } from "rivetkit"; +import { actor, CreateVarsContext } from "rivetkit"; // Define vars with initialization logic const counter = actor({ state: { count: 0 }, - + // Define vars using a creation function - createVars: (c: InitContext, driver: any) => { - return { + createVars: (c: CreateVarsContext, driver: any) => { + return { lastAccessTime: Date.now(), emitter: createNanoEvents() }; @@ -63,7 +63,7 @@ const counter = actor({ ``` -If accepting arguments to `createVars`, you **must** define the types: `createVars(c: InitContext, driver: any)` +If accepting arguments to `createVars`, you **must** define the types: `createVars(c: CreateVarsContext, driver: any)` Otherwise, the return type will not be inferred and `c.vars` will be of type `unknown`. @@ -134,14 +134,14 @@ The `createVars` function receives a second parameter that provides access to dr For example, the Redis driver exposes access to the Redis instance: ```typescript -import { actor, InitContext } from "rivetkit"; +import { actor, CreateVarsContext } from "rivetkit"; import { DriverContext } from "@rivetkit/redis"; const myActor = actor({ state: { count: 0 }, - + // The second parameter provides driver-specific context - createVars: (ctx: InitContext, driver: DriverContext) => ({ driver }), + createVars: (ctx: CreateVarsContext, driver: DriverContext) => ({ driver }), actions: { accessDriverFeatures: (c) => { diff --git a/website/src/content/docs/actors/external-sql.mdx b/website/src/content/docs/actors/external-sql.mdx index d9315d8476..782b1aff5f 100644 --- a/website/src/content/docs/actors/external-sql.mdx +++ b/website/src/content/docs/actors/external-sql.mdx @@ -36,7 +36,7 @@ Here's a basic example of a user actor that creates a database record on start a ```typescript {{ "title": "registry.ts" }} -import { actor, setup, InitContext } from "rivetkit"; +import { actor, setup, CreateContext } from "rivetkit"; import { Pool } from "pg"; interface ActorInput { @@ -55,7 +55,7 @@ const pool = new Pool({ // Create the user actor export const userActor = actor({ - createState: (c: InitContext, input: ActorInput) => ({ + createState: (c: CreateContext, input: ActorInput) => ({ requestCount: 0, username: input.username, email: input.email, @@ -143,7 +143,7 @@ Here's the same user actor pattern using Drizzle ORM for more type-safe database ```typescript {{ "title": "registry.ts" }} -import { actor, setup, InitContext } from "rivetkit"; +import { actor, setup, CreateContext } from "rivetkit"; import { drizzle } from "drizzle-orm/node-postgres"; import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { eq } from "drizzle-orm"; @@ -172,7 +172,7 @@ const db = drizzle(pool); // Create the user actor export const userActor = actor({ - createState: (c: InitContext, input: ActorInput) => ({ + createState: (c: CreateContext, input: ActorInput) => ({ requestCount: 0, username: input.username, email: input.email, diff --git a/website/src/content/docs/actors/helper-types.mdx b/website/src/content/docs/actors/helper-types.mdx index e049bf83fd..ea0ae0aa2b 100644 --- a/website/src/content/docs/actors/helper-types.mdx +++ b/website/src/content/docs/actors/helper-types.mdx @@ -1,73 +1,3 @@ # Helper Types -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 outside of the actor's handlers. Rivet provides helper types to extract the context types from actor definitions. - -### `ActorContextOf` - -Extracts the full actor context type from an actor definition. This is the type of the context object (`c`) available in [lifecycle hooks](/docs/actors/lifecycle) and in [actions](/docs/actors/actions). - -```typescript -import { actor, ActorContextOf } from "rivetkit"; - -const chatRoom = actor({ - state: { messages: [] }, - actions: { - onWake: (c, message) => { - // Can ActorContext be used in lifecycle hooks - exampleFunction(c, "Actor started"); - }, - actions: { - sendMessage: (c, message) => { - // Can ActorContext also be used in actions - processChatRoomContext(c, mssage); - } - } -}); - -// Now you can use this type elsewhere -function logMessage(context: ActorContextOf, message: string) { - console.log(context.state.messages); - context.broadcast("newEvent", { type: "system", message }); -} -``` - -### `ActionContextOf` - -Extracts the action context type from an actor definition. This is the type of the context object (`c`) available in [actions](/docs/actors/actions). This cannot be used in [lifecycle hooks](/docs/actors/lifecycle). - -```typescript -import { actor, ActionContextOf } from "rivetkit"; - -const counterWithProcessing = actor({ - state: { count: 0 }, - actions: { - increment: (c) => { - // Use our helper function to process the context - processCounterAction(c); - return c.state.count; - } - } -}); - -function processCounterAction(context: ActionContextOf) { - context.state.count++; -} -``` - -## API Reference - -- [`ActorContextOf`](/typedoc/types/rivetkit.mod.ActorContextOf.html) - Extract context from actor -- [`ActionContextOf`](/typedoc/types/rivetkit.mod.ActionContextOf.html) - Extract context from action -- [`ActorConfig`](/typedoc/types/rivetkit.mod.ActorConfig.html) - Actor configuration type -- [`ActorConfigInput`](/typedoc/types/rivetkit.mod.ActorConfigInput.html) - Actor configuration input -- [`RegistryActors`](/typedoc/types/rivetkit.mod.RegistryActors.html) - Extract actors from registry -- [`ExtractActorsFromRegistry`](/typedoc/types/rivetkit.client_mod.ExtractActorsFromRegistry.html) - Utility type -- [`ExtractRegistryFromClient`](/typedoc/types/rivetkit.client_mod.ExtractRegistryFromClient.html) - Utility type -- [`AnyActorDefinition`](/typedoc/types/rivetkit.mod.AnyActorDefinition.html) - Any actor definition type -- [`AnyActorInstance`](/typedoc/types/rivetkit.mod.AnyActorInstance.html) - Any actor instance type -- [`AnyClient`](/typedoc/types/rivetkit.mod.AnyClient.html) - Any client type +This page has moved to [Types](/docs/actors/types). diff --git a/website/src/content/docs/actors/input.mdx b/website/src/content/docs/actors/input.mdx index 1fcc5c2c6a..816351aa3b 100644 --- a/website/src/content/docs/actors/input.mdx +++ b/website/src/content/docs/actors/input.mdx @@ -38,7 +38,7 @@ interface ChatRoomInput { } const chatRoom = actor({ - createState: (c: InitContext, input: ChatRoomInput) => ({ + createState: (c: CreateContext, input: ChatRoomInput) => ({ name: input?.roomName ?? "Unnamed Room", isPrivate: input?.isPrivate ?? false, maxUsers: input?.maxUsers ?? 50, @@ -81,7 +81,7 @@ const GameInputSchema = z.object({ }); const game = actor({ - createState: (c: InitContext, inputRaw: z.infer) => { + createState: (c: CreateContext, inputRaw: z.infer) => { // Validate input const input = GameInputSchema.parse(inputRaw); @@ -147,7 +147,7 @@ interface GameInput { } const game = actor({ - createState: (c: InitContext, input: GameInput) => ({ + createState: (c: CreateContext, input: GameInput) => ({ gameMode: input.gameMode, maxPlayers: input.maxPlayers, difficulty: input.difficulty ?? "medium", @@ -165,7 +165,7 @@ If you need to access input data in actions, store it in the actor's state: ```typescript const game = actor({ - createState: (c: InitContext, input: GameInput) => ({ + createState: (c: CreateContext, input: GameInput) => ({ // Store input configuration in state config: { gameMode: input.gameMode, diff --git a/website/src/content/docs/actors/lifecycle.mdx b/website/src/content/docs/actors/lifecycle.mdx index 0cbf548918..cc0fb3b08d 100644 --- a/website/src/content/docs/actors/lifecycle.mdx +++ b/website/src/content/docs/actors/lifecycle.mdx @@ -267,7 +267,7 @@ There are two ways to define the initial state for connections: ### `onBeforeConnect` -[API Reference](/typedoc/interfaces/rivetkit.mod.OnBeforeConnectContext.html) +[API Reference](/typedoc/interfaces/rivetkit.mod.BeforeConnectContext.html) The `onBeforeConnect` hook is called whenever a new client connects to the actor. Can be async. Clients can pass parameters when connecting, accessible via `params`. This hook is used for connection validation and can throw errors to reject connections. @@ -314,7 +314,7 @@ Connections cannot interact with the actor until this method completes successfu ### `onConnect` -[API Reference](/typedoc/interfaces/rivetkit.mod.OnConnectContext.html) +[API Reference](/typedoc/interfaces/rivetkit.mod.ConnectContext.html) Executed after the client has successfully connected. Can be async. Receives the connection object as a second parameter. @@ -637,12 +637,12 @@ function logActorStarted(c: ActorContextOf) { } ``` -See [Helper Types](/docs/actors/helper-types) for more details on using `ActorContextOf`. +See [Types](/docs/actors/types) for more details on using `ActorContextOf`. ## Full Example ```typescript -import { actor, InitContext } from "rivetkit"; +import { actor, CreateContext } from "rivetkit"; interface CounterInput { initialCount?: number; @@ -670,7 +670,7 @@ interface ConnState { const counter = actor({ // Initialize state with input - createState: (c: InitContext, input: CounterInput): CounterState => ({ + createState: (c: CreateContext, input: CounterInput): CounterState => ({ count: input.initialCount ?? 0, stepSize: input.stepSize ?? 1, name: input.name ?? "Unnamed Counter", diff --git a/website/src/content/docs/actors/state.mdx b/website/src/content/docs/actors/state.mdx index 11ea7e4579..0385a5a091 100644 --- a/website/src/content/docs/actors/state.mdx +++ b/website/src/content/docs/actors/state.mdx @@ -58,7 +58,7 @@ const counter = actor({ To accept a custom input parameters for the initial state, use: ```typescript -import { actor, InitContext } from "rivetkit"; +import { actor, CreateContext } from "rivetkit"; interface CounterInput { startingCount: number; @@ -67,7 +67,7 @@ interface CounterInput { // State with initialization logic const counter = actor({ // Define state using a creation function - createState: (c: InitContext, input: CounterInput) => { + createState: (c: CreateContext, input: CounterInput) => { return { count: input.startingCount }; }, @@ -80,9 +80,9 @@ const counter = actor({ Read more about [input parameters](/docs/actors/input) here. -If accepting arguments to `createState`, you **must** define the types: `createSTate(c: InitContext, input: MyType)` +If accepting arguments to `createState`, you **must** define the types: `createState(c: CreateContext, input: MyType)` -Otherwise, the return type will not be inferred and `c.vars` will be of type `unknown`. +Otherwise, the return type will not be inferred and `c.state` will be of type `unknown`. @@ -192,6 +192,6 @@ State is currently constrained to the following types: ## API Reference -- [`InitContext`](/typedoc/types/rivetkit.mod.InitContext.html) - Context available during actor initialization +- [`CreateContext`](/typedoc/types/rivetkit.mod.CreateContext.html) - Context available during actor state creation - [`ActorContext`](/typedoc/interfaces/rivetkit.mod.ActorContext.html) - Context available throughout actor lifecycle - [`ActorDefinition`](/typedoc/interfaces/rivetkit.mod.ActorDefinition.html) - Interface for defining actors with state diff --git a/website/src/content/docs/actors/types.mdx b/website/src/content/docs/actors/types.mdx new file mode 100644 index 0000000000..8b26f60150 --- /dev/null +++ b/website/src/content/docs/actors/types.mdx @@ -0,0 +1,77 @@ +# Types + +TypeScript types for working with Rivet Actors. This page covers context types used in lifecycle hooks and actions, as well as helper types for extracting types from actor definitions. + +## Context Types + +Context types define what properties and methods are available in different parts of the actor lifecycle. + +```typescript +import { actor } from "rivetkit"; + +const counter = actor({ + state: { count: 0 }, + + // CreateContext in createState hook + createState: (c, input: { initial: number }) => { + return { count: input.initial }; + }, + + // ActionContext in actions + actions: { + increment: (c) => { + c.state.count += 1; + return c.state.count; + } + } +}); +``` + +### Extracting Context Types + +When writing helper functions that work with actor contexts, use context extractor types like `CreateContextOf` or `ActionContextOf` to extract the appropriate context type from your actor definition. + +```typescript +import { actor, CreateContextOf, ActionContextOf } from "rivetkit"; + +const gameRoom = actor({ + state: { + players: [] as string[], + score: 0 + }, + + createState: (c, input: { roomId: string }) => { + initializeRoom(c, input.roomId); + return { players: [], score: 0 }; + }, + + actions: { + addPlayer: (c, playerId: string) => { + validatePlayer(c, playerId); + c.state.players.push(playerId); + } + } +}); + +// Extract CreateContext type for createState hook +function initializeRoom( + context: CreateContextOf, + roomId: string +) { + console.log(`Initializing room: ${roomId}`); + // context.state is not available here (being created) + // context.vars is not available here (not created yet) +} + +// Extract ActionContext type for actions +function validatePlayer( + context: ActionContextOf, + playerId: string +) { + // Full context available in actions + if (context.state.players.includes(playerId)) { + throw new Error("Player already in room"); + } +} +``` + diff --git a/website/src/content/docs/connect/cloudflare-workers.mdx b/website/src/content/docs/connect/cloudflare-workers.mdx index ddafcbaa07..46564eece8 100644 --- a/website/src/content/docs/connect/cloudflare-workers.mdx +++ b/website/src/content/docs/connect/cloudflare-workers.mdx @@ -96,14 +96,14 @@ const myActor = actor({ The Cloudflare Workers driver provides access to the Durable Object state and environment through the driver context in `createVars`. ```typescript -import { actor, InitContext } from "rivetkit"; +import { actor, CreateVarsContext } from "rivetkit"; import type { DriverContext } from "@rivetkit/cloudflare-workers"; const myActor = actor({ state: { count: 0 }, - + // Save the Cloudflare driver context - createVars: (ctx: InitContext, driver: DriverContext) => ({ + createVars: (ctx: CreateVarsContext, driver: DriverContext) => ({ state: driver.state, }), diff --git a/website/src/sitemap/mod.ts b/website/src/sitemap/mod.ts index ae09cc9eff..6446ec1d7d 100644 --- a/website/src/sitemap/mod.ts +++ b/website/src/sitemap/mod.ts @@ -255,8 +255,8 @@ export const sitemap = [ href: "/docs/actors/ai-and-user-generated-actors", }, { - title: "Helper Types", - href: "/docs/actors/helper-types", + title: "Types", + href: "/docs/actors/types", //icon: faCode, }, {