Skip to content

Commit e409caa

Browse files
committed
docs(actors): document the actors module to the standard of the other modules
The actors page published as 18 lines: a truncated type signature, two sentences and one snippet. connect(), subscribe(), send(), close() and unsubscribe() did not appear at all. Adds a module overview covering what an Actor instance is, a capability list, the supported authentication modes, and the note that connections stay open until closed. Every public method now has a description, @PARAM, @returns and at least one @example, and each example opens with a comment so the pipeline renders it as the code-block title. Cross-references use explicit same-page anchors such as [connect()](#connect). Every type on this page is appended into it, so {@link Connection.close} resolves to a file the pipeline then unlinks and would 404, while a bare {@link close} resolves to a working anchor and is kept. Plain code spans are used only where no heading exists (ActorNameRegistry, ActorSubscription) or where the reference would point at the section it already sits in. Every behavioural claim is checked against src/modules/actors.ts and src/client.ts rather than inferred. See the PR description for the line-by-line trace.
1 parent 259b5df commit e409caa

1 file changed

Lines changed: 156 additions & 28 deletions

File tree

src/modules/actors.types.ts

Lines changed: 156 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
* Extend this interface to add typed `subscribe` callbacks and `send` payloads
33
* for your deployed Actors.
44
*
5-
* This is separate from {@link ActorNameRegistry} (which is auto-generated
5+
* This is separate from `ActorNameRegistry` (which is auto-generated
66
* by `base44 types generate`), so there are no conflicts.
77
*
88
* @example
99
* ```typescript
10+
* // Declare message types for a deployed actor
1011
* declare module "@base44/sdk" {
1112
* interface ActorRegistry {
1213
* ChatRoom: {
@@ -21,7 +22,7 @@ export interface ActorRegistry {}
2122

2223
/**
2324
* Auto-populated by `base44 types generate` with the names of your deployed actors.
24-
* Do not edit this interface manually. Use {@link ActorRegistry} for message types.
25+
* Do not edit this interface manually. Use `ActorRegistry` for message types.
2526
*/
2627
export interface ActorNameRegistry {}
2728

@@ -39,83 +40,210 @@ type ToServerFor<N extends string> = N extends keyof ActorRegistry
3940
: unknown
4041
: unknown;
4142

42-
/** Options for {@link ActorRef.connect}. */
43+
/** Options for [connect()](#connect). */
4344
export interface ActorConnectOptions {
4445
/**
45-
* The connection id, used as the actor's `conn.id`. Supply a stable value
46-
* (e.g. persisted per tab) so a reconnect reuses the same server-side
47-
* identity; omit for an auto-generated per-connection id.
46+
* The connection id, used as the actor's `conn.id`. Supply a stable value,
47+
* such as one persisted per tab, so a reconnect reuses the same server-side
48+
* identity. Omit it for an auto-generated per-connection id.
4849
*/
4950
id?: string;
5051
}
5152

52-
/** Handle for one listener registered via {@link Connection.subscribe}. */
53+
/** Handle for one listener registered via `subscribe()`. */
5354
export interface ActorSubscription {
54-
/** Remove this listener; other listeners and the socket stay live. */
55+
/**
56+
* Removes this listener. Other listeners on the same connection, and the
57+
* connection itself, stay live. To close the connection as well, call
58+
* [close()](#close).
59+
*
60+
* @example
61+
* ```typescript
62+
* // Stop listening without closing the connection
63+
* const sub = conn.subscribe((msg) => console.log(msg));
64+
* sub.unsubscribe();
65+
* ```
66+
*/
5567
unsubscribe(): void;
5668
}
5769

5870
/**
59-
* A live connection to an actor instance, returned by {@link ActorRef.connect}.
71+
* A live connection to an actor instance, returned by [connect()](#connect).
6072
* `subscribe`/`send` are always valid. You only get a `Connection` once the
6173
* socket has been opened, so there's no pre-connect state to guard against.
6274
*/
6375
export interface Connection<N extends string = string> {
64-
/** The connection id (the value the actor sees as `conn.id`). */
76+
/** The connection id, which is the value the actor sees as `conn.id`. */
6577
readonly id: string;
6678

67-
/** Register a message listener. Multiple are allowed; returns a per-listener unsubscribe. */
79+
/**
80+
* Registers a listener for messages sent by the actor. Any number of
81+
* listeners can be registered on one connection, and each receives every
82+
* message.
83+
*
84+
* The callback payload is typed when the actor is declared in
85+
* [ActorRegistry](#actorregistry), and is `unknown` otherwise.
86+
*
87+
* @param callback - Called with each message the actor sends to this client.
88+
* @returns An `ActorSubscription` that removes this one listener.
89+
*
90+
* @example
91+
* ```typescript
92+
* // Listen for messages from the actor
93+
* const sub = conn.subscribe((msg) => {
94+
* if (msg.type === "message") console.log(msg.text);
95+
* });
96+
* ```
97+
*/
6898
subscribe(callback: (data: ToClientFor<N>) => void): ActorSubscription;
6999

70-
/** Send a message. Buffered by the socket until it's open; dropped after
71-
* {@link close}. */
100+
/**
101+
* Sends a message to the actor.
102+
*
103+
* Messages sent before the socket finishes opening are buffered and flushed
104+
* on open. Messages sent after {@link close} are dropped silently.
105+
*
106+
* The payload is typed when the actor is declared in
107+
* [ActorRegistry](#actorregistry), and is `unknown` otherwise.
108+
*
109+
* @param data - The message to send to the actor.
110+
*
111+
* @example
112+
* ```typescript
113+
* // Send a message to the actor
114+
* conn.send({ type: "message", text: "hi" });
115+
* ```
116+
*/
72117
send(data: ToServerFor<N>): void;
73118

74119
/**
75-
* Tear down the socket, heartbeat, and all listeners. Safe to call more
76-
* than once. A connection also closes itself when it fails permanently.
77-
* See {@link ActorRef.connect}.
120+
* Closes the connection, tearing down the socket, the heartbeat, and every
121+
* listener registered on it. Safe to call more than once.
122+
*
123+
* A connection also closes itself when it fails permanently. See
124+
* [connect()](#connect) for how to recover from that.
125+
*
126+
* @example
127+
* ```typescript
128+
* // Close when the view that opened the connection goes away.
129+
* useEffect(() => {
130+
* const conn = base44.actors.ChatRoom(roomId).connect();
131+
* conn.subscribe(setMessage);
132+
* return () => conn.close();
133+
* }, [roomId]);
134+
* ```
78135
*/
79136
close(): void;
80137
}
81138

82139
/**
83140
* A handle to one actor instance, obtained from `base44.actors.MyActor(id)`. Call
84-
* {@link connect} to open the socket and get a {@link Connection}.
141+
* {@link connect} to open the socket and get a [Connection](#connection).
85142
*/
86143
export interface ActorRef<N extends string = string> {
87144
/**
88-
* Open the WebSocket and return the {@link Connection}. Idempotent while the
89-
* connection is open.
145+
* Opens the WebSocket to this actor instance and returns the
146+
* [Connection](#connection). Idempotent while the connection is open, so calling it
147+
* again returns the same connection rather than opening a second socket.
148+
*
149+
* The returned connection is usable straight away. Messages passed to
150+
* [send()](#send) before the socket finishes opening are buffered and
151+
* flushed on open.
152+
*
153+
* A connection that fails permanently, for example because the actor doesn't
154+
* exist or the caller isn't allowed to connect, closes itself and reports the
155+
* error to the client's `onError` handler. Call `connect()` again once the
156+
* cause is fixed to get a fresh [Connection](#connection), then re-subscribe, as
157+
* listeners do not carry over.
158+
*
159+
* @param options - Connection options. See [ActorConnectOptions](#actorconnectoptions).
160+
* @returns A live [Connection](#connection) to this actor instance.
161+
*
162+
* @example
163+
* ```typescript
164+
* // Connect to an actor instance
165+
* const conn = base44.actors.ChatRoom("room-1").connect();
166+
* ```
167+
*
168+
* @example
169+
* ```typescript
170+
* // Reuse a stable connection id so a reconnect keeps the same
171+
* // server-side identity.
172+
* let id = sessionStorage.getItem("chat-conn-id") ?? crypto.randomUUID();
173+
* sessionStorage.setItem("chat-conn-id", id);
90174
*
91-
* A connection that fails permanently (for example, the actor doesn't exist
92-
* or the caller isn't allowed to connect) closes itself and reports the
93-
* error to the client's `onError` handler. Call `connect()` again after
94-
* fixing the cause to get a fresh {@link Connection}, and re-subscribe.
175+
* const conn = base44.actors.ChatRoom("room-1").connect({ id });
176+
* ```
95177
*/
96178
connect(options?: ActorConnectOptions): Connection<N>;
97179
}
98180

99181
/**
100182
* Client for a single named Actor. Call it with an instance id to get an
101-
* {@link ActorRef}. Typed automatically when the actor is registered in
102-
* {@link ActorRegistry}.
183+
* [ActorRef](#actorref). Typed automatically when the actor is registered in
184+
* [ActorRegistry](#actorregistry).
103185
*/
104186
export interface ActorClient<N extends string = string> {
105187
(instanceId: string): ActorRef<N>;
106188
}
107189

108190
/**
109-
* The actors module provides access to Cloudflare Durable Object-backed
191+
* Actors module for real-time messaging with Cloudflare Durable Object-backed
110192
* Actors deployed by the Base44 platform.
111193
*
194+
* An Actor is a named server-side object with persistent state. Each instance
195+
* is addressed by an id, so `base44.actors.ChatRoom("room-1")` and
196+
* `base44.actors.ChatRoom("room-2")` are separate instances with separate
197+
* state. Clients open a WebSocket to an instance and exchange messages with it.
198+
*
199+
* This module provides:
200+
* - Per-instance WebSocket connections, opened with [connect()](#connect)
201+
* - Message listeners, registered with [subscribe()](#subscribe)
202+
* - Message sending, with [send()](#send)
203+
* - Automatic reconnection with backoff, including recovery from half-open
204+
* sockets that stop delivering messages without emitting a close event
205+
* - End-to-end typing of message payloads through [ActorRegistry](#actorregistry)
206+
*
207+
* This module is available to use with a client in anonymous and user
208+
* authentication modes. It is not available on `base44.asServiceRole`.
209+
*
210+
* Connections stay open until you call [close()](#close), so close them
211+
* when the view that opened them goes away.
212+
*
213+
* @example
112214
* ```typescript
113-
* const conn = base44.actors.MyActor("room-1").connect();
114-
* const sub = conn.subscribe((msg) => console.log(msg)); // typed via ActorRegistry
215+
* // Open a connection to one instance of the ChatRoom actor.
216+
* const conn = base44.actors.ChatRoom("room-1").connect();
217+
*
218+
* const sub = conn.subscribe((msg) => {
219+
* console.log(msg);
220+
* });
221+
*
115222
* conn.send({ type: "message", text: "hi" });
223+
*
224+
* // Later, when the view goes away.
116225
* sub.unsubscribe();
117226
* conn.close();
118227
* ```
228+
*
229+
* @example
230+
* ```typescript
231+
* // Register the actor to type both directions of the conversation.
232+
* declare module "@base44/sdk" {
233+
* interface ActorRegistry {
234+
* ChatRoom: {
235+
* toClient: { type: "joined" | "message"; from?: string; text?: string };
236+
* toServer: { type: "message"; text: string };
237+
* };
238+
* }
239+
* }
240+
*
241+
* const conn = base44.actors.ChatRoom("room-1").connect();
242+
* conn.subscribe((msg) => {
243+
* // msg is typed as the toClient union.
244+
* if (msg.type === "message") console.log(msg.text);
245+
* });
246+
* ```
119247
*/
120248
export type ActorsModule = {
121249
[K in AllActorNames]: K extends keyof ActorRegistry

0 commit comments

Comments
 (0)