(
channelId: string,
message: SlackBlockMessage,
options: { requirePrivate?: boolean | 'strict-public-only' } = {},
)
| 538 | * `requirePrivate` unset — behavior is unchanged. |
| 539 | */ |
| 540 | export async function sendChannelMessage( |
| 541 | channelId: string, |
| 542 | message: SlackBlockMessage, |
| 543 | options: { requirePrivate?: boolean | 'strict-public-only' } = {}, |
| 544 | ): Promise<{ ok: boolean; ts?: string; error?: string; skipped?: SendSkipReason }> { |
| 545 | if (options.requirePrivate) { |
| 546 | const state = await verifyChannelStillPrivate(channelId); |
| 547 | if (state === 'public') { |
| 548 | return { ok: false, error: 'channel_no_longer_private', skipped: 'not_private' }; |
| 549 | } |
| 550 | if (state === 'unknown' && options.requirePrivate !== 'strict-public-only') { |
| 551 | return { ok: false, error: 'channel_privacy_unknown', skipped: 'privacy_unknown' }; |
| 552 | } |
| 553 | // state === 'private' → fall through; state === 'unknown' with |
| 554 | // 'strict-public-only' → fall through with the warn log already |
| 555 | // emitted by verifyChannelStillPrivate. |
| 556 | } |
| 557 | |
| 558 | try { |
| 559 | const response = await slackPostRequest<{ ts: string }>('chat.postMessage', { |
| 560 | channel: channelId, |
| 561 | text: message.text, |
| 562 | blocks: message.blocks, |
| 563 | thread_ts: message.thread_ts, |
| 564 | reply_broadcast: message.reply_broadcast, |
| 565 | }); |
| 566 | |
| 567 | logger.info({ channelId, ts: response.ts }, 'Sent Slack channel message'); |
| 568 | return { ok: true, ts: response.ts }; |
| 569 | } catch (error) { |
| 570 | const errorMessage = error instanceof Error ? error.message : 'Unknown error'; |
| 571 | logger.error({ error, channelId }, 'Failed to send Slack channel message'); |
| 572 | return { ok: false, error: errorMessage }; |
| 573 | } |
| 574 | } |
| 575 | |
| 576 | /** |
| 577 | * Update (edit in place) a previously posted channel message. |
no test coverage detected