chat 4.23.0 → 4.24.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.
@@ -353,7 +353,8 @@ function Button(options) {
353
353
  label: options.label,
354
354
  style: options.style,
355
355
  value: options.value,
356
- disabled: options.disabled
356
+ disabled: options.disabled,
357
+ actionType: options.actionType
357
358
  };
358
359
  }
359
360
  function LinkButton(options) {
@@ -475,7 +476,9 @@ function fromReactElement(element) {
475
476
  id: props.id,
476
477
  label: props.label ?? label,
477
478
  style: props.style,
478
- value: props.value
479
+ value: props.value,
480
+ actionType: props.actionType,
481
+ disabled: props.disabled
479
482
  });
480
483
  }
481
484
  case "LinkButton": {
@@ -851,7 +854,9 @@ function resolveJSXElement(element) {
851
854
  id: props.id,
852
855
  label,
853
856
  style: props.style,
854
- value: props.value
857
+ value: props.value,
858
+ actionType: props.actionType,
859
+ disabled: props.disabled
855
860
  });
856
861
  }
857
862
  if (type === LinkButton) {
@@ -1103,4 +1108,3 @@ export {
1103
1108
  toModalElement,
1104
1109
  isJSX
1105
1110
  };
1106
- //# sourceMappingURL=chunk-JW7GYSMH.js.map
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from '@workflow/serde';
2
2
  import { Root, List, Content, Blockquote, Code, Emphasis, InlineCode, Delete, Link, ListItem, Paragraph, Strong, TableCell, Table as Table$1, TableRow, Text } from 'mdast';
3
3
  export { Blockquote, Code, Content, Delete, Emphasis, InlineCode, Link, List, ListItem, Table as MdastTable, Paragraph, Root, Strong, TableCell, TableRow, Text } from 'mdast';
4
- import { C as ChatElement, a as CardElement, M as ModalElement, b as CardChild, A as ActionsComponent, B as ButtonComponent, c as CardComponent, d as cardChildToFallbackText$1, e as CardLinkComponent, T as TextComponent, D as DividerComponent, F as FieldComponent, f as FieldsComponent, g as fromReactElement$1, I as ImageComponent, i as isCardElement$1, h as isJSX$1, L as LinkButtonComponent, S as SectionComponent, j as Table$2, t as toCardElement$1, k as toModalElement$1, l as fromReactModalElement$1, m as isModalElement$1, n as ModalComponent, R as RadioSelectComponent, o as SelectComponent, p as SelectOptionComponent, q as TextInputComponent } from './jsx-runtime-DraWieqP.js';
5
- export { r as ActionsElement, s as ButtonElement, u as ButtonOptions, V as ButtonProps, v as ButtonStyle, W as CardJSXElement, X as CardJSXProps, Y as CardLinkProps, w as CardOptions, Z as CardProps, _ as ContainerProps, x as DividerElement, $ as DividerProps, y as FieldElement, a0 as FieldProps, z as FieldsElement, E as ImageElement, a1 as ImageProps, G as LinkButtonElement, H as LinkButtonOptions, a2 as LinkButtonProps, J as LinkElement, a8 as ModalChild, a9 as ModalOptions, a3 as ModalProps, aa as RadioSelectElement, ab as RadioSelectOptions, K as SectionElement, ac as SelectElement, ad as SelectOptionElement, a4 as SelectOptionProps, ae as SelectOptions, a5 as SelectProps, N as TableAlignment, O as TableElement, P as TableOptions, Q as TextElement, af as TextInputElement, ag as TextInputOptions, a6 as TextInputProps, a7 as TextProps, U as TextStyle } from './jsx-runtime-DraWieqP.js';
4
+ import { C as ChatElement, a as CardElement, M as ModalElement, b as CardChild, A as ActionsComponent, B as ButtonComponent, c as CardComponent, d as cardChildToFallbackText$1, e as CardLinkComponent, T as TextComponent, D as DividerComponent, F as FieldComponent, f as FieldsComponent, g as fromReactElement$1, I as ImageComponent, i as isCardElement$1, h as isJSX$1, L as LinkButtonComponent, S as SectionComponent, j as Table$2, t as toCardElement$1, k as toModalElement$1, l as fromReactModalElement$1, m as isModalElement$1, n as ModalComponent, R as RadioSelectComponent, o as SelectComponent, p as SelectOptionComponent, q as TextInputComponent } from './jsx-runtime-DxATbnrP.js';
5
+ export { r as ActionsElement, s as ButtonElement, u as ButtonOptions, V as ButtonProps, v as ButtonStyle, W as CardJSXElement, X as CardJSXProps, Y as CardLinkProps, w as CardOptions, Z as CardProps, _ as ContainerProps, x as DividerElement, $ as DividerProps, y as FieldElement, a0 as FieldProps, z as FieldsElement, E as ImageElement, a1 as ImageProps, G as LinkButtonElement, H as LinkButtonOptions, a2 as LinkButtonProps, J as LinkElement, a8 as ModalChild, a9 as ModalOptions, a3 as ModalProps, aa as RadioSelectElement, ab as RadioSelectOptions, K as SectionElement, ac as SelectElement, ad as SelectOptionElement, a4 as SelectOptionProps, ae as SelectOptions, a5 as SelectProps, N as TableAlignment, O as TableElement, P as TableOptions, Q as TextElement, af as TextInputElement, ag as TextInputOptions, a6 as TextInputProps, a7 as TextProps, U as TextStyle } from './jsx-runtime-DxATbnrP.js';
6
6
 
7
7
  interface MessageHistoryConfig {
8
8
  /** Maximum messages to keep per thread (default: 100) */
@@ -436,6 +436,18 @@ interface ChatConfig<TAdapters extends Record<string, Adapter> = Record<string,
436
436
  * Options for webhook handling.
437
437
  */
438
438
  interface WebhookOptions {
439
+ /**
440
+ * Override the default modal-opening behavior to handle it inline
441
+ * within the current webhook response cycle.
442
+ * When provided, called instead of adapter.openModal().
443
+ * Used by Teams to return modal content in the HTTP invoke response.
444
+ *
445
+ * The returned `viewId` is platform-specific (e.g. Slack's view ID).
446
+ * Adapters that don't produce a view ID may return void.
447
+ */
448
+ onOpenModal?: (modal: ModalElement, contextId: string) => Promise<{
449
+ viewId: string;
450
+ } | undefined>;
439
451
  /**
440
452
  * Function to run message handling in the background.
441
453
  * Use this to ensure fast webhook responses while processing continues.
@@ -726,7 +738,7 @@ interface ChatInstance {
726
738
  */
727
739
  processAction(event: Omit<ActionEvent, "thread" | "openModal"> & {
728
740
  adapter: Adapter;
729
- }, options?: WebhookOptions): void;
741
+ }, options: WebhookOptions | undefined): Promise<void>;
730
742
  processAppHomeOpened(event: AppHomeOpenedEvent, options?: WebhookOptions): void;
731
743
  processAssistantContextChanged(event: AssistantContextChangedEvent, options?: WebhookOptions): void;
732
744
  processAssistantThreadStarted(event: AssistantThreadStartedEvent, options?: WebhookOptions): void;
@@ -777,7 +789,7 @@ interface ChatInstance {
777
789
  processSlashCommand(event: Omit<SlashCommandEvent, "channel" | "openModal"> & {
778
790
  adapter: Adapter;
779
791
  channelId: string;
780
- }, options?: WebhookOptions): void;
792
+ }, options: WebhookOptions | undefined): void;
781
793
  }
