From e409caab636503c43553f35ce82a424d84ed43c2 Mon Sep 17 00:00:00 2001 From: danielle korn Date: Sun, 6 Sep 2026 09:57:39 +0300 Subject: [PATCH 1/2] docs(actors): document the actors module to the standard of the other modules The actors page published as 18 lines: a truncated type signature, two sentences and one snippet. connect(), subscribe(), send(), close() and unsubscribe() did not appear at all. Adds a module overview covering what an Actor instance is, a capability list, the supported authentication modes, and the note that connections stay open until closed. Every public method now has a description, @param, @returns and at least one @example, and each example opens with a comment so the pipeline renders it as the code-block title. Cross-references use explicit same-page anchors such as [connect()](#connect). Every type on this page is appended into it, so {@link Connection.close} resolves to a file the pipeline then unlinks and would 404, while a bare {@link close} resolves to a working anchor and is kept. Plain code spans are used only where no heading exists (ActorNameRegistry, ActorSubscription) or where the reference would point at the section it already sits in. Every behavioural claim is checked against src/modules/actors.ts and src/client.ts rather than inferred. See the PR description for the line-by-line trace. --- src/modules/actors.types.ts | 184 ++++++++++++++++++++++++++++++------ 1 file changed, 156 insertions(+), 28 deletions(-) diff --git a/src/modules/actors.types.ts b/src/modules/actors.types.ts index 34efba77..e3219531 100644 --- a/src/modules/actors.types.ts +++ b/src/modules/actors.types.ts @@ -2,11 +2,12 @@ * Extend this interface to add typed `subscribe` callbacks and `send` payloads * for your deployed Actors. * - * This is separate from {@link ActorNameRegistry} (which is auto-generated + * This is separate from `ActorNameRegistry` (which is auto-generated * by `base44 types generate`), so there are no conflicts. * * @example * ```typescript + * // Declare message types for a deployed actor * declare module "@base44/sdk" { * interface ActorRegistry { * ChatRoom: { @@ -21,7 +22,7 @@ export interface ActorRegistry {} /** * Auto-populated by `base44 types generate` with the names of your deployed actors. - * Do not edit this interface manually. Use {@link ActorRegistry} for message types. + * Do not edit this interface manually. Use `ActorRegistry` for message types. */ export interface ActorNameRegistry {} @@ -39,83 +40,210 @@ type ToServerFor = N extends keyof ActorRegistry : unknown : unknown; -/** Options for {@link ActorRef.connect}. */ +/** Options for [connect()](#connect). */ export interface ActorConnectOptions { /** - * The connection id, used as the actor's `conn.id`. Supply a stable value - * (e.g. persisted per tab) so a reconnect reuses the same server-side - * identity; omit for an auto-generated per-connection id. + * The connection id, used as the actor's `conn.id`. Supply a stable value, + * such as one persisted per tab, so a reconnect reuses the same server-side + * identity. Omit it for an auto-generated per-connection id. */ id?: string; } -/** Handle for one listener registered via {@link Connection.subscribe}. */ +/** Handle for one listener registered via `subscribe()`. */ export interface ActorSubscription { - /** Remove this listener; other listeners and the socket stay live. */ + /** + * Removes this listener. Other listeners on the same connection, and the + * connection itself, stay live. To close the connection as well, call + * [close()](#close). + * + * @example + * ```typescript + * // Stop listening without closing the connection + * const sub = conn.subscribe((msg) => console.log(msg)); + * sub.unsubscribe(); + * ``` + */ unsubscribe(): void; } /** - * A live connection to an actor instance, returned by {@link ActorRef.connect}. + * A live connection to an actor instance, returned by [connect()](#connect). * `subscribe`/`send` are always valid. You only get a `Connection` once the * socket has been opened, so there's no pre-connect state to guard against. */ export interface Connection { - /** The connection id (the value the actor sees as `conn.id`). */ + /** The connection id, which is the value the actor sees as `conn.id`. */ readonly id: string; - /** Register a message listener. Multiple are allowed; returns a per-listener unsubscribe. */ + /** + * Registers a listener for messages sent by the actor. Any number of + * listeners can be registered on one connection, and each receives every + * message. + * + * The callback payload is typed when the actor is declared in + * [ActorRegistry](#actorregistry), and is `unknown` otherwise. + * + * @param callback - Called with each message the actor sends to this client. + * @returns An `ActorSubscription` that removes this one listener. + * + * @example + * ```typescript + * // Listen for messages from the actor + * const sub = conn.subscribe((msg) => { + * if (msg.type === "message") console.log(msg.text); + * }); + * ``` + */ subscribe(callback: (data: ToClientFor) => void): ActorSubscription; - /** Send a message. Buffered by the socket until it's open; dropped after - * {@link close}. */ + /** + * Sends a message to the actor. + * + * Messages sent before the socket finishes opening are buffered and flushed + * on open. Messages sent after {@link close} are dropped silently. + * + * The payload is typed when the actor is declared in + * [ActorRegistry](#actorregistry), and is `unknown` otherwise. + * + * @param data - The message to send to the actor. + * + * @example + * ```typescript + * // Send a message to the actor + * conn.send({ type: "message", text: "hi" }); + * ``` + */ send(data: ToServerFor): void; /** - * Tear down the socket, heartbeat, and all listeners. Safe to call more - * than once. A connection also closes itself when it fails permanently. - * See {@link ActorRef.connect}. + * Closes the connection, tearing down the socket, the heartbeat, and every + * listener registered on it. Safe to call more than once. + * + * A connection also closes itself when it fails permanently. See + * [connect()](#connect) for how to recover from that. + * + * @example + * ```typescript + * // Close when the view that opened the connection goes away. + * useEffect(() => { + * const conn = base44.actors.ChatRoom(roomId).connect(); + * conn.subscribe(setMessage); + * return () => conn.close(); + * }, [roomId]); + * ``` */ close(): void; } /** * A handle to one actor instance, obtained from `base44.actors.MyActor(id)`. Call - * {@link connect} to open the socket and get a {@link Connection}. + * {@link connect} to open the socket and get a [Connection](#connection). */ export interface ActorRef { /** - * Open the WebSocket and return the {@link Connection}. Idempotent while the - * connection is open. + * Opens the WebSocket to this actor instance and returns the + * [Connection](#connection). Idempotent while the connection is open, so calling it + * again returns the same connection rather than opening a second socket. + * + * The returned connection is usable straight away. Messages passed to + * [send()](#send) before the socket finishes opening are buffered and + * flushed on open. + * + * A connection that fails permanently, for example because the actor doesn't + * exist or the caller isn't allowed to connect, closes itself and reports the + * error to the client's `onError` handler. Call `connect()` again once the + * cause is fixed to get a fresh [Connection](#connection), then re-subscribe, as + * listeners do not carry over. + * + * @param options - Connection options. See [ActorConnectOptions](#actorconnectoptions). + * @returns A live [Connection](#connection) to this actor instance. + * + * @example + * ```typescript + * // Connect to an actor instance + * const conn = base44.actors.ChatRoom("room-1").connect(); + * ``` + * + * @example + * ```typescript + * // Reuse a stable connection id so a reconnect keeps the same + * // server-side identity. + * let id = sessionStorage.getItem("chat-conn-id") ?? crypto.randomUUID(); + * sessionStorage.setItem("chat-conn-id", id); * - * A connection that fails permanently (for example, the actor doesn't exist - * or the caller isn't allowed to connect) closes itself and reports the - * error to the client's `onError` handler. Call `connect()` again after - * fixing the cause to get a fresh {@link Connection}, and re-subscribe. + * const conn = base44.actors.ChatRoom("room-1").connect({ id }); + * ``` */ connect(options?: ActorConnectOptions): Connection; } /** * Client for a single named Actor. Call it with an instance id to get an - * {@link ActorRef}. Typed automatically when the actor is registered in - * {@link ActorRegistry}. + * [ActorRef](#actorref). Typed automatically when the actor is registered in + * [ActorRegistry](#actorregistry). */ export interface ActorClient { (instanceId: string): ActorRef; } /** - * The actors module provides access to Cloudflare Durable Object-backed + * Actors module for real-time messaging with Cloudflare Durable Object-backed * Actors deployed by the Base44 platform. * + * An Actor is a named server-side object with persistent state. Each instance + * is addressed by an id, so `base44.actors.ChatRoom("room-1")` and + * `base44.actors.ChatRoom("room-2")` are separate instances with separate + * state. Clients open a WebSocket to an instance and exchange messages with it. + * + * This module provides: + * - Per-instance WebSocket connections, opened with [connect()](#connect) + * - Message listeners, registered with [subscribe()](#subscribe) + * - Message sending, with [send()](#send) + * - Automatic reconnection with backoff, including recovery from half-open + * sockets that stop delivering messages without emitting a close event + * - End-to-end typing of message payloads through [ActorRegistry](#actorregistry) + * + * This module is available to use with a client in anonymous and user + * authentication modes. It is not available on `base44.asServiceRole`. + * + * Connections stay open until you call [close()](#close), so close them + * when the view that opened them goes away. + * + * @example * ```typescript - * const conn = base44.actors.MyActor("room-1").connect(); - * const sub = conn.subscribe((msg) => console.log(msg)); // typed via ActorRegistry + * // Open a connection to one instance of the ChatRoom actor. + * const conn = base44.actors.ChatRoom("room-1").connect(); + * + * const sub = conn.subscribe((msg) => { + * console.log(msg); + * }); + * * conn.send({ type: "message", text: "hi" }); + * + * // Later, when the view goes away. * sub.unsubscribe(); * conn.close(); * ``` + * + * @example + * ```typescript + * // Register the actor to type both directions of the conversation. + * declare module "@base44/sdk" { + * interface ActorRegistry { + * ChatRoom: { + * toClient: { type: "joined" | "message"; from?: string; text?: string }; + * toServer: { type: "message"; text: string }; + * }; + * } + * } + * + * const conn = base44.actors.ChatRoom("room-1").connect(); + * conn.subscribe((msg) => { + * // msg is typed as the toClient union. + * if (msg.type === "message") console.log(msg.text); + * }); + * ``` */ export type ActorsModule = { [K in AllActorNames]: K extends keyof ActorRegistry From e0764c251e3654eba2a302fe58cce99dfba14690 Mon Sep 17 00:00:00 2001 From: danielle korn Date: Sun, 6 Sep 2026 09:57:39 +0300 Subject: [PATCH 2/2] fix(docs-gen): publish the actor types on the actors page ActorRef, Connection, ActorConnectOptions and ActorRegistry were absent from types-to-expose.json, so every method on the actors module was stripped before rendering and the page had nowhere to put them. Exposes them and appends them into the actors page, matching how connectors and entities carry their supporting types, so the nav keeps listing only modules. ActorSubscription and ActorClient stay unexposed: ActorSubscription already renders inline as the return type of subscribe() and appending it too produced a duplicate unsubscribe() section. Also drops the actors suppression added while the JSDoc was missing. --- .../mintlify-post-processing/appended-articles.json | 10 +++++++++- .../types-to-delete-after-processing.json | 1 - scripts/mintlify-post-processing/types-to-expose.json | 7 ++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/mintlify-post-processing/appended-articles.json b/scripts/mintlify-post-processing/appended-articles.json index 37180997..46cbcd67 100644 --- a/scripts/mintlify-post-processing/appended-articles.json +++ b/scripts/mintlify-post-processing/appended-articles.json @@ -7,7 +7,9 @@ "interfaces/ConnectorApiResponse", "type-aliases/ConnectorApiResponsePhase" ], - "interfaces/AppModule": ["interfaces/AppPublicSettingsResponse"], + "interfaces/AppModule": [ + "interfaces/AppPublicSettingsResponse" + ], "type-aliases/EntitiesModule": [ "interfaces/EntityHandler", "type-aliases/EntityRecord", @@ -25,5 +27,11 @@ "type-aliases/integrations": [ "interfaces/CoreIntegrations", "interfaces/CustomIntegrationsModule" + ], + "type-aliases/ActorsModule": [ + "interfaces/ActorRef", + "interfaces/Connection", + "interfaces/ActorConnectOptions", + "interfaces/ActorRegistry" ] } diff --git a/scripts/mintlify-post-processing/types-to-delete-after-processing.json b/scripts/mintlify-post-processing/types-to-delete-after-processing.json index 247c3b9e..5083520f 100644 --- a/scripts/mintlify-post-processing/types-to-delete-after-processing.json +++ b/scripts/mintlify-post-processing/types-to-delete-after-processing.json @@ -1,5 +1,4 @@ [ - "actors", "AiGatewayConnection", "DeleteManyResult", "DeleteResult", diff --git a/scripts/mintlify-post-processing/types-to-expose.json b/scripts/mintlify-post-processing/types-to-expose.json index 5d7ef016..8ef88015 100644 --- a/scripts/mintlify-post-processing/types-to-expose.json +++ b/scripts/mintlify-post-processing/types-to-expose.json @@ -1,4 +1,8 @@ [ + "ActorConnectOptions", + "ActorRef", + "ActorRegistry", + "ActorsModule", "AgentName", "AgentNameRegistry", "AgentsModule", @@ -9,12 +13,14 @@ "AppModule", "AppPublicSettingsResponse", "AuthModule", + "Connection", "ConnectorApiRequest", "ConnectorApiResponse", "ConnectorApiResponsePhase", "ConnectorIntegrationType", "ConnectorIntegrationTypeRegistry", "ConnectorsModule", + "CoreIntegrations", "CustomIntegrationsModule", "DeleteManyResult", "DeleteResult", @@ -27,7 +33,6 @@ "FunctionsModule", "ImportResult", "IntegrationsModule", - "CoreIntegrations", "SortField", "SsoModule", "UpdateManyResult"