chat 3.0.0 → 4.0.1

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.
@@ -0,0 +1,1312 @@
1
+ import { C as CardElement, a as CardJSXElement, b as CardChild, A as Actions$1, B as Button$1, c as Card$1, T as Text$1, D as Divider$1, F as Field$1, d as Fields$1, f as fromReactElement$1, I as Image$1, i as isCardElement$1, e as isJSX$1, S as Section$1, t as toCardElement$1 } from './jsx-runtime-D7zHSnXe.js';
2
+ export { g as ActionsElement, h as ButtonElement, j as ButtonOptions, k as ButtonStyle, l as CardOptions, m as DividerElement, n as FieldElement, o as FieldsElement, p as ImageElement, q as SectionElement, r as TextElement, s as TextStyle } from './jsx-runtime-D7zHSnXe.js';
3
+ import { Root, Content, Blockquote, Code, Emphasis, InlineCode, Link, Paragraph, Delete, Strong, Text } from 'mdast';
4
+ export { Blockquote, Code, Content, Delete, Emphasis, InlineCode, Link, List, ListItem, Paragraph, Root, Strong, Text } from 'mdast';
5
+
6
+ /**
7
+ * Core types for chat-sdk
8
+ */
9
+
10
+ type LogLevel = "debug" | "info" | "warn" | "error" | "silent";
11
+ interface Logger {
12
+ debug(message: string, ...args: unknown[]): void;
13
+ info(message: string, ...args: unknown[]): void;
14
+ warn(message: string, ...args: unknown[]): void;
15
+ error(message: string, ...args: unknown[]): void;
16
+ /** Create a sub-logger with a prefix */
17
+ child(prefix: string): Logger;
18
+ }
19
+ /**
20
+ * Default console logger implementation.
21
+ */
22
+ declare class ConsoleLogger implements Logger {
23
+ private level;
24
+ private prefix;
25
+ constructor(level?: LogLevel, prefix?: string);
26
+ private shouldLog;
27
+ child(prefix: string): Logger;
28
+ debug(message: string, ...args: unknown[]): void;
29
+ info(message: string, ...args: unknown[]): void;
30
+ warn(message: string, ...args: unknown[]): void;
31
+ error(message: string, ...args: unknown[]): void;
32
+ }
33
+ /**
34
+ * Chat configuration with type-safe adapter inference.
35
+ * @template TAdapters - Record of adapter name to adapter instance
36
+ */
37
+ interface ChatConfig<TAdapters extends Record<string, Adapter> = Record<string, Adapter>> {
38
+ /** Default bot username across all adapters */
39
+ userName: string;
40
+ /** Map of adapter name to adapter instance */
41
+ adapters: TAdapters;
42
+ /** State adapter for subscriptions and locking */
43
+ state: StateAdapter;
44
+ /**
45
+ * Logger instance or log level. Defaults to "info".
46
+ * Pass "silent" to disable all logging.
47
+ */
48
+ logger?: Logger | LogLevel;
49
+ }
50
+ /**
51
+ * Options for webhook handling.
52
+ */
53
+ interface WebhookOptions {
54
+ /**
55
+ * Function to run message handling in the background.
56
+ * Use this to ensure fast webhook responses while processing continues.
57
+ *
58
+ * @example
59
+ * // Next.js App Router
60
+ * import { after } from "next/server";
61
+ * chat.webhooks.slack(request, { waitUntil: (p) => after(() => p) });
62
+ *
63
+ * @example
64
+ * // Vercel Functions
65
+ * import { waitUntil } from "@vercel/functions";
66
+ * chat.webhooks.slack(request, { waitUntil });
67
+ */
68
+ waitUntil?: (task: Promise<unknown>) => void;
69
+ }
70
+ /**
71
+ * Adapter interface with generics for platform-specific types.
72
+ * @template TThreadId - Platform-specific thread ID data type
73
+ * @template TRawMessage - Platform-specific raw message type
74
+ */
75
+ interface Adapter<TThreadId = unknown, TRawMessage = unknown> {
76
+ /** Unique name for this adapter (e.g., "slack", "teams") */
77
+ readonly name: string;
78
+ /** Bot username (can override global userName) */
79
+ readonly userName: string;
80
+ /** Bot user ID for platforms that use IDs in mentions (e.g., Slack's <@U123>) */
81
+ readonly botUserId?: string;
82
+ /** Called when Chat instance is created (internal use) */
83
+ initialize(chat: ChatInstance): Promise<void>;
84
+ /** Handle incoming webhook request */
85
+ handleWebhook(request: Request, options?: WebhookOptions): Promise<Response>;
86
+ /** Post a message to a thread */
87
+ postMessage(threadId: string, message: PostableMessage): Promise<RawMessage<TRawMessage>>;
88
+ /** Edit an existing message */
89
+ editMessage(threadId: string, messageId: string, message: PostableMessage): Promise<RawMessage<TRawMessage>>;
90
+ /** Delete a message */
91
+ deleteMessage(threadId: string, messageId: string): Promise<void>;
92
+ /** Add a reaction to a message */
93
+ addReaction(threadId: string, messageId: string, emoji: EmojiValue | string): Promise<void>;
94
+ /** Remove a reaction from a message */
95
+ removeReaction(threadId: string, messageId: string, emoji: EmojiValue | string): Promise<void>;
96
+ /** Show typing indicator */
97
+ startTyping(threadId: string): Promise<void>;
98
+ /** Fetch messages from a thread */
99
+ fetchMessages(threadId: string, options?: FetchOptions): Promise<Message<TRawMessage>[]>;
100
+ /** Fetch thread metadata */
101
+ fetchThread(threadId: string): Promise<ThreadInfo>;
102
+ /** Encode platform-specific data into a thread ID string */
103
+ encodeThreadId(platformData: TThreadId): string;
104
+ /** Decode thread ID string back to platform-specific data */
105
+ decodeThreadId(threadId: string): TThreadId;
106
+ /** Parse platform message format to normalized format */
107
+ parseMessage(raw: TRawMessage): Message<TRawMessage>;
108
+ /** Render formatted content to platform-specific string */
109
+ renderFormatted(content: FormattedContent): string;
110
+ /**
111
+ * Optional hook called when a thread is subscribed to.
112
+ * Adapters can use this to set up platform-specific subscriptions
113
+ * (e.g., Google Chat Workspace Events).
114
+ */
115
+ onThreadSubscribe?(threadId: string): Promise<void>;
116
+ /**
117
+ * Open a direct message conversation with a user.
118
+ *
119
+ * @param userId - The platform-specific user ID
120
+ * @returns The thread ID for the DM conversation
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * const dmThreadId = await adapter.openDM("U123456");
125
+ * await adapter.postMessage(dmThreadId, "Hello!");
126
+ * ```
127
+ */
128
+ openDM?(userId: string): Promise<string>;
129
+ /**
130
+ * Check if a thread is a direct message conversation.
131
+ *
132
+ * @param threadId - The thread ID to check
133
+ * @returns True if the thread is a DM, false otherwise
134
+ */
135
+ isDM?(threadId: string): boolean;
136
+ }
137
+ /** Internal interface for Chat instance passed to adapters */
138
+ interface ChatInstance {
139
+ /**
140
+ * Process an incoming message from an adapter.
141
+ * Handles waitUntil registration and error catching internally.
142
+ *
143
+ * @param adapter - The adapter that received the message
144
+ * @param threadId - The thread ID
145
+ * @param message - Either a parsed message, or a factory function for lazy async parsing
146
+ * @param options - Webhook options including waitUntil
147
+ */
148
+ processMessage(adapter: Adapter, threadId: string, message: Message | (() => Promise<Message>), options?: WebhookOptions): void;
149
+ /**
150
+ * @deprecated Use processMessage instead. This method is for internal use.
151
+ */
152
+ handleIncomingMessage(adapter: Adapter, threadId: string, message: Message): Promise<void>;
153
+ /**
154
+ * Process an incoming reaction event from an adapter.
155
+ * Handles waitUntil registration and error catching internally.
156
+ *
157
+ * @param event - The reaction event (without adapter field, will be added)
158
+ * @param options - Webhook options including waitUntil
159
+ */
160
+ processReaction(event: Omit<ReactionEvent, "adapter" | "thread"> & {
161
+ adapter?: Adapter;
162
+ }, options?: WebhookOptions): void;
163
+ /**
164
+ * Process an incoming action event (button click) from an adapter.
165
+ * Handles waitUntil registration and error catching internally.
166
+ *
167
+ * @param event - The action event (without thread field, will be added)
168
+ * @param options - Webhook options including waitUntil
169
+ */
170
+ processAction(event: Omit<ActionEvent, "thread"> & {
171
+ adapter: Adapter;
172
+ }, options?: WebhookOptions): void;
173
+ getState(): StateAdapter;
174
+ getUserName(): string;
175
+ /** Get the configured logger, optionally with a child prefix */
176
+ getLogger(prefix?: string): Logger;
177
+ }
178
+ interface StateAdapter {
179
+ /** Connect to the state backend */
180
+ connect(): Promise<void>;
181
+ /** Disconnect from the state backend */
182
+ disconnect(): Promise<void>;
183
+ /** Subscribe to a thread (persists across restarts) */
184
+ subscribe(threadId: string): Promise<void>;
185
+ /** Unsubscribe from a thread */
186
+ unsubscribe(threadId: string): Promise<void>;
187
+ /** Check if subscribed to a thread */
188
+ isSubscribed(threadId: string): Promise<boolean>;
189
+ /** List all subscriptions, optionally filtered by adapter */
190
+ listSubscriptions(adapterName?: string): AsyncIterable<string>;
191
+ /** Acquire a lock on a thread (returns null if already locked) */
192
+ acquireLock(threadId: string, ttlMs: number): Promise<Lock | null>;
193
+ /** Release a lock */
194
+ releaseLock(lock: Lock): Promise<void>;
195
+ /** Extend a lock's TTL */
196
+ extendLock(lock: Lock, ttlMs: number): Promise<boolean>;
197
+ /** Get a cached value by key */
198
+ get<T = unknown>(key: string): Promise<T | null>;
199
+ /** Set a cached value with optional TTL in milliseconds */
200
+ set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void>;
201
+ /** Delete a cached value */
202
+ delete(key: string): Promise<void>;
203
+ }
204
+ interface Lock {
205
+ threadId: string;
206
+ token: string;
207
+ expiresAt: number;
208
+ }
209
+ interface Thread<TRawMessage = unknown> {
210
+ /** Unique thread ID (format: "adapter:channel:thread") */
211
+ readonly id: string;
212
+ /** The adapter this thread belongs to */
213
+ readonly adapter: Adapter;
214
+ /** Channel/conversation ID */
215
+ readonly channelId: string;
216
+ /** Whether this is a direct message conversation */
217
+ readonly isDM: boolean;
218
+ /** Recently fetched messages (cached) */
219
+ recentMessages: Message<TRawMessage>[];
220
+ /** Async iterator for all messages in the thread */
221
+ allMessages: AsyncIterable<Message<TRawMessage>>;
222
+ /**
223
+ * Check if this thread is currently subscribed.
224
+ *
225
+ * In subscribed message handlers, this is optimized to return true immediately
226
+ * without a state lookup, since we already know we're in a subscribed context.
227
+ *
228
+ * @returns Promise resolving to true if subscribed, false otherwise
229
+ */
230
+ isSubscribed(): Promise<boolean>;
231
+ /**
232
+ * Subscribe to future messages in this thread.
233
+ *
234
+ * Once subscribed, all messages in this thread will trigger `onSubscribedMessage` handlers.
235
+ * The initial message that triggered subscription will NOT fire the handler.
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * chat.onNewMention(async (thread, message) => {
240
+ * await thread.subscribe(); // Subscribe to follow-up messages
241
+ * await thread.post("I'm now watching this thread!");
242
+ * });
243
+ * ```
244
+ */
245
+ subscribe(): Promise<void>;
246
+ /**
247
+ * Unsubscribe from this thread.
248
+ *
249
+ * Future messages will no longer trigger `onSubscribedMessage` handlers.
250
+ */
251
+ unsubscribe(): Promise<void>;
252
+ /**
253
+ * Post a message to this thread.
254
+ *
255
+ * @param message - String, PostableMessage, or JSX Card element to send
256
+ * @returns A SentMessage with methods to edit, delete, or add reactions
257
+ *
258
+ * @example
259
+ * ```typescript
260
+ * // Simple string
261
+ * await thread.post("Hello!");
262
+ *
263
+ * // Markdown
264
+ * await thread.post({ markdown: "**Bold** and _italic_" });
265
+ *
266
+ * // With emoji
267
+ * await thread.post(`${emoji.thumbs_up} Great job!`);
268
+ *
269
+ * // JSX Card (with @jsxImportSource chat-sdk)
270
+ * await thread.post(
271
+ * <Card title="Welcome!">
272
+ * <Text>Hello world</Text>
273
+ * </Card>
274
+ * );
275
+ * ```
276
+ */
277
+ post(message: string | PostableMessage | CardJSXElement): Promise<SentMessage<TRawMessage>>;
278
+ /**
279
+ * Show typing indicator in the thread.
280
+ *
281
+ * Some platforms support persistent typing indicators, others just send once.
282
+ */
283
+ startTyping(): Promise<void>;
284
+ /**
285
+ * Refresh `recentMessages` from the API.
286
+ *
287
+ * Fetches the latest 50 messages and updates `recentMessages`.
288
+ */
289
+ refresh(): Promise<void>;
290
+ /**
291
+ * Get a platform-specific mention string for a user.
292
+ * Use this to @-mention a user in a message.
293
+ * @example
294
+ * await thread.post(`Hey ${thread.mentionUser(userId)}, check this out!`);
295
+ */
296
+ mentionUser(userId: string): string;
297
+ }
298
+ interface ThreadInfo {
299
+ id: string;
300
+ channelId: string;
301
+ channelName?: string;
302
+ /** Whether this is a direct message conversation */
303
+ isDM?: boolean;
304
+ /** Platform-specific metadata */
305
+ metadata: Record<string, unknown>;
306
+ }
307
+ interface FetchOptions {
308
+ /** Maximum number of messages to fetch */
309
+ limit?: number;
310
+ /** Fetch messages before this message ID */
311
+ before?: string;
312
+ /** Fetch messages after this message ID */
313
+ after?: string;
314
+ }
315
+ /**
316
+ * Formatted content using mdast AST.
317
+ * This is the canonical representation of message formatting.
318
+ */
319
+ type FormattedContent = Root;
320
+ interface Message<TRawMessage = unknown> {
321
+ /** Unique message ID */
322
+ readonly id: string;
323
+ /** Thread this message belongs to */
324
+ readonly threadId: string;
325
+ /** Plain text content (all formatting stripped) */
326
+ text: string;
327
+ /**
328
+ * Structured formatting as an AST (mdast Root).
329
+ * This is the canonical representation - use this for processing.
330
+ * Use `stringifyMarkdown(message.formatted)` to get markdown string.
331
+ */
332
+ formatted: FormattedContent;
333
+ /** Platform-specific raw payload (escape hatch) */
334
+ raw: TRawMessage;
335
+ /** Message author */
336
+ author: Author;
337
+ /** Message metadata */
338
+ metadata: MessageMetadata;
339
+ /** Attachments */
340
+ attachments: Attachment[];
341
+ /**
342
+ * Whether the bot is @-mentioned in this message.
343
+ *
344
+ * This is set by the Chat SDK before passing the message to handlers.
345
+ * It checks for `@username` in the message text using the adapter's
346
+ * configured `userName` and optional `botUserId`.
347
+ *
348
+ * @example
349
+ * ```typescript
350
+ * chat.onSubscribedMessage(async (thread, message) => {
351
+ * if (message.isMention) {
352
+ * await thread.post("You mentioned me!");
353
+ * }
354
+ * });
355
+ * ```
356
+ */
357
+ isMention?: boolean;
358
+ }
359
+ /** Raw message returned from adapter (before wrapping as SentMessage) */
360
+ interface RawMessage<TRawMessage = unknown> {
361
+ id: string;
362
+ threadId: string;
363
+ raw: TRawMessage;
364
+ }
365
+ interface Author {
366
+ /** Unique user ID */
367
+ userId: string;
368
+ /** Username/handle for @-mentions */
369
+ userName: string;
370
+ /** Display name */
371
+ fullName: string;
372
+ /** Whether the author is a bot */
373
+ isBot: boolean | "unknown";
374
+ /** Whether the author is this bot */
375
+ isMe: boolean;
376
+ }
377
+ interface MessageMetadata {
378
+ /** When the message was sent */
379
+ dateSent: Date;
380
+ /** Whether the message has been edited */
381
+ edited: boolean;
382
+ /** When the message was last edited */
383
+ editedAt?: Date;
384
+ }
385
+ interface SentMessage<TRawMessage = unknown> extends Message<TRawMessage> {
386
+ /** Edit this message with text, a PostableMessage, or a JSX Card element */
387
+ edit(newContent: string | PostableMessage | CardJSXElement): Promise<SentMessage<TRawMessage>>;
388
+ /** Delete this message */
389
+ delete(): Promise<void>;
390
+ /** Add a reaction to this message */
391
+ addReaction(emoji: EmojiValue | string): Promise<void>;
392
+ /** Remove a reaction from this message */
393
+ removeReaction(emoji: EmojiValue | string): Promise<void>;
394
+ }
395
+ /**
396
+ * A message that can be posted to a thread.
397
+ *
398
+ * - `string` - Raw text, passed through as-is to the platform
399
+ * - `{ raw: string }` - Explicit raw text, passed through as-is
400
+ * - `{ markdown: string }` - Markdown text, converted to platform format
401
+ * - `{ ast: Root }` - mdast AST, converted to platform format
402
+ * - `{ card: CardElement }` - Rich card with buttons (Block Kit / Adaptive Cards / GChat Cards)
403
+ * - `CardElement` - Direct card element
404
+ */
405
+ type PostableMessage = string | PostableRaw | PostableMarkdown | PostableAst | PostableCard | CardElement;
406
+ interface PostableRaw {
407
+ /** Raw text passed through as-is to the platform */
408
+ raw: string;
409
+ /** File/image attachments */
410
+ attachments?: Attachment[];
411
+ /** Files to upload */
412
+ files?: FileUpload[];
413
+ }
414
+ interface PostableMarkdown {
415
+ /** Markdown text, converted to platform format */
416
+ markdown: string;
417
+ /** File/image attachments */
418
+ attachments?: Attachment[];
419
+ /** Files to upload */
420
+ files?: FileUpload[];
421
+ }
422
+ interface PostableAst {
423
+ /** mdast AST, converted to platform format */
424
+ ast: Root;
425
+ /** File/image attachments */
426
+ attachments?: Attachment[];
427
+ /** Files to upload */
428
+ files?: FileUpload[];
429
+ }
430
+ interface PostableCard {
431
+ /** Rich card element */
432
+ card: CardElement;
433
+ /** Fallback text for platforms/clients that can't render cards */
434
+ fallbackText?: string;
435
+ /** Files to upload */
436
+ files?: FileUpload[];
437
+ }
438
+ interface Attachment {
439
+ /** Type of attachment */
440
+ type: "image" | "file" | "video" | "audio";
441
+ /** URL to the file (for linking/downloading) */
442
+ url?: string;
443
+ /** Binary data (for uploading or if already fetched) */
444
+ data?: Buffer | Blob;
445
+ /** Filename */
446
+ name?: string;
447
+ /** MIME type */
448
+ mimeType?: string;
449
+ /** File size in bytes */
450
+ size?: number;
451
+ /** Image/video width (if applicable) */
452
+ width?: number;
453
+ /** Image/video height (if applicable) */
454
+ height?: number;
455
+ /**
456
+ * Fetch the attachment data.
457
+ * For platforms that require authentication (like Slack private URLs),
458
+ * this method handles the auth automatically.
459
+ */
460
+ fetchData?: () => Promise<Buffer>;
461
+ }
462
+ /**
463
+ * File to upload with a message.
464
+ */
465
+ interface FileUpload {
466
+ /** Binary data */
467
+ data: Buffer | Blob | ArrayBuffer;
468
+ /** Filename */
469
+ filename: string;
470
+ /** MIME type (optional, will be inferred from filename if not provided) */
471
+ mimeType?: string;
472
+ }
473
+ /**
474
+ * Handler for new @-mentions of the bot.
475
+ *
476
+ * **Important**: This handler is ONLY called for mentions in **unsubscribed** threads.
477
+ * Once a thread is subscribed (via `thread.subscribe()`), subsequent messages
478
+ * including @-mentions go to `onSubscribedMessage` handlers instead.
479
+ *
480
+ * To detect mentions in subscribed threads, check `message.isMention`:
481
+ *
482
+ * @example
483
+ * ```typescript
484
+ * // Handle new mentions (unsubscribed threads only)
485
+ * chat.onNewMention(async (thread, message) => {
486
+ * await thread.subscribe(); // Subscribe to follow-up messages
487
+ * await thread.post("Hello! I'll be watching this thread.");
488
+ * });
489
+ *
490
+ * // Handle all messages in subscribed threads
491
+ * chat.onSubscribedMessage(async (thread, message) => {
492
+ * if (message.isMention) {
493
+ * // User @-mentioned us in a thread we're already watching
494
+ * await thread.post("You mentioned me again!");
495
+ * }
496
+ * });
497
+ * ```
498
+ */
499
+ type MentionHandler = (thread: Thread, message: Message) => Promise<void>;
500
+ /**
501
+ * Handler for messages matching a regex pattern.
502
+ *
503
+ * Registered via `chat.onNewMessage(pattern, handler)`. Called when a message
504
+ * matches the pattern in an unsubscribed thread.
505
+ */
506
+ type MessageHandler = (thread: Thread, message: Message) => Promise<void>;
507
+ /**
508
+ * Handler for messages in subscribed threads.
509
+ *
510
+ * Called for all messages in threads that have been subscribed via `thread.subscribe()`.
511
+ * This includes:
512
+ * - Follow-up messages from users
513
+ * - Messages that @-mention the bot (check `message.isMention`)
514
+ *
515
+ * Does NOT fire for:
516
+ * - The message that triggered the subscription (e.g., the initial @mention)
517
+ * - Messages sent by the bot itself
518
+ *
519
+ * @example
520
+ * ```typescript
521
+ * chat.onSubscribedMessage(async (thread, message) => {
522
+ * // Handle all follow-up messages
523
+ * if (message.isMention) {
524
+ * // User @-mentioned us in a subscribed thread
525
+ * }
526
+ * await thread.post(`Got your message: ${message.text}`);
527
+ * });
528
+ * ```
529
+ */
530
+ type SubscribedMessageHandler = (thread: Thread, message: Message) => Promise<void>;
531
+ /**
532
+ * Well-known emoji that work across platforms (Slack and Google Chat).
533
+ * These are normalized to a common format regardless of platform.
534
+ */
535
+ type WellKnownEmoji = "thumbs_up" | "thumbs_down" | "clap" | "wave" | "pray" | "muscle" | "ok_hand" | "point_up" | "point_down" | "point_left" | "point_right" | "raised_hands" | "shrug" | "facepalm" | "heart" | "smile" | "laugh" | "thinking" | "sad" | "cry" | "angry" | "love_eyes" | "cool" | "wink" | "surprised" | "worried" | "confused" | "neutral" | "sleeping" | "sick" | "mind_blown" | "relieved" | "grimace" | "rolling_eyes" | "hug" | "zany" | "check" | "x" | "question" | "exclamation" | "warning" | "stop" | "info" | "100" | "fire" | "star" | "sparkles" | "lightning" | "boom" | "eyes" | "green_circle" | "yellow_circle" | "red_circle" | "blue_circle" | "white_circle" | "black_circle" | "rocket" | "party" | "confetti" | "balloon" | "gift" | "trophy" | "medal" | "lightbulb" | "gear" | "wrench" | "hammer" | "bug" | "link" | "lock" | "unlock" | "key" | "pin" | "memo" | "clipboard" | "calendar" | "clock" | "hourglass" | "bell" | "megaphone" | "speech_bubble" | "email" | "inbox" | "outbox" | "package" | "folder" | "file" | "chart_up" | "chart_down" | "coffee" | "pizza" | "beer" | "arrow_up" | "arrow_down" | "arrow_left" | "arrow_right" | "refresh" | "sun" | "cloud" | "rain" | "snow" | "rainbow";
536
+ /**
537
+ * Platform-specific emoji formats for a single emoji.
538
+ */
539
+ interface EmojiFormats {
540
+ /** Slack emoji name (without colons), e.g., "+1", "heart" */
541
+ slack: string | string[];
542
+ /** Google Chat unicode emoji, e.g., "👍", "❤️" */
543
+ gchat: string | string[];
544
+ }
545
+ /**
546
+ * Emoji map type - can be extended by users to add custom emoji.
547
+ *
548
+ * @example
549
+ * ```typescript
550
+ * // Extend with custom emoji
551
+ * declare module "chat" {
552
+ * interface CustomEmojiMap {
553
+ * "custom_emoji": EmojiFormats;
554
+ * }
555
+ * }
556
+ *
557
+ * const myEmojiMap: EmojiMapConfig = {
558
+ * custom_emoji: { slack: "custom", gchat: "🎯" },
559
+ * };
560
+ * ```
561
+ */
562
+ interface CustomEmojiMap {
563
+ }
564
+ /**
565
+ * Full emoji type including well-known and custom emoji.
566
+ */
567
+ type Emoji = WellKnownEmoji | keyof CustomEmojiMap;
568
+ /**
569
+ * Configuration for emoji mapping.
570
+ */
571
+ type EmojiMapConfig = Partial<Record<Emoji, EmojiFormats>>;
572
+ /**
573
+ * Immutable emoji value object with object identity.
574
+ *
575
+ * These objects are singletons - the same emoji name always returns
576
+ * the same frozen object instance, enabling `===` comparison.
577
+ *
578
+ * @example
579
+ * ```typescript
580
+ * // Object identity comparison works
581
+ * if (event.emoji === emoji.thumbs_up) {
582
+ * console.log("User gave a thumbs up!");
583
+ * }
584
+ *
585
+ * // Works in template strings via toString()
586
+ * await thread.post(`${emoji.thumbs_up} Great job!`);
587
+ * ```
588
+ */
589
+ interface EmojiValue {
590
+ /** The normalized emoji name (e.g., "thumbs_up") */
591
+ readonly name: string;
592
+ /** Returns the placeholder string for message formatting */
593
+ toString(): string;
594
+ /** Returns the placeholder string (for JSON.stringify) */
595
+ toJSON(): string;
596
+ }
597
+ /**
598
+ * Reaction event fired when a user adds or removes a reaction.
599
+ */
600
+ interface ReactionEvent<TRawMessage = unknown> {
601
+ /** The normalized emoji as an EmojiValue singleton (enables `===` comparison) */
602
+ emoji: EmojiValue;
603
+ /** The raw platform-specific emoji (e.g., "+1" for Slack, "👍" for GChat) */
604
+ rawEmoji: string;
605
+ /** Whether the reaction was added (true) or removed (false) */
606
+ added: boolean;
607
+ /** The user who added/removed the reaction */
608
+ user: Author;
609
+ /** The message that was reacted to (if available) */
610
+ message?: Message<TRawMessage>;
611
+ /** The message ID that was reacted to */
612
+ messageId: string;
613
+ /** The thread ID */
614
+ threadId: string;
615
+ /**
616
+ * The thread where the reaction occurred.
617
+ * Use this to post replies or check subscription status.
618
+ *
619
+ * @example
620
+ * ```typescript
621
+ * chat.onReaction([emoji.thumbs_up], async (event) => {
622
+ * await event.thread.post(`Thanks for the ${event.emoji}!`);
623
+ * });
624
+ * ```
625
+ */
626
+ thread: Thread<TRawMessage>;
627
+ /** The adapter that received the event */
628
+ adapter: Adapter;
629
+ /** Platform-specific raw event data */
630
+ raw: unknown;
631
+ }
632
+ /**
633
+ * Handler for reaction events.
634
+ *
635
+ * @example
636
+ * ```typescript
637
+ * // Handle specific emoji
638
+ * chat.onReaction(["thumbs_up", "heart"], async (event) => {
639
+ * console.log(`${event.user.userName} ${event.added ? "added" : "removed"} ${event.emoji}`);
640
+ * });
641
+ *
642
+ * // Handle all reactions
643
+ * chat.onReaction(async (event) => {
644
+ * // ...
645
+ * });
646
+ * ```
647
+ */
648
+ type ReactionHandler = (event: ReactionEvent) => Promise<void>;
649
+ /**
650
+ * Action event fired when a user clicks a button in a card.
651
+ *
652
+ * @example
653
+ * ```typescript
654
+ * chat.onAction("approve", async (event) => {
655
+ * await event.thread.post(`Order ${event.value} approved by ${event.user.userName}`);
656
+ * });
657
+ * ```
658
+ */
659
+ interface ActionEvent<TRawMessage = unknown> {
660
+ /** The action ID from the button (matches Button's `id` prop) */
661
+ actionId: string;
662
+ /** Optional value/payload from the button */
663
+ value?: string;
664
+ /** User who clicked the button */
665
+ user: Author;
666
+ /** The thread where the action occurred */
667
+ thread: Thread<TRawMessage>;
668
+ /** The message ID containing the card */
669
+ messageId: string;
670
+ /** The thread ID */
671
+ threadId: string;
672
+ /** The adapter that received the event */
673
+ adapter: Adapter;
674
+ /** Platform-specific raw event data */
675
+ raw: unknown;
676
+ }
677
+ /**
678
+ * Handler for action events (button clicks in cards).
679
+ *
680
+ * @example
681
+ * ```typescript
682
+ * // Handle specific action
683
+ * chat.onAction("approve", async (event) => {
684
+ * await event.thread.post("Approved!");
685
+ * });
686
+ *
687
+ * // Handle multiple actions
688
+ * chat.onAction(["approve", "reject"], async (event) => {
689
+ * if (event.actionId === "approve") {
690
+ * // ...
691
+ * }
692
+ * });
693
+ *
694
+ * // Handle all actions (catch-all)
695
+ * chat.onAction(async (event) => {
696
+ * console.log(`Action: ${event.actionId}`);
697
+ * });
698
+ * ```
699
+ */
700
+ type ActionHandler = (event: ActionEvent) => Promise<void>;
701
+ declare class ChatError extends Error {
702
+ readonly code: string;
703
+ readonly cause?: unknown | undefined;
704
+ constructor(message: string, code: string, cause?: unknown | undefined);
705
+ }
706
+ declare class RateLimitError extends ChatError {
707
+ readonly retryAfterMs?: number | undefined;
708
+ constructor(message: string, retryAfterMs?: number | undefined, cause?: unknown);
709
+ }
710
+ declare class LockError extends ChatError {
711
+ constructor(message: string, cause?: unknown);
712
+ }
713
+ declare class NotImplementedError extends ChatError {
714
+ readonly feature?: string | undefined;
715
+ constructor(message: string, feature?: string | undefined, cause?: unknown);
716
+ }
717
+
718
+ /** Filter can be EmojiValue objects, emoji names, or raw emoji formats */
719
+ type EmojiFilter = EmojiValue | string;
720
+ /**
721
+ * Type-safe webhook handler that is available for each adapter.
722
+ */
723
+ type WebhookHandler = (request: Request, options?: WebhookOptions) => Promise<Response>;
724
+ /**
725
+ * Creates a type-safe webhooks object based on the adapter names.
726
+ */
727
+ type Webhooks<TAdapters extends Record<string, Adapter>> = {
728
+ [K in keyof TAdapters]: WebhookHandler;
729
+ };
730
+ /**
731
+ * Main Chat class with type-safe adapter inference.
732
+ *
733
+ * @example
734
+ * const chat = new Chat({
735
+ * userName: "mybot",
736
+ * adapters: {
737
+ * slack: createSlackAdapter({ ... }),
738
+ * teams: createTeamsAdapter({ ... }),
739
+ * },
740
+ * state: createMemoryState(),
741
+ * });
742
+ *
743
+ * // Type-safe: only 'slack' and 'teams' are valid
744
+ * chat.webhooks.slack(request, { waitUntil });
745
+ */
746
+ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Adapter>> implements ChatInstance {
747
+ private adapters;
748
+ private state;
749
+ private userName;
750
+ private logger;
751
+ private mentionHandlers;
752
+ private messagePatterns;
753
+ private subscribedMessageHandlers;
754
+ private reactionHandlers;
755
+ private actionHandlers;
756
+ /** Initialization state */
757
+ private initPromise;
758
+ private initialized;
759
+ /**
760
+ * Type-safe webhook handlers keyed by adapter name.
761
+ * @example
762
+ * chat.webhooks.slack(request, { backgroundTask: waitUntil });
763
+ */
764
+ readonly webhooks: Webhooks<TAdapters>;
765
+ constructor(config: ChatConfig<TAdapters>);
766
+ /**
767
+ * Handle a webhook request for a specific adapter.
768
+ * Automatically initializes adapters on first call.
769
+ */
770
+ private handleWebhook;
771
+ /**
772
+ * Ensure the chat instance is initialized.
773
+ * This is called automatically before handling webhooks.
774
+ */
775
+ private ensureInitialized;
776
+ private doInitialize;
777
+ /**
778
+ * Gracefully shut down the chat instance.
779
+ */
780
+ shutdown(): Promise<void>;
781
+ /**
782
+ * Register a handler for new @-mentions of the bot.
783
+ *
784
+ * **Important**: This handler is ONLY called for mentions in **unsubscribed** threads.
785
+ * Once a thread is subscribed (via `thread.subscribe()`), subsequent messages
786
+ * including @-mentions go to `onSubscribedMessage` handlers instead.
787
+ *
788
+ * To detect mentions in subscribed threads, check `message.isMention`:
789
+ *
790
+ * @example
791
+ * ```typescript
792
+ * // Handle new mentions (unsubscribed threads only)
793
+ * chat.onNewMention(async (thread, message) => {
794
+ * await thread.subscribe(); // Subscribe to follow-up messages
795
+ * await thread.post("Hello! I'll be watching this thread.");
796
+ * });
797
+ *
798
+ * // Handle all messages in subscribed threads
799
+ * chat.onSubscribedMessage(async (thread, message) => {
800
+ * if (message.isMention) {
801
+ * // User @-mentioned us in a thread we're already watching
802
+ * await thread.post("You mentioned me again!");
803
+ * }
804
+ * });
805
+ * ```
806
+ */
807
+ onNewMention(handler: MentionHandler): void;
808
+ /**
809
+ * Register a handler for messages matching a regex pattern.
810
+ *
811
+ * @param pattern - Regular expression to match against message text
812
+ * @param handler - Handler called when pattern matches
813
+ *
814
+ * @example
815
+ * ```typescript
816
+ * // Match messages starting with "!help"
817
+ * chat.onNewMessage(/^!help/, async (thread, message) => {
818
+ * await thread.post("Available commands: !help, !status, !ping");
819
+ * });
820
+ * ```
821
+ */
822
+ onNewMessage(pattern: RegExp, handler: MessageHandler): void;
823
+ /**
824
+ * Register a handler for messages in subscribed threads.
825
+ *
826
+ * Called for all messages in threads that have been subscribed via `thread.subscribe()`.
827
+ * This includes:
828
+ * - Follow-up messages from users
829
+ * - Messages that @-mention the bot (check `message.isMention`)
830
+ *
831
+ * Does NOT fire for:
832
+ * - The message that triggered the subscription (e.g., the initial @mention)
833
+ * - Messages sent by the bot itself
834
+ *
835
+ * @example
836
+ * ```typescript
837
+ * chat.onSubscribedMessage(async (thread, message) => {
838
+ * // Handle all follow-up messages
839
+ * if (message.isMention) {
840
+ * // User @-mentioned us in a subscribed thread
841
+ * }
842
+ * await thread.post(`Got your message: ${message.text}`);
843
+ * });
844
+ * ```
845
+ */
846
+ onSubscribedMessage(handler: SubscribedMessageHandler): void;
847
+ /**
848
+ * Register a handler for reaction events.
849
+ *
850
+ * @example
851
+ * ```typescript
852
+ * // Handle specific emoji using EmojiValue objects (recommended)
853
+ * chat.onReaction([emoji.thumbs_up, emoji.heart], async (event) => {
854
+ * if (event.emoji === emoji.thumbs_up) {
855
+ * console.log("Thumbs up!");
856
+ * }
857
+ * });
858
+ *
859
+ * // Handle all reactions
860
+ * chat.onReaction(async (event) => {
861
+ * console.log(`${event.added ? "Added" : "Removed"} ${event.emoji.name}`);
862
+ * });
863
+ * ```
864
+ *
865
+ * @param emojiOrHandler - Either an array of emoji to filter (EmojiValue or string), or the handler
866
+ * @param handler - The handler (if emoji filter is provided)
867
+ */
868
+ onReaction(handler: ReactionHandler): void;
869
+ onReaction(emoji: EmojiFilter[], handler: ReactionHandler): void;
870
+ /**
871
+ * Register a handler for action events (button clicks in cards).
872
+ *
873
+ * @example
874
+ * ```typescript
875
+ * // Handle specific action
876
+ * chat.onAction("approve", async (event) => {
877
+ * await event.thread.post("Approved!");
878
+ * });
879
+ *
880
+ * // Handle multiple actions
881
+ * chat.onAction(["approve", "reject"], async (event) => {
882
+ * if (event.actionId === "approve") {
883
+ * await event.thread.post("Approved!");
884
+ * } else {
885
+ * await event.thread.post("Rejected!");
886
+ * }
887
+ * });
888
+ *
889
+ * // Handle all actions (catch-all)
890
+ * chat.onAction(async (event) => {
891
+ * console.log(`Action: ${event.actionId}`);
892
+ * });
893
+ * ```
894
+ *
895
+ * @param actionIdOrHandler - Either an action ID, array of action IDs, or the handler
896
+ * @param handler - The handler (if action ID filter is provided)
897
+ */
898
+ onAction(handler: ActionHandler): void;
899
+ onAction(actionId: string, handler: ActionHandler): void;
900
+ onAction(actionIds: string[], handler: ActionHandler): void;
901
+ /**
902
+ * Get an adapter by name with type safety.
903
+ */
904
+ getAdapter<K extends keyof TAdapters>(name: K): TAdapters[K];
905
+ /**
906
+ * Process an incoming message from an adapter.
907
+ * Handles waitUntil registration and error catching internally.
908
+ * Adapters should call this instead of handleIncomingMessage directly.
909
+ */
910
+ processMessage(adapter: Adapter, threadId: string, messageOrFactory: Message | (() => Promise<Message>), options?: WebhookOptions): void;
911
+ /**
912
+ * Process an incoming reaction event from an adapter.
913
+ * Handles waitUntil registration and error catching internally.
914
+ */
915
+ processReaction(event: Omit<ReactionEvent, "adapter" | "thread"> & {
916
+ adapter?: Adapter;
917
+ }, options?: WebhookOptions): void;
918
+ /**
919
+ * Process an incoming action event (button click) from an adapter.
920
+ * Handles waitUntil registration and error catching internally.
921
+ */
922
+ processAction(event: Omit<ActionEvent, "thread"> & {
923
+ adapter: Adapter;
924
+ }, options?: WebhookOptions): void;
925
+ /**
926
+ * Handle an action event internally.
927
+ */
928
+ private handleActionEvent;
929
+ /**
930
+ * Handle a reaction event internally.
931
+ */
932
+ private handleReactionEvent;
933
+ getState(): StateAdapter;
934
+ getUserName(): string;
935
+ getLogger(prefix?: string): Logger;
936
+ /**
937
+ * Open a direct message conversation with a user.
938
+ *
939
+ * Accepts either a user ID string or an Author object (from message.author or event.user).
940
+ *
941
+ * The adapter is automatically inferred from the userId format:
942
+ * - Slack: `U...` (e.g., "U03STHCA1JM")
943
+ * - Teams: `29:...` (e.g., "29:198PbJuw...")
944
+ * - Google Chat: `users/...` (e.g., "users/117994873354375860089")
945
+ *
946
+ * @param user - Platform-specific user ID string, or an Author object
947
+ * @returns A Thread that can be used to post messages
948
+ *
949
+ * @example
950
+ * ```ts
951
+ * // Using user ID directly
952
+ * const dmThread = await chat.openDM("U123456");
953
+ * await dmThread.post("Hello via DM!");
954
+ *
955
+ * // Using Author object from a message
956
+ * chat.onSubscribedMessage(async (thread, message) => {
957
+ * const dmThread = await chat.openDM(message.author);
958
+ * await dmThread.post("Hello via DM!");
959
+ * });
960
+ * ```
961
+ */
962
+ openDM(user: string | Author): Promise<Thread>;
963
+ /**
964
+ * Infer which adapter to use based on the userId format.
965
+ */
966
+ private inferAdapterFromUserId;
967
+ /**
968
+ * Handle an incoming message from an adapter.
969
+ * This is called by adapters when they receive a webhook.
970
+ *
971
+ * The Chat class handles common concerns centrally:
972
+ * - Deduplication: Same message may arrive multiple times (e.g., Slack sends
973
+ * both `message` and `app_mention` events, GChat sends direct webhook + Pub/Sub)
974
+ * - Bot filtering: Messages from the bot itself are skipped
975
+ * - Locking: Only one instance processes a thread at a time
976
+ */
977
+ handleIncomingMessage(adapter: Adapter, threadId: string, message: Message): Promise<void>;
978
+ private createThread;
979
+ /**
980
+ * Detect if the bot was mentioned in the message.
981
+ * All adapters normalize mentions to @name format, so we just check for @username.
982
+ */
983
+ private detectMention;
984
+ private escapeRegex;
985
+ private runHandlers;
986
+ }
987
+
988
+ /**
989
+ * Get or create an immutable singleton EmojiValue.
990
+ *
991
+ * Always returns the same frozen object for the same name,
992
+ * enabling `===` comparison for emoji identity.
993
+ *
994
+ * @example
995
+ * ```typescript
996
+ * const e1 = getEmoji("thumbs_up");
997
+ * const e2 = getEmoji("thumbs_up");
998
+ * console.log(e1 === e2); // true - same object
999
+ * ```
1000
+ */
1001
+ declare function getEmoji(name: string): EmojiValue;
1002
+ /**
1003
+ * Default emoji map for well-known emoji.
1004
+ * Maps normalized emoji names to platform-specific formats.
1005
+ */
1006
+ declare const DEFAULT_EMOJI_MAP: Record<string, EmojiFormats>;
1007
+ /**
1008
+ * Emoji resolver that handles conversion between platform formats and normalized names.
1009
+ */
1010
+ declare class EmojiResolver {
1011
+ private emojiMap;
1012
+ private slackToNormalized;
1013
+ private gchatToNormalized;
1014
+ constructor(customMap?: EmojiMapConfig);
1015
+ private buildReverseMaps;
1016
+ /**
1017
+ * Convert a Slack emoji name to normalized EmojiValue.
1018
+ * Returns an EmojiValue for the raw emoji if no mapping exists.
1019
+ */
1020
+ fromSlack(slackEmoji: string): EmojiValue;
1021
+ /**
1022
+ * Convert a Google Chat unicode emoji to normalized EmojiValue.
1023
+ * Returns an EmojiValue for the raw emoji if no mapping exists.
1024
+ */
1025
+ fromGChat(gchatEmoji: string): EmojiValue;
1026
+ /**
1027
+ * Convert a Teams reaction type to normalized EmojiValue.
1028
+ * Teams uses specific names: like, heart, laugh, surprised, sad, angry
1029
+ * Returns an EmojiValue for the raw reaction if no mapping exists.
1030
+ */
1031
+ fromTeams(teamsReaction: string): EmojiValue;
1032
+ /**
1033
+ * Convert a normalized emoji (or EmojiValue) to Slack format.
1034
+ * Returns the first Slack format if multiple exist.
1035
+ */
1036
+ toSlack(emoji: EmojiValue | string): string;
1037
+ /**
1038
+ * Convert a normalized emoji (or EmojiValue) to Google Chat format.
1039
+ * Returns the first GChat format if multiple exist.
1040
+ */
1041
+ toGChat(emoji: EmojiValue | string): string;
1042
+ /**
1043
+ * Check if an emoji (in any format) matches a normalized emoji name or EmojiValue.
1044
+ */
1045
+ matches(rawEmoji: string, normalized: EmojiValue | string): boolean;
1046
+ /**
1047
+ * Add or override emoji mappings.
1048
+ */
1049
+ extend(customMap: EmojiMapConfig): void;
1050
+ }
1051
+ /**
1052
+ * Default emoji resolver instance.
1053
+ */
1054
+ declare const defaultEmojiResolver: EmojiResolver;
1055
+ /**
1056
+ * Convert emoji placeholders in text to platform-specific format.
1057
+ *
1058
+ * @example
1059
+ * ```typescript
1060
+ * convertEmojiPlaceholders("Thanks! {{emoji:thumbs_up}}", "slack");
1061
+ * // Returns: "Thanks! :+1:"
1062
+ *
1063
+ * convertEmojiPlaceholders("Thanks! {{emoji:thumbs_up}}", "gchat");
1064
+ * // Returns: "Thanks! 👍"
1065
+ * ```
1066
+ */
1067
+ declare function convertEmojiPlaceholders(text: string, platform: "slack" | "gchat" | "teams", resolver?: EmojiResolver): string;
1068
+ /** Base emoji object with well-known emoji as EmojiValue singletons */
1069
+ type BaseEmojiHelper = {
1070
+ [K in WellKnownEmoji]: EmojiValue;
1071
+ } & {
1072
+ /** Create an EmojiValue for a custom emoji name */
1073
+ custom: (name: string) => EmojiValue;
1074
+ };
1075
+ /** Extended emoji object including custom emoji from module augmentation */
1076
+ type ExtendedEmojiHelper = BaseEmojiHelper & {
1077
+ [K in keyof CustomEmojiMap]: EmojiValue;
1078
+ };
1079
+ /**
1080
+ * Create a type-safe emoji helper with custom emoji.
1081
+ *
1082
+ * Returns immutable singleton EmojiValue objects that support:
1083
+ * - Object identity comparison (`event.emoji === emoji.thumbs_up`)
1084
+ * - Template string interpolation (`${emoji.thumbs_up}` → "{{emoji:thumbs_up}}")
1085
+ *
1086
+ * Custom emoji are automatically registered with the default resolver,
1087
+ * so placeholders will convert correctly in messages.
1088
+ *
1089
+ * @example
1090
+ * ```typescript
1091
+ * // First, extend the CustomEmojiMap type (usually in a .d.ts file)
1092
+ * declare module "chat" {
1093
+ * interface CustomEmojiMap {
1094
+ * unicorn: EmojiFormats;
1095
+ * company_logo: EmojiFormats;
1096
+ * }
1097
+ * }
1098
+ *
1099
+ * // Then create the emoji helper with your custom emoji
1100
+ * const emoji = createEmoji({
1101
+ * unicorn: { slack: "unicorn_face", gchat: "🦄" },
1102
+ * company_logo: { slack: "company", gchat: "🏢" },
1103
+ * });
1104
+ *
1105
+ * // Object identity works for comparisons
1106
+ * if (event.emoji === emoji.unicorn) { ... }
1107
+ *
1108
+ * // Template strings work for messages
1109
+ * await thread.post(`${emoji.unicorn} Magic!`);
1110
+ * // Slack: ":unicorn_face: Magic!"
1111
+ * // GChat: "🦄 Magic!"
1112
+ * ```
1113
+ */
1114
+ declare function createEmoji<T extends Record<string, {
1115
+ slack: string | string[];
1116
+ gchat: string | string[];
1117
+ }>>(customEmoji?: T): BaseEmojiHelper & {
1118
+ [K in keyof T]: EmojiValue;
1119
+ };
1120
+ /**
1121
+ * Type-safe emoji helper for embedding emoji in messages.
1122
+ *
1123
+ * @example
1124
+ * ```typescript
1125
+ * import { emoji } from "chat";
1126
+ *
1127
+ * await thread.post(`Great job! ${emoji.thumbs_up} ${emoji.fire}`);
1128
+ * // Slack: "Great job! :+1: :fire:"
1129
+ * // GChat: "Great job! 👍 🔥"
1130
+ * ```
1131
+ *
1132
+ * For custom emoji, use `createEmoji()` with module augmentation:
1133
+ * @example
1134
+ * ```typescript
1135
+ * // types.d.ts
1136
+ * declare module "chat" {
1137
+ * interface CustomEmojiMap {
1138
+ * unicorn: EmojiFormats;
1139
+ * }
1140
+ * }
1141
+ *
1142
+ * // bot.ts
1143
+ * const emoji = createEmoji({ unicorn: { slack: "unicorn", gchat: "🦄" } });
1144
+ * await thread.post(`${emoji.unicorn} Magic!`);
1145
+ * ```
1146
+ */
1147
+ declare const emoji: ExtendedEmojiHelper;
1148
+
1149
+ /**
1150
+ * Markdown parsing and conversion utilities using unified/remark.
1151
+ */
1152
+
1153
+ /**
1154
+ * Parse markdown string into an AST.
1155
+ * Supports GFM (GitHub Flavored Markdown) for strikethrough, tables, etc.
1156
+ */
1157
+ declare function parseMarkdown(markdown: string): Root;
1158
+ /**
1159
+ * Stringify an AST back to markdown.
1160
+ */
1161
+ declare function stringifyMarkdown(ast: Root): string;
1162
+ /**
1163
+ * Extract plain text from an AST (strips all formatting).
1164
+ */
1165
+ declare function toPlainText(ast: Root): string;
1166
+ /**
1167
+ * Extract plain text from a markdown string.
1168
+ */
1169
+ declare function markdownToPlainText(markdown: string): string;
1170
+ /**
1171
+ * Walk the AST and transform nodes.
1172
+ */
1173
+ declare function walkAst<T extends Content | Root>(node: T, visitor: (node: Content) => Content | null): T;
1174
+ /**
1175
+ * Create a text node.
1176
+ */
1177
+ declare function text(value: string): Text;
1178
+ /**
1179
+ * Create a strong (bold) node.
1180
+ */
1181
+ declare function strong(children: Content[]): Strong;
1182
+ /**
1183
+ * Create an emphasis (italic) node.
1184
+ */
1185
+ declare function emphasis(children: Content[]): Emphasis;
1186
+ /**
1187
+ * Create a delete (strikethrough) node.
1188
+ */
1189
+ declare function strikethrough(children: Content[]): Delete;
1190
+ /**
1191
+ * Create an inline code node.
1192
+ */
1193
+ declare function inlineCode(value: string): InlineCode;
1194
+ /**
1195
+ * Create a code block node.
1196
+ */
1197
+ declare function codeBlock(value: string, lang?: string): Code;
1198
+ /**
1199
+ * Create a link node.
1200
+ */
1201
+ declare function link(url: string, children: Content[], title?: string): Link;
1202
+ /**
1203
+ * Create a blockquote node.
1204
+ */
1205
+ declare function blockquote(children: Content[]): Blockquote;
1206
+ /**
1207
+ * Create a paragraph node.
1208
+ */
1209
+ declare function paragraph(children: Content[]): Paragraph;
1210
+ /**
1211
+ * Create a root node (top-level AST container).
1212
+ */
1213
+ declare function root(children: Content[]): Root;
1214
+ /**
1215
+ * Interface for platform-specific format converters.
1216
+ *
1217
+ * The AST (mdast Root) is the canonical representation.
1218
+ * All conversions go through the AST:
1219
+ *
1220
+ * Platform Format <-> AST <-> Markdown String
1221
+ *
1222
+ * Adapters implement this interface to convert between
1223
+ * their platform-specific format and the standard AST.
1224
+ */
1225
+ interface FormatConverter {
1226
+ /**
1227
+ * Render an AST to the platform's native format.
1228
+ * This is the primary method used when sending messages.
1229
+ */
1230
+ fromAst(ast: Root): string;
1231
+ /**
1232
+ * Parse platform's native format into an AST.
1233
+ * This is the primary method used when receiving messages.
1234
+ */
1235
+ toAst(platformText: string): Root;
1236
+ /**
1237
+ * Extract plain text from platform format.
1238
+ * Convenience method - default implementation uses toAst + toPlainText.
1239
+ */
1240
+ extractPlainText(platformText: string): string;
1241
+ }
1242
+ /**
1243
+ * @deprecated Use FormatConverter instead
1244
+ */
1245
+ interface MarkdownConverter extends FormatConverter {
1246
+ fromMarkdown(markdown: string): string;
1247
+ toMarkdown(platformText: string): string;
1248
+ toPlainText(platformText: string): string;
1249
+ }
1250
+ /**
1251
+ * Base class for format converters with default implementations.
1252
+ */
1253
+ declare abstract class BaseFormatConverter implements FormatConverter {
1254
+ abstract fromAst(ast: Root): string;
1255
+ abstract toAst(platformText: string): Root;
1256
+ extractPlainText(platformText: string): string;
1257
+ fromMarkdown(markdown: string): string;
1258
+ toMarkdown(platformText: string): string;
1259
+ /** @deprecated Use extractPlainText instead */
1260
+ toPlainText(platformText: string): string;
1261
+ /**
1262
+ * Convert a PostableMessage to platform format (text only).
1263
+ * - string: passed through as raw text (no conversion)
1264
+ * - { raw: string }: passed through as raw text (no conversion)
1265
+ * - { markdown: string }: converted from markdown to platform format
1266
+ * - { ast: Root }: converted from AST to platform format
1267
+ * - { card: CardElement }: returns fallback text (cards should be handled by adapter)
1268
+ * - CardElement: returns fallback text (cards should be handled by adapter)
1269
+ *
1270
+ * Note: For cards, adapters should check for card content first and render
1271
+ * them using platform-specific card APIs, using this method only for fallback.
1272
+ */
1273
+ renderPostable(message: PostableMessageInput): string;
1274
+ /**
1275
+ * Generate fallback text from a card element.
1276
+ * Override in subclasses for platform-specific formatting.
1277
+ */
1278
+ protected cardToFallbackText(card: CardElement): string;
1279
+ /**
1280
+ * Convert card child element to fallback text.
1281
+ */
1282
+ protected cardChildToFallbackText(child: CardChild): string | null;
1283
+ }
1284
+ /**
1285
+ * Type for PostableMessage input (for rendering to text)
1286
+ */
1287
+ type PostableMessageInput = string | {
1288
+ raw: string;
1289
+ } | {
1290
+ markdown: string;
1291
+ } | {
1292
+ ast: Root;
1293
+ } | {
1294
+ card: CardElement;
1295
+ fallbackText?: string;
1296
+ } | CardElement;
1297
+
1298
+ declare const Actions: typeof Actions$1;
1299
+ declare const Button: typeof Button$1;
1300
+ declare const Card: typeof Card$1;
1301
+ declare const CardText: typeof Text$1;
1302
+ declare const Divider: typeof Divider$1;
1303
+ declare const Field: typeof Field$1;
1304
+ declare const Fields: typeof Fields$1;
1305
+ declare const fromReactElement: typeof fromReactElement$1;
1306
+ declare const Image: typeof Image$1;
1307
+ declare const isCardElement: typeof isCardElement$1;
1308
+ declare const isJSX: typeof isJSX$1;
1309
+ declare const Section: typeof Section$1;
1310
+ declare const toCardElement: typeof toCardElement$1;
1311
+
1312
+ export { type ActionEvent, type ActionHandler, Actions, type Adapter, 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 FetchOptions, Field, Fields, type FileUpload, type FormatConverter, type FormattedContent, Image, type Lock, LockError, type LogLevel, type Logger, type MarkdownConverter, type MentionHandler, type Message, type MessageHandler, type MessageMetadata, NotImplementedError, type PostableAst, type PostableCard, type PostableMarkdown, type PostableMessage, type PostableRaw, RateLimitError, type RawMessage, type ReactionEvent, type ReactionHandler, Section, type SentMessage, type StateAdapter, type SubscribedMessageHandler, type Thread, type ThreadInfo, type WebhookOptions, type WellKnownEmoji, blockquote, codeBlock, convertEmojiPlaceholders, createEmoji, defaultEmojiResolver, emoji, emphasis, fromReactElement, getEmoji, inlineCode, isCardElement, isJSX, link, markdownToPlainText, paragraph, parseMarkdown, root, strikethrough, stringifyMarkdown, strong, text, toCardElement, toPlainText, walkAst };