782
794
  /** Lock scope determines which messages contend for the same lock. */
783
795
  type LockScope = "thread" | "channel";
@@ -1787,7 +1799,7 @@ interface ModalCloseResponse {
1787
1799
  action: "close";
1788
1800
  }
1789
1801
  type ModalResponse = ModalCloseResponse | ModalErrorsResponse | ModalUpdateResponse | ModalPushResponse;
1790
- type ModalSubmitHandler = (event: ModalSubmitEvent) => void | Promise<ModalResponse | undefined>;
1802
+ type ModalSubmitHandler = (event: ModalSubmitEvent) => void | Promise<ModalResponse | void | undefined>;
1791
1803
  type ModalCloseHandler = (event: ModalCloseEvent) => void | Promise<void>;
1792
1804
  /**
1793
1805
  * Event emitted when a user invokes a slash command.
@@ -2411,8 +2423,48 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
2411
2423
  */
2412
2424
  onAction(handler: ActionHandler): void;
2413
2425
  onAction(actionIds: string[] | string, handler: ActionHandler): void;
2426
+ /**
2427
+ * Register a handler for modal form submissions.
2428
+ *
2429
+ * @example
2430
+ * ```typescript
2431
+ * // Handle specific modal
2432
+ * chat.onModalSubmit("settings-modal", async (event) => {
2433
+ * const name = event.values["name"];
2434
+ * await event.relatedThread?.post(`Updated name to ${name}`);
2435
+ * });
2436
+ *
2437
+ * // Handle all modal submissions
2438
+ * chat.onModalSubmit(async (event) => {
2439
+ * console.log(`Modal ${event.callbackId} submitted`);
2440
+ * });
2441
+ * ```
2442
+ *
2443
+ * @param callbackIdOrHandler - Either a callback ID, array of callback IDs, or the handler
2444
+ * @param handler - The handler (if callback ID filter is provided)
2445
+ */
2414
2446
  onModalSubmit(handler: ModalSubmitHandler): void;
