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
65 changes: 37 additions & 28 deletions packages/core/src/actor/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,40 @@ type CreateVars<S, CP, CS, V, I, AD, DB> =
}
| Record<never, never>;

// Creates auth config
//
// This must have only one or the other or else AD will not be able to be inferred
type OnAuth<CP, AD> =
| {
/**
* Called on the HTTP server before clients can interact with the actor.
*
* Only called for public endpoints. Calls to actors from within the backend
* do not trigger this handler.
*
* Data returned from this handler will be available on `c.conn.auth`.
*
* This function is required for any public HTTP endpoint access. Use this hook
* to validate client credentials and return authentication data that will be
* available on connections. This runs on the HTTP server (not the actor)
* in order to reduce load on the actor & prevent denial of server attacks
* against individual actors.
*
* If you need access to actor state for authentication, use onBeforeConnect
* with an empty onAuth function instead.
*
* You can also provide your own authentication middleware on your router if you
* choose, then use onAuth to pass the authentication data (e.g. user ID) to the
* actor itself.
*
* @param opts Authentication options including request and intent
* @returns Authentication data to attach to connections (must be serializable)
* @throws Throw an error to deny access to the actor
*/
onAuth: (opts: OnAuthOptions<CP>) => AD | Promise<AD>;
}
| Record<never, never>;

export interface Actions<S, CP, CS, V, I, AD, DB> {
[Action: string]: (
c: ActionContext<S, CP, CS, V, I, AD, DB>,
Expand All @@ -189,7 +223,7 @@ export interface Actions<S, CP, CS, V, I, AD, DB> {
*/
export type AuthIntent = "get" | "create" | "connect" | "action" | "message";

interface OnAuthOptions<CP> {
export interface OnAuthOptions<CP = unknown> {
req: Request;
/**
* @experimental
Expand All @@ -208,33 +242,6 @@ interface BaseActorConfig<
DB,
R extends Actions<S, CP, CS, V, I, AD, DB>,
> {
/**
* Called on the HTTP server before clients can interact with the actor.
*
* Only called for public endpoints. Calls to actors from within the backend
* do not trigger this handler.
*
* Data returned from this handler will be available on `c.conn.auth`.
*
* This function is required for any public HTTP endpoint access. Use this hook
* to validate client credentials and return authentication data that will be
* available on connections. This runs on the HTTP server (not the actor)
* in order to reduce load on the actor & prevent denial of server attacks
* against individual actors.
*
* If you need access to actor state for authentication, use onBeforeConnect
* with an empty onAuth function instead.
*
* You can also provide your own authentication middleware on your router if you
* choose, then use onAuth to pass the authentication data (e.g. user ID) to the
* actor itself.
*
* @param opts Authentication options including request and intent
* @returns Authentication data to attach to connections (must be serializable)
* @throws Throw an error to deny access to the actor
*/
onAuth?: (opts: OnAuthOptions<CP>) => AD | Promise<AD>;

/**
* Called when the actor is first initialized.
*
Expand Down Expand Up @@ -389,6 +396,7 @@ export type ActorConfig<S, CP, CS, V, I, AD, DB> = Omit<
| "db"
> &
BaseActorConfig<S, CP, CS, V, I, AD, DB, Actions<S, CP, CS, V, I, AD, DB>> &
OnAuth<CP, AD> &
CreateState<S, CP, CS, V, I, AD, DB> &
CreateConnState<S, CP, CS, V, I, AD, DB> &
CreateVars<S, CP, CS, V, I, AD, DB> &
Expand Down Expand Up @@ -424,6 +432,7 @@ export type ActorConfigInput<
| "db"
> &
BaseActorConfig<S, CP, CS, V, I, AD, DB, R> &
OnAuth<CP, AD> &
CreateState<S, CP, CS, V, I, AD, DB> &
CreateConnState<S, CP, CS, V, I, AD, DB> &
CreateVars<S, CP, CS, V, I, AD, DB> &
Expand Down
24 changes: 12 additions & 12 deletions packages/core/src/actor/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,6 @@ import {
} from "./config";
import { ActorDefinition } from "./definition";

export type { ActorContext } from "./context";
export { UserError, type UserErrorOptions } from "./errors";
export type { Conn } from "./connection";
export type { ActionContext } from "./action";
export type { ActorConfig, OnConnectOptions } from "./config";
export type { Encoding } from "@/actor/protocol/serde";
export type {
ActorDefinition,
AnyActorDefinition,
ActorContextOf,
ActionContextOf,
} from "./definition";

export function actor<
S,
Expand All @@ -43,3 +31,15 @@ export function actor<
return new ActorDefinition(config);
}
export type { ActorKey } from "@/manager/protocol/query";
export type { ActorContext } from "./context";
export { UserError, type UserErrorOptions } from "./errors";
export type { Conn } from "./connection";
export type { ActionContext } from "./action";
export type * from "./config";
export type { Encoding } from "@/actor/protocol/serde";
export type {
ActorDefinition,
AnyActorDefinition,
ActorContextOf,
ActionContextOf,
} from "./definition";
2 changes: 1 addition & 1 deletion packages/core/src/manager/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export async function authenticateRequest(
intents: Set<AuthIntent>,
params: unknown,
): Promise<unknown> {
if (!actorDefinition.config.onAuth) {
if (!("onAuth" in actorDefinition.config)) {
throw new errors.Forbidden(
"Actor requires authentication but no onAuth handler is defined",
);
Expand Down
Loading