chat 4.11.0 → 4.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -234,6 +234,29 @@ interface Adapter<TThreadId = unknown, TRawMessage = unknown> {
234
234
  * @returns The raw message after streaming completes
235
235
  */
236
236
  stream?(threadId: string, textStream: AsyncIterable<string>, options?: StreamOptions): Promise<RawMessage<TRawMessage>>;
237
+ /**
238
+ * Derive channel ID from a thread ID.
239
+ * Default fallback: first two colon-separated parts (e.g., "slack:C123").
240
+ * Adapters with different structures should override this.
241
+ */
242
+ channelIdFromThreadId?(threadId: string): string;
243
+ /**
244
+ * Fetch channel-level messages (top-level, not thread replies).
245
+ * For example, Slack's conversations.history vs conversations.replies.
246
+ */
247
+ fetchChannelMessages?(channelId: string, options?: FetchOptions): Promise<FetchResult<TRawMessage>>;
248
+ /**
249
+ * List threads in a channel.
250
+ */
251
+ listThreads?(channelId: string, options?: ListThreadsOptions): Promise<ListThreadsResult<TRawMessage>>;
252
+ /**
253
+ * Fetch channel info/metadata.
254
+ */
255
+ fetchChannelInfo?(channelId: string): Promise<ChannelInfo>;
256
+ /**
257
+ * Post a message to channel top-level (not in a thread).
258
+ */
259
+ postChannelMessage?(channelId: string, message: AdapterPostableMessage): Promise<RawMessage<TRawMessage>>;
237
260
  }
238
261
  /**
239
262
  * Options for streaming messages.
@@ -286,19 +309,30 @@ interface ChatInstance {
286
309
  /**
287
310
  * Process a modal submit event from an adapter.
288
311
  *
289
- * @param event - The modal submit event (without relatedThread/relatedMessage)
290
- * @param contextId - Context ID for retrieving stored thread/message context
312
+ * @param event - The modal submit event (without relatedThread/relatedMessage/relatedChannel)
313
+ * @param contextId - Context ID for retrieving stored thread/message/channel context
291
314
  * @param options - Webhook options
292
315
  */
293
- processModalSubmit(event: Omit<ModalSubmitEvent, "relatedThread" | "relatedMessage">, contextId?: string, options?: WebhookOptions): Promise<ModalResponse | undefined>;
316
+ processModalSubmit(event: Omit<ModalSubmitEvent, "relatedThread" | "relatedMessage" | "relatedChannel">, contextId?: string, options?: WebhookOptions): Promise<ModalResponse | undefined>;
294
317
  /**
295
318
  * Process a modal close event from an adapter.
296
319
  *
297
- * @param event - The modal close event (without relatedThread/relatedMessage)
298
- * @param contextId - Context ID for retrieving stored thread/message context
320
+ * @param event - The modal close event (without relatedThread/relatedMessage/relatedChannel)
321
+ * @param contextId - Context ID for retrieving stored thread/message/channel context
299
322
  * @param options - Webhook options
300
323
  */
301
- processModalClose(event: Omit<ModalCloseEvent, "relatedThread" | "relatedMessage">, contextId?: string, options?: WebhookOptions): void;
324
+ processModalClose(event: Omit<ModalCloseEvent, "relatedThread" | "relatedMessage" | "relatedChannel">, contextId?: string, options?: WebhookOptions): void;
325
+ /**
326
+ * Process an incoming slash command from an adapter.
327
+ * Handles waitUntil registration and error catching internally.
328
+ *
329
+ * @param event - The slash command event
330
+ * @param options - Webhook options including waitUntil
331
+ */
332
+ processSlashCommand(event: Omit<SlashCommandEvent, "channel" | "openModal"> & {
333
+ adapter: Adapter;
334
+ channelId: string;
335
+ }, options?: WebhookOptions): void;
302
336
  getState(): StateAdapter;
303
337
  getUserName(): string;
304
338
  /** Get the configured logger, optionally with a child prefix */
