From 5bb3f317cf79f4334041827658281db4e1197582 Mon Sep 17 00:00:00 2001 From: Ashley Huynh Date: Wed, 6 Aug 2025 13:50:22 -0400 Subject: [PATCH 1/5] Add markdown_text property to chat.postMessage --- packages/web-api/src/types/request/chat.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/web-api/src/types/request/chat.ts b/packages/web-api/src/types/request/chat.ts index e611d1211..cc4b67364 100644 --- a/packages/web-api/src/types/request/chat.ts +++ b/packages/web-api/src/types/request/chat.ts @@ -184,6 +184,9 @@ export type ChatPostMessageArguments = TokenOverridable & Unfurls & { /** @description Disable Slack markup parsing by setting to `false`. Enabled by default. */ mrkdwn?: boolean; + /** @description Accepts message text formatted in markdown. This argument should not be used + * in conjunction with blocks or text. Limit this field to 12,000 characters. */ + markdown_text?: string; }; // https://docs.slack.dev/reference/methods/chat.scheduleMessage From 3972719d4670f7f239824ecb10c8c3962602bc0d Mon Sep 17 00:00:00 2001 From: Ashley Huynh Date: Thu, 7 Aug 2025 18:56:46 -0400 Subject: [PATCH 2/5] Add chat.postEphemeral, chat.update, and chat.scheduleMEssage to the mix --- packages/web-api/src/types/request/chat.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/web-api/src/types/request/chat.ts b/packages/web-api/src/types/request/chat.ts index cc4b67364..e9651a33d 100644 --- a/packages/web-api/src/types/request/chat.ts +++ b/packages/web-api/src/types/request/chat.ts @@ -168,6 +168,9 @@ export type ChatPostEphemeralArguments = TokenOverridable & * The user should be in the channel specified by the `channel` argument. */ user: string; + /** @description Accepts message text formatted in markdown. This argument should not be used + * in conjunction with blocks or text. Limit this field to 12,000 characters. */ + markdown_text?: string; } & Authorship & Parse & LinkNames & @@ -194,6 +197,9 @@ export type ChatScheduleMessageArguments = TokenOverridable & MessageContents & { /** @description Unix EPOCH timestamp of time in future to send the message. */ post_at: string | number; + /** @description Accepts message text formatted in markdown. This argument should not be used + * in conjunction with blocks or text. Limit this field to 12,000 characters. */ + markdown_text?: string; } & ReplyInThread & Parse & LinkNames & @@ -268,4 +274,7 @@ export type ChatUpdateArguments = MessageContents & { file_ids?: string[]; /** @description Broadcast an existing thread reply to make it visible to everyone in the channel or conversation. */ reply_broadcast?: boolean; + /** @description Accepts message text formatted in markdown. This argument should not be used + * in conjunction with blocks or text. Limit this field to 12,000 characters. */ + markdown_text?: string; }; From ea3ed7c9c88265d58403b08b6bdf95f9aa0e68a8 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 20 Aug 2025 18:05:01 -0700 Subject: [PATCH 3/5] docs: include example in jsdoc --- packages/web-api/src/types/request/chat.ts | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/web-api/src/types/request/chat.ts b/packages/web-api/src/types/request/chat.ts index e9651a33d..75a195279 100644 --- a/packages/web-api/src/types/request/chat.ts +++ b/packages/web-api/src/types/request/chat.ts @@ -168,8 +168,10 @@ export type ChatPostEphemeralArguments = TokenOverridable & * The user should be in the channel specified by the `channel` argument. */ user: string; - /** @description Accepts message text formatted in markdown. This argument should not be used - * in conjunction with blocks or text. Limit this field to 12,000 characters. */ + /** + * @description Accepts message text formatted in markdown. This argument should not be used in conjunction with blocks or text. Limit this field to 12,000 characters. + * @example **This is bold text** + */ markdown_text?: string; } & Authorship & Parse & @@ -187,8 +189,10 @@ export type ChatPostMessageArguments = TokenOverridable & Unfurls & { /** @description Disable Slack markup parsing by setting to `false`. Enabled by default. */ mrkdwn?: boolean; - /** @description Accepts message text formatted in markdown. This argument should not be used - * in conjunction with blocks or text. Limit this field to 12,000 characters. */ + /** + * @description Accepts message text formatted in markdown. This argument should not be used in conjunction with blocks or text. Limit this field to 12,000 characters. + * @example **This is bold text** + */ markdown_text?: string; }; @@ -197,8 +201,10 @@ export type ChatScheduleMessageArguments = TokenOverridable & MessageContents & { /** @description Unix EPOCH timestamp of time in future to send the message. */ post_at: string | number; - /** @description Accepts message text formatted in markdown. This argument should not be used - * in conjunction with blocks or text. Limit this field to 12,000 characters. */ + /** + * @description Accepts message text formatted in markdown. This argument should not be used in conjunction with blocks or text. Limit this field to 12,000 characters. + * @example **This is bold text** + */ markdown_text?: string; } & ReplyInThread & Parse & @@ -274,7 +280,9 @@ export type ChatUpdateArguments = MessageContents & { file_ids?: string[]; /** @description Broadcast an existing thread reply to make it visible to everyone in the channel or conversation. */ reply_broadcast?: boolean; - /** @description Accepts message text formatted in markdown. This argument should not be used - * in conjunction with blocks or text. Limit this field to 12,000 characters. */ + /** + * @description Accepts message text formatted in markdown. This argument should not be used in conjunction with blocks or text. Limit this field to 12,000 characters. + * @example **This is bold text** + */ markdown_text?: string; }; From 46359c64cf353c9546c10ab845e1f852b6a743b0 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 20 Aug 2025 18:37:29 -0700 Subject: [PATCH 4/5] fix: avoid sending warning to logs when markdown_text is provided --- packages/web-api/src/WebClient.spec.ts | 15 +++++++++++++++ packages/web-api/src/WebClient.ts | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/web-api/src/WebClient.spec.ts b/packages/web-api/src/WebClient.spec.ts index eeb46e9a1..80770dd24 100644 --- a/packages/web-api/src/WebClient.spec.ts +++ b/packages/web-api/src/WebClient.spec.ts @@ -219,6 +219,21 @@ describe('WebClient', () => { }); } + const markdownTextPatterns = textWarningTestPatterns.reduce((acc, { method, args }) => { + const textPatterns = [{ markdown_text: '# example' }].map((v) => ({ + method, + args: Object.assign({}, v, args), + })); + return acc.concat(textPatterns); + }, [] as MethodArgs[]); + for (const { method, args } of markdownTextPatterns) { + it(`should not send warning to logs when client executes ${method} with markdown_text argument`, async () => { + const warnClient = new WebClient(token, { logLevel: LogLevel.WARN, logger }); + await warnClient.apiCall(method, args); + assert.isTrue((logger.warn as sinon.SinonStub).calledThrice); + }); + } + const textPatterns = textWarningTestPatterns.reduce((acc, { method, args }) => { const textPatterns = [{ text: '' }, { text: null }, {}].map((v) => ({ method, diff --git a/packages/web-api/src/WebClient.ts b/packages/web-api/src/WebClient.ts index 36eecc0ac..bbccfaee0 100644 --- a/packages/web-api/src/WebClient.ts +++ b/packages/web-api/src/WebClient.ts @@ -995,7 +995,8 @@ function warnIfFallbackIsMissing(method: string, logger: Logger, options?: Recor args.attachments.some((attachment) => !attachment.fallback || attachment.fallback.trim() === ''); const isEmptyText = (args: Record) => - args.text === undefined || args.text === null || args.text === ''; + (args.text === undefined || args.text === null || args.text === '') && + (args.markdown_text === undefined || args.markdown === null || args.markdown_text === ''); const buildMissingTextWarning = () => `The top-level \`text\` argument is missing in the request payload for a ${method} call - It's a best practice to always provide a \`text\` argument when posting a message. The \`text\` is used in places where the content cannot be rendered such as: system push notifications, assistive technology such as screen readers, etc.`; From 67ac56a39d507feb77897f37170ee350432988bb Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 20 Aug 2025 19:06:14 -0700 Subject: [PATCH 5/5] fix: accept markdown_text as a possible message content in typings --- packages/web-api/src/types/request/chat.ts | 30 +++++---------- .../web-api/test/types/methods/chat.test-d.ts | 37 ++++++++++++++++--- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/packages/web-api/src/types/request/chat.ts b/packages/web-api/src/types/request/chat.ts index 75a195279..61d91c4ef 100644 --- a/packages/web-api/src/types/request/chat.ts +++ b/packages/web-api/src/types/request/chat.ts @@ -68,11 +68,19 @@ export interface ChannelAndAttachments extends Channel, Partial { */ attachments: MessageAttachment[]; } +export interface ChannelAndMarkdownText extends Channel { + /** + * @description Accepts message text formatted in markdown. This argument should not be used in conjunction with `blocks` or `text`. Limit this field to 12,000 characters. + * @example **This is bold text** + */ + markdown_text: string; +} // Models message-creation arguments, user must provide one of the following combinations: // 1. channel and text // 2. channel and blocks // 3. channel and attachments -type MessageContents = ChannelAndText | ChannelAndBlocks | ChannelAndAttachments; +// 4. channel and markdown_text +type MessageContents = ChannelAndText | ChannelAndBlocks | ChannelAndAttachments | ChannelAndMarkdownText; export interface ThreadTS { /** * @description Provide another message's `ts` value to post this message in a thread. Avoid using a reply's `ts` @@ -168,11 +176,6 @@ export type ChatPostEphemeralArguments = TokenOverridable & * The user should be in the channel specified by the `channel` argument. */ user: string; - /** - * @description Accepts message text formatted in markdown. This argument should not be used in conjunction with blocks or text. Limit this field to 12,000 characters. - * @example **This is bold text** - */ - markdown_text?: string; } & Authorship & Parse & LinkNames & @@ -189,11 +192,6 @@ export type ChatPostMessageArguments = TokenOverridable & Unfurls & { /** @description Disable Slack markup parsing by setting to `false`. Enabled by default. */ mrkdwn?: boolean; - /** - * @description Accepts message text formatted in markdown. This argument should not be used in conjunction with blocks or text. Limit this field to 12,000 characters. - * @example **This is bold text** - */ - markdown_text?: string; }; // https://docs.slack.dev/reference/methods/chat.scheduleMessage @@ -201,11 +199,6 @@ export type ChatScheduleMessageArguments = TokenOverridable & MessageContents & { /** @description Unix EPOCH timestamp of time in future to send the message. */ post_at: string | number; - /** - * @description Accepts message text formatted in markdown. This argument should not be used in conjunction with blocks or text. Limit this field to 12,000 characters. - * @example **This is bold text** - */ - markdown_text?: string; } & ReplyInThread & Parse & LinkNames & @@ -280,9 +273,4 @@ export type ChatUpdateArguments = MessageContents & { file_ids?: string[]; /** @description Broadcast an existing thread reply to make it visible to everyone in the channel or conversation. */ reply_broadcast?: boolean; - /** - * @description Accepts message text formatted in markdown. This argument should not be used in conjunction with blocks or text. Limit this field to 12,000 characters. - * @example **This is bold text** - */ - markdown_text?: string; }; diff --git a/packages/web-api/test/types/methods/chat.test-d.ts b/packages/web-api/test/types/methods/chat.test-d.ts index cf5349a30..2d861b046 100644 --- a/packages/web-api/test/types/methods/chat.test-d.ts +++ b/packages/web-api/test/types/methods/chat.test-d.ts @@ -98,12 +98,12 @@ expectError(web.chat.postEphemeral()); // lacking argument expectError(web.chat.postEphemeral({})); // empty argument expectError( web.chat.postEphemeral({ - channel: 'C1234', // missing text/attachments/blocks and user + channel: 'C1234', // missing text/attachments/blocks/markdown_text and user }), ); expectError( web.chat.postEphemeral({ - channel: 'C1234', // missing text/attachments/blocks + channel: 'C1234', // missing text/attachments/blocks/markdown_text user: 'U1234', }), ); @@ -250,6 +250,13 @@ expectAssignable>([ as_user: false, // ... or with as_user=false }, ]); +expectAssignable>([ + { + channel: 'C1234', + user: 'U1234', + markdown_text: '**bold**', + }, +]); // chat.postMessage // -- sad path @@ -257,7 +264,7 @@ expectError(web.chat.postMessage()); // lacking argument expectError(web.chat.postMessage({})); // empty argument expectError( web.chat.postMessage({ - channel: 'C1234', // missing text/attachments/blocks + channel: 'C1234', // missing text/attachments/blocks/markdown_text }), ); expectError( @@ -376,6 +383,12 @@ expectAssignable>([ as_user: false, // ... or with as_user=false }, ]); +expectAssignable>([ + { + channel: 'C1234', + markdown_text: '**bold**', + }, +]); expectAssignable>([ { channel: 'C1234', @@ -425,7 +438,7 @@ expectError( ); expectError( web.chat.scheduleMessage({ - channel: 'C1234', // missing text/attachments/blocks + channel: 'C1234', // missing text/attachments/blocks/markdown_text post_at: 'U1234', }), ); @@ -511,6 +524,13 @@ expectAssignable>([ text: 'fallback', }, ]); +expectAssignable>([ + { + channel: 'C1234', + markdown_text: '**bold**', + post_at: 299876400, + }, +]); expectAssignable>([ { channel: 'C1234', @@ -612,7 +632,7 @@ expectError( ); expectError( web.chat.update({ - channel: 'C1234', // missing text/attachments/blocks + channel: 'C1234', // missing text/attachments/blocks/markdown_text ts: '1234.56', }), ); @@ -705,6 +725,13 @@ expectAssignable>([ text: 'fallback', }, ]); +expectAssignable>([ + { + channel: 'C1234', + ts: '1234.56', + markdown_text: '**bold**', + }, +]); expectAssignable>([ { channel: 'C1234',