The Message class represents a chat message with structured formatting (mdast AST), metadata, attachments, and platform-specific raw data. It supports serialization for workflow engines.
Constructor
new Message < TRawMessage >( data : MessageData < TRawMessage > )
data
MessageData<TRawMessage>
required
Message data object Show MessageData properties
Thread this message belongs to
Plain text content (all formatting stripped)
Structured formatting as mdast AST (canonical representation)
Platform-specific raw payload (escape hatch)
Message metadata (dateSent, edited, etc.)
Attachments (images, files, videos, audio)
Whether the bot is @-mentioned in this message
Properties
Unique message ID.
threadId
readonly threadId : string
Thread this message belongs to.
text
Plain text content with all formatting stripped.
console . log ( message . text ); // "Hello world"
formatted : FormattedContent
Structured formatting as an mdast AST (Root). This is the canonical representation - use this for processing.
Use stringifyMarkdown(message.formatted) from the chat package to convert the AST back to a markdown string.
import { stringifyMarkdown } from "chat" ;
const markdown = stringifyMarkdown ( message . formatted );
console . log ( markdown ); // "**Hello** _world_"
raw
Platform-specific raw payload. Use this as an escape hatch when you need to access platform-specific fields not exposed by the normalized Message interface.
// Slack-specific data
const slackMessage = message . raw as SlackMessage ;
if ( slackMessage . team_id ) {
console . log ( `Team: ${ slackMessage . team_id } ` );
}
author
Message author information.
Username/handle for @-mentions
Whether the author is a bot
Whether the author is this bot
console . log ( `From: ${ message . author . fullName } ` );
if ( message . author . isBot ) {
console . log ( "This is a bot message" );
}
metadata : MessageMetadata
Message metadata including timestamps and edit status.
Show MessageMetadata properties
When the message was sent
Whether the message has been edited
When the message was last edited (if applicable)
console . log ( `Sent: ${ message . metadata . dateSent . toISOString () } ` );
if ( message . metadata . edited ) {
console . log ( `Edited: ${ message . metadata . editedAt ?. toISOString () } ` );
}
attachments
attachments : Attachment []
Files, images, videos, or audio attached to the message.
Show Attachment properties
type
'image' | 'file' | 'video' | 'audio'
Type of attachment
URL to the file (for linking/downloading)
Image/video width (if applicable)
Image/video height (if applicable)
data
Buffer | Blob | undefined
Binary data (for uploading or if already fetched)
fetchData
() => Promise<Buffer> | undefined
Fetch the attachment data. For platforms that require authentication (like Slack private URLs), this method handles auth automatically.
for ( const attachment of message . attachments ) {
if ( attachment . type === "image" ) {
console . log ( `Image: ${ attachment . url } ` );
console . log ( `Size: ${ attachment . width } x ${ attachment . height } ` );
}
}
isMention
Whether the bot is @-mentioned in this message.
This is set by the Chat SDK before passing the message to handlers. It checks for @username in the message text using the adapter’s configured userName and optional botUserId.
chat . onSubscribedMessage ( async ( thread , message ) => {
if ( message . isMention ) {
await thread . post ( "You mentioned me!" );
}
});
Methods
toJSON()
toJSON (): SerializedMessage
Serialize the message to a plain JSON object. Use this to pass message data to external systems like workflow engines.
Serialized message with dates as ISO strings Show SerializedMessage properties
Type marker for deserialization
Platform-specific raw payload
Metadata with dates as ISO strings
Attachments (data and fetchData omitted as not serializable)
Attachment data (Buffer) and fetchData (function) are omitted as they’re not serializable.
const serialized = message . toJSON ();
await workflow . start ( "process-message" , { message: serialized });
Static Methods
fromJSON()
static fromJSON < TRawMessage = unknown > (
json : SerializedMessage
): Message < TRawMessage >
Reconstruct a Message from serialized JSON data. Converts ISO date strings back to Date objects.
json
SerializedMessage
required
Serialized message data
Reconstructed Message instance
const message = Message . fromJSON ( serializedMessage );
console . log ( message . metadata . dateSent ); // Date object
Type Parameters
Platform-specific raw message type
Usage Examples
Accessing Message Content
chat . onNewMention ( async ( thread , message ) => {
console . log ( `User: ${ message . author . fullName } ` );
console . log ( `Text: ${ message . text } ` );
console . log ( `Sent: ${ message . metadata . dateSent . toISOString () } ` );
if ( message . attachments . length > 0 ) {
console . log ( `Attachments: ${ message . attachments . length } ` );
}
});
Checking for Mentions
chat . onSubscribedMessage ( async ( thread , message ) => {
if ( message . isMention ) {
await thread . post ( `Thanks for mentioning me, ${ message . author . fullName } !` );
}
});
Processing Attachments
chat . onNewMessage ( / ^ analyze image/ , async ( thread , message ) => {
const images = message . attachments . filter ( a => a . type === "image" );
if ( images . length === 0 ) {
await thread . post ( "Please attach an image to analyze." );
return ;
}
for ( const image of images ) {
console . log ( `Processing: ${ image . name } ` );
console . log ( `Size: ${ image . width } x ${ image . height } ` );
// Fetch image data if needed
if ( image . fetchData ) {
const data = await image . fetchData ();
// Process image data...
}
}
});
Working with Formatted Content
import { stringifyMarkdown , toPlainText } from "chat" ;
chat . onSubscribedMessage ( async ( thread , message ) => {
// Get as markdown
const markdown = stringifyMarkdown ( message . formatted );
console . log ( `Markdown: ${ markdown } ` );
// Get as plain text (same as message.text)
const plain = toPlainText ( message . formatted );
console . log ( `Plain: ${ plain } ` );
});
Serialization for Workflows
import { Chat } from "chat" ;
import { workflow } from "@workflow/engine" ;
chat . onNewMention ( async ( thread , message ) => {
// Serialize message for workflow
const serialized = message . toJSON ();
await workflow . start ( "process-inquiry" , {
message: serialized ,
thread: thread . toJSON (),
});
});
// In workflow handler
workflow . on ( "process-inquiry" , async ( data ) => {
// Deserialize message
const message = Message . fromJSON ( data . message );
console . log ( message . text ); // Works!
console . log ( message . metadata . dateSent ); // Date object restored
});
interface SlackMessage {
team_id ?: string ;
channel ?: string ;
ts ?: string ;
blocks ?: unknown [];
}
chat . onNewMention ( async ( thread , message ) => {
// Access Slack-specific fields
const slackData = message . raw as SlackMessage ;
if ( slackData . team_id ) {
console . log ( `Team: ${ slackData . team_id } ` );
}
if ( slackData . blocks ) {
console . log ( `Has ${ slackData . blocks . length } Block Kit blocks` );
}
});
See Also