@@ -335,54 +369,121 @@ interface Lock {
335
369
  token: string;
336
370
  expiresAt: number;
337
371
  }
338
- /** Default TTL for thread state (30 days in milliseconds) */
339
- declare const THREAD_STATE_TTL_MS: number;
340
372
  /**
341
- * Thread interface with support for custom state.
342
- * @template TState - Custom state type stored per-thread (default: Record<string, unknown>)
373
+ * Base interface for entities that can receive messages.
374
+ * Both Thread and Channel extend this interface.
375
+ *
376
+ * @template TState - Custom state type stored per entity
343
377
  * @template TRawMessage - Platform-specific raw message type
344
378
  */
345
- interface Thread<TState = Record<string, unknown>, TRawMessage = unknown> {
346
- /** Unique thread ID (format: "adapter:channel:thread") */
379
+ interface Postable<TState = Record<string, unknown>, TRawMessage = unknown> {
380
+ /** Unique ID */
347
381
  readonly id: string;
348
- /** The adapter this thread belongs to */
382
+ /** The adapter this entity belongs to */
349
383
  readonly adapter: Adapter;
350
- /** Channel/conversation ID */
351
- readonly channelId: string;
352
384
  /** Whether this is a direct message conversation */
353
385
  readonly isDM: boolean;
354
386
  /**
355
- * Get the current thread state.
387
+ * Get the current state.
356
388
  * Returns null if no state has been set.
357
- *
358
- * @example
359
- * ```typescript
360
- * const state = await thread.state;
361
- * if (state?.aiMode) {
362
- * // AI mode is enabled
363
- * }
364
- * ```
365
389
  */
366
390
  readonly state: Promise<TState | null>;
367
391
  /**
368
- * Set the thread state. Merges with existing state by default.
369
- * State is persisted for 30 days.
370
- *
371
- * @param state - Partial state to merge, or full state if replace is true
372
- * @param options - Options for setting state
373
- *
374
- * @example
375
- * ```typescript
376
- * // Merge with existing state
377
- * await thread.setState({ aiMode: true });
378
- *
379
- * // Replace entire state
380
- * await thread.setState({ aiMode: true }, { replace: true });
381
- * ```
392
+ * Set the state. Merges with existing state by default.
382
393
  */
383
394
  setState(state: Partial<TState>, options?: {
384
395
  replace?: boolean;
385
396
  }): Promise<void>;
397
+ /**
398
+ * Iterate messages newest first (backward from most recent).
399
+ * Auto-paginates lazily — only fetches pages as consumed.
400
+ */
401
+ readonly messages: AsyncIterable<Message<TRawMessage>>;
402
+ /**
403
+ * Post a message.
404
+ */
405
+ post(message: string | PostableMessage | CardJSXElement): Promise<SentMessage<TRawMessage>>;
406
+ /**
407
+ * Post an ephemeral message visible only to a specific user.
408
+ */
409
+ postEphemeral(user: string | Author, message: AdapterPostableMessage | CardJSXElement, options: PostEphemeralOptions): Promise<EphemeralMessage | null>;
410
+ /** Show typing indicator */
411
+ startTyping(): Promise<void>;
412
+ /**
413
+ * Get a platform-specific mention string for a user.
414
+ */
415
+ mentionUser(userId: string): string;
416
+ }
417
+ /**
418
+ * Represents a channel/conversation container that holds threads.
419
+ * Extends Postable for message posting capabilities.
420
+ *
421
+ * @template TState - Custom state type stored per channel
422
+ * @template TRawMessage - Platform-specific raw message type
423
+ */
424
+ interface Channel<TState = Record<string, unknown>, TRawMessage = unknown> extends Postable<TState, TRawMessage> {
425
+ /** Channel name (e.g., "#general"). Null until fetchInfo() is called. */
426
+ readonly name: string | null;
427
+ /**
428
+ * Iterate threads in this channel, most recently active first.
429
+ * Returns ThreadSummary (lightweight) for efficiency.
430
+ * Empty iterable on threadless platforms.
431
+ */
432
+ threads(): AsyncIterable<ThreadSummary<TRawMessage>>;
433
+ /** Fetch channel metadata from the platform */
434
+ fetchMetadata(): Promise<ChannelInfo>;
435
+ }
436
+ /**
437
+ * Lightweight summary of a thread within a channel.
438
+ */
439
+ interface ThreadSummary<TRawMessage = unknown> {
440
+ /** Full thread ID */
441
+ id: string;
442
+ /** Root/first message of the thread */
443
+ rootMessage: Message<TRawMessage>;
444
+ /** Reply count (if available) */
445
+ replyCount?: number;
446
+ /** Timestamp of most recent reply */
447
+ lastReplyAt?: Date;
448
+ }
449
+ /**
450
+ * Channel metadata returned by fetchInfo().
451
+ */
452
+ interface ChannelInfo {
453
+ id: string;
454
+ name?: string;
455
+ isDM?: boolean;
456
+ memberCount?: number;
457
+ metadata: Record<string, unknown>;
458
+ }
459
+ /**
460
+ * Options for listing threads in a channel.
461
+ */
462
+ interface ListThreadsOptions {
463
+ limit?: number;
464
+ cursor?: string;
465
+ }
466
+ /**
467
+ * Result of listing threads in a channel.
468
+ */
469
+ interface ListThreadsResult<TRawMessage = unknown> {
470
+ threads: ThreadSummary<TRawMessage>[];
471
+ nextCursor?: string;
472
+ }
473
+ /** Default TTL for thread state (30 days in milliseconds) */
474
+ declare const THREAD_STATE_TTL_MS: number;
475
+ /**
476
+ * Thread interface with support for custom state.
477
+ * Extends Postable for shared message posting capabilities.
478
+ *
479
+ * @template TState - Custom state type stored per-thread (default: Record<string, unknown>)
480
+ * @template TRawMessage - Platform-specific raw message type
481
+ */
482
+ interface Thread<TState = Record<string, unknown>, TRawMessage = unknown> extends Postable<TState, TRawMessage> {
483
+ /** Channel/conversation ID */
484
+ readonly channelId: string;
485
+ /** Get the Channel containing this thread */
486
+ readonly channel: Channel<TState, TRawMessage>;
386
487
  /** Recently fetched messages (cached) */
387
488
  recentMessages: Message<TRawMessage>[];
388
489
  /**
@@ -1014,6 +1115,11 @@ interface ModalSubmitEvent<TRawMessage = unknown> {
1014
1115
  * This is a SentMessage with edit/delete capabilities.
1015
1116
  */
1016
1117
  relatedMessage?: SentMessage<TRawMessage>;
1118
+ /**
1119
+ * The channel where the modal was originally triggered from.
1120
+ * Available when the modal was opened via SlashCommandEvent.openModal().
1121
+ */
1122
+ relatedChannel?: Channel<Record<string, unknown>, TRawMessage>;
1017
1123
  }
1018
1124
  /**
1019
1125
  * Event emitted when a user closes/cancels a modal (requires notifyOnClose).
@@ -1045,6 +1151,11 @@ interface ModalCloseEvent<TRawMessage = unknown> {
1045
1151
  * This is a SentMessage with edit/delete capabilities.
1046
1152
  */
1047
1153
  relatedMessage?: SentMessage<TRawMessage>;
1154
+ /**
1155
+ * The channel where the modal was originally triggered from.
1156
+ * Available when the modal was opened via SlashCommandEvent.openModal().
1157
+ */
1158
+ relatedChannel?: Channel<Record<string, unknown>, TRawMessage>;
1048
1159
  }