2415
2447
  onModalSubmit(callbackIds: string[] | string, handler: ModalSubmitHandler): void;
2448
+ /**
2449
+ * Register a handler for modal close/cancel events.
2450
+ * Only fires when the modal was created with `notifyOnClose: true`.
2451
+ *
2452
+ * @example
2453
+ * ```typescript
2454
+ * // Handle specific modal close
2455
+ * chat.onModalClose("settings-modal", async (event) => {
2456
+ * console.log("User cancelled settings");
2457
+ * });
2458
+ *
2459
+ * // Handle all modal close events
2460
+ * chat.onModalClose(async (event) => {
2461
+ * console.log(`Modal ${event.callbackId} closed`);
2462
+ * });
2463
+ * ```
2464
+ *
2465
+ * @param callbackIdOrHandler - Either a callback ID, array of callback IDs, or the handler
2466
+ * @param handler - The handler (if callback ID filter is provided)
2467
+ */
2416
2468
  onModalClose(handler: ModalCloseHandler): void;
2417
2469
  onModalClose(callbackIds: string[] | string, handler: ModalCloseHandler): void;
2418
2470
  /**
@@ -2500,7 +2552,7 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
2500
2552
  */
2501
2553
  processAction(event: Omit<ActionEvent, "thread" | "openModal"> & {
2502
2554
  adapter: Adapter;
2503
- }, options?: WebhookOptions): void;
2555
+ }, options: WebhookOptions | undefined): Promise<void>;
2504
2556
  processModalSubmit(event: Omit<ModalSubmitEvent, "relatedThread" | "relatedMessage" | "relatedChannel">, contextId?: string, _options?: WebhookOptions): Promise<ModalResponse | undefined>;
2505
2557
  processModalClose(event: Omit<ModalCloseEvent, "relatedThread" | "relatedMessage" | "relatedChannel">, contextId?: string, options?: WebhookOptions): void;
