From cbfabc4efdd9ac54be1289f6ee733bc8c69c28f7 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Fri, 8 Aug 2025 16:18:13 -0700 Subject: [PATCH] chore(core): clean up lifecycle hooks for easier type inference --- examples/cloudflare-workers/src/registry.ts | 2 +- internal-docs/CONFIG_TYPES.md | 21 + .../driver-test-suite/action-inputs.ts | 4 +- .../core/fixtures/driver-test-suite/auth.ts | 10 +- .../fixtures/driver-test-suite/lifecycle.ts | 11 +- .../driver-test-suite/raw-http-auth.ts | 3 +- .../driver-test-suite/raw-websocket-auth.ts | 3 +- .../driver-test-suite/raw-websocket.ts | 4 +- packages/core/src/actor/action.ts | 55 +- packages/core/src/actor/config.ts | 524 +++++++++++++----- packages/core/src/actor/context.ts | 45 +- packages/core/src/actor/instance.ts | 13 +- packages/core/src/actor/mod.ts | 61 +- packages/core/src/manager/auth.ts | 3 +- 14 files changed, 551 insertions(+), 208 deletions(-) create mode 100644 internal-docs/CONFIG_TYPES.md diff --git a/examples/cloudflare-workers/src/registry.ts b/examples/cloudflare-workers/src/registry.ts index 3880bedb7..24fd9b44b 100644 --- a/examples/cloudflare-workers/src/registry.ts +++ b/examples/cloudflare-workers/src/registry.ts @@ -1,4 +1,4 @@ -import { ActorContext, actor, setup } from "@rivetkit/actor"; +import { actor, setup } from "@rivetkit/actor"; export const counter = actor({ onAuth: () => { diff --git a/internal-docs/CONFIG_TYPES.md b/internal-docs/CONFIG_TYPES.md new file mode 100644 index 000000000..9b8245777 --- /dev/null +++ b/internal-docs/CONFIG_TYPES.md @@ -0,0 +1,21 @@ +# Config Types + +## Inferred types + +- All types must be included in `ActorTypes` so the user can hardcode types + +- If using input parameters for inferring types, they must be raw parameters. e.g.: + + ```typescript + // It's hard for users to infer TConnParams + onAuth: (opts: OnAuthOpts) => TAuthData, + // Because you would have to import & use an extra type + onAuth: (opts: OnAuthOpts) => TAuthData, + ``` + +- When inferring via return data, you must use a union. e.g.: + + ```typescript + { state: TState } | { createState: () => TState } | undefined + ``` + diff --git a/packages/core/fixtures/driver-test-suite/action-inputs.ts b/packages/core/fixtures/driver-test-suite/action-inputs.ts index b910a0522..062b5ee3f 100644 --- a/packages/core/fixtures/driver-test-suite/action-inputs.ts +++ b/packages/core/fixtures/driver-test-suite/action-inputs.ts @@ -8,14 +8,14 @@ export interface State { // Test actor that can capture input during creation export const inputActor = actor({ onAuth: () => {}, - createState: (c, { input }): State => { + createState: (c, input): State => { return { initialInput: input, onCreateInput: undefined, }; }, - onCreate: (c, { input }) => { + onCreate: (c, input) => { c.state.onCreateInput = input; }, diff --git a/packages/core/fixtures/driver-test-suite/auth.ts b/packages/core/fixtures/driver-test-suite/auth.ts index f23aa16fe..7746b04ae 100644 --- a/packages/core/fixtures/driver-test-suite/auth.ts +++ b/packages/core/fixtures/driver-test-suite/auth.ts @@ -3,8 +3,7 @@ import { actor, UserError } from "@rivetkit/core"; // Basic auth actor - requires API key export const authActor = actor({ state: { requests: 0 }, - onAuth: (opts) => { - const { request, intents, params } = opts; + onAuth: (params) => { const apiKey = (params as any)?.apiKey; if (!apiKey) { throw new UserError("API key required", { code: "missing_auth" }); @@ -28,8 +27,7 @@ export const authActor = actor({ // Intent-specific auth actor - checks different permissions for different intents export const intentAuthActor = actor({ state: { value: 0 }, - onAuth: (opts) => { - const { request, intents, params } = opts; + onAuth: (params, { request, intents }) => { console.log("intents", intents, params); const role = (params as any)?.role; @@ -82,9 +80,7 @@ export const noAuthActor = actor({ // Async auth actor - tests promise-based authentication export const asyncAuthActor = actor({ state: { count: 0 }, - onAuth: async (opts) => { - const { params } = opts; - + onAuth: async (params) => { const token = (params as any)?.token; if (!token) { throw new UserError("Token required", { code: "missing_token" }); diff --git a/packages/core/fixtures/driver-test-suite/lifecycle.ts b/packages/core/fixtures/driver-test-suite/lifecycle.ts index e30af1948..697596654 100644 --- a/packages/core/fixtures/driver-test-suite/lifecycle.ts +++ b/packages/core/fixtures/driver-test-suite/lifecycle.ts @@ -1,22 +1,21 @@ import { actor } from "@rivetkit/core"; +type ConnParams = { trackLifecycle?: boolean } | undefined; + export const counterWithLifecycle = actor({ onAuth: () => {}, state: { count: 0, events: [] as string[], }, - createConnState: ( - c, - opts: { params: { trackLifecycle?: boolean } | undefined }, - ) => ({ + createConnState: (c, params: ConnParams) => ({ joinTime: Date.now(), }), onStart: (c) => { c.state.events.push("onStart"); }, - onBeforeConnect: (c, conn) => { - if (conn.params?.trackLifecycle) c.state.events.push("onBeforeConnect"); + onBeforeConnect: (c, params) => { + if (params?.trackLifecycle) c.state.events.push("onBeforeConnect"); }, onConnect: (c, conn) => { if (conn.params?.trackLifecycle) c.state.events.push("onConnect"); diff --git a/packages/core/fixtures/driver-test-suite/raw-http-auth.ts b/packages/core/fixtures/driver-test-suite/raw-http-auth.ts index 2f2ce1e4b..6d89f0291 100644 --- a/packages/core/fixtures/driver-test-suite/raw-http-auth.ts +++ b/packages/core/fixtures/driver-test-suite/raw-http-auth.ts @@ -5,8 +5,7 @@ export const rawHttpAuthActor = actor({ state: { requestCount: 0, }, - onAuth: (opts) => { - const { params } = opts; + onAuth: (params) => { const apiKey = (params as any)?.apiKey; if (!apiKey) { throw new UserError("API key required", { code: "missing_auth" }); diff --git a/packages/core/fixtures/driver-test-suite/raw-websocket-auth.ts b/packages/core/fixtures/driver-test-suite/raw-websocket-auth.ts index 3a0705cc2..c90cb4b24 100644 --- a/packages/core/fixtures/driver-test-suite/raw-websocket-auth.ts +++ b/packages/core/fixtures/driver-test-suite/raw-websocket-auth.ts @@ -11,8 +11,7 @@ export const rawWebSocketAuthActor = actor({ connectionCount: 0, messageCount: 0, }, - onAuth: (opts) => { - const { params } = opts; + onAuth: (params) => { const apiKey = (params as any)?.apiKey; if (!apiKey) { throw new UserError("API key required", { code: "missing_auth" }); diff --git a/packages/core/fixtures/driver-test-suite/raw-websocket.ts b/packages/core/fixtures/driver-test-suite/raw-websocket.ts index f3a184d45..48124b3df 100644 --- a/packages/core/fixtures/driver-test-suite/raw-websocket.ts +++ b/packages/core/fixtures/driver-test-suite/raw-websocket.ts @@ -9,9 +9,9 @@ export const rawWebSocketActor = actor({ connectionCount: 0, messageCount: 0, }, - onAuth(opts) { + onAuth(params) { // Allow all connections and pass through connection params - return { connParams: opts.params }; + return { connParams: params }; }, onWebSocket(ctx, websocket, opts) { ctx.state.connectionCount = ctx.state.connectionCount + 1; diff --git a/packages/core/src/actor/action.ts b/packages/core/src/actor/action.ts index f165bde76..a6be1f765 100644 --- a/packages/core/src/actor/action.ts +++ b/packages/core/src/actor/action.ts @@ -14,15 +14,23 @@ import type { Schedule } from "./schedule"; * @typeParam A Actor this action belongs to */ export class ActionContext< - S, - CP, - CS, - V, - I, - AD, - DB extends AnyDatabaseProvider, + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase extends AnyDatabaseProvider, > { - #actorContext: ActorContext; + #actorContext: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >; /** * Should not be called directly. @@ -31,8 +39,24 @@ export class ActionContext< * @param conn - The connection associated with the action */ constructor( - actorContext: ActorContext, - public readonly conn: Conn, + actorContext: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, + public readonly conn: Conn< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, ) { this.#actorContext = actorContext; } @@ -40,14 +64,14 @@ export class ActionContext< /** * Get the actor state */ - get state(): S { + get state(): TState { return this.#actorContext.state; } /** * Get the actor variables */ - get vars(): V { + get vars(): TVars { return this.#actorContext.vars; } @@ -103,7 +127,10 @@ export class ActionContext< /** * Gets the map of connections. */ - get conns(): Map> { + get conns(): Map< + ConnId, + Conn + > { return this.#actorContext.conns; } @@ -117,7 +144,7 @@ export class ActionContext< /** * @experimental */ - get db(): InferDatabaseClient { + get db(): InferDatabaseClient { return this.#actorContext.db; } diff --git a/packages/core/src/actor/config.ts b/packages/core/src/actor/config.ts index 7e109de5e..85aa78044 100644 --- a/packages/core/src/actor/config.ts +++ b/packages/core/src/actor/config.ts @@ -5,6 +5,34 @@ import type { Conn } from "./connection"; import type { ActorContext } from "./context"; import type { AnyDatabaseProvider } from "./database"; +export type InitContext = ActorContext< + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined +>; + +export interface ActorTypes< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase extends AnyDatabaseProvider, +> { + state?: TState; + connParams?: TConnParams; + connState?: TConnState; + vars?: TVars; + input?: TInput; + authData?: TAuthData; + database?: TDatabase; +} + // This schema is used to validate the input at runtime. The generic types are defined below in `ActorConfig`. // // We don't use Zod generics with `z.custom` because: @@ -22,7 +50,7 @@ export const ActorConfigSchema = z onBeforeActionResponse: z.function().optional(), onFetch: z.function().optional(), onWebSocket: z.function().optional(), - actions: z.record(z.function()), + actions: z.record(z.function()).default({}), state: z.any().optional(), createState: z.function().optional(), connState: z.any().optional(), @@ -80,106 +108,92 @@ export const ActorConfigSchema = z }, ); -export interface OnCreateOptions { - input?: I; -} - -export interface CreateStateOptions { - input?: I; -} - -export interface OnConnectOptions { +export interface OnConnectOptions { /** * The request object associated with the connection. * * @experimental */ request?: Request; - params: CP; } // Creates state config // -// This must have only one or the other or else S will not be able to be inferred +// This must have only one or the other or else TState will not be able to be inferred // // Data returned from this handler will be available on `c.state`. -type CreateState = - | { state: S } +type CreateState< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase, +> = + | { state: TState } | { - createState: ( - c: ActorContext< - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined - >, - opts: CreateStateOptions, - ) => S | Promise; + createState: (c: InitContext, input: TInput) => TState | Promise; } | Record; // Creates connection state config // -// This must have only one or the other or else S will not be able to be inferred +// This must have only one or the other or else TState will not be able to be inferred // // Data returned from this handler will be available on `c.conn.state`. -type CreateConnState = - | { connState: CS } +type CreateConnState< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase, +> = + | { connState: TConnState } | { createConnState: ( - c: ActorContext< - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined - >, - opts: OnConnectOptions, - ) => CS | Promise; + c: InitContext, + params: TConnParams, + opts: OnConnectOptions, + ) => TConnState | Promise; } | Record; // Creates vars config // -// This must have only one or the other or else S will not be able to be inferred +// This must have only one or the other or else TState will not be able to be inferred /** * @experimental */ -type CreateVars = +type CreateVars< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase, +> = | { /** * @experimental */ - vars: V; + vars: TVars; } | { /** * @experimental */ - createVars: ( - c: ActorContext< - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined - >, - driverCtx: DC, - ) => V | Promise; + createVars: (c: InitContext, driverCtx: any) => TVars | Promise; } | Record; // Creates auth config // -// This must have only one or the other or else AD will not be able to be inferred -type OnAuth = +// This must have only one or the other or else TAuthData will not be able to be inferred +type OnAuth = | { /** * Called on the HTTP server before clients can interact with the actor. @@ -206,45 +220,71 @@ type OnAuth = * @returns Authentication data to attach to connections (must be serializable) * @throws Throw an error to deny access to the actor */ - onAuth: (opts: OnAuthOptions) => AD | Promise; + onAuth: ( + params: TConnParams, + opts: OnAuthOptions, + ) => TAuthData | Promise; } | Record; -export interface Actions { +export interface Actions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase extends AnyDatabaseProvider, +> { [Action: string]: ( - c: ActionContext, + c: ActionContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, ...args: any[] ) => any; } -//export type ActorConfig = BaseActorConfig & -// ActorConfigLifecycle & -// CreateState & -// CreateConnState; +//export type ActorConfig = BaseActorConfig & +// ActorConfigLifecycle & +// CreateState & +// CreateConnState; /** * @experimental */ export type AuthIntent = "get" | "create" | "connect" | "action" | "message"; -export interface OnAuthOptions { +export interface OnAuthOptions { request: Request; /** * @experimental */ intents: Set; - params: CP; } interface BaseActorConfig< - S, - CP, - CS, - V, - I, - AD, - DB extends AnyDatabaseProvider, - R extends Actions, + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase extends AnyDatabaseProvider, + TActions extends Actions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, > { /** * Called when the actor is first initialized. @@ -253,8 +293,16 @@ interface BaseActorConfig< * This is called before any other lifecycle hooks. */ onCreate?: ( - c: ActorContext, - opts: OnCreateOptions, + c: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, + input: TInput, ) => void | Promise; /** @@ -265,7 +313,17 @@ interface BaseActorConfig< * * @returns Void or a Promise that resolves when startup is complete */ - onStart?: (c: ActorContext) => void | Promise; + onStart?: ( + c: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, + ) => void | Promise; /** * Called when the actor's state changes. @@ -276,8 +334,16 @@ interface BaseActorConfig< * @param newState The updated state */ onStateChange?: ( - c: ActorContext, - newState: S, + c: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, + newState: TState, ) => void; /** @@ -301,8 +367,17 @@ interface BaseActorConfig< * @throws Throw an error to reject the connection */ onBeforeConnect?: ( - c: ActorContext, - opts: OnConnectOptions, + c: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, + params: TConnParams, + opts: OnConnectOptions, ) => void | Promise; /** @@ -315,8 +390,24 @@ interface BaseActorConfig< * @returns Void or a Promise that resolves when connection handling is complete */ onConnect?: ( - c: ActorContext, - conn: Conn, + c: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, + conn: Conn< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, ) => void | Promise; /** @@ -329,8 +420,24 @@ interface BaseActorConfig< * @returns Void or a Promise that resolves when disconnect handling is complete */ onDisconnect?: ( - c: ActorContext, - conn: Conn, + c: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, + conn: Conn< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, ) => void | Promise; /** @@ -346,7 +453,15 @@ interface BaseActorConfig< * @returns The modified output to send to the client */ onBeforeActionResponse?: ( - c: ActorContext, + c: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, name: string, args: unknown[], output: Out, @@ -362,9 +477,17 @@ interface BaseActorConfig< * @returns A Response object to send back, or void to continue with default routing */ onFetch?: ( - c: ActorContext, + c: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, request: Request, - opts: { auth: AD }, + opts: { auth: TAuthData }, ) => Response | Promise; /** @@ -377,20 +500,28 @@ interface BaseActorConfig< * @param request The original HTTP upgrade request */ onWebSocket?: ( - c: ActorContext, + c: ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, websocket: UniversalWebSocket, - opts: { request: Request; auth: AD }, + opts: { request: Request; auth: TAuthData }, ) => void | Promise; - actions: R; + actions: TActions; } -type ActorDatabaseConfig = +type ActorDatabaseConfig = | { /** * @experimental */ - db: DB; + db: TDatabase; } | Record; @@ -398,13 +529,13 @@ type ActorDatabaseConfig = // 2. Omit keys that we'll manually define (because of generics) // 3. Define our own types that have generic constraints export type ActorConfig< - S, - CP, - CS, - V, - I, - AD, - DB extends AnyDatabaseProvider, + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase extends AnyDatabaseProvider, > = Omit< z.infer, | "actions" @@ -426,24 +557,83 @@ export type ActorConfig< | "createVars" | "db" > & - BaseActorConfig> & - OnAuth & - CreateState & - CreateConnState & - CreateVars & - ActorDatabaseConfig; + BaseActorConfig< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase, + Actions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + > + > & + OnAuth & + CreateState< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + > & + CreateConnState< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + > & + CreateVars< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + > & + ActorDatabaseConfig; // See description on `ActorConfig` export type ActorConfigInput< - S, - CP, - CS, - V, - I, - AD, - DB extends AnyDatabaseProvider, - R extends Actions, -> = Omit< + TState = undefined, + TConnParams = undefined, + TConnState = undefined, + TVars = undefined, + TInput = undefined, + TAuthData = undefined, + TDatabase extends AnyDatabaseProvider = undefined, + TActions extends Actions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + > = Record, +> = { + types?: ActorTypes< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >; +} & Omit< z.input, | "actions" | "onAuth" @@ -464,34 +654,92 @@ export type ActorConfigInput< | "createVars" | "db" > & - BaseActorConfig & - OnAuth & - CreateState & - CreateConnState & - CreateVars & - ActorDatabaseConfig; + BaseActorConfig< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase, + TActions + > & + OnAuth & + CreateState< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + > & + CreateConnState< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + > & + CreateVars< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + > & + ActorDatabaseConfig; // For testing type definitions: export function test< - S, - CP, - CS, - V, - I, - AD, - DB extends AnyDatabaseProvider, - R extends Actions, + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase extends AnyDatabaseProvider, + TActions extends Actions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, >( - input: ActorConfigInput, -): ActorConfig { + input: ActorConfigInput< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase, + TActions + >, +): ActorConfig< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase +> { const config = ActorConfigSchema.parse(input) as ActorConfig< - S, - CP, - CS, - V, - I, - AD, - DB + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase >; return config; } diff --git a/packages/core/src/actor/context.ts b/packages/core/src/actor/context.ts index dcb24d964..b6238359d 100644 --- a/packages/core/src/actor/context.ts +++ b/packages/core/src/actor/context.ts @@ -10,24 +10,50 @@ import type { Schedule } from "./schedule"; /** * ActorContext class that provides access to actor methods and state */ -export class ActorContext { - #actor: ActorInstance; - - constructor(actor: ActorInstance) { +export class ActorContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase extends AnyDatabaseProvider, +> { + #actor: ActorInstance< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >; + + constructor( + actor: ActorInstance< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, + ) { this.#actor = actor; } /** * Get the actor state */ - get state(): S { + get state(): TState { return this.#actor.state; } /** * Get the actor variables */ - get vars(): V { + get vars(): TVars { return this.#actor.vars; } @@ -86,7 +112,10 @@ export class ActorContext { /** * Gets the map of connections. */ - get conns(): Map> { + get conns(): Map< + ConnId, + Conn + > { return this.#actor.conns; } @@ -102,7 +131,7 @@ export class ActorContext { * @experimental * @throws {DatabaseNotEnabled} If the database is not enabled. */ - get db(): InferDatabaseClient { + get db(): InferDatabaseClient { return this.#actor.db; } diff --git a/packages/core/src/actor/instance.ts b/packages/core/src/actor/instance.ts index 9b8f1c5f0..4c5a64c72 100644 --- a/packages/core/src/actor/instance.ts +++ b/packages/core/src/actor/instance.ts @@ -11,7 +11,7 @@ import type { UniversalWebSocket } from "@/common/websocket-interface"; import { ActorInspector } from "@/inspector/actor"; import type { Registry, RegistryConfig } from "@/mod"; import type { ActionContext } from "./action"; -import type { ActorConfig } from "./config"; +import type { ActorConfig, OnConnectOptions } from "./config"; import { Conn, type ConnId } from "./connection"; import { ActorContext } from "./context"; import type { AnyDatabaseProvider, InferDatabaseClient } from "./database"; @@ -630,7 +630,7 @@ export class ActorInstance< undefined, undefined >, - { input: persistData.i }, + persistData.i!, ); } else if ("state" in this.#config) { stateData = structuredClone(this.#config.state); @@ -656,9 +656,7 @@ export class ActorInstance< // Notify creation if (this.#config.onCreate) { - await this.#config.onCreate(this.actorContext, { - input: persistData.i, - }); + await this.#config.onCreate(this.actorContext, persistData.i!); } } } @@ -725,12 +723,12 @@ export class ActorInstance< const onBeforeConnectOpts = { request, - params, - }; + } satisfies OnConnectOptions; if (this.#config.onBeforeConnect) { await this.#config.onBeforeConnect( this.actorContext, + params, onBeforeConnectOpts, ); } @@ -747,6 +745,7 @@ export class ActorInstance< undefined, undefined >, + params, onBeforeConnectOpts, ); if (dataOrPromise instanceof Promise) { diff --git a/packages/core/src/actor/mod.ts b/packages/core/src/actor/mod.ts index 24c0c5dcd..a2ced24f7 100644 --- a/packages/core/src/actor/mod.ts +++ b/packages/core/src/actor/mod.ts @@ -3,30 +3,57 @@ import { type ActorConfig, type ActorConfigInput, ActorConfigSchema, + ActorTypes, } from "./config"; import type { AnyDatabaseProvider } from "./database"; import { ActorDefinition } from "./definition"; export function actor< - S, - CP, - CS, - V, - I, - AD, - DB extends AnyDatabaseProvider, - R extends Actions, + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase extends AnyDatabaseProvider, + TActions extends Actions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase + >, >( - input: ActorConfigInput, -): ActorDefinition { + input: ActorConfigInput< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase, + TActions + >, +): ActorDefinition< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase, + TActions +> { const config = ActorConfigSchema.parse(input) as ActorConfig< - S, - CP, - CS, - V, - I, - AD, - DB + TState, + TConnParams, + TConnState, + TVars, + TInput, + TAuthData, + TDatabase >; return new ActorDefinition(config); } diff --git a/packages/core/src/manager/auth.ts b/packages/core/src/manager/auth.ts index 8f890318c..0084482a9 100644 --- a/packages/core/src/manager/auth.ts +++ b/packages/core/src/manager/auth.ts @@ -71,10 +71,9 @@ export async function authenticateRequest( } try { - const dataOrPromise = actorDefinition.config.onAuth({ + const dataOrPromise = actorDefinition.config.onAuth(params, { request: c.req.raw, intents, - params, }); if (dataOrPromise instanceof Promise) { return await dataOrPromise;