1049
1160
  type ModalErrorsResponse = {
1050
1161
  action: "errors";
@@ -1064,6 +1175,87 @@ type ModalCloseResponse = {
1064
1175
  type ModalResponse = ModalCloseResponse | ModalErrorsResponse | ModalUpdateResponse | ModalPushResponse;
1065
1176
  type ModalSubmitHandler = (event: ModalSubmitEvent) => Promise<ModalResponse | undefined>;
1066
1177
  type ModalCloseHandler = (event: ModalCloseEvent) => Promise<void>;
1178
+ /**
1179
+ * Event emitted when a user invokes a slash command.
1180
+ *
1181
+ * Slash commands are triggered when a user types `/command` in the message composer.
1182
+ * The event provides access to the channel where the command was invoked, allowing
1183
+ * you to post responses using standard SDK methods.
1184
+ *
1185
+ * @example
1186
+ * ```typescript
1187
+ * chat.onSlashCommand("/help", async (event) => {
1188
+ * // Post visible to everyone in the channel
1189
+ * await event.channel.post("Here are the available commands...");
1190
+ * });
1191
+ *
1192
+ * chat.onSlashCommand("/secret", async (event) => {
1193
+ * // Post ephemeral (only the invoking user sees it)
1194
+ * await event.channel.postEphemeral(
1195
+ * event.user,
1196
+ * "This is just for you!",
1197
+ * { fallbackToDM: false }
1198
+ * );
1199
+ * });
1200
+ *
1201
+ * chat.onSlashCommand("/feedback", async (event) => {
1202
+ * // Open a modal
1203
+ * await event.openModal({
1204
+ * type: "modal",
1205
+ * callbackId: "feedback_modal",
1206
+ * title: "Submit Feedback",
1207
+ * children: [{ type: "text_input", id: "feedback", label: "Your feedback" }],
1208
+ * });
1209
+ * });
1210
+ * ```
1211
+ */
1212
+ interface SlashCommandEvent<TState = Record<string, unknown>> {
1213
+ /** The slash command name (e.g., "/help") */
1214
+ command: string;
1215
+ /** Arguments text after the command (e.g., "topic search" from "/help topic search") */
1216
+ text: string;
1217
+ /** The user who invoked the command */
1218
+ user: Author;
1219
+ /** The channel where the command was invoked */
1220
+ channel: Channel<TState>;
1221
+ /** The adapter that received this event */
1222
+ adapter: Adapter;
1223
+ /** Platform-specific raw payload */
1224
+ raw: unknown;
1225
+ /** Trigger ID for opening modals (time-limited, typically ~3 seconds) */
1226
+ triggerId?: string;
1227
+ /**
1228
+ * Open a modal/dialog form in response to this slash command.
1229
+ *
1230
+ * @param modal - The modal element to display (JSX or ModalElement)
1231
+ * @returns The view/dialog ID, or undefined if modals are not supported
1232
+ */
1233
+ openModal(modal: ModalElement | CardJSXElement): Promise<{
1234
+ viewId: string;
1235
+ } | undefined>;
1236
+ }
1237
+ /**
1238
+ * Handler for slash command events.
1239
+ *
1240
+ * @example
1241
+ * ```typescript
1242
+ * // Handle a specific command
1243
+ * chat.onSlashCommand("/status", async (event) => {
1244
+ * await event.channel.post("All systems operational!");
1245
+ * });
1246
+ *
1247
+ * // Handle multiple commands
1248
+ * chat.onSlashCommand(["/help", "/info"], async (event) => {
1249
+ * await event.channel.post(`You invoked ${event.command}`);
1250
+ * });
1251
+ *
1252
+ * // Catch-all handler
1253
+ * chat.onSlashCommand(async (event) => {
1254
+ * console.log(`Command: ${event.command}, Args: ${event.text}`);
1255
+ * });
1256
+ * ```
1257
+ */
1258
+ type SlashCommandHandler<TState = Record<string, unknown>> = (event: SlashCommandEvent<TState>) => Promise<void>;
1067
1259
 
1068
1260
  /**
1069
1261
  * Message class with serialization support for workflow engines.
@@ -1212,6 +1404,77 @@ declare class Message<TRawMessage = unknown> {
1212
1404
  static [WORKFLOW_DESERIALIZE](data: SerializedMessage): Message;
1213
1405
  }
1214
1406
 
1407
+ /**
1408
+ * Serialized channel data for passing to external systems (e.g., workflow engines).
1409
+ */
1410
+ interface SerializedChannel {
1411
+ _type: "chat:Channel";
1412
+ id: string;
1413
+ adapterName: string;
1414
+ isDM: boolean;
1415
+ }
1416
+ /**
1417
+ * Config for creating a ChannelImpl with explicit adapter/state instances.
1418
+ */
1419
+ interface ChannelImplConfigWithAdapter {
1420
+ id: string;
1421
+ adapter: Adapter;
1422
+ stateAdapter: StateAdapter;
1423
+ isDM?: boolean;
1424
+ }
1425
+ /**
1426
+ * Config for creating a ChannelImpl with lazy adapter resolution.
1427
+ */
1428
+ interface ChannelImplConfigLazy {
1429
+ id: string;
1430
+ adapterName: string;
1431
+ isDM?: boolean;
1432
+ }
1433
+ type ChannelImplConfig = ChannelImplConfigWithAdapter | ChannelImplConfigLazy;
1434
+ declare class ChannelImpl<TState = Record<string, unknown>> implements Channel<TState> {
1435
+ readonly id: string;
1436
+ readonly isDM: boolean;
1437
+ private _adapter?;
1438
+ private _adapterName?;
1439
+ private _stateAdapterInstance?;
1440
+ private _name;
1441
+ constructor(config: ChannelImplConfig);
1442
+ get adapter(): Adapter;
1443
+ private get _stateAdapter();
1444
+ get name(): string | null;
1445
+ get state(): Promise<TState | null>;
1446
+ setState(newState: Partial<TState>, options?: {
1447
+ replace?: boolean;
1448
+ }): Promise<void>;
1449
+ /**
1450
+ * Iterate messages newest first (backward from most recent).
1451
+ * Uses adapter.fetchChannelMessages if available, otherwise falls back
1452
+ * to adapter.fetchMessages with the channel ID.
1453
+ */
1454
+ get messages(): AsyncIterable<Message>;
1455
+ /**
1456
+ * Iterate threads in this channel, most recently active first.
1457
+ */
1458
+ threads(): AsyncIterable<ThreadSummary>;
1459
+ fetchMetadata(): Promise<ChannelInfo>;
1460
+ post(message: string | PostableMessage | CardJSXElement): Promise<SentMessage>;
1461
+ private postSingleMessage;
1462
+ postEphemeral(user: string | Author, message: AdapterPostableMessage | CardJSXElement, options: PostEphemeralOptions): Promise<EphemeralMessage | null>;
1463
+ startTyping(): Promise<void>;
1464
+ mentionUser(userId: string): string;
1465
+ toJSON(): SerializedChannel;
1466
+ static fromJSON<TState = Record<string, unknown>>(json: SerializedChannel, adapter?: Adapter): ChannelImpl<TState>;
1467
+ static [WORKFLOW_SERIALIZE](instance: ChannelImpl): SerializedChannel;
1468
+ static [WORKFLOW_DESERIALIZE](data: SerializedChannel): ChannelImpl;
1469
+ private createSentMessage;
1470
+ }
1471
+ /**
1472
+ * Derive the channel ID from a thread ID.
1473
+ * Uses adapter.channelIdFromThreadId if available, otherwise defaults to
1474
+ * first two colon-separated parts.
1475
+ */
1476
+ declare function deriveChannelId(adapter: Adapter, threadId: string): string;
1477
+
1215
1478
  /** Filter can be EmojiValue objects, emoji names, or raw emoji formats */
1216
1479
  type EmojiFilter = EmojiValue | string;
1217
1480
  /**
@@ -1288,6 +1551,7 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
1288
1551
  private actionHandlers;
1289
1552
  private modalSubmitHandlers;
1290
1553
  private modalCloseHandlers;
1554
+ private slashCommandHandlers;
1291
1555
  /** Initialization state */
1292
1556
  private initPromise;
1293
1557
  private initialized;
@@ -1445,6 +1709,45 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
1445
1709
  onModalClose(handler: ModalCloseHandler): void;
1446
1710
  onModalClose(callbackId: string, handler: ModalCloseHandler): void;
1447
1711
  onModalClose(callbackIds: string[], handler: ModalCloseHandler): void;
1712
+ /**
1713
+ * Register a handler for slash command events.
1714
+ *
1715
+ * Slash commands are triggered when a user types `/command` in the message composer.
1716
+ * Use `event.channel.post()` or `event.channel.postEphemeral()` to respond.
1717
+ *
1718
+ * @example
1719
+ * ```typescript
1720
+ * // Handle a specific command
1721
+ * chat.onSlashCommand("/help", async (event) => {
1722
+ * await event.channel.post("Here are the available commands...");
1723
+ * });
1724
+ *
1725
+ * // Handle multiple commands
1726
+ * chat.onSlashCommand(["/status", "/health"], async (event) => {
1727
+ * await event.channel.post("All systems operational!");
1728
+ * });
1729
+ *
1730
+ * // Handle all commands (catch-all)
1731
+ * chat.onSlashCommand(async (event) => {
1732
+ * console.log(`Received command: ${event.command} ${event.text}`);
1733
+ * });
1734
+ *
1735
+ * // Open a modal from a slash command
1736
+ * chat.onSlashCommand("/feedback", async (event) => {
1737
+ * await event.openModal({
1738
+ * callbackId: "feedback_modal",
1739
+ * title: "Submit Feedback",
1740
+ * inputs: [{ id: "feedback", type: "text_input", label: "Your feedback" }],
1741
+ * });
1742
+ * });
1743
+ * ```
1744
+ *
1745
+ * @param commandOrHandler - Either a command, array of commands, or the handler
1746
+ * @param handler - The handler (if command filter is provided)
1747
+ */
1748
+ onSlashCommand(handler: SlashCommandHandler<TState>): void;
1749
+ onSlashCommand(command: string, handler: SlashCommandHandler<TState>): void;
1750
+ onSlashCommand(commands: string[], handler: SlashCommandHandler<TState>): void;
1448
1751
  /**
1449
1752
  * Get an adapter by name with type safety.
1450
1753
  */
@@ -1489,16 +1792,28 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
1489
1792
  processAction(event: Omit<ActionEvent, "thread" | "openModal"> & {
1490
1793
  adapter: Adapter;
1491
1794
  }, options?: WebhookOptions): void;
1492
- processModalSubmit(event: Omit<ModalSubmitEvent, "relatedThread" | "relatedMessage">, contextId?: string, _options?: WebhookOptions): Promise<ModalResponse | undefined>;
1493
- processModalClose(event: Omit<ModalCloseEvent, "relatedThread" | "relatedMessage">, contextId?: string, options?: WebhookOptions): void;
1795
+ processModalSubmit(event: Omit<ModalSubmitEvent, "relatedThread" | "relatedMessage" | "relatedChannel">, contextId?: string, _options?: WebhookOptions): Promise<ModalResponse | undefined>;
1796
+ processModalClose(event: Omit<ModalCloseEvent, "relatedThread" | "relatedMessage" | "relatedChannel">, contextId?: string, options?: WebhookOptions): void;
1797
+ /**
1798
+ * Process an incoming slash command from an adapter.
1799
+ * Handles waitUntil registration and error catching internally.
1800
+ */
1801
+ processSlashCommand(event: Omit<SlashCommandEvent, "channel" | "openModal"> & {
1802
+ adapter: Adapter;
1803
+ channelId: string;
1804
+ }, options?: WebhookOptions): void;
1805
+ /**
1806
+ * Handle a slash command event internally.
1807
+ */
1808
+ private handleSlashCommandEvent;
1494
1809
  /**
1495
1810
  * Store modal context server-side with a context ID.
1496
- * Called when opening a modal to preserve thread/message for the submit handler.
1811
+ * Called when opening a modal to preserve thread/message/channel for the submit handler.
1497
1812
  */
1498
1813
  private storeModalContext;
1499
1814
  /**
1500
1815
  * Retrieve and delete modal context from server-side storage.
1501
- * Called when processing modal submit/close to reconstruct thread/message.
1816
+ * Called when processing modal submit/close to reconstruct thread/message/channel.
1502
1817
  */
1503
1818
  private retrieveModalContext;
1504
1819
  /**
@@ -1540,6 +1855,33 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
1540
1855
  * ```
1541
1856
  */
1542
1857
  openDM(user: string | Author): Promise<Thread<TState>>;
1858
+ /**
1859
+ * Get a Channel by its channel ID.
1860
+ *
1861
+ * The adapter is automatically inferred from the channel ID prefix.
1862
+ *
1863
+ * @param channelId - Channel ID (e.g., "slack:C123ABC", "gchat:spaces/ABC123")
1864
+ * @returns A Channel that can be used to list threads, post messages, iterate messages, etc.
1865
+ *
1866
+ * @example
1867
+ * ```typescript
1868
+ * const channel = chat.channel("slack:C123ABC");
1869
+ *
1870
+ * // Iterate messages newest first
1871
+ * for await (const msg of channel.messages) {
1872
+ * console.log(msg.text);
1873
+ * }
1874
+ *
1875
+ * // List threads
1876
+ * for await (const t of channel.threads()) {
1877
+ * console.log(t.rootMessage.text, t.replyCount);
1878
+ * }
1879
+ *
1880
+ * // Post to channel
1881
+ * await channel.post("Hello channel!");
1882
+ * ```
1883
+ */
1884
+ channel(channelId: string): Channel<TState>;
1543
1885
  /**
1544
1886
  * Infer which adapter to use based on the userId format.
1545
1887
  */
@@ -1620,6 +1962,8 @@ declare class ThreadImpl<TState = Record<string, unknown>> implements Thread<TSt
1620
1962
  private _currentMessage?;
1621
1963
  /** Update interval for fallback streaming */
1622
1964
  private _streamingUpdateIntervalMs;
1965
+ /** Cached channel instance */
1966
+ private _channel?;
1623
1967
  constructor(config: ThreadImplConfig);
1624
1968
  /**
1625
1969
  * Get the adapter for this thread.
@@ -1645,6 +1989,16 @@ declare class ThreadImpl<TState = Record<string, unknown>> implements Thread<TSt
1645
1989
  setState(newState: Partial<TState>, options?: {
1646
1990
  replace?: boolean;
1647
1991
  }): Promise<void>;
1992
+ /**
1993
+ * Get the Channel containing this thread.
1994
+ * Lazy-created and cached.
1995
+ */
1996
+ get channel(): Channel<TState>;
1997
+ /**
1998
+ * Iterate messages newest first (backward from most recent).
1999
+ * Auto-paginates lazily.
2000
+ */
2001
+ get messages(): AsyncIterable<Message>;
1648
2002
  get allMessages(): AsyncIterable<Message>;
1649
2003
  isSubscribed(): Promise<boolean>;
1650
2004
  subscribe(): Promise<void>;
@@ -2103,4 +2457,4 @@ declare const Select: typeof Select$1;
2103
2457
  declare const SelectOption: typeof SelectOption$1;
2104
2458
  declare const TextInput: typeof TextInput$1;
2105
2459
 
2106
- export { type ActionEvent, type ActionHandler, Actions, type Adapter, type AdapterPostableMessage, type Attachment, type Author, BaseFormatConverter, Button, Card, CardChild, CardElement, CardJSXElement, CardText, Chat, type ChatConfig, ChatError, type ChatInstance, ConsoleLogger, type CustomEmojiMap, DEFAULT_EMOJI_MAP, Divider, type Emoji, type EmojiFormats, type EmojiMapConfig, EmojiResolver, type EmojiValue, type EphemeralMessage, type FetchDirection, type FetchOptions, type FetchResult, Field, Fields, type FileUpload, type FormatConverter, type FormattedContent, Image, LinkButton, type Lock, LockError, type LogLevel, type Logger, type MarkdownConverter, type MentionHandler, Message, type MessageData, type MessageHandler, type MessageMetadata, Modal, type ModalCloseEvent, type ModalCloseHandler, type ModalCloseResponse, ModalElement, type ModalErrorsResponse, type ModalPushResponse, type ModalResponse, type ModalSubmitEvent, type ModalSubmitHandler, type ModalUpdateResponse, NotImplementedError, type PostEphemeralOptions, type PostableAst, type PostableCard, type PostableMarkdown, type PostableMessage, type PostableRaw, RadioSelect, RateLimitError, type RawMessage, type ReactionEvent, type ReactionHandler, Section, Select, SelectOption, type SentMessage, type SerializedMessage, type SerializedThread, type StateAdapter, type StreamOptions, type SubscribedMessageHandler, THREAD_STATE_TTL_MS, TextInput, type Thread, ThreadImpl, type ThreadInfo, type WebhookOptions, type WellKnownEmoji, blockquote, codeBlock, convertEmojiPlaceholders, createEmoji, defaultEmojiResolver, emoji, emphasis, fromReactElement, fromReactModalElement, getEmoji, getNodeChildren, getNodeValue, inlineCode, isBlockquoteNode, isCardElement, isCodeNode, isDeleteNode, isEmphasisNode, isInlineCodeNode, isJSX, isLinkNode, isListItemNode, isListNode, isModalElement, isParagraphNode, isStrongNode, isTextNode, link, markdownToPlainText, paragraph, parseMarkdown, root, strikethrough, stringifyMarkdown, strong, text, toCardElement, toModalElement, toPlainText, walkAst };
2460
+ export { type ActionEvent, type ActionHandler, Actions, type Adapter, type AdapterPostableMessage, type Attachment, type Author, BaseFormatConverter, Button, Card, CardChild, CardElement, CardJSXElement, CardText, type Channel, ChannelImpl, type ChannelInfo, Chat, type ChatConfig, ChatError, type ChatInstance, ConsoleLogger, type CustomEmojiMap, DEFAULT_EMOJI_MAP, Divider, type Emoji, type EmojiFormats, type EmojiMapConfig, EmojiResolver, type EmojiValue, type EphemeralMessage, type FetchDirection, type FetchOptions, type FetchResult, Field, Fields, type FileUpload, type FormatConverter, type FormattedContent, Image, LinkButton, type ListThreadsOptions, type ListThreadsResult, type Lock, LockError, type LogLevel, type Logger, type MarkdownConverter, type MentionHandler, Message, type MessageData, type MessageHandler, type MessageMetadata, Modal, type ModalCloseEvent, type ModalCloseHandler, type ModalCloseResponse, ModalElement, type ModalErrorsResponse, type ModalPushResponse, type ModalResponse, type ModalSubmitEvent, type ModalSubmitHandler, type ModalUpdateResponse, NotImplementedError, type PostEphemeralOptions, type Postable, type PostableAst, type PostableCard, type PostableMarkdown, type PostableMessage, type PostableRaw, RadioSelect, RateLimitError, type RawMessage, type ReactionEvent, type ReactionHandler, Section, Select, SelectOption, type SentMessage, type SerializedChannel, type SerializedMessage, type SerializedThread, type SlashCommandEvent, type SlashCommandHandler, type StateAdapter, type StreamOptions, type SubscribedMessageHandler, THREAD_STATE_TTL_MS, TextInput, type Thread, ThreadImpl, type ThreadInfo, type ThreadSummary, type WebhookOptions, type WellKnownEmoji, blockquote, codeBlock, convertEmojiPlaceholders, createEmoji, defaultEmojiResolver, deriveChannelId, emoji, emphasis, fromReactElement, fromReactModalElement, getEmoji, getNodeChildren, getNodeValue, inlineCode, isBlockquoteNode, isCardElement, isCodeNode, isDeleteNode, isEmphasisNode, isInlineCodeNode, isJSX, isLinkNode, isListItemNode, isListNode, isModalElement, isParagraphNode, isStrongNode, isTextNode, link, markdownToPlainText, paragraph, parseMarkdown, root, strikethrough, stringifyMarkdown, strong, text, toCardElement, toModalElement, toPlainText, walkAst };