From 491c300a1fc85657b81e39f38a41e85b0719b87d Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Mon, 21 Sep 2026 23:52:20 -0400 Subject: [PATCH 01/24] docs(actors): update JSDoc for actors SDK module Rewrites JSDoc across actors.types.ts to align with established terminology and writing style: session vs instance, client vs page, incoming/outgoing message direction, and full @param/@returns/@example coverage on all public methods. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../appended-articles.json | 9 + .../typedoc-mintlify-content.js | 2 +- .../types-to-expose.json | 8 + src/actor.ts | 4 +- src/modules/actors.types.ts | 169 ++++++++++++++---- 5 files changed, 152 insertions(+), 40 deletions(-) diff --git a/scripts/mintlify-post-processing/appended-articles.json b/scripts/mintlify-post-processing/appended-articles.json index 27fb69b8..5bc68c3b 100644 --- a/scripts/mintlify-post-processing/appended-articles.json +++ b/scripts/mintlify-post-processing/appended-articles.json @@ -18,6 +18,15 @@ "type-aliases/AgentName", "interfaces/AgentNameRegistry" ], + "type-aliases/ActorsModule": [ + "interfaces/ActorRef", + "interfaces/Connection", + "interfaces/ActorConnectOptions", + "interfaces/ActorSubscription", + "interfaces/ActorClient", + "interfaces/ActorRegistry", + "interfaces/ActorNameRegistry" + ], "type-aliases/integrations": [ "interfaces/CoreIntegrations", "interfaces/CustomIntegrationsModule" diff --git a/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-content.js b/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-content.js index 6bf1e0ac..a4b5d004 100644 --- a/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-content.js +++ b/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-content.js @@ -45,7 +45,7 @@ export function convertExamplesToCodeGroup(content) { const exampleSectionRegex = /^(#{2,4})\s+(Example|Examples)\s*$([\s\S]*?)(?=^#{2,4}\s|\n<\/ResponseField>|\n\*\*\*|$(?!\n))/gm; return content.replace(exampleSectionRegex, (match, headingLevel, exampleHeading, exampleContent) => { - const codeBlockRegex = /```([\w-]*)\s*([^\n]*)\n([\s\S]*?)```/g; + const codeBlockRegex = /```([\w-]*)[ \t]*([^\n]*)\n([\s\S]*?)```/g; const examples = []; let codeMatch; diff --git a/scripts/mintlify-post-processing/types-to-expose.json b/scripts/mintlify-post-processing/types-to-expose.json index 5d7ef016..3ac0b660 100644 --- a/scripts/mintlify-post-processing/types-to-expose.json +++ b/scripts/mintlify-post-processing/types-to-expose.json @@ -1,4 +1,12 @@ [ + "ActorClient", + "ActorConnectOptions", + "ActorNameRegistry", + "ActorRef", + "ActorRegistry", + "ActorSubscription", + "ActorsModule", + "Connection", "AgentName", "AgentNameRegistry", "AgentsModule", diff --git a/src/actor.ts b/src/actor.ts index 153224cd..c4c893bc 100644 --- a/src/actor.ts +++ b/src/actor.ts @@ -28,8 +28,8 @@ export interface Storage { get(key: string): Promise; put(key: string, value: unknown): Promise; delete(key: string): Promise; - /** Wipe the room's entire persisted storage (match-end cleanup). Safe: a - * later rejoin re-bootstraps exactly like a brand-new room. */ + /** Wipe the session's entire persisted storage. A later connection starts + * with the same empty storage as a new session. */ deleteAll(): Promise; } diff --git a/src/modules/actors.types.ts b/src/modules/actors.types.ts index bb55bbed..3b0d4d86 100644 --- a/src/modules/actors.types.ts +++ b/src/modules/actors.types.ts @@ -1,9 +1,10 @@ /** - * Extend this interface to add typed `subscribe` callbacks and `send` payloads - * for your deployed Actors. + * Maps actor names to their incoming and outgoing message types. * - * This is separate from {@link ActorNameRegistry} (which is auto-generated - * by `base44 types generate`), so there are no conflicts. + * Extend this interface through module augmentation when you want typed actor + * messages without generating types with the CLI. For each actor, `toServer` + * defines incoming messages that a client sends to the actor. `toClient` defines + * outgoing messages that the actor sends to connected clients. * * @example * ```typescript @@ -20,8 +21,10 @@ 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. + * Lists actor names when your project includes types generated by the CLI. + * + * The generated names provide autocomplete for deployed actors. To define + * incoming and outgoing message types manually, augment {@link ActorRegistry}. */ export interface ActorNameRegistry {} @@ -39,79 +42,171 @@ type ToServerFor = N extends keyof ActorRegistry : unknown : unknown; -/** Options for {@link ActorRef.connect}. */ +/** + * Options for {@link ActorRef.connect}. + */ export interface ActorConnectOptions { /** - * The connection id — becomes 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. + * Connection ID that the actor receives as `conn.id`. + * + * Specify a stable value, such as a value persisted per client, so + * reconnections from that client reuse the same connection ID. Omit this property + * to generate an ID. */ id?: string; } -/** Handle for one listener registered via {@link Connection.subscribe}. */ +/** + * Represents an outgoing-message listener registered with + * {@link Connection.subscribe}. + */ export interface ActorSubscription { - /** Remove this listener; other listeners and the socket stay live. */ + /** + * Removes this listener. Other listeners and the socket stay open. + * + * @example + * ```typescript + * const sub = conn.subscribe((msg) => console.log(msg)); + * sub.unsubscribe(); + * ``` + */ unsubscribe(): void; } /** - * A live connection to an actor instance, returned by {@link ActorRef.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. + * Represents a client's WebSocket connection to an actor session. + * + * {@link ActorRef.connect} returns this object while the socket connects. + * The socket buffers messages sent during connection setup until it opens. */ export interface Connection { - /** The connection id (the value the actor sees as `conn.id`). */ + /** Connection ID that the actor receives as `conn.id`. */ readonly id: string; - /** Register a message listener. Multiple are allowed; returns a per-listener unsubscribe. */ + /** + * Registers a listener for outgoing messages from the actor. + * + * You can register multiple listeners on the same connection. + * + * @param callback - Called with each outgoing message sent to this connection. + * @returns A handle you can use to remove this listener without closing the socket. + * + * @example + * ```typescript + * const conn = base44.actors.Chat("session-1").connect(); + * 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 an incoming message to the actor. + * + * The socket buffers messages until it opens. After {@link close}, the socket + * drops further sends. + * + * @param data - Incoming message to send. Typed through {@link ActorRegistry} when configured. + * + * @example + * ```typescript + * conn.send({ type: "message", text: "Hello" }); + * ``` + */ 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 and removes all listeners. + * + * Safe to call more than once. A connection also closes itself when it fails + * permanently. See {@link ActorRef.connect} for how to open a fresh connection. + * + * @example + * ```typescript + * conn.close(); + * ``` */ close(): void; } /** - * A handle to one actor instance — `base44.actors.MyActor(id)`. Call - * {@link connect} to open the socket and get a {@link Connection}. + * Represents an actor session selected by actor name and session ID. + * + * Call {@link connect} to open the WebSocket and get a {@link Connection}. */ export interface ActorRef { /** - * Open the WebSocket and return the {@link Connection}. Idempotent while the - * connection is open. + * Creates or returns the {@link Connection} for this session. + * + * Repeated calls return the same connection until it closes. After a permanent + * failure, such as a missing actor or denied connection, fix the cause and call + * `connect()` again. Add subscriptions to the new connection. * - * 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. + * @param options - Optional connection settings, such as a stable connection ID. + * @returns The {@link Connection} for this actor session. + * + * @example + * ```typescript + * const conn = base44.actors.Chat("session-1").connect({ id: "tab-abc" }); + * conn.subscribe((msg) => console.log(msg)); + * ``` */ 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}. + * Selects a session for a named actor. + * + * Typed automatically when the actor is registered in {@link ActorRegistry} or + * {@link ActorNameRegistry}. */ export interface ActorClient { + /** + * Gets a reference to an actor session. + * + * Clients that specify the same actor name and session ID join the same session. + * + * @param instanceId - Session ID that identifies which session to connect to. + * @returns A reference to the actor session. + * + * @example + * ```typescript + * const session = base44.actors.Chat("lobby-1"); + * const conn = session.connect(); + * ``` + */ (instanceId: string): ActorRef; } /** - * The actors module provides access to Cloudflare Durable Object-backed - * Actors deployed by the Base44 platform. + * Provides access to actors and their shared, live sessions. + * + * Select an actor by name and session ID, then connect a client to the + * session. Clients in the same session can exchange realtime messages through the + * actor. The client works in the browser and in Node. + * + * ## Connection flow + * + * - Connect to a session with `base44.actors.(sessionId).connect()`. + * - Subscribe to outgoing messages with {@link Connection.subscribe}. + * - Send incoming messages with {@link Connection.send}. + * - Close the connection with {@link Connection.close}. * + * See [Actors Overview](/developers/backend/resources/actors/overview) + * for actor concepts and terminology, and the [Actor Class Reference](/developers/backend/resources/actors/reference) + * for the backend class API. + * + * ## Authentication modes + * + * This module is available in anonymous or user authentication mode + * (`base44.actors`). It isn't available with service role authentication. Apps that + * require login can reject anonymous connections in the actor's `handleConnect()` method. + * + * @example * ```typescript - * const conn = base44.actors.MyActor("room-1").connect(); - * const sub = conn.subscribe((msg) => console.log(msg)); // typed via ActorRegistry + * const conn = base44.actors.Chat("session-1").connect({ id: "tab-1" }); + * const sub = conn.subscribe((msg) => console.log(msg)); * conn.send({ type: "message", text: "hi" }); * sub.unsubscribe(); * conn.close(); From 3f15267cc18023e46a553e32db709bd3d22227d6 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Mon, 21 Sep 2026 23:55:34 -0400 Subject: [PATCH 02/24] revert: remove pipeline script changes from actors JSDoc PR Co-Authored-By: Claude Sonnet 4.6 (1M context) --- scripts/mintlify-post-processing/appended-articles.json | 9 --------- .../typedoc-plugin/typedoc-mintlify-content.js | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/scripts/mintlify-post-processing/appended-articles.json b/scripts/mintlify-post-processing/appended-articles.json index 5bc68c3b..27fb69b8 100644 --- a/scripts/mintlify-post-processing/appended-articles.json +++ b/scripts/mintlify-post-processing/appended-articles.json @@ -18,15 +18,6 @@ "type-aliases/AgentName", "interfaces/AgentNameRegistry" ], - "type-aliases/ActorsModule": [ - "interfaces/ActorRef", - "interfaces/Connection", - "interfaces/ActorConnectOptions", - "interfaces/ActorSubscription", - "interfaces/ActorClient", - "interfaces/ActorRegistry", - "interfaces/ActorNameRegistry" - ], "type-aliases/integrations": [ "interfaces/CoreIntegrations", "interfaces/CustomIntegrationsModule" diff --git a/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-content.js b/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-content.js index a4b5d004..6bf1e0ac 100644 --- a/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-content.js +++ b/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-content.js @@ -45,7 +45,7 @@ export function convertExamplesToCodeGroup(content) { const exampleSectionRegex = /^(#{2,4})\s+(Example|Examples)\s*$([\s\S]*?)(?=^#{2,4}\s|\n<\/ResponseField>|\n\*\*\*|$(?!\n))/gm; return content.replace(exampleSectionRegex, (match, headingLevel, exampleHeading, exampleContent) => { - const codeBlockRegex = /```([\w-]*)[ \t]*([^\n]*)\n([\s\S]*?)```/g; + const codeBlockRegex = /```([\w-]*)\s*([^\n]*)\n([\s\S]*?)```/g; const examples = []; let codeMatch; From 2877d2df67fae839705240157e8457f01c34c1aa Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 23 Sep 2026 00:33:49 -0400 Subject: [PATCH 03/24] docs(actors): align JSDoc with docs terminology and add cross-links - Use 'session' consistently instead of 'instance' throughout descriptions - Replace implementation-focused comments with developer-facing language - Add links to sample flows, overview concepts, and types generate CLI command - Simplify field and method descriptions per style guide Co-Authored-By: Claude Sonnet 4.6 (1M context) --- src/modules/actors.types.ts | 67 ++++++++++++++----------------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/src/modules/actors.types.ts b/src/modules/actors.types.ts index 3b0d4d86..07e42f3a 100644 --- a/src/modules/actors.types.ts +++ b/src/modules/actors.types.ts @@ -6,6 +6,11 @@ * defines incoming messages that a client sends to the actor. `toClient` defines * outgoing messages that the actor sends to connected clients. * + * To generate types from deployed actors instead, use the + * [`types generate`](/developers/references/cli/commands/types-generate) CLI command. + * See [Typing messages in the client](/developers/backend/resources/actors/overview#typing-messages-in-the-client) + * for how to define your message types. + * * @example * ```typescript * declare module "@base44/sdk" { @@ -21,7 +26,8 @@ export interface ActorRegistry {} /** - * Lists actor names when your project includes types generated by the CLI. + * Lists actor names when your project includes types generated by the CLI + * with [`types generate`](/developers/references/cli/commands/types-generate). * * The generated names provide autocomplete for deployed actors. To define * incoming and outgoing message types manually, augment {@link ActorRegistry}. @@ -49,9 +55,11 @@ export interface ActorConnectOptions { /** * Connection ID that the actor receives as `conn.id`. * - * Specify a stable value, such as a value persisted per client, so - * reconnections from that client reuse the same connection ID. Omit this property - * to generate an ID. + * Use a stable value, such as one stored per browser tab, so the actor + * can recognize the same client if it reconnects. If omitted, the SDK generates one. + * + * See [Connection ID](/developers/backend/resources/actors/overview#connection-id) + * for more details. */ id?: string; } @@ -63,12 +71,6 @@ export interface ActorConnectOptions { export interface ActorSubscription { /** * Removes this listener. Other listeners and the socket stay open. - * - * @example - * ```typescript - * const sub = conn.subscribe((msg) => console.log(msg)); - * sub.unsubscribe(); - * ``` */ unsubscribe(): void; } @@ -90,14 +92,6 @@ export interface Connection { * * @param callback - Called with each outgoing message sent to this connection. * @returns A handle you can use to remove this listener without closing the socket. - * - * @example - * ```typescript - * const conn = base44.actors.Chat("session-1").connect(); - * const sub = conn.subscribe((msg) => { - * if (msg.type === "message") console.log(msg.text); - * }); - * ``` */ subscribe(callback: (data: ToClientFor) => void): ActorSubscription; @@ -108,11 +102,6 @@ export interface Connection { * drops further sends. * * @param data - Incoming message to send. Typed through {@link ActorRegistry} when configured. - * - * @example - * ```typescript - * conn.send({ type: "message", text: "Hello" }); - * ``` */ send(data: ToServerFor): void; @@ -121,11 +110,6 @@ export interface Connection { * * Safe to call more than once. A connection also closes itself when it fails * permanently. See {@link ActorRef.connect} for how to open a fresh connection. - * - * @example - * ```typescript - * conn.close(); - * ``` */ close(): void; } @@ -143,14 +127,11 @@ export interface ActorRef { * failure, such as a missing actor or denied connection, fix the cause and call * `connect()` again. Add subscriptions to the new connection. * + * See [Connect a client to a session](/developers/backend/resources/actors/samples#connect-a-client-to-a-session) + * for a sample flow. + * * @param options - Optional connection settings, such as a stable connection ID. * @returns The {@link Connection} for this actor session. - * - * @example - * ```typescript - * const conn = base44.actors.Chat("session-1").connect({ id: "tab-abc" }); - * conn.subscribe((msg) => console.log(msg)); - * ``` */ connect(options?: ActorConnectOptions): Connection; } @@ -169,12 +150,6 @@ export interface ActorClient { * * @param instanceId - Session ID that identifies which session to connect to. * @returns A reference to the actor session. - * - * @example - * ```typescript - * const session = base44.actors.Chat("lobby-1"); - * const conn = session.connect(); - * ``` */ (instanceId: string): ActorRef; } @@ -194,8 +169,16 @@ export interface ActorClient { * - Close the connection with {@link Connection.close}. * * See [Actors Overview](/developers/backend/resources/actors/overview) - * for actor concepts and terminology, and the [Actor Class Reference](/developers/backend/resources/actors/reference) - * for the backend class API. + * for actor concepts and terminology, [Actor Class Reference](/developers/backend/resources/actors/reference) + * for the backend class API, and [Sample Flows](/developers/backend/resources/actors/samples) + * for common patterns. + * + * ## See also + * + * - [Actors Overview](/developers/backend/resources/actors/overview) — Actor concepts, sessions, message types, storage, and timers + * - [Actor Class Reference](/developers/backend/resources/actors/reference) — Backend class API + * - [Sample Flows](/developers/backend/resources/actors/samples) — Connect a client, run ticks, schedule wakes, and persist data + * - [`types generate`](/developers/references/cli/commands/types-generate) — Generate TypeScript types from deployed actors * * ## Authentication modes * From c13a506cc24ad414bc7f00f7fa64f13c92c5bfc8 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 23 Sep 2026 00:43:29 -0400 Subject: [PATCH 04/24] docs(actors): append actor and connector helper types into their host pages Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../appended-articles.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/mintlify-post-processing/appended-articles.json b/scripts/mintlify-post-processing/appended-articles.json index 27fb69b8..e3a9a330 100644 --- a/scripts/mintlify-post-processing/appended-articles.json +++ b/scripts/mintlify-post-processing/appended-articles.json @@ -2,7 +2,10 @@ "interfaces/ConnectorsModule": [ "type-aliases/ConnectorIntegrationType", "interfaces/ConnectorIntegrationTypeRegistry", - "interfaces/UserConnectorsModule" + "interfaces/UserConnectorsModule", + "interfaces/ConnectorApiRequest", + "interfaces/ConnectorApiResponse", + "type-aliases/ConnectorApiResponsePhase" ], "type-aliases/EntitiesModule": [ "interfaces/EntityHandler", @@ -21,5 +24,14 @@ "type-aliases/integrations": [ "interfaces/CoreIntegrations", "interfaces/CustomIntegrationsModule" + ], + "type-aliases/ActorsModule": [ + "interfaces/ActorRef", + "interfaces/Connection", + "interfaces/ActorConnectOptions", + "interfaces/ActorSubscription", + "interfaces/ActorClient", + "interfaces/ActorRegistry", + "interfaces/ActorNameRegistry" ] } From 745b44ba090ce3c9802adb848b5af82f1d04286b Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 23 Sep 2026 00:46:12 -0400 Subject: [PATCH 05/24] docs(actors): remove See also section from ActorsModule JSDoc Co-Authored-By: Claude Sonnet 4.6 (1M context) --- src/modules/actors.types.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/modules/actors.types.ts b/src/modules/actors.types.ts index 07e42f3a..4cc52990 100644 --- a/src/modules/actors.types.ts +++ b/src/modules/actors.types.ts @@ -173,13 +173,6 @@ export interface ActorClient { * for the backend class API, and [Sample Flows](/developers/backend/resources/actors/samples) * for common patterns. * - * ## See also - * - * - [Actors Overview](/developers/backend/resources/actors/overview) — Actor concepts, sessions, message types, storage, and timers - * - [Actor Class Reference](/developers/backend/resources/actors/reference) — Backend class API - * - [Sample Flows](/developers/backend/resources/actors/samples) — Connect a client, run ticks, schedule wakes, and persist data - * - [`types generate`](/developers/references/cli/commands/types-generate) — Generate TypeScript types from deployed actors - * * ## Authentication modes * * This module is available in anonymous or user authentication mode From 9528fe67b80b8ca8a77541a31e1692b5c2ef7f58 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 23 Sep 2026 00:47:23 -0400 Subject: [PATCH 06/24] docs(actors): link auth modes section to manage client connections sample Co-Authored-By: Claude Sonnet 4.6 (1M context) --- src/modules/actors.types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/actors.types.ts b/src/modules/actors.types.ts index 4cc52990..8a61b6e7 100644 --- a/src/modules/actors.types.ts +++ b/src/modules/actors.types.ts @@ -178,6 +178,8 @@ export interface ActorClient { * This module is available in anonymous or user authentication mode * (`base44.actors`). It isn't available with service role authentication. Apps that * require login can reject anonymous connections in the actor's `handleConnect()` method. + * See [Manage client connections](/developers/backend/resources/actors/samples#manage-client-connections) + * for a sample flow. * * @example * ```typescript From f8c0a448311c08f9d783f10201c63c97ce01dc81 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 23 Sep 2026 00:51:05 -0400 Subject: [PATCH 07/24] docs(actors): fix broken links and improve ActorsModule intro - Replace {link} cross-references with anchor links for types appended to the same page - Rewrite ActorsModule intro to lead with client capabilities Co-Authored-By: Claude Sonnet 4.6 (1M context) --- src/modules/actors.types.ts | 45 ++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/modules/actors.types.ts b/src/modules/actors.types.ts index 8a61b6e7..eb54c9de 100644 --- a/src/modules/actors.types.ts +++ b/src/modules/actors.types.ts @@ -30,7 +30,7 @@ export interface ActorRegistry {} * with [`types generate`](/developers/references/cli/commands/types-generate). * * The generated names provide autocomplete for deployed actors. To define - * incoming and outgoing message types manually, augment {@link ActorRegistry}. + * incoming and outgoing message types manually, augment [ActorRegistry](#actorregistry). */ export interface ActorNameRegistry {} @@ -49,7 +49,7 @@ type ToServerFor = N extends keyof ActorRegistry : unknown; /** - * Options for {@link ActorRef.connect}. + * Options for [ActorRef.connect](#connect). */ export interface ActorConnectOptions { /** @@ -66,7 +66,7 @@ export interface ActorConnectOptions { /** * Represents an outgoing-message listener registered with - * {@link Connection.subscribe}. + * [Connection.subscribe](#subscribe). */ export interface ActorSubscription { /** @@ -78,7 +78,7 @@ export interface ActorSubscription { /** * Represents a client's WebSocket connection to an actor session. * - * {@link ActorRef.connect} returns this object while the socket connects. + * [ActorRef.connect](#connect) returns this object while the socket connects. * The socket buffers messages sent during connection setup until it opens. */ export interface Connection { @@ -98,10 +98,10 @@ export interface Connection { /** * Sends an incoming message to the actor. * - * The socket buffers messages until it opens. After {@link close}, the socket + * The socket buffers messages until it opens. After [close](#close), the socket * drops further sends. * - * @param data - Incoming message to send. Typed through {@link ActorRegistry} when configured. + * @param data - Incoming message to send. Typed through [ActorRegistry](#actorregistry) when configured. */ send(data: ToServerFor): void; @@ -109,7 +109,7 @@ export interface Connection { * Closes the connection and removes all listeners. * * Safe to call more than once. A connection also closes itself when it fails - * permanently. See {@link ActorRef.connect} for how to open a fresh connection. + * permanently. See [ActorRef.connect](#connect) for how to open a fresh connection. */ close(): void; } @@ -117,11 +117,11 @@ export interface Connection { /** * Represents an actor session selected by actor name and session ID. * - * Call {@link connect} to open the WebSocket and get a {@link Connection}. + * Call [connect](#connect) to open the WebSocket and get a [Connection](#connection). */ export interface ActorRef { /** - * Creates or returns the {@link Connection} for this session. + * Creates or returns the [Connection](#connection) for this session. * * Repeated calls return the same connection until it closes. After a permanent * failure, such as a missing actor or denied connection, fix the cause and call @@ -131,7 +131,7 @@ export interface ActorRef { * for a sample flow. * * @param options - Optional connection settings, such as a stable connection ID. - * @returns The {@link Connection} for this actor session. + * @returns The [Connection](#connection) for this actor session. */ connect(options?: ActorConnectOptions): Connection; } @@ -139,8 +139,8 @@ export interface ActorRef { /** * Selects a session for a named actor. * - * Typed automatically when the actor is registered in {@link ActorRegistry} or - * {@link ActorNameRegistry}. + * Typed automatically when the actor is registered in [ActorRegistry](#actorregistry) or + * [ActorNameRegistry](#actornameregistry). */ export interface ActorClient { /** @@ -157,16 +157,25 @@ export interface ActorClient { /** * Provides access to actors and their shared, live sessions. * - * Select an actor by name and session ID, then connect a client to the - * session. Clients in the same session can exchange realtime messages through the - * actor. The client works in the browser and in Node. + * Use `base44.actors` to connect clients to a running actor session. The actors + * client lets you: + * + * - Subscribe to messages the actor sends — either broadcast to all connected + * clients or sent to your client directly. + * - Send messages to the actor from the client. + * - Share a session across multiple clients: any clients with the same actor + * name and session ID connect to the same session. + * - Type your messages using [ActorRegistry](#actorregistry) for autocomplete + * and compile-time safety. + * + * The client works in the browser and in Node.js. * * ## Connection flow * * - Connect to a session with `base44.actors.(sessionId).connect()`. - * - Subscribe to outgoing messages with {@link Connection.subscribe}. - * - Send incoming messages with {@link Connection.send}. - * - Close the connection with {@link Connection.close}. + * - Subscribe to outgoing messages with [Connection.subscribe](#subscribe). + * - Send incoming messages with [Connection.send](#send). + * - Close the connection with [Connection.close](#close). * * See [Actors Overview](/developers/backend/resources/actors/overview) * for actor concepts and terminology, [Actor Class Reference](/developers/backend/resources/actors/reference) From 7103cbaaef3b98926adb68bc597128d06cf91610 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 23 Sep 2026 00:55:49 -0400 Subject: [PATCH 08/24] docs(actors): rewrite ActorsModule intro with capability-first framing Co-Authored-By: Claude Sonnet 4.6 (1M context) --- src/modules/actors.types.ts | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/modules/actors.types.ts b/src/modules/actors.types.ts index eb54c9de..3880d5b8 100644 --- a/src/modules/actors.types.ts +++ b/src/modules/actors.types.ts @@ -155,32 +155,19 @@ export interface ActorClient { } /** - * Provides access to actors and their shared, live sessions. + * Use `base44.actors` to connect your frontend to [actor sessions](/developers/backend/resources/actors/overview), + * shared live backend processes where clients exchange messages in realtime. * - * Use `base44.actors` to connect clients to a running actor session. The actors - * client lets you: - * - * - Subscribe to messages the actor sends — either broadcast to all connected - * clients or sent to your client directly. - * - Send messages to the actor from the client. + * - Connect to a session with `base44.actors.(sessionId).connect()`. + * - Subscribe to messages the actor sends using [Connection.subscribe](#subscribe), + * either broadcast to all clients or sent directly to your client. + * - Send messages to the actor with [Connection.send](#send). * - Share a session across multiple clients: any clients with the same actor * name and session ID connect to the same session. * - Type your messages using [ActorRegistry](#actorregistry) for autocomplete * and compile-time safety. * - * The client works in the browser and in Node.js. - * - * ## Connection flow - * - * - Connect to a session with `base44.actors.(sessionId).connect()`. - * - Subscribe to outgoing messages with [Connection.subscribe](#subscribe). - * - Send incoming messages with [Connection.send](#send). - * - Close the connection with [Connection.close](#close). - * - * See [Actors Overview](/developers/backend/resources/actors/overview) - * for actor concepts and terminology, [Actor Class Reference](/developers/backend/resources/actors/reference) - * for the backend class API, and [Sample Flows](/developers/backend/resources/actors/samples) - * for common patterns. + * Learn more about [actors](/developers/backend/resources/actors/overview). * * ## Authentication modes * From 72711218dd0da0a6e0dad47496a16862ed292d6b Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 23 Sep 2026 01:04:55 -0400 Subject: [PATCH 09/24] docs(actors): update ActorsModule JSDoc and fix Connection JSDoc blank line Co-Authored-By: Claude Sonnet 4.6 (1M context) --- src/modules/actors.types.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/modules/actors.types.ts b/src/modules/actors.types.ts index 3880d5b8..bf6662f0 100644 --- a/src/modules/actors.types.ts +++ b/src/modules/actors.types.ts @@ -156,7 +156,9 @@ export interface ActorClient { /** * Use `base44.actors` to connect your frontend to [actor sessions](/developers/backend/resources/actors/overview), - * shared live backend processes where clients exchange messages in realtime. + * shared live backend processes where clients can exchange messages in realtime. + * + * With the Actors SDK module you can: * * - Connect to a session with `base44.actors.(sessionId).connect()`. * - Subscribe to messages the actor sends using [Connection.subscribe](#subscribe), @@ -171,14 +173,17 @@ export interface ActorClient { * * ## Authentication modes * - * This module is available in anonymous or user authentication mode - * (`base44.actors`). It isn't available with service role authentication. Apps that - * require login can reject anonymous connections in the actor's `handleConnect()` method. - * See [Manage client connections](/developers/backend/resources/actors/samples#manage-client-connections) - * for a sample flow. - * + * This module is available in anonymous or user authentication mode. + * Apps that require login can reject anonymous connections in the actor's `handleConnect()` method. + * Learn more about [managing client connections](/developers/backend/resources/actors/samples#manage-client-connections). + + * @example + * + * The following example displays the general lifecycle of a client connected to an actor named `Chat`: + * * ```typescript + * Example * const conn = base44.actors.Chat("session-1").connect({ id: "tab-1" }); * const sub = conn.subscribe((msg) => console.log(msg)); * conn.send({ type: "message", text: "hi" }); From a7da00137787aa3510d75aaa61be96fb3aa6639c Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Mon, 5 Oct 2026 14:31:42 +0300 Subject: [PATCH 10/24] Update actors docs Co-Authored-By: Claude Sonnet 5.5 --- src/actor.ts | 4 +- src/modules/actors.types.ts | 136 +++++++++++++++++++++++------------- 2 files changed, 89 insertions(+), 51 deletions(-) diff --git a/src/actor.ts b/src/actor.ts index c4c893bc..4854eead 100644 --- a/src/actor.ts +++ b/src/actor.ts @@ -28,8 +28,8 @@ export interface Storage { get(key: string): Promise; put(key: string, value: unknown): Promise; delete(key: string): Promise; - /** Wipe the session's entire persisted storage. A later connection starts - * with the same empty storage as a new session. */ + /** Deletes all persisted storage for the session. A later connection starts + * with empty storage, the same as a new session. */ deleteAll(): Promise; } diff --git a/src/modules/actors.types.ts b/src/modules/actors.types.ts index bf6662f0..b5d225ea 100644 --- a/src/modules/actors.types.ts +++ b/src/modules/actors.types.ts @@ -8,14 +8,15 @@ * * To generate types from deployed actors instead, use the * [`types generate`](/developers/references/cli/commands/types-generate) CLI command. - * See [Typing messages in the client](/developers/backend/resources/actors/overview#typing-messages-in-the-client) - * for how to define your message types. + * To learn how incoming and outgoing messages work, see + * [message types](/developers/backend/resources/actors/overview#message-types). * * @example * ```typescript + * // Type messages for an actor * declare module "@base44/sdk" { * interface ActorRegistry { - * ChatRoom: { + * chatRoom: { * toClient: { type: "joined" | "left" | "message"; userId?: string; from?: string; text?: string }; * toServer: { type: "message"; text: string }; * }; @@ -49,28 +50,35 @@ type ToServerFor = N extends keyof ActorRegistry : unknown; /** - * Options for [ActorRef.connect](#connect). + * Configures the connection that [ActorRef.connect](#connect) opens. */ export interface ActorConnectOptions { /** * Connection ID that the actor receives as `conn.id`. * - * Use a stable value, such as one stored per browser tab, so the actor - * can recognize the same client if it reconnects. If omitted, the SDK generates one. + * To let the actor recognize the same client if it reconnects, use a stable + * value, such as an ID stored per browser tab. If you omit this property, the + * SDK generates a connection ID. * - * See [Connection ID](/developers/backend/resources/actors/overview#connection-id) - * for more details. + * For more about connection IDs, see + * [connections](/developers/backend/resources/actors/reference#connections). */ id?: string; } /** - * Represents an outgoing-message listener registered with + * Represents a listener for messages from the actor, registered with * [Connection.subscribe](#subscribe). */ export interface ActorSubscription { /** * Removes this listener. Other listeners and the socket stay open. + * + * @example + * ```typescript + * // Remove a listener + * sub.unsubscribe(); + * ``` */ unsubscribe(): void; } @@ -78,44 +86,68 @@ export interface ActorSubscription { /** * Represents a client's WebSocket connection to an actor session. * - * [ActorRef.connect](#connect) returns this object while the socket connects. - * The socket buffers messages sent during connection setup until it opens. + * [ActorRef.connect](#connect) returns this object. The socket buffers messages + * you send before it opens. */ export interface Connection { /** Connection ID that the actor receives as `conn.id`. */ readonly id: string; /** - * Registers a listener for outgoing messages from the actor. + * Registers a listener for messages from the actor. * * You can register multiple listeners on the same connection. * - * @param callback - Called with each outgoing message sent to this connection. - * @returns A handle you can use to remove this listener without closing the socket. + * @param callback - Callback that runs for each message the actor sends to this connection. + * @returns A subscription handle. Call `unsubscribe()` on it to remove this listener without closing the socket. + * + * @example + * ```typescript + * // Listen for messages from the actor + * const sub = conn.subscribe((msg) => { + * console.log(msg); + * }); + * + * // Stop listening without closing the socket. + * sub.unsubscribe(); + * ``` */ subscribe(callback: (data: ToClientFor) => void): ActorSubscription; /** - * Sends an incoming message to the actor. + * Sends a message to the actor. * - * The socket buffers messages until it opens. After [close](#close), the socket - * drops further sends. + * The socket buffers messages until it opens. After you call [close](#close), + * the socket drops further sends. * - * @param data - Incoming message to send. Typed through [ActorRegistry](#actorregistry) when configured. + * @param data - Message to send to the actor. The type comes from [ActorRegistry](#actorregistry) when you register the actor there. + * + * @example + * ```typescript + * // Send a message to the actor + * conn.send({ type: "message", text: "Hello" }); + * ``` */ send(data: ToServerFor): void; /** * Closes the connection and removes all listeners. * - * Safe to call more than once. A connection also closes itself when it fails - * permanently. See [ActorRef.connect](#connect) for how to open a fresh connection. + * You can call this method more than once. A connection also closes itself + * when it fails permanently. To open a new connection, call + * [ActorRef.connect](#connect) again. + * + * @example + * ```typescript + * // Close the connection + * conn.close(); + * ``` */ close(): void; } /** - * Represents an actor session selected by actor name and session ID. + * Represents a reference to an actor session, identified by actor name and session ID. * * Call [connect](#connect) to open the WebSocket and get a [Connection](#connection). */ @@ -123,15 +155,22 @@ export interface ActorRef { /** * Creates or returns the [Connection](#connection) for this session. * - * Repeated calls return the same connection until it closes. After a permanent - * failure, such as a missing actor or denied connection, fix the cause and call - * `connect()` again. Add subscriptions to the new connection. + * Repeated calls return the same connection until it closes. If the connection + * fails permanently, for example because the actor doesn't exist or the actor + * denies the connection, fix the cause and call `connect()` again. Then + * subscribe again on the new connection. * - * See [Connect a client to a session](/developers/backend/resources/actors/samples#connect-a-client-to-a-session) - * for a sample flow. + * For a sample flow, see + * [connect a client to a session](/developers/backend/resources/actors/sample-flows#connect-a-client-to-a-session). * * @param options - Optional connection settings, such as a stable connection ID. * @returns The [Connection](#connection) for this actor session. + * + * @example + * ```typescript + * // Connect to a session + * const conn = base44.actors.chatRoom("session-1").connect({ id: "tab-1" }); + * ``` */ connect(options?: ActorConnectOptions): Connection; } @@ -139,8 +178,9 @@ export interface ActorRef { /** * Selects a session for a named actor. * - * Typed automatically when the actor is registered in [ActorRegistry](#actorregistry) or - * [ActorNameRegistry](#actornameregistry). + * TypeScript infers message types when you register the actor in + * [ActorRegistry](#actorregistry). [ActorNameRegistry](#actornameregistry) + * provides autocomplete for actor names only. */ export interface ActorClient { /** @@ -150,41 +190,39 @@ export interface ActorClient { * * @param instanceId - Session ID that identifies which session to connect to. * @returns A reference to the actor session. + * + * @example + * ```typescript + * // Select a session + * const session = base44.actors.chatRoom("session-1"); + * ``` */ (instanceId: string): ActorRef; } /** - * Use `base44.actors` to connect your frontend to [actor sessions](/developers/backend/resources/actors/overview), + * Connects your frontend to [actor sessions](/developers/backend/resources/actors/overview), * shared live backend processes where clients can exchange messages in realtime. - * - * With the Actors SDK module you can: * - * - Connect to a session with `base44.actors.(sessionId).connect()`. - * - Subscribe to messages the actor sends using [Connection.subscribe](#subscribe), - * either broadcast to all clients or sent directly to your client. - * - Send messages to the actor with [Connection.send](#send). - * - Share a session across multiple clients: any clients with the same actor - * name and session ID connect to the same session. - * - Type your messages using [ActorRegistry](#actorregistry) for autocomplete - * and compile-time safety. + * The following table lists what you can do with the actors module: * - * Learn more about [actors](/developers/backend/resources/actors/overview). + * | Member | Purpose | + * |---|---| + * | [`connect()`](#connect) | Opens a connection to a session. Clients that use the same actor name and session ID join the same session. | + * | [`subscribe()`](#subscribe) | Receives messages from an actor. | + * | [`send()`](#send) | Sends a message to an actor. | + * | [`ActorRegistry`](#actorregistry) | Defines message types for autocomplete and compile-time safety. | * * ## Authentication modes * - * This module is available in anonymous or user authentication mode. + * This module is available in anonymous and user authentication modes. * Apps that require login can reject anonymous connections in the actor's `handleConnect()` method. - * Learn more about [managing client connections](/developers/backend/resources/actors/samples#manage-client-connections). - - + * To learn more, see [manage client connections](/developers/backend/resources/actors/sample-flows#manage-client-connections). + * * @example - * - * The following example displays the general lifecycle of a client connected to an actor named `Chat`: - * * ```typescript - * Example - * const conn = base44.actors.Chat("session-1").connect({ id: "tab-1" }); + * // Connect, subscribe, send, and close + * const conn = base44.actors.chatRoom("session-1").connect({ id: "tab-1" }); * const sub = conn.subscribe((msg) => console.log(msg)); * conn.send({ type: "message", text: "hi" }); * sub.unsubscribe(); From 13a10379bc07eb93f326e3c6fcdf068098cd3992 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Mon, 5 Oct 2026 14:41:13 +0300 Subject: [PATCH 11/24] Remove connector entries from appended articles Co-Authored-By: Claude Sonnet 5.5 --- scripts/mintlify-post-processing/appended-articles.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/mintlify-post-processing/appended-articles.json b/scripts/mintlify-post-processing/appended-articles.json index e3a9a330..45e5db85 100644 --- a/scripts/mintlify-post-processing/appended-articles.json +++ b/scripts/mintlify-post-processing/appended-articles.json @@ -2,10 +2,7 @@ "interfaces/ConnectorsModule": [ "type-aliases/ConnectorIntegrationType", "interfaces/ConnectorIntegrationTypeRegistry", - "interfaces/UserConnectorsModule", - "interfaces/ConnectorApiRequest", - "interfaces/ConnectorApiResponse", - "type-aliases/ConnectorApiResponsePhase" + "interfaces/UserConnectorsModule" ], "type-aliases/EntitiesModule": [ "interfaces/EntityHandler", From 4f81b151165f0cbf7f6d8c34f7960ed5c462a37e Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 08:49:40 +0300 Subject: [PATCH 12/24] Restructure actors reference page Co-Authored-By: Claude Sonnet 5.5 --- .../file-processing/file-processing.js | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) diff --git a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js index a3fc1e38..eeec9ee0 100755 --- a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -2201,6 +2201,231 @@ function applyMethodOrdering(dir) { } } +/** + * Split MDX content into `## ` sections, ignoring headings inside code fences. + * The first entry is the preamble (title: null) before the first `## ` heading. + */ +function splitH2Sections(content) { + const sections = []; + let current = { title: null, lines: [] }; + let inFence = false; + for (const line of content.split("\n")) { + if (line.startsWith("```")) inFence = !inFence; + const match = !inFence && line.match(/^## (.+)$/); + if (match) { + sections.push(current); + current = { title: match[1].trim(), lines: [line] }; + } else { + current.lines.push(line); + } + } + sections.push(current); + return sections; +} + +/** + * Split lines into blocks that start at a heading of the given prefix + * (for example "### "), ignoring headings inside code fences. + * The first entry holds any lines before the first matching heading. + */ +function splitBlocksAt(lines, prefix) { + const blocks = [{ heading: null, lines: [] }]; + let inFence = false; + for (const line of lines) { + if (line.startsWith("```")) inFence = !inFence; + if (!inFence && line.startsWith(prefix)) { + blocks.push({ heading: line.slice(prefix.length).trim(), lines: [line] }); + } else { + blocks[blocks.length - 1].lines.push(line); + } + } + return blocks; +} + +/** Trim leading/trailing blank lines and `***` separators. */ +function trimBlockLines(lines) { + const out = [...lines]; + const isNoise = (l) => l.trim() === "" || l.trim() === "***"; + while (out.length && isNoise(out[0])) out.shift(); + while (out.length && isNoise(out[out.length - 1])) out.pop(); + return out; +} + +/** Shift ATX heading levels (outside code fences) by `delta`. */ +function shiftHeadings(lines, delta) { + let inFence = false; + return lines.map((line) => { + if (line.startsWith("```")) inFence = !inFence; + const match = !inFence && line.match(/^(#{1,6}) (.*)$/); + if (!match) return line; + return "#".repeat(Math.min(6, Math.max(1, match[1].length + delta))) + " " + match[2]; + }); +} + +/** + * Restructure the generated actors page so its table of contents matches the + * other module pages: Overview, one methods section per documented interface, + * then a single Type Definitions section. + * + * TypeDoc renders each appended interface (ActorRef, Connection, ActorClient, + * and so on) as its own `## ` section with its own `## Methods`/`## Properties`, + * and inlines return types, so the raw page repeats headings and nests + * `unsubscribe()` under `subscribe()`. Returns { content, modified }. If the + * page does not have the expected shape, it is left unchanged. + */ +function restructureActorsPage(content) { + const TYPE_SECTIONS = [ + "Overview", + "Connection", + "ActorConnectOptions", + "ActorSubscription", + "ActorClient", + "ActorRegistry", + "ActorNameRegistry", + ]; + const CHILD_SECTIONS = ["Methods", "Properties", "Parameters", "Returns"]; + + const sections = splitH2Sections(content); + const preamble = sections.shift(); + const groups = {}; + let context = null; + for (const section of sections) { + if (TYPE_SECTIONS.includes(section.title)) { + context = section.title; + groups[context] = { head: section, children: [] }; + } else if (CHILD_SECTIONS.includes(section.title) && context) { + groups[context].children.push(section); + } else { + return { content, modified: false }; + } + } + if (TYPE_SECTIONS.some((name) => !groups[name])) return { content, modified: false }; + + // ActorRef is rendered inside Overview as `### ActorRef`; its methods are the + // first `## Methods` section after Overview. + const overview = groups.Overview; + const overviewBlocks = splitBlocksAt(overview.head.lines, "### "); + const refIndex = overviewBlocks.findIndex((b) => b.heading === "ActorRef"); + const refMethods = overview.children.filter((c) => c.title === "Methods"); + if (refIndex === -1 || refMethods.length !== 1) return { content, modified: false }; + const refIntro = trimBlockLines(overviewBlocks[refIndex].lines.slice(1)); + overviewBlocks.splice(refIndex, 1); + const overviewLines = trimBlockLines(overviewBlocks.flatMap((b) => b.lines)); + + // connect(): replace the inlined Connection return type with a link. + const connectBlocks = splitBlocksAt(refMethods[0].lines.slice(1), "### "); + const connect = connectBlocks.find((b) => b.heading === "connect()"); + if (!connect) return { content, modified: false }; + const replaceReturns = (lines, replacement) => { + const start = lines.findIndex((l) => l === "#### Returns"); + if (start === -1) return null; + let end = lines.findIndex((l, i) => i > start && /^#### /.test(l)); + if (end === -1) end = lines.length; + return [...lines.slice(0, start), ...replacement, "", ...lines.slice(end)]; + }; + const connectLines = replaceReturns(trimBlockLines(connect.lines), [ + "#### Returns", + "", + "[`Connection`](#connection)", + "", + "The connection for this actor session.", + ]); + if (!connectLines) return { content, modified: false }; + + // Connection methods: subscribe(), send(), close(). TypeDoc inlines the + // ActorSubscription return type, which adds a nested `## Methods` with + // unsubscribe() and moves subscribe()'s example after it. + const connection = groups.Connection; + const methodBlocks = connection.children + .filter((c) => c.title === "Methods") + .flatMap((c) => splitBlocksAt(c.lines.slice(1), "### ").filter((b) => b.heading)); + const byName = (name) => methodBlocks.find((b) => b.heading === name); + const subscribe = byName("subscribe()"); + const unsubscribeDup = byName("unsubscribe()"); + const send = byName("send()"); + const close = byName("close()"); + if (!subscribe || !unsubscribeDup || !send || !close) return { content, modified: false }; + + const dupLines = trimBlockLines(unsubscribeDup.lines); + const lastExample = dupLines.map((l, i) => (l === "#### Example" ? i : -1)).filter((i) => i >= 0).pop(); + if (lastExample === undefined) return { content, modified: false }; + const subscribeExample = dupLines.slice(lastExample); + const subscribeLines = replaceReturns(trimBlockLines(subscribe.lines), [ + "#### Returns", + "", + "[`ActorSubscription`](#actorsubscription)", + "", + "A subscription handle. Call `unsubscribe()` on it to remove this listener without closing the socket.", + ]); + if (!subscribeLines) return { content, modified: false }; + + // Type definitions: each type becomes `### Name`, and its child sections are + // folded in without repeating `Methods`/`Properties` headings. + const typeDefinition = (name) => { + const group = groups[name]; + const out = [`### ${name}`, "", ...trimBlockLines(group.head.lines.slice(1)), ""]; + for (const child of group.children) { + // Connection's methods are already documented under `## Connection Methods`. + if (name === "Connection" && child.title === "Methods") continue; + const body = trimBlockLines(child.lines.slice(1)); + if (child.title === "Properties") { + out.push(...body, ""); + } else if (child.title === "Methods") { + out.push(...shiftHeadings(body, 1), ""); + } else { + out.push(`#### ${child.title}`, "", ...shiftHeadings(body, 1), ""); + } + } + return out.join("\n").replace("[`ActorRef`](ActorRef)", "[`ActorRef`](#actorref-methods)"); + }; + + const joinMethods = (blocks) => blocks.map((b) => trimBlockLines(b).join("\n")).join("\n\n***\n\n"); + const output = [ + ...preamble.lines, + ...overviewLines, + "", + "## ActorRef Methods", + "", + ...refIntro, + "", + joinMethods([connectLines]), + "", + "## Connection Methods", + "", + joinMethods([[...subscribeLines, "", ...subscribeExample], send.lines, close.lines]), + "", + "## Type Definitions", + "", + ["Connection", "ActorClient", "ActorConnectOptions", "ActorSubscription", "ActorRegistry", "ActorNameRegistry"] + .map(typeDefinition) + .join("\n"), + ].join("\n"); + + return { content: output.replace(/\n{3,}/g, "\n\n").replace(/\s+$/, "") + "\n", modified: true }; +} + +/** + * Apply the actors page restructuring to `type-aliases/actors.mdx`. + */ +function applyActorsPageRestructuring(dir) { + if (!fs.existsSync(dir)) return; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const entryPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + applyActorsPageRestructuring(entryPath); + } else if (entry.name === "actors.mdx" && path.basename(dir) === "type-aliases") { + const content = fs.readFileSync(entryPath, "utf-8"); + const { content: updated, modified } = restructureActorsPage(content); + if (modified) { + fs.writeFileSync(entryPath, updated, "utf-8"); + console.log(`Restructured actors page: ${path.relative(DOCS_DIR, entryPath)}`); + } else { + console.warn(`Warning: actors page has an unexpected structure and was left unchanged: ${path.relative(DOCS_DIR, entryPath)}`); + } + } + } +} + function main() { console.log("Processing TypeDoc MDX files for Mintlify...\n"); @@ -2253,6 +2478,9 @@ function main() { // Reorder methods according to method-order.json applyMethodOrdering(DOCS_DIR); + // Restructure the actors page so its table of contents matches other module pages + applyActorsPageRestructuring(DOCS_DIR); + // Link type names in Type Declarations sections to their corresponding headings applyTypeDeclarationLinking(DOCS_DIR); From e9bce6801f62a71b18e674c22208579e9a2d88f3 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 09:03:58 +0300 Subject: [PATCH 13/24] Simplify actors page restructuring Co-Authored-By: Claude Sonnet 5.5 --- .../file-processing/file-processing.js | 257 ++++++++++-------- 1 file changed, 143 insertions(+), 114 deletions(-) diff --git a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js index eeec9ee0..aa570e10 100755 --- a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -2262,146 +2262,175 @@ function shiftHeadings(lines, delta) { }); } +// Types on the generated actors page, in the order they appear under "## Type Definitions". +const ACTORS_TYPE_DEFINITION_ORDER = [ + "Connection", + "ActorClient", + "ActorConnectOptions", + "ActorSubscription", + "ActorRegistry", + "ActorNameRegistry", +]; +const ACTORS_TYPE_SECTIONS = ["Overview", ...ACTORS_TYPE_DEFINITION_ORDER]; +const ACTORS_CHILD_SECTIONS = ["Methods", "Properties", "Parameters", "Returns"]; + +/** + * Group the page's `## ` sections under the type they belong to, so that a + * `## Methods` section follows the type it documents. Returns null if the page + * has a section that this restructuring does not know about. + */ +function groupActorsSections(content) { + const [preamble, ...sections] = splitH2Sections(content); + const groups = {}; + let current = null; + for (const section of sections) { + if (ACTORS_TYPE_SECTIONS.includes(section.title)) { + current = groups[section.title] = { head: section, children: [] }; + } else if (ACTORS_CHILD_SECTIONS.includes(section.title) && current) { + current.children.push(section); + } else { + return null; + } + } + return ACTORS_TYPE_SECTIONS.every((name) => groups[name]) ? { preamble, groups } : null; +} + +/** Find the block with the given heading, or undefined. */ +function findBlock(blocks, heading) { + return blocks.find((block) => block.heading === heading); +} + +/** All `### ` method blocks inside a group's `## Methods` sections. */ +function methodBlocksOf(group) { + return group.children + .filter((child) => child.title === "Methods") + .flatMap((child) => splitBlocksAt(child.lines.slice(1), "### ")) + .filter((block) => block.heading); +} + +/** + * Replace a method's "#### Returns" section. TypeDoc inlines the return type + * there (for example the whole Connection type), so this swaps it for a link. + */ +function replaceReturnsSection(lines, returnType, description) { + const start = lines.indexOf("#### Returns"); + if (start === -1) return null; + const next = lines.findIndex((line, i) => i > start && line.startsWith("#### ")); + const end = next === -1 ? lines.length : next; + const link = `[\`${returnType}\`](#${returnType.toLowerCase()})`; + return [...lines.slice(0, start), "#### Returns", "", link, "", description, "", ...lines.slice(end)]; +} + +/** + * TypeDoc renders ActorRef as a `### ActorRef` block inside Overview, with its + * methods in the first `## Methods` section. Returns the Overview without it, + * plus the ActorRef intro and the `connect()` block, or null if not found. + */ +function extractActorRef(overview) { + const blocks = splitBlocksAt(overview.head.lines, "### "); + const refBlock = findBlock(blocks, "ActorRef"); + const methods = overview.children.filter((child) => child.title === "Methods"); + const connect = methods.length === 1 && findBlock(splitBlocksAt(methods[0].lines.slice(1), "### "), "connect()"); + if (!refBlock || !connect) return null; + + const connectLines = replaceReturnsSection( + trimBlockLines(connect.lines), + "Connection", + "The connection for this actor session." + ); + if (!connectLines) return null; + return { + overviewLines: trimBlockLines(blocks.filter((b) => b !== refBlock).flatMap((b) => b.lines)), + refIntro: trimBlockLines(refBlock.lines.slice(1)), + connectLines, + }; +} + +/** + * Build the Connection methods: subscribe(), send(), close(). TypeDoc inlines + * the ActorSubscription return type under subscribe(), which adds a duplicate + * unsubscribe() block and moves subscribe()'s example after it. + */ +function buildConnectionMethods(connection) { + const blocks = methodBlocksOf(connection); + const [subscribe, duplicate, send, close] = ["subscribe()", "unsubscribe()", "send()", "close()"].map((name) => + findBlock(blocks, name) + ); + if (!subscribe || !duplicate || !send || !close) return null; + + const duplicateLines = trimBlockLines(duplicate.lines); + const exampleStart = duplicateLines.lastIndexOf("#### Example"); + const subscribeLines = replaceReturnsSection( + trimBlockLines(subscribe.lines), + "ActorSubscription", + "A subscription handle. Call `unsubscribe()` on it to remove this listener without closing the socket." + ); + if (exampleStart === -1 || !subscribeLines) return null; + + return [[...subscribeLines, "", ...duplicateLines.slice(exampleStart)], send.lines, close.lines]; +} + +/** + * Render a type under "## Type Definitions": the type becomes `### Name`, and + * its child sections are folded in without repeating Methods/Properties headings. + */ +function buildActorsTypeDefinition({ head, children }, name) { + const out = [`### ${name}`, "", ...trimBlockLines(head.lines.slice(1)), ""]; + for (const child of children) { + // Connection's methods are documented under "## Connection Methods". + if (name === "Connection" && child.title === "Methods") continue; + const body = trimBlockLines(child.lines.slice(1)); + if (child.title === "Properties") out.push(...body, ""); + else if (child.title === "Methods") out.push(...shiftHeadings(body, 1), ""); + else out.push(`#### ${child.title}`, "", ...shiftHeadings(body, 1), ""); + } + return out.join("\n").replace("[`ActorRef`](ActorRef)", "[`ActorRef`](#actorref-methods)"); +} + +/** Join method blocks with the `***` separators used between methods on other pages. */ +function joinMethodBlocks(blocks) { + return blocks.map((lines) => trimBlockLines(lines).join("\n")).join("\n\n***\n\n"); +} + /** * Restructure the generated actors page so its table of contents matches the * other module pages: Overview, one methods section per documented interface, * then a single Type Definitions section. * * TypeDoc renders each appended interface (ActorRef, Connection, ActorClient, - * and so on) as its own `## ` section with its own `## Methods`/`## Properties`, + * and so on) as its own `## ` section with its own `## Methods`/`## Properties` * and inlines return types, so the raw page repeats headings and nests * `unsubscribe()` under `subscribe()`. Returns { content, modified }. If the * page does not have the expected shape, it is left unchanged. */ function restructureActorsPage(content) { - const TYPE_SECTIONS = [ - "Overview", - "Connection", - "ActorConnectOptions", - "ActorSubscription", - "ActorClient", - "ActorRegistry", - "ActorNameRegistry", - ]; - const CHILD_SECTIONS = ["Methods", "Properties", "Parameters", "Returns"]; - - const sections = splitH2Sections(content); - const preamble = sections.shift(); - const groups = {}; - let context = null; - for (const section of sections) { - if (TYPE_SECTIONS.includes(section.title)) { - context = section.title; - groups[context] = { head: section, children: [] }; - } else if (CHILD_SECTIONS.includes(section.title) && context) { - groups[context].children.push(section); - } else { - return { content, modified: false }; - } - } - if (TYPE_SECTIONS.some((name) => !groups[name])) return { content, modified: false }; - - // ActorRef is rendered inside Overview as `### ActorRef`; its methods are the - // first `## Methods` section after Overview. - const overview = groups.Overview; - const overviewBlocks = splitBlocksAt(overview.head.lines, "### "); - const refIndex = overviewBlocks.findIndex((b) => b.heading === "ActorRef"); - const refMethods = overview.children.filter((c) => c.title === "Methods"); - if (refIndex === -1 || refMethods.length !== 1) return { content, modified: false }; - const refIntro = trimBlockLines(overviewBlocks[refIndex].lines.slice(1)); - overviewBlocks.splice(refIndex, 1); - const overviewLines = trimBlockLines(overviewBlocks.flatMap((b) => b.lines)); - - // connect(): replace the inlined Connection return type with a link. - const connectBlocks = splitBlocksAt(refMethods[0].lines.slice(1), "### "); - const connect = connectBlocks.find((b) => b.heading === "connect()"); - if (!connect) return { content, modified: false }; - const replaceReturns = (lines, replacement) => { - const start = lines.findIndex((l) => l === "#### Returns"); - if (start === -1) return null; - let end = lines.findIndex((l, i) => i > start && /^#### /.test(l)); - if (end === -1) end = lines.length; - return [...lines.slice(0, start), ...replacement, "", ...lines.slice(end)]; - }; - const connectLines = replaceReturns(trimBlockLines(connect.lines), [ - "#### Returns", - "", - "[`Connection`](#connection)", - "", - "The connection for this actor session.", - ]); - if (!connectLines) return { content, modified: false }; - - // Connection methods: subscribe(), send(), close(). TypeDoc inlines the - // ActorSubscription return type, which adds a nested `## Methods` with - // unsubscribe() and moves subscribe()'s example after it. - const connection = groups.Connection; - const methodBlocks = connection.children - .filter((c) => c.title === "Methods") - .flatMap((c) => splitBlocksAt(c.lines.slice(1), "### ").filter((b) => b.heading)); - const byName = (name) => methodBlocks.find((b) => b.heading === name); - const subscribe = byName("subscribe()"); - const unsubscribeDup = byName("unsubscribe()"); - const send = byName("send()"); - const close = byName("close()"); - if (!subscribe || !unsubscribeDup || !send || !close) return { content, modified: false }; - - const dupLines = trimBlockLines(unsubscribeDup.lines); - const lastExample = dupLines.map((l, i) => (l === "#### Example" ? i : -1)).filter((i) => i >= 0).pop(); - if (lastExample === undefined) return { content, modified: false }; - const subscribeExample = dupLines.slice(lastExample); - const subscribeLines = replaceReturns(trimBlockLines(subscribe.lines), [ - "#### Returns", - "", - "[`ActorSubscription`](#actorsubscription)", - "", - "A subscription handle. Call `unsubscribe()` on it to remove this listener without closing the socket.", - ]); - if (!subscribeLines) return { content, modified: false }; - - // Type definitions: each type becomes `### Name`, and its child sections are - // folded in without repeating `Methods`/`Properties` headings. - const typeDefinition = (name) => { - const group = groups[name]; - const out = [`### ${name}`, "", ...trimBlockLines(group.head.lines.slice(1)), ""]; - for (const child of group.children) { - // Connection's methods are already documented under `## Connection Methods`. - if (name === "Connection" && child.title === "Methods") continue; - const body = trimBlockLines(child.lines.slice(1)); - if (child.title === "Properties") { - out.push(...body, ""); - } else if (child.title === "Methods") { - out.push(...shiftHeadings(body, 1), ""); - } else { - out.push(`#### ${child.title}`, "", ...shiftHeadings(body, 1), ""); - } - } - return out.join("\n").replace("[`ActorRef`](ActorRef)", "[`ActorRef`](#actorref-methods)"); - }; + const unchanged = { content, modified: false }; + const grouped = groupActorsSections(content); + const actorRef = grouped && extractActorRef(grouped.groups.Overview); + const connectionMethods = grouped && buildConnectionMethods(grouped.groups.Connection); + if (!actorRef || !connectionMethods) return unchanged; - const joinMethods = (blocks) => blocks.map((b) => trimBlockLines(b).join("\n")).join("\n\n***\n\n"); + const { preamble, groups } = grouped; const output = [ ...preamble.lines, - ...overviewLines, + ...actorRef.overviewLines, "", "## ActorRef Methods", "", - ...refIntro, + ...actorRef.refIntro, "", - joinMethods([connectLines]), + joinMethodBlocks([actorRef.connectLines]), "", "## Connection Methods", "", - joinMethods([[...subscribeLines, "", ...subscribeExample], send.lines, close.lines]), + joinMethodBlocks(connectionMethods), "", "## Type Definitions", "", - ["Connection", "ActorClient", "ActorConnectOptions", "ActorSubscription", "ActorRegistry", "ActorNameRegistry"] - .map(typeDefinition) - .join("\n"), + ACTORS_TYPE_DEFINITION_ORDER.map((name) => buildActorsTypeDefinition(groups[name], name)).join("\n"), ].join("\n"); - return { content: output.replace(/\n{3,}/g, "\n\n").replace(/\s+$/, "") + "\n", modified: true }; + return { content: output.replace(/\n{3,}/g, "\n\n").trimEnd() + "\n", modified: true }; } /** From 9104a33098761ca38000fe50059b4bce94a1b3d3 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 09:55:15 +0300 Subject: [PATCH 14/24] Fix actors page table of contents Co-Authored-By: Claude Sonnet 5.5 --- .../appended-articles.json | 2 +- .../file-processing/file-processing.js | 308 +++--------------- 2 files changed, 54 insertions(+), 256 deletions(-) diff --git a/packages/sdk/scripts/mintlify-post-processing/appended-articles.json b/packages/sdk/scripts/mintlify-post-processing/appended-articles.json index 45e5db85..b7336b0d 100644 --- a/packages/sdk/scripts/mintlify-post-processing/appended-articles.json +++ b/packages/sdk/scripts/mintlify-post-processing/appended-articles.json @@ -25,8 +25,8 @@ "type-aliases/ActorsModule": [ "interfaces/ActorRef", "interfaces/Connection", - "interfaces/ActorConnectOptions", "interfaces/ActorSubscription", + "interfaces/ActorConnectOptions", "interfaces/ActorClient", "interfaces/ActorRegistry", "interfaces/ActorNameRegistry" diff --git a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js index aa570e10..8301e663 100755 --- a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -1284,6 +1284,19 @@ function applyTypeDeclarationLinking(dir) { } } +/** + * Interfaces that are appended to a module page and have methods of their own. + * Each keeps its own `## ` heading with its methods directly underneath, so the + * generic `## Methods` heading that follows it is dropped. The value renames the + * heading, or is null to keep the interface name. + */ +const TYPES_WITH_OWN_METHODS = { + EntityHandler: "Entity Handler Methods", + ActorRef: null, + Connection: null, + ActorSubscription: null, +}; + /** * Group intro sections (like "Built-in User Entity", "Generated Types") under an "Overview" heading * The Overview heading goes at the top of the page content, and intro paragraph becomes part of Overview @@ -1323,7 +1336,7 @@ function groupIntroSections(content) { // Find the first main section heading (Methods, EntityHandler, Properties, etc.) // These mark the end of intro/overview sections - const mainSectionNames = ["Methods", "EntityHandler", "Properties", "Type Definitions"]; + const mainSectionNames = ["Methods", "Properties", "Type Definitions", ...Object.keys(TYPES_WITH_OWN_METHODS)]; let mainSectionIndex = -1; for (let i = insertIndex; i < lines.length; i++) { @@ -1423,6 +1436,11 @@ function groupTypeDefinitions(content) { { types: ["AgentName", "AgentNameRegistry"], indicator: "AgentName" + }, + // Actors module + { + types: ["ActorConnectOptions", "ActorClient", "ActorRegistry", "ActorNameRegistry"], + indicator: "ActorConnectOptions" } ]; @@ -1690,22 +1708,30 @@ function mergeSectionWithMethods(content, filePath) { for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); - // Handle EntityHandler + Methods → Entity Handler Methods - if (line === "## EntityHandler") { - // Look ahead to find the next ## Methods heading + // Handle interfaces with their own methods (see TYPES_WITH_OWN_METHODS): drop the + // generic ## Methods heading so the methods sit directly under the interface. + const typeName = line.startsWith("## ") ? line.slice(3) : ""; + if (Object.hasOwn(TYPES_WITH_OWN_METHODS, typeName)) { + // Look ahead to the next ## Methods heading, noting a ## Properties heading on the way let methodsIndex = -1; + let propertiesIndex = -1; for (let j = i + 1; j < lines.length; j++) { const nextLine = lines[j].trim(); - if (nextLine.startsWith("## ")) { + if (nextLine === "## Properties") { + propertiesIndex = j; + } else if (nextLine.startsWith("## ")) { if (nextLine === "## Methods") { methodsIndex = j; } break; } } - + if (methodsIndex !== -1) { - lines[i] = "## Entity Handler Methods"; + lines[i] = `## ${TYPES_WITH_OWN_METHODS[typeName] ?? typeName}`; + if (propertiesIndex !== -1) { + lines[propertiesIndex] = "### Properties"; + } lines.splice(methodsIndex, 1); modified = true; } @@ -2202,257 +2228,29 @@ function applyMethodOrdering(dir) { } /** - * Split MDX content into `## ` sections, ignoring headings inside code fences. - * The first entry is the preamble (title: null) before the first `## ` heading. + * Tidy the generated actors page. TypeDoc inlines the ActorSubscription return + * type under `subscribe()`, which adds a duplicate `unsubscribe()` block, and the + * types under Type Definitions keep repeated `Properties`/`Parameters`/`Returns` + * headings. This drops the duplicate, folds those headings, and fixes the dead + * `ActorRef` link. A page without the expected shape is left unchanged. */ -function splitH2Sections(content) { - const sections = []; - let current = { title: null, lines: [] }; - let inFence = false; - for (const line of content.split("\n")) { - if (line.startsWith("```")) inFence = !inFence; - const match = !inFence && line.match(/^## (.+)$/); - if (match) { - sections.push(current); - current = { title: match[1].trim(), lines: [line] }; - } else { - current.lines.push(line); - } - } - sections.push(current); - return sections; -} - -/** - * Split lines into blocks that start at a heading of the given prefix - * (for example "### "), ignoring headings inside code fences. - * The first entry holds any lines before the first matching heading. - */ -function splitBlocksAt(lines, prefix) { - const blocks = [{ heading: null, lines: [] }]; - let inFence = false; - for (const line of lines) { - if (line.startsWith("```")) inFence = !inFence; - if (!inFence && line.startsWith(prefix)) { - blocks.push({ heading: line.slice(prefix.length).trim(), lines: [line] }); - } else { - blocks[blocks.length - 1].lines.push(line); - } - } - return blocks; -} - -/** Trim leading/trailing blank lines and `***` separators. */ -function trimBlockLines(lines) { - const out = [...lines]; - const isNoise = (l) => l.trim() === "" || l.trim() === "***"; - while (out.length && isNoise(out[0])) out.shift(); - while (out.length && isNoise(out[out.length - 1])) out.pop(); - return out; -} - -/** Shift ATX heading levels (outside code fences) by `delta`. */ -function shiftHeadings(lines, delta) { - let inFence = false; - return lines.map((line) => { - if (line.startsWith("```")) inFence = !inFence; - const match = !inFence && line.match(/^(#{1,6}) (.*)$/); - if (!match) return line; - return "#".repeat(Math.min(6, Math.max(1, match[1].length + delta))) + " " + match[2]; - }); -} - -// Types on the generated actors page, in the order they appear under "## Type Definitions". -const ACTORS_TYPE_DEFINITION_ORDER = [ - "Connection", - "ActorClient", - "ActorConnectOptions", - "ActorSubscription", - "ActorRegistry", - "ActorNameRegistry", -]; -const ACTORS_TYPE_SECTIONS = ["Overview", ...ACTORS_TYPE_DEFINITION_ORDER]; -const ACTORS_CHILD_SECTIONS = ["Methods", "Properties", "Parameters", "Returns"]; - -/** - * Group the page's `## ` sections under the type they belong to, so that a - * `## Methods` section follows the type it documents. Returns null if the page - * has a section that this restructuring does not know about. - */ -function groupActorsSections(content) { - const [preamble, ...sections] = splitH2Sections(content); - const groups = {}; - let current = null; - for (const section of sections) { - if (ACTORS_TYPE_SECTIONS.includes(section.title)) { - current = groups[section.title] = { head: section, children: [] }; - } else if (ACTORS_CHILD_SECTIONS.includes(section.title) && current) { - current.children.push(section); - } else { - return null; - } +function restructureActorsPage() { + const file = path.join(DOCS_DIR, "content", "type-aliases", "actors.mdx"); + if (!fs.existsSync(file)) return; + + const duplicateUnsubscribe = /\n## Methods\n\n### unsubscribe\(\)[\s\S]*?<\/CodeGroup>\n/; + const [page, types] = fs.readFileSync(file, "utf-8").split("\n## Type Definitions\n"); + if (types === undefined || !duplicateUnsubscribe.test(page)) { + console.warn("Warning: actors page has an unexpected structure and was left unchanged"); + return; } - return ACTORS_TYPE_SECTIONS.every((name) => groups[name]) ? { preamble, groups } : null; -} - -/** Find the block with the given heading, or undefined. */ -function findBlock(blocks, heading) { - return blocks.find((block) => block.heading === heading); -} - -/** All `### ` method blocks inside a group's `## Methods` sections. */ -function methodBlocksOf(group) { - return group.children - .filter((child) => child.title === "Methods") - .flatMap((child) => splitBlocksAt(child.lines.slice(1), "### ")) - .filter((block) => block.heading); -} - -/** - * Replace a method's "#### Returns" section. TypeDoc inlines the return type - * there (for example the whole Connection type), so this swaps it for a link. - */ -function replaceReturnsSection(lines, returnType, description) { - const start = lines.indexOf("#### Returns"); - if (start === -1) return null; - const next = lines.findIndex((line, i) => i > start && line.startsWith("#### ")); - const end = next === -1 ? lines.length : next; - const link = `[\`${returnType}\`](#${returnType.toLowerCase()})`; - return [...lines.slice(0, start), "#### Returns", "", link, "", description, "", ...lines.slice(end)]; -} -/** - * TypeDoc renders ActorRef as a `### ActorRef` block inside Overview, with its - * methods in the first `## Methods` section. Returns the Overview without it, - * plus the ActorRef intro and the `connect()` block, or null if not found. - */ -function extractActorRef(overview) { - const blocks = splitBlocksAt(overview.head.lines, "### "); - const refBlock = findBlock(blocks, "ActorRef"); - const methods = overview.children.filter((child) => child.title === "Methods"); - const connect = methods.length === 1 && findBlock(splitBlocksAt(methods[0].lines.slice(1), "### "), "connect()"); - if (!refBlock || !connect) return null; - - const connectLines = replaceReturnsSection( - trimBlockLines(connect.lines), - "Connection", - "The connection for this actor session." - ); - if (!connectLines) return null; - return { - overviewLines: trimBlockLines(blocks.filter((b) => b !== refBlock).flatMap((b) => b.lines)), - refIntro: trimBlockLines(refBlock.lines.slice(1)), - connectLines, - }; -} + const tidiedTypes = types + .replace(/^## Properties\n\n/gm, "") + .replace(/^## (Parameters|Returns)$/gm, "#### $1") + .replace("[`ActorRef`](ActorRef)", "[`ActorRef`](#actorref)"); -/** - * Build the Connection methods: subscribe(), send(), close(). TypeDoc inlines - * the ActorSubscription return type under subscribe(), which adds a duplicate - * unsubscribe() block and moves subscribe()'s example after it. - */ -function buildConnectionMethods(connection) { - const blocks = methodBlocksOf(connection); - const [subscribe, duplicate, send, close] = ["subscribe()", "unsubscribe()", "send()", "close()"].map((name) => - findBlock(blocks, name) - ); - if (!subscribe || !duplicate || !send || !close) return null; - - const duplicateLines = trimBlockLines(duplicate.lines); - const exampleStart = duplicateLines.lastIndexOf("#### Example"); - const subscribeLines = replaceReturnsSection( - trimBlockLines(subscribe.lines), - "ActorSubscription", - "A subscription handle. Call `unsubscribe()` on it to remove this listener without closing the socket." - ); - if (exampleStart === -1 || !subscribeLines) return null; - - return [[...subscribeLines, "", ...duplicateLines.slice(exampleStart)], send.lines, close.lines]; -} - -/** - * Render a type under "## Type Definitions": the type becomes `### Name`, and - * its child sections are folded in without repeating Methods/Properties headings. - */ -function buildActorsTypeDefinition({ head, children }, name) { - const out = [`### ${name}`, "", ...trimBlockLines(head.lines.slice(1)), ""]; - for (const child of children) { - // Connection's methods are documented under "## Connection Methods". - if (name === "Connection" && child.title === "Methods") continue; - const body = trimBlockLines(child.lines.slice(1)); - if (child.title === "Properties") out.push(...body, ""); - else if (child.title === "Methods") out.push(...shiftHeadings(body, 1), ""); - else out.push(`#### ${child.title}`, "", ...shiftHeadings(body, 1), ""); - } - return out.join("\n").replace("[`ActorRef`](ActorRef)", "[`ActorRef`](#actorref-methods)"); -} - -/** Join method blocks with the `***` separators used between methods on other pages. */ -function joinMethodBlocks(blocks) { - return blocks.map((lines) => trimBlockLines(lines).join("\n")).join("\n\n***\n\n"); -} - -/** - * Restructure the generated actors page so its table of contents matches the - * other module pages: Overview, one methods section per documented interface, - * then a single Type Definitions section. - * - * TypeDoc renders each appended interface (ActorRef, Connection, ActorClient, - * and so on) as its own `## ` section with its own `## Methods`/`## Properties` - * and inlines return types, so the raw page repeats headings and nests - * `unsubscribe()` under `subscribe()`. Returns { content, modified }. If the - * page does not have the expected shape, it is left unchanged. - */ -function restructureActorsPage(content) { - const unchanged = { content, modified: false }; - const grouped = groupActorsSections(content); - const actorRef = grouped && extractActorRef(grouped.groups.Overview); - const connectionMethods = grouped && buildConnectionMethods(grouped.groups.Connection); - if (!actorRef || !connectionMethods) return unchanged; - - const { preamble, groups } = grouped; - const output = [ - ...preamble.lines, - ...actorRef.overviewLines, - "", - "## ActorRef Methods", - "", - ...actorRef.refIntro, - "", - joinMethodBlocks([actorRef.connectLines]), - "", - "## Connection Methods", - "", - joinMethodBlocks(connectionMethods), - "", - "## Type Definitions", - "", - ACTORS_TYPE_DEFINITION_ORDER.map((name) => buildActorsTypeDefinition(groups[name], name)).join("\n"), - ].join("\n"); - - return { content: output.replace(/\n{3,}/g, "\n\n").trimEnd() + "\n", modified: true }; -} - -/** - * Apply the actors page restructuring to `type-aliases/actors.mdx`. - */ -function applyActorsPageRestructuring(dir) { - if (!fs.existsSync(dir)) return; - for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { - const entryPath = path.join(dir, entry.name); - if (entry.isDirectory()) { - applyActorsPageRestructuring(entryPath); - } else if (entry.name === "actors.mdx" && path.basename(dir) === "type-aliases") { - const content = fs.readFileSync(entryPath, "utf-8"); - const { content: updated, modified } = restructureActorsPage(content); - if (modified) { - fs.writeFileSync(entryPath, updated, "utf-8"); - console.log(`Restructured actors page: ${path.relative(DOCS_DIR, entryPath)}`); - } else { - console.warn(`Warning: actors page has an unexpected structure and was left unchanged: ${path.relative(DOCS_DIR, entryPath)}`); - } - } - } + fs.writeFileSync(file, `${page.replace(duplicateUnsubscribe, "\n")}\n## Type Definitions\n${tidiedTypes}`, "utf-8"); } function main() { @@ -2508,7 +2306,7 @@ function main() { applyMethodOrdering(DOCS_DIR); // Restructure the actors page so its table of contents matches other module pages - applyActorsPageRestructuring(DOCS_DIR); + restructureActorsPage(); // Link type names in Type Declarations sections to their corresponding headings applyTypeDeclarationLinking(DOCS_DIR); From de105e174a0162d3320cc21532e2e4b24dab645d Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 09:57:15 +0300 Subject: [PATCH 15/24] Add actors module intro Co-Authored-By: Claude Sonnet 5.5 --- packages/sdk/src/modules/actors.types.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/sdk/src/modules/actors.types.ts b/packages/sdk/src/modules/actors.types.ts index b5d225ea..2662eaaa 100644 --- a/packages/sdk/src/modules/actors.types.ts +++ b/packages/sdk/src/modules/actors.types.ts @@ -201,17 +201,17 @@ export interface ActorClient { } /** - * Connects your frontend to [actor sessions](/developers/backend/resources/actors/overview), - * shared live backend processes where clients can exchange messages in realtime. + * Actors module for connecting your app to actors. An actor is a backend process that you define + * in your project and that multiple clients connect to at the same time. Each client joins a + * session, identified by the actor name and a session ID, and clients in the same session share + * its state. * - * The following table lists what you can do with the actors module: + * This module is the client side of an actor. Use it to join a session, send messages to the + * actor, and receive the messages it sends back in realtime. * - * | Member | Purpose | - * |---|---| - * | [`connect()`](#connect) | Opens a connection to a session. Clients that use the same actor name and session ID join the same session. | - * | [`subscribe()`](#subscribe) | Receives messages from an actor. | - * | [`send()`](#send) | Sends a message to an actor. | - * | [`ActorRegistry`](#actorregistry) | Defines message types for autocomplete and compile-time safety. | + * To learn how actors work, see the [actors overview](/developers/backend/resources/actors/overview). + * For a sample flow, see + * [connect a client to a session](/developers/backend/resources/actors/sample-flows#connect-a-client-to-a-session). * * ## Authentication modes * From 0fa992f909fea55904e0b72c7f769a23c8babc31 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 10:15:29 +0300 Subject: [PATCH 16/24] Update actors module docs Co-Authored-By: Claude Sonnet 5.5 --- .../file-processing/file-processing.js | 3 +- packages/sdk/src/modules/actors.types.ts | 29 ++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js index 8301e663..16510089 100755 --- a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -140,8 +140,9 @@ function processLinksInFile(filePath) { // Remove undesirable type-alias definition lines like: // > **IntegrationsModule** = `object` & `object` // > **EntitiesModule** = `TypedEntitiesModule` & `DynamicEntitiesModule` + // > **ActorsModule** = `{ [K in AllActorNames]: ... }` & `Record`\<`string`, `ActorClient`\> // These appear in type alias files using intersection types and are not useful in docs. - const typeDefinitionRegex = /^> \*\*\w+\*\* = `\w+` & `\w+`\s*$/m; + const typeDefinitionRegex = /^> \*\*\w+Module\*\* = .+\s*$/m; if (typeDefinitionRegex.test(content)) { content = content.replace(typeDefinitionRegex, ""); modified = true; diff --git a/packages/sdk/src/modules/actors.types.ts b/packages/sdk/src/modules/actors.types.ts index 2662eaaa..d7253388 100644 --- a/packages/sdk/src/modules/actors.types.ts +++ b/packages/sdk/src/modules/actors.types.ts @@ -201,23 +201,32 @@ export interface ActorClient { } /** - * Actors module for connecting your app to actors. An actor is a backend process that you define - * in your project and that multiple clients connect to at the same time. Each client joins a - * session, identified by the actor name and a session ID, and clients in the same session share - * its state. + * Actors module for connecting a client to an [actor](/developers/backend/resources/actors/overview) session and exchanging messages. * - * This module is the client side of an actor. Use it to join a session, send messages to the - * actor, and receive the messages it sends back in realtime. + * An actor is a long-running backend process that multiple clients connect to simultaneously. A session + * is a running instance of an actor, identified by the actor name and a session ID. Each + * session manages its own state, storage, and client connections independently. + * + * The actors module supports the following functionality: + * + * - [`connect()`](#connect): Open a WebSocket connection to a session. + * - [`subscribe()`](#subscribe): Receive messages from the actor. + * - [`unsubscribe()`](#unsubscribe): Stop receiving messages from the actor without closing the connection. + * - [`send()`](#send): Send messages to the actor. + * - [`close()`](#close): Close the WebSocket connection to the actor. * - * To learn how actors work, see the [actors overview](/developers/backend/resources/actors/overview). * For a sample flow, see * [connect a client to a session](/developers/backend/resources/actors/sample-flows#connect-a-client-to-a-session). * * ## Authentication modes * - * This module is available in anonymous and user authentication modes. - * Apps that require login can reject anonymous connections in the actor's `handleConnect()` method. - * To learn more, see [manage client connections](/developers/backend/resources/actors/sample-flows#manage-client-connections). + * This module is available to use with a client in anonymous or user authentication mode. Access it + * through `base44.actors`. It isn't available in + * [service role authentication mode](/developers/references/sdk/getting-started/client#service-role). + * + * The actor receives each client's [identity](/developers/backend/resources/actors/reference#connections) + * when the client connects. A client that hasn't logged in connects as anonymous, and a client that + * has [logged in](/developers/references/sdk/docs/interfaces/auth) connects as authenticated. * * @example * ```typescript From eea89910401494641a35a84bf1cfd92ba685a473 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 10:18:38 +0300 Subject: [PATCH 17/24] Remove actors module example Co-Authored-By: Claude Sonnet 5.5 --- packages/sdk/src/modules/actors.types.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/sdk/src/modules/actors.types.ts b/packages/sdk/src/modules/actors.types.ts index d7253388..0241e2b6 100644 --- a/packages/sdk/src/modules/actors.types.ts +++ b/packages/sdk/src/modules/actors.types.ts @@ -227,16 +227,6 @@ export interface ActorClient { * The actor receives each client's [identity](/developers/backend/resources/actors/reference#connections) * when the client connects. A client that hasn't logged in connects as anonymous, and a client that * has [logged in](/developers/references/sdk/docs/interfaces/auth) connects as authenticated. - * - * @example - * ```typescript - * // Connect, subscribe, send, and close - * const conn = base44.actors.chatRoom("session-1").connect({ id: "tab-1" }); - * const sub = conn.subscribe((msg) => console.log(msg)); - * conn.send({ type: "message", text: "hi" }); - * sub.unsubscribe(); - * conn.close(); - * ``` */ export type ActorsModule = { [K in AllActorNames]: K extends keyof ActorRegistry From 527a9759cd1473ed0dad8200a49bd2e824001e79 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 10:24:02 +0300 Subject: [PATCH 18/24] Simplify actors page step Co-Authored-By: Claude Sonnet 5.5 --- .../file-processing/file-processing.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js index 41d5614e..3ef20380 100755 --- a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -2542,28 +2542,25 @@ function applyOverloadPresentation(dir) { /** * Tidy the generated actors page. TypeDoc inlines the ActorSubscription return - * type under `subscribe()`, which adds a duplicate `unsubscribe()` block, and the - * types under Type Definitions keep repeated `Properties`/`Parameters`/`Returns` - * headings. This drops the duplicate, folds those headings, and fixes the dead - * `ActorRef` link. A page without the expected shape is left unchanged. + * type under `subscribe()`, which adds a duplicate `unsubscribe()` block. This + * drops the duplicate and fixes the dead `ActorRef` link. A page without the + * expected shape is left unchanged. */ function restructureActorsPage() { const file = path.join(DOCS_DIR, "content", "type-aliases", "actors.mdx"); if (!fs.existsSync(file)) return; const duplicateUnsubscribe = /\n## Methods\n\n### unsubscribe\(\)[\s\S]*?<\/CodeGroup>\n/; - const [page, types] = fs.readFileSync(file, "utf-8").split("\n## Type Definitions\n"); - if (types === undefined || !duplicateUnsubscribe.test(page)) { + const content = fs.readFileSync(file, "utf-8"); + if (!duplicateUnsubscribe.test(content)) { console.warn("Warning: actors page has an unexpected structure and was left unchanged"); return; } - const tidiedTypes = types - .replace(/^## Properties\n\n/gm, "") - .replace(/^## (Parameters|Returns)$/gm, "#### $1") + const tidied = content + .replace(duplicateUnsubscribe, "\n") .replace("[`ActorRef`](ActorRef)", "[`ActorRef`](#actorref)"); - - fs.writeFileSync(file, `${page.replace(duplicateUnsubscribe, "\n")}\n## Type Definitions\n${tidiedTypes}`, "utf-8"); + fs.writeFileSync(file, tidied, "utf-8"); } function main() { From beb107e7c740bbdaa8336ac75133d58d98dfd7f4 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 10:49:12 +0300 Subject: [PATCH 19/24] Simplify actors page: method links and ActorConnectOptions Co-Authored-By: Claude Sonnet 5.5 --- .../mintlify-post-processing/appended-articles.json | 1 - .../file-processing/file-processing.js | 4 ++-- .../types-to-delete-after-processing.json | 1 + packages/sdk/src/modules/actors.types.ts | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/sdk/scripts/mintlify-post-processing/appended-articles.json b/packages/sdk/scripts/mintlify-post-processing/appended-articles.json index 0cdfa664..3002ae7a 100644 --- a/packages/sdk/scripts/mintlify-post-processing/appended-articles.json +++ b/packages/sdk/scripts/mintlify-post-processing/appended-articles.json @@ -27,7 +27,6 @@ "interfaces/ActorRef", "interfaces/Connection", "interfaces/ActorSubscription", - "interfaces/ActorConnectOptions", "interfaces/ActorClient", "interfaces/ActorRegistry", "interfaces/ActorNameRegistry" diff --git a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js index 3ef20380..042c5a30 100755 --- a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -1593,8 +1593,8 @@ function groupTypeDefinitions(content) { }, // Actors module { - types: ["ActorConnectOptions", "ActorClient", "ActorRegistry", "ActorNameRegistry"], - indicator: "ActorConnectOptions" + types: ["ActorClient", "ActorRegistry", "ActorNameRegistry"], + indicator: "ActorClient" } ]; diff --git a/packages/sdk/scripts/mintlify-post-processing/types-to-delete-after-processing.json b/packages/sdk/scripts/mintlify-post-processing/types-to-delete-after-processing.json index 894f1272..92d90b4e 100644 --- a/packages/sdk/scripts/mintlify-post-processing/types-to-delete-after-processing.json +++ b/packages/sdk/scripts/mintlify-post-processing/types-to-delete-after-processing.json @@ -1,5 +1,6 @@ [ "AiGatewayConnection", + "ActorConnectOptions", "DeleteManyResult", "DeleteResult", "EntityAggregateResult", diff --git a/packages/sdk/src/modules/actors.types.ts b/packages/sdk/src/modules/actors.types.ts index 0241e2b6..f43dda59 100644 --- a/packages/sdk/src/modules/actors.types.ts +++ b/packages/sdk/src/modules/actors.types.ts @@ -50,7 +50,7 @@ type ToServerFor = N extends keyof ActorRegistry : unknown; /** - * Configures the connection that [ActorRef.connect](#connect) opens. + * Configures the connection that [`connect()`](#connect) opens. */ export interface ActorConnectOptions { /** @@ -68,7 +68,7 @@ export interface ActorConnectOptions { /** * Represents a listener for messages from the actor, registered with - * [Connection.subscribe](#subscribe). + * [`subscribe()`](#subscribe). */ export interface ActorSubscription { /** @@ -86,7 +86,7 @@ export interface ActorSubscription { /** * Represents a client's WebSocket connection to an actor session. * - * [ActorRef.connect](#connect) returns this object. The socket buffers messages + * [`connect()`](#connect) returns this object. The socket buffers messages * you send before it opens. */ export interface Connection { @@ -117,7 +117,7 @@ export interface Connection { /** * Sends a message to the actor. * - * The socket buffers messages until it opens. After you call [close](#close), + * The socket buffers messages until it opens. After you call [`close()`](#close), * the socket drops further sends. * * @param data - Message to send to the actor. The type comes from [ActorRegistry](#actorregistry) when you register the actor there. @@ -135,7 +135,7 @@ export interface Connection { * * You can call this method more than once. A connection also closes itself * when it fails permanently. To open a new connection, call - * [ActorRef.connect](#connect) again. + * [`connect()`](#connect) again. * * @example * ```typescript @@ -149,7 +149,7 @@ export interface Connection { /** * Represents a reference to an actor session, identified by actor name and session ID. * - * Call [connect](#connect) to open the WebSocket and get a [Connection](#connection). + * Call [`connect()`](#connect) to open the WebSocket and get a [Connection](#connection). */ export interface ActorRef { /** From 5213b875a8e3d9365ebab6ae2d56ecda6e6bc320 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 11:32:39 +0300 Subject: [PATCH 20/24] Polish actors module docs Co-Authored-By: Claude Sonnet 5.5 --- .../file-processing/file-processing.js | 25 ++++++----- packages/sdk/src/modules/actors.types.ts | 45 +++++++++---------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js index 042c5a30..090bbaa1 100755 --- a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -1433,14 +1433,15 @@ function applyTypeDeclarationLinking(dir) { /** * Interfaces that are appended to a module page and have methods of their own. * Each keeps its own `## ` heading with its methods directly underneath, so the - * generic `## Methods` heading that follows it is dropped. The value renames the - * heading, or is null to keep the interface name. + * generic `## Methods` heading that follows it is dropped, along with any + * `## Properties` section. The value renames the heading, or is null to keep the + * interface name. */ const TYPES_WITH_OWN_METHODS = { EntityHandler: "Entity Handler Methods", - ActorRef: null, - Connection: null, - ActorSubscription: null, + ActorRef: "ActorRef methods", + Connection: "Connection methods", + ActorSubscription: "ActorSubscription methods", }; /** @@ -1890,10 +1891,10 @@ function mergeSectionWithMethods(content, filePath) { if (methodsIndex !== -1) { lines[i] = `## ${TYPES_WITH_OWN_METHODS[typeName] ?? typeName}`; - if (propertiesIndex !== -1) { - lines[propertiesIndex] = "### Properties"; - } - lines.splice(methodsIndex, 1); + // Drop the ## Properties section too: the heading and its content sit + // between the type heading and ## Methods. + const removeFrom = propertiesIndex !== -1 ? propertiesIndex : methodsIndex; + lines.splice(removeFrom, methodsIndex - removeFrom + 1); modified = true; } } @@ -2543,8 +2544,8 @@ function applyOverloadPresentation(dir) { /** * Tidy the generated actors page. TypeDoc inlines the ActorSubscription return * type under `subscribe()`, which adds a duplicate `unsubscribe()` block. This - * drops the duplicate and fixes the dead `ActorRef` link. A page without the - * expected shape is left unchanged. + * drops the duplicate and points links to `ActorRef` at its renamed heading. A page + * without the expected shape is left unchanged. */ function restructureActorsPage() { const file = path.join(DOCS_DIR, "content", "type-aliases", "actors.mdx"); @@ -2559,7 +2560,7 @@ function restructureActorsPage() { const tidied = content .replace(duplicateUnsubscribe, "\n") - .replace("[`ActorRef`](ActorRef)", "[`ActorRef`](#actorref)"); + .replace("](#actorref)", "](#actorref-methods)"); fs.writeFileSync(file, tidied, "utf-8"); } diff --git a/packages/sdk/src/modules/actors.types.ts b/packages/sdk/src/modules/actors.types.ts index f43dda59..8257ef3d 100644 --- a/packages/sdk/src/modules/actors.types.ts +++ b/packages/sdk/src/modules/actors.types.ts @@ -1,13 +1,14 @@ /** * Maps actor names to their incoming and outgoing message types. * - * Extend this interface through module augmentation when you want typed actor - * messages without generating types with the CLI. For each actor, `toServer` - * defines incoming messages that a client sends to the actor. `toClient` defines - * outgoing messages that the actor sends to connected clients. + * Extend this interface when you want typed actor + * messages without generating types with the CLI: + * - `toServer`: Defines incoming messages that a client sends to the actor. + * - `toClient`: Defines outgoing messages that the actor sends to connected clients. * - * To generate types from deployed actors instead, use the + * To generate types from deployed actors, use the * [`types generate`](/developers/references/cli/commands/types-generate) CLI command. + * * To learn how incoming and outgoing messages work, see * [message types](/developers/backend/resources/actors/overview#message-types). * @@ -56,11 +57,11 @@ export interface ActorConnectOptions { /** * Connection ID that the actor receives as `conn.id`. * - * To let the actor recognize the same client if it reconnects, use a stable + * To let the actor recognize a client when it reconnects, use a stable * value, such as an ID stored per browser tab. If you omit this property, the - * SDK generates a connection ID. + * SDK generates a new connection ID. * - * For more about connection IDs, see + * Learn more about * [connections](/developers/backend/resources/actors/reference#connections). */ id?: string; @@ -84,10 +85,11 @@ export interface ActorSubscription { } /** - * Represents a client's WebSocket connection to an actor session. - * - * [`connect()`](#connect) returns this object. The socket buffers messages - * you send before it opens. + * Represents a client's WebSocket connection to an actor session, returned after calling + * [`connect()`](#connect). The socket queues messages you send before it opens. + * + * Learn more about + * [connections](/developers/backend/resources/actors/reference#connections). */ export interface Connection { /** Connection ID that the actor receives as `conn.id`. */ @@ -117,8 +119,8 @@ export interface Connection { /** * Sends a message to the actor. * - * The socket buffers messages until it opens. After you call [`close()`](#close), - * the socket drops further sends. + * The socket queues messages until it opens. When you call [`close()`](#close), + * the socket drops any further sent messages. * * @param data - Message to send to the actor. The type comes from [ActorRegistry](#actorregistry) when you register the actor there. * @@ -134,8 +136,7 @@ export interface Connection { * Closes the connection and removes all listeners. * * You can call this method more than once. A connection also closes itself - * when it fails permanently. To open a new connection, call - * [`connect()`](#connect) again. + * when it fails permanently. * * @example * ```typescript @@ -149,22 +150,20 @@ export interface Connection { /** * Represents a reference to an actor session, identified by actor name and session ID. * - * Call [`connect()`](#connect) to open the WebSocket and get a [Connection](#connection). + * Call [`connect()`](#connect) to open the WebSocket and get a [Connection](#returns). */ export interface ActorRef { /** - * Creates or returns the [Connection](#connection) for this session. + * Creates or returns the [Connection](#returns) for this session. * - * Repeated calls return the same connection until it closes. If the connection - * fails permanently, for example because the actor doesn't exist or the actor - * denies the connection, fix the cause and call `connect()` again. Then - * subscribe again on the new connection. + * Calling `connect()` again on the same session reference returns the same + * connection until it closes. * * For a sample flow, see * [connect a client to a session](/developers/backend/resources/actors/sample-flows#connect-a-client-to-a-session). * * @param options - Optional connection settings, such as a stable connection ID. - * @returns The [Connection](#connection) for this actor session. + * @returns The [Connection](#returns) for this actor session. * * @example * ```typescript From 136b32aad5f31b064da303b289f4796646f3316d Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 11:37:33 +0300 Subject: [PATCH 21/24] Use link tags and rename Actor methods Co-Authored-By: Claude Sonnet 5.5 --- .../file-processing/file-processing.js | 6 ++--- packages/sdk/src/modules/actors.types.ts | 27 +++++++++---------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js index 090bbaa1..f1cf9efe 100755 --- a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -1439,7 +1439,7 @@ function applyTypeDeclarationLinking(dir) { */ const TYPES_WITH_OWN_METHODS = { EntityHandler: "Entity Handler Methods", - ActorRef: "ActorRef methods", + ActorRef: "Actor methods", Connection: "Connection methods", ActorSubscription: "ActorSubscription methods", }; @@ -2544,7 +2544,7 @@ function applyOverloadPresentation(dir) { /** * Tidy the generated actors page. TypeDoc inlines the ActorSubscription return * type under `subscribe()`, which adds a duplicate `unsubscribe()` block. This - * drops the duplicate and points links to `ActorRef` at its renamed heading. A page + * drops the duplicate and points links to `ActorRef` at its renamed heading, Actor methods. A page * without the expected shape is left unchanged. */ function restructureActorsPage() { @@ -2560,7 +2560,7 @@ function restructureActorsPage() { const tidied = content .replace(duplicateUnsubscribe, "\n") - .replace("](#actorref)", "](#actorref-methods)"); + .replace("](#actorref)", "](#actor-methods)"); fs.writeFileSync(file, tidied, "utf-8"); } diff --git a/packages/sdk/src/modules/actors.types.ts b/packages/sdk/src/modules/actors.types.ts index 8257ef3d..ee7d0ad9 100644 --- a/packages/sdk/src/modules/actors.types.ts +++ b/packages/sdk/src/modules/actors.types.ts @@ -32,7 +32,7 @@ export interface ActorRegistry {} * with [`types generate`](/developers/references/cli/commands/types-generate). * * The generated names provide autocomplete for deployed actors. To define - * incoming and outgoing message types manually, augment [ActorRegistry](#actorregistry). + * incoming and outgoing message types manually, augment {@linkcode ActorRegistry}. */ export interface ActorNameRegistry {} @@ -51,7 +51,7 @@ type ToServerFor = N extends keyof ActorRegistry : unknown; /** - * Configures the connection that [`connect()`](#connect) opens. + * Configures the connection that {@linkcode ActorRef.connect | connect()} opens. */ export interface ActorConnectOptions { /** @@ -60,16 +60,13 @@ export interface ActorConnectOptions { * To let the actor recognize a client when it reconnects, use a stable * value, such as an ID stored per browser tab. If you omit this property, the * SDK generates a new connection ID. - * - * Learn more about - * [connections](/developers/backend/resources/actors/reference#connections). */ id?: string; } /** * Represents a listener for messages from the actor, registered with - * [`subscribe()`](#subscribe). + * {@linkcode Connection.subscribe | subscribe()}. */ export interface ActorSubscription { /** @@ -119,10 +116,10 @@ export interface Connection { /** * Sends a message to the actor. * - * The socket queues messages until it opens. When you call [`close()`](#close), + * The socket queues messages until it opens. When you call {@linkcode Connection.close | close()}, * the socket drops any further sent messages. * - * @param data - Message to send to the actor. The type comes from [ActorRegistry](#actorregistry) when you register the actor there. + * @param data - Message to send to the actor. The type comes from {@linkcode ActorRegistry} when you register the actor there. * * @example * ```typescript @@ -150,7 +147,7 @@ export interface Connection { /** * Represents a reference to an actor session, identified by actor name and session ID. * - * Call [`connect()`](#connect) to open the WebSocket and get a [Connection](#returns). + * Call {@linkcode ActorRef.connect | connect()} to open the WebSocket and get a [Connection](#returns). */ export interface ActorRef { /** @@ -178,7 +175,7 @@ export interface ActorRef { * Selects a session for a named actor. * * TypeScript infers message types when you register the actor in - * [ActorRegistry](#actorregistry). [ActorNameRegistry](#actornameregistry) + * {@linkcode ActorRegistry}. {@linkcode ActorNameRegistry} * provides autocomplete for actor names only. */ export interface ActorClient { @@ -208,11 +205,11 @@ export interface ActorClient { * * The actors module supports the following functionality: * - * - [`connect()`](#connect): Open a WebSocket connection to a session. - * - [`subscribe()`](#subscribe): Receive messages from the actor. - * - [`unsubscribe()`](#unsubscribe): Stop receiving messages from the actor without closing the connection. - * - [`send()`](#send): Send messages to the actor. - * - [`close()`](#close): Close the WebSocket connection to the actor. + * - {@linkcode ActorRef.connect | connect()}: Open a WebSocket connection to a session. + * - {@linkcode Connection.subscribe | subscribe()}: Receive messages from the actor. + * - {@linkcode ActorSubscription.unsubscribe | unsubscribe()}: Stop receiving messages from the actor without closing the connection. + * - {@linkcode Connection.send | send()}: Send messages to the actor. + * - {@linkcode Connection.close | close()}: Close the WebSocket connection to the actor. * * For a sample flow, see * [connect a client to a session](/developers/backend/resources/actors/sample-flows#connect-a-client-to-a-session). From 6ccf4fbf6698a16c1e951ad906a081420fc04400 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 11:43:38 +0300 Subject: [PATCH 22/24] Update actors module intro Co-Authored-By: Claude Sonnet 5.5 --- packages/sdk/src/modules/actors.types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sdk/src/modules/actors.types.ts b/packages/sdk/src/modules/actors.types.ts index ee7d0ad9..5b7934d3 100644 --- a/packages/sdk/src/modules/actors.types.ts +++ b/packages/sdk/src/modules/actors.types.ts @@ -197,14 +197,14 @@ export interface ActorClient { } /** - * Actors module for connecting a client to an [actor](/developers/backend/resources/actors/overview) session and exchanging messages. + * Actors module for connecting a client to an [actor](/developers/backend/resources/actors/overview) sessions, managing connections, and exchanging messages. * * An actor is a long-running backend process that multiple clients connect to simultaneously. A session * is a running instance of an actor, identified by the actor name and a session ID. Each * session manages its own state, storage, and client connections independently. * - * The actors module supports the following functionality: - * + * The actors module supports several objects with the following functionality: + * * - {@linkcode ActorRef.connect | connect()}: Open a WebSocket connection to a session. * - {@linkcode Connection.subscribe | subscribe()}: Receive messages from the actor. * - {@linkcode ActorSubscription.unsubscribe | unsubscribe()}: Stop receiving messages from the actor without closing the connection. From 9b8f28ab8d2fd00c939a0a79a6c2f45bcd814f27 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 12:03:42 +0300 Subject: [PATCH 23/24] Fix actors module intro wording Co-Authored-By: Claude Sonnet 5.5 --- packages/sdk/src/modules/actors.types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/src/modules/actors.types.ts b/packages/sdk/src/modules/actors.types.ts index 5b7934d3..b3ae5a4b 100644 --- a/packages/sdk/src/modules/actors.types.ts +++ b/packages/sdk/src/modules/actors.types.ts @@ -197,7 +197,7 @@ export interface ActorClient { } /** - * Actors module for connecting a client to an [actor](/developers/backend/resources/actors/overview) sessions, managing connections, and exchanging messages. + * Actors module for connecting a client to [actor](/developers/backend/resources/actors/overview) sessions, managing connections, and exchanging messages. * * An actor is a long-running backend process that multiple clients connect to simultaneously. A session * is a running instance of an actor, identified by the actor name and a session ID. Each From 2288fd34719a1b23c38e0fa8cf510eea93fea553 Mon Sep 17 00:00:00 2001 From: "Abraham (Avi) Soclof" Date: Wed, 7 Oct 2026 14:43:23 +0300 Subject: [PATCH 24/24] Update actors module docs Co-Authored-By: Claude Sonnet 5.5 --- .../file-processing/file-processing.js | 2 +- packages/sdk/src/modules/actors.types.ts | 28 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js index f1cf9efe..43a7dcb9 100755 --- a/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/packages/sdk/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -1441,7 +1441,7 @@ const TYPES_WITH_OWN_METHODS = { EntityHandler: "Entity Handler Methods", ActorRef: "Actor methods", Connection: "Connection methods", - ActorSubscription: "ActorSubscription methods", + ActorSubscription: "Subscription methods", }; /** diff --git a/packages/sdk/src/modules/actors.types.ts b/packages/sdk/src/modules/actors.types.ts index b3ae5a4b..72e5f372 100644 --- a/packages/sdk/src/modules/actors.types.ts +++ b/packages/sdk/src/modules/actors.types.ts @@ -82,8 +82,8 @@ export interface ActorSubscription { } /** - * Represents a client's WebSocket connection to an actor session, returned after calling - * [`connect()`](#connect). The socket queues messages you send before it opens. + * Represents a client's [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) connection to an actor session, returned after calling + * [`connect()`](#connect). The WebSocket queues messages you send before it opens. * * Learn more about * [connections](/developers/backend/resources/actors/reference#connections). @@ -116,8 +116,8 @@ export interface Connection { /** * Sends a message to the actor. * - * The socket queues messages until it opens. When you call {@linkcode Connection.close | close()}, - * the socket drops any further sent messages. + * The WebSocket queues messages until it opens. When you call {@linkcode Connection.close | close()}, + * the WebSocket drops any messages you send afterward. * * @param data - Message to send to the actor. The type comes from {@linkcode ActorRegistry} when you register the actor there. * @@ -147,11 +147,11 @@ export interface Connection { /** * Represents a reference to an actor session, identified by actor name and session ID. * - * Call {@linkcode ActorRef.connect | connect()} to open the WebSocket and get a [Connection](#returns). + * Call {@linkcode ActorRef.connect | connect()} to open the WebSocket and get a [connection](/developers/backend/resources/actors/overview#connections). */ export interface ActorRef { /** - * Creates or returns the [Connection](#returns) for this session. + * Creates or returns the connection for this session. * * Calling `connect()` again on the same session reference returns the same * connection until it closes. @@ -160,7 +160,7 @@ export interface ActorRef { * [connect a client to a session](/developers/backend/resources/actors/sample-flows#connect-a-client-to-a-session). * * @param options - Optional connection settings, such as a stable connection ID. - * @returns The [Connection](#returns) for this actor session. + * @returns The connection for this actor session. * * @example * ```typescript @@ -197,19 +197,17 @@ export interface ActorClient { } /** - * Actors module for connecting a client to [actor](/developers/backend/resources/actors/overview) sessions, managing connections, and exchanging messages. + * Actors module for interacting with [actors](/developers/backend/resources/actors/overview) from your app. * * An actor is a long-running backend process that multiple clients connect to simultaneously. A session * is a running instance of an actor, identified by the actor name and a session ID. Each * session manages its own state, storage, and client connections independently. * - * The actors module supports several objects with the following functionality: - * - * - {@linkcode ActorRef.connect | connect()}: Open a WebSocket connection to a session. - * - {@linkcode Connection.subscribe | subscribe()}: Receive messages from the actor. - * - {@linkcode ActorSubscription.unsubscribe | unsubscribe()}: Stop receiving messages from the actor without closing the connection. - * - {@linkcode Connection.send | send()}: Send messages to the actor. - * - {@linkcode Connection.close | close()}: Close the WebSocket connection to the actor. + * The actors module provides the functionality to: + * + * - Manage connections: {@link ActorRef.connect | Open} and {@link Connection.close | close} a WebSocket connection to a session. + * - Exchange messages: {@link Connection.send | Send} and {@link Connection.subscribe | listen} for messages to and from an actor. + * - Manage subscriptions: {@link Connection.subscribe | Subscribe} and {@link ActorSubscription.unsubscribe | unsubscribe} from actor messages without closing the connection. * * For a sample flow, see * [connect a client to a session](/developers/backend/resources/actors/sample-flows#connect-a-client-to-a-session).