2506
2558
  /**
@@ -2510,7 +2562,7 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
2510
2562
  processSlashCommand(event: Omit<SlashCommandEvent, "channel" | "openModal"> & {
2511
2563
  adapter: Adapter;
2512
2564
  channelId: string;
2513
- }, options?: WebhookOptions): void;
2565
+ }, options: WebhookOptions | undefined): void;
2514
2566
  processAssistantThreadStarted(event: AssistantThreadStartedEvent, options?: WebhookOptions): void;
2515
2567
  processAssistantContextChanged(event: AssistantContextChangedEvent, options?: WebhookOptions): void;
2516
2568
  processAppHomeOpened(event: AppHomeOpenedEvent, options?: WebhookOptions): void;
package/dist/index.js CHANGED
@@ -59,7 +59,7 @@ import {
59
59
  toModalElement,
60
60
  toPlainText,
61
61
  walkAst
62
- } from "./chunk-JW7GYSMH.js";
62
+ } from "./chunk-OPV5U4WG.js";
63
63
 
64
64
  // src/ai.ts
65
65
  var TEXT_MIME_PREFIXES = [
@@ -2243,7 +2243,7 @@ var Chat = class {
2243
2243
  * Handles waitUntil registration and error catching internally.
2244
2244
  */
2245
2245
  processAction(event, options) {
2246
- const task = this.handleActionEvent(event).catch((err) => {
2246
+ const task = this.handleActionEvent(event, options).catch((err) => {
2247
2247
  this.logger.error("Action processing error", {
2248
2248
  error: err,
2249
2249
  actionId: event.actionId,
@@ -2253,6 +2253,7 @@ var Chat = class {
2253
2253
  if (options?.waitUntil) {
2254
2254
  options.waitUntil(task);
2255
2255
  }
2256
+ return task;
2256
2257
  }
2257
2258
  async processModalSubmit(event, contextId, _options) {
2258
2259
  const { relatedThread, relatedMessage, relatedChannel } = await this.retrieveModalContext(event.adapter.name, contextId);
@@ -2307,7 +2308,7 @@ var Chat = class {
2307
2308
  * Handles waitUntil registration and error catching internally.
2308
2309
  */
2309
2310
  processSlashCommand(event, options) {
2310
- const task = this.handleSlashCommandEvent(event).catch((err) => {
2311
+ const task = this.handleSlashCommandEvent(event, options).catch((err) => {
2311
2312
  this.logger.error("Slash command processing error", {
2312
2313
  error: err,
2313
2314
  command: event.command,
@@ -2382,7 +2383,7 @@ var Chat = class {
2382
2383
  /**
2383
2384
  * Handle a slash command event internally.
2384
2385
  */
2385
- async handleSlashCommandEvent(event) {
2386
+ async handleSlashCommandEvent(event, options) {
2386
2387
  this.logger.debug("Incoming slash command", {
2387
2388
  adapter: event.adapter.name,
2388
2389
  command: event.command,
@@ -2404,11 +2405,11 @@ var Chat = class {
2404
2405
  ...event,
2405
2406
  channel,
2406
2407
  openModal: async (modal) => {
2407
- if (!event.triggerId) {
2408
+ if (!(event.triggerId || options?.onOpenModal)) {
2408
2409
  this.logger.warn("Cannot open modal: no triggerId available");
2409
2410
  return void 0;
2410
2411
  }
2411
- if (!event.adapter.openModal) {
2412
+ if (!(options?.onOpenModal || event.adapter.openModal)) {
2412
2413
  this.logger.warn(
2413
2414
  `Cannot open modal: ${event.adapter.name} does not support modals`
2414
2415
  );
@@ -2423,18 +2424,24 @@ var Chat = class {
2423
2424
  modalElement = converted;
2424
2425
  }
2425
2426
  const contextId = crypto.randomUUID();
2426
- this.storeModalContext(
2427
+ await this.storeModalContext(
2427
2428
  event.adapter.name,
2428
2429
  contextId,
2429
2430
  void 0,
2430
2431
  void 0,
2431
2432
  channel
2432
2433
  );
2433
- return event.adapter.openModal(
2434
- event.triggerId,
2435
- modalElement,
2436
- contextId
2437
- );
2434
+ if (options?.onOpenModal) {
2435
+ return options.onOpenModal(modalElement, contextId);
2436
+ }
2437
+ if (event.triggerId && event.adapter.openModal) {
2438
+ return event.adapter.openModal(
2439
+ event.triggerId,
2440
+ modalElement,
2441
+ contextId
2442
+ );
2443
+ }
2444
+ return void 0;
2438
2445
  }
2439
2446
  };
2440
2447
  this.logger.debug("Checking slash command handlers", {
@@ -2459,19 +2466,21 @@ var Chat = class {
2459
2466
  * Store modal context server-side with a context ID.
2460
2467
  * Called when opening a modal to preserve thread/message/channel for the submit handler.
2461
2468
  */
2462
- storeModalContext(adapterName, contextId, thread, message, channel) {
2469
+ async storeModalContext(adapterName, contextId, thread, message, channel) {
2463
2470
  const key = `modal-context:${adapterName}:${contextId}`;
2464
2471
  const context = {
2465
2472
  thread: thread?.toJSON(),
2466
2473
  message: message?.toJSON(),
2467
2474
  channel: channel?.toJSON()
2468
2475
  };
2469
- this._stateAdapter.set(key, context, MODAL_CONTEXT_TTL_MS).catch((err) => {
2476
+ try {
2477
+ await this._stateAdapter.set(key, context, MODAL_CONTEXT_TTL_MS);
2478
+ } catch (err) {
2470
2479
  this.logger.error("Failed to store modal context", {
2471
2480
  contextId,
2472
2481
  error: err
2473
2482
  });
2474
- });
2483
+ }
2475
2484
  }
2476
2485
  /**
2477
2486
  * Retrieve and delete modal context from server-side storage.
@@ -2494,6 +2503,7 @@ var Chat = class {
2494
2503
  relatedChannel: void 0
2495
2504
  };
2496
2505
  }
2506
+ await this._stateAdapter.delete(key);
2497
2507
  const adapter = this.adapters.get(adapterName);
2498
2508
  let relatedThread;
2499
2509
  if (stored.thread) {
@@ -2513,7 +2523,7 @@ var Chat = class {
2513
2523
  /**
2514
2524
  * Handle an action event internally.
2515
2525
  */
2516
- async handleActionEvent(event) {
2526
+ async handleActionEvent(event, options) {
2517
2527
  this.logger.debug("Incoming action", {
2518
2528
  adapter: event.adapter.name,
2519
2529
  actionId: event.actionId,
@@ -2549,11 +2559,11 @@ var Chat = class {
2549
2559
  ...event,
2550
2560
  thread,
2551
2561
  openModal: async (modal) => {
2552
- if (!event.triggerId) {
2562
+ if (!(event.triggerId || options?.onOpenModal)) {
2553
2563
  this.logger.warn("Cannot open modal: no triggerId available");
2554
2564
  return void 0;
2555
2565
  }
2556
- if (!event.adapter.openModal) {
2566
+ if (!(options?.onOpenModal || event.adapter.openModal)) {
2557
2567
  this.logger.warn(
2558
2568
  `Cannot open modal: ${event.adapter.name} does not support modals`
2559
2569
  );
@@ -2589,18 +2599,24 @@ var Chat = class {
2589
2599
  }
2590
2600
  const contextId = crypto.randomUUID();
2591
2601
  const channel = thread ? thread.channel : void 0;
2592
- this.storeModalContext(
2602
+ await this.storeModalContext(
2593
2603
  event.adapter.name,
2594
2604
  contextId,
2595
2605
  thread ? thread : void 0,
2596
2606
  message,
2597
2607
  channel
2598
2608
  );
2599
- return event.adapter.openModal(
2600
- event.triggerId,
2601
- modalElement,
2602
- contextId
2603
- );
2609
+ if (options?.onOpenModal) {
2610
+ return options.onOpenModal(modalElement, contextId);
2611
+ }
2612
+ if (event.triggerId && event.adapter.openModal) {
2613
+ return event.adapter.openModal(
2614
+ event.triggerId,
2615
+ modalElement,
2616
+ contextId
2617
+ );
2618
+ }
2619
+ return void 0;
2604
2620
  }
2605
2621
  };
2606
2622
  this.logger.debug("Checking action handlers", {
@@ -3198,8 +3214,7 @@ var Chat = class {
3198
3214
  }
3199
3215
  }
3200
3216
  createThread(adapter, threadId, initialMessage, isSubscribedContext = false) {
3201
- const parts = threadId.split(":");
3202
- const channelId = parts[1] || "";
3217
+ const channelId = adapter.channelIdFromThreadId(threadId);
3203
3218
  const isDM = adapter.isDM?.(threadId) ?? false;
3204
3219
  const channelVisibility = adapter.getChannelVisibility?.(threadId) ?? "unknown";
3205
3220
  return new ThreadImpl({
@@ -3794,4 +3809,3 @@ export {
3794
3809
  toPlainText,
3795
3810
  walkAst
3796
3811
  };
3797
- //# sourceMappingURL=index.js.map
@@ -50,6 +50,8 @@ type ButtonStyle = "primary" | "danger" | "default";
50
50
  type TextStyle = "plain" | "bold" | "muted";
51
51
  /** Button element for interactive actions */
52
52
  interface ButtonElement {
53
+ /** Whether this button triggers a regular action or opens a modal dialog. Default: "action" */
54
+ actionType?: "action" | "modal";
53
55
  /** If true, the button is displayed in an inactive state and doesn't respond to user actions */
54
56
  disabled?: boolean;
55
57
  /** Unique action ID for callback routing */
@@ -237,6 +239,8 @@ declare function Section(children: CardChild[]): SectionElement;
237
239
  declare function Actions(children: (ButtonElement | LinkButtonElement | SelectElement | RadioSelectElement)[]): ActionsElement;
238
240
  /** Options for Button */
239
241
  interface ButtonOptions {
242
+ /** Whether this button triggers a regular action or opens a modal dialog. Default: "action" */
243
+ actionType?: "action" | "modal";
240
244
  /** If true, the button is displayed in an inactive state and doesn't respond to user actions */
241
245
  disabled?: boolean;
242
246
  /** Unique action ID for callback routing */
@@ -504,7 +508,9 @@ interface TextProps {
504
508
  }
505
509
  /** Props for Button component in JSX */
506
510
  interface ButtonProps {
511
+ actionType?: "action" | "modal";
507
512
  children?: string | number | (string | number | undefined)[];
513
+ disabled?: boolean;
508
514
  id: string;
509
515
  label?: string;
510
516
  style?: ButtonStyle;
@@ -1 +1 @@
1
- export { A as ActionsComponent, B as ButtonComponent, V as ButtonProps, c as CardComponent, W as CardJSXElement, X as CardJSXProps, e as CardLinkComponent, Y as CardLinkProps, Z as CardProps, C as ChatElement, _ as ContainerProps, D as DividerComponent, $ as DividerProps, F as FieldComponent, a0 as FieldProps, f as FieldsComponent, an as Fragment, I as ImageComponent, a1 as ImageProps, ao as JSX, L as LinkButtonComponent, a2 as LinkButtonProps, n as ModalComponent, a3 as ModalProps, R as RadioSelectComponent, S as SectionComponent, o as SelectComponent, p as SelectOptionComponent, a4 as SelectOptionProps, a5 as SelectProps, ai as TableComponent, ah as TableProps, T as TextComponent, q as TextInputComponent, a6 as TextInputProps, a7 as TextProps, aj as isCardLinkProps, h as isJSX, ak as jsx, am as jsxDEV, al as jsxs, t as toCardElement, k as toModalElement } from './jsx-runtime-DraWieqP.js';
1
+ export { A as ActionsComponent, B as ButtonComponent, V as ButtonProps, c as CardComponent, W as CardJSXElement, X as CardJSXProps, e as CardLinkComponent, Y as CardLinkProps, Z as CardProps, C as ChatElement, _ as ContainerProps, D as DividerComponent, $ as DividerProps, F as FieldComponent, a0 as FieldProps, f as FieldsComponent, an as Fragment, I as ImageComponent, a1 as ImageProps, ao as JSX, L as LinkButtonComponent, a2 as LinkButtonProps, n as ModalComponent, a3 as ModalProps, R as RadioSelectComponent, S as SectionComponent, o as SelectComponent, p as SelectOptionComponent, a4 as SelectOptionProps, a5 as SelectProps, ai as TableComponent, ah as TableProps, T as TextComponent, q as TextInputComponent, a6 as TextInputProps, a7 as TextProps, aj as isCardLinkProps, h as isJSX, ak as jsx, am as jsxDEV, al as jsxs, t as toCardElement, k as toModalElement } from './jsx-runtime-DxATbnrP.js';
@@ -7,7 +7,7 @@ import {
7
7
  jsxs,
8
8
  toCardElement,
9
9
  toModalElement
10
- } from "./chunk-JW7GYSMH.js";
10
+ } from "./chunk-OPV5U4WG.js";
11
11
  export {
12
12
  Fragment,
13
13
  isCardLinkProps,
@@ -18,4 +18,3 @@ export {
18
18
  toCardElement,
19
19
  toModalElement
20
20
  };
21
- //# sourceMappingURL=jsx-runtime.js.map
package/docs/adapters.mdx CHANGED
@@ -64,7 +64,7 @@ Ready to build your own? Follow the [building](/docs/contributing/building) guid
64
64
  ⚠️ indicates partial support — the feature works with limitations. See individual adapter pages for details.
65
65
  </Callout>
66
66
 
67
- ## How adapters work
67
+ ## How [adapters](/adapters) work
68
68
 
69
69
  Each adapter implements a standard interface that the `Chat` class uses to route events and send messages. When a webhook arrives:
70
70
 
@@ -73,9 +73,9 @@ Each adapter implements a standard interface that the `Chat` class uses to route
73
73
  3. Routes to your handlers via the `Chat` class
74
74
  4. Converts outgoing messages from markdown/AST/cards to the platform's native format
75
75
 
76
- ## Using multiple adapters
76
+ ## Using multiple [adapters](/adapters)
77
77
 
78
- Register multiple adapters and your event handlers work across all of them:
78
+ Register multiple [adapters](/adapters) and your event handlers work across all of them:
79
79
 
80
80
  ```typescript title="lib/bot.ts" lineNumbers
81
81
  import { Chat } from "chat";
@@ -14,7 +14,7 @@ Learn the core patterns for handling incoming events and posting messages back t
14
14
  <Card title="Posting Messages" description="Different ways to render and send messages with thread.post()." href="/docs/posting-messages" />
15
15
  </Cards>
16
16
 
17
- ## Adapters
17
+ ## [Adapters](/adapters)
18
18
 
19
19
  Connect your bot to chat platforms and persist state across restarts.
20
20
 
@@ -23,6 +23,8 @@ Connect your bot to chat platforms and persist state across restarts.
23
23
  <Card title="State Adapters" description="Pluggable state adapters for thread subscriptions, distributed locking, and caching." href="/docs/state" />
24
24
  </Cards>
25
25
 
26
+ Browse all official and community adapters on the [Adapters](/adapters) page.
27
+
26
28
  ## Guides
27
29
 
28
30
  Step-by-step tutorials to get up and running on your platform of choice.
package/docs/index.mdx CHANGED
@@ -11,7 +11,7 @@ Chat SDK is a TypeScript library for building chat bots that work across multipl
11
11
  Building a chat bot that works across multiple platforms typically means maintaining separate codebases, learning different APIs, and handling platform-specific quirks individually. Chat SDK abstracts these differences behind a unified interface.
12
12
 
13
13
  - **Single codebase** for all platforms
14
- - **Type-safe** adapters and event handlers with full TypeScript support
14
+ - **Type-safe** [adapters](/adapters) and event handlers with full TypeScript support
15
15
  - **Event-driven** architecture with handlers for mentions, messages, reactions, button clicks, slash commands, and modals
16
16
  - **Thread subscriptions** for multi-turn conversations
17
17
  - **Rich UI** with JSX cards, buttons, and modals that render natively on each platform
@@ -22,8 +22,8 @@ Building a chat bot that works across multiple platforms typically means maintai
22
22
 
23
23
  Chat SDK has three core concepts:
24
24
 
25
- 1. **Chat** — the main entry point that coordinates adapters and routes events to your handlers
26
- 2. **Adapters** — platform-specific implementations that handle webhook parsing, message formatting, and API calls
25
+ 1. **Chat** — the main entry point that coordinates [adapters](/adapters) and routes events to your handlers
26
+ 2. **[Adapters](/adapters)** — platform-specific implementations that handle webhook parsing, message formatting, and API calls
27
27
  3. **State** — a pluggable persistence layer for thread subscriptions and distributed locking
28
28
 
29
29
  ```typescript title="lib/bot.ts" lineNumbers
package/docs/state.mdx CHANGED
@@ -8,7 +8,7 @@ prerequisites:
8
8
 
9
9
  State adapters handle persistent storage for thread subscriptions, distributed locks (to prevent duplicate processing), and caching. You must provide a state adapter when creating a `Chat` instance. Browse all available state adapters on the [Adapters](/adapters) page.
10
10
 
11
- ## What state adapters manage
11
+ ## What state [adapters](/adapters) manage
12
12
 
13
13
  ### Thread subscriptions
14
14
 
package/docs/usage.mdx CHANGED
@@ -39,9 +39,9 @@ bot.onNewMention(async (thread) => {
39
39
 
40
40
  Each adapter factory auto-detects credentials from environment variables (`SLACK_BOT_TOKEN`, `SLACK_SIGNING_SECRET`, `REDIS_URL`, etc.), so you can get started with zero config. Pass explicit values to override.
41
41
 
42
- ## Multiple adapters
42
+ ## Multiple [adapters](/adapters)
43
43
 
44
- Register multiple adapters to deploy your bot across platforms simultaneously:
44
+ Register multiple [adapters](/adapters) to deploy your bot across platforms simultaneously:
45
45
 
46
46
  ```typescript title="lib/bot.ts" lineNumbers
47
47
  import { Chat } from "chat";
@@ -76,7 +76,7 @@ Your event handlers work identically across all registered adapters — the SDK
76
76
  | `fallbackStreamingPlaceholderText` | `string \| null` | `"..."` | Placeholder text while streaming starts. Set to `null` to skip |
77
77
  | `onLockConflict` | `'drop' \| 'force' \| (threadId, message) => 'drop' \| 'force'` | `"drop"` | Behavior when a thread lock is already held. `'force'` releases the existing lock and re-acquires it, enabling interrupt/steerability for long-running handlers |
78
78
 
79
- ## Accessing adapters
79
+ ## Accessing [adapters](/adapters)
80
80
 
81
81
  Use `getAdapter` to access platform-specific APIs when you need functionality beyond the unified interface:
82
82
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chat",
3
- "version": "4.23.0",
3
+ "version": "4.24.0",
4
4
  "description": "Unified chat abstraction for Slack, Teams, Google Chat, and Discord",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",