@lytics/slack-client
v1.1.2
Published
TypeScript client for posting rich Slack messages with Block Kit formatting, retry logic, and fluent API
Readme
@lytics/slack-client
TypeScript client library for posting messages to Slack webhooks. Provides type-safe methods with rich Block Kit formatting, fluent API, retry logic, and dry-run support.
Features
- 🔐 Type-safe API: Full TypeScript support with Slack Block Kit types
- 🎨 Rich formatting: Slack Block Kit message builder with fluent API
- ✨ Fluent interface: Chainable methods for building complex messages
- 🔄 Retry logic: Automatic retries with exponential backoff
- 🛡️ Error handling: Custom error types for different failure scenarios
- 🧪 Dry-run mode: Test messages without actually posting
- ⚡ Zero dependencies: Uses Node.js native
fetchAPI
Installation
npm install @lytics/slack-client
# or
pnpm add @lytics/slack-client
# or
yarn add @lytics/slack-clientUsage
Basic Example
import { SlackClient } from '@lytics/slack-client';
const client = new SlackClient({
webhook_url: process.env.SLACK_WEBHOOK_URL!,
});
// Post a PR summary
await client.postPRSummary(categorizedPRs, 10);PR Summary with Categories
import { SlackClient, type CategorizedPRs } from '@lytics/slack-client';
const categorizedPRs: CategorizedPRs = {
seeking_reviews: [
{
number: 123,
title: 'Add new feature',
url: 'https://github.com/org/repo/pull/123',
author: 'user1',
approvals: 0,
days_open: 2,
repo: 'org/repo',
},
],
ready_to_merge: [
{
number: 124,
title: 'Fix bug',
url: 'https://github.com/org/repo/pull/124',
author: 'user2',
approvals: 2,
days_open: 1,
repo: 'org/repo',
},
],
stale: [],
};
const client = new SlackClient({
webhook_url: process.env.SLACK_WEBHOOK_URL!,
});
await client.postPRSummary(categorizedPRs, 2);Custom Messages with Fluent API
The MessageBuilder provides a fluent API for building custom Slack messages:
import { SlackClient, MessageBuilder } from '@lytics/slack-client';
const client = new SlackClient({
webhook_url: process.env.SLACK_WEBHOOK_URL!,
});
// Build a custom message using fluent API
const message = new MessageBuilder()
.setHeader('🚀 Deployment Complete')
.setSummary('Deployed to *production* at 12:00 PM')
.addSection('✅ Services Updated', '3 services deployed successfully', [
'*api-gateway*: v1.2.2 → v1.2.3',
'*auth-service*: v2.1.0 → v2.1.1',
'*database*: applied 5 migrations',
])
.setFooter('_Deployed by @engineer • <https://ci.com/build/456|View Build>_')
.build();
await client.postMessage(message);Advanced: Custom Messages with Block Kit
For full control, you can also build messages manually using Block Kit:
import { SlackClient, type SlackMessage } from '@lytics/slack-client';
const client = new SlackClient({
webhook_url: process.env.SLACK_WEBHOOK_URL!,
});
const message: SlackMessage = {
text: 'Custom notification',
blocks: [
{
type: 'header',
text: {
type: 'plain_text',
text: '🚀 Deployment Complete',
emoji: true,
},
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: 'The deployment to *production* was successful!',
},
},
],
};
await client.postMessage(message);Dry-Run Mode
const client = new SlackClient(
{
webhook_url: process.env.SLACK_WEBHOOK_URL!,
},
true // Enable dry-run mode
);
// This will log the message instead of posting
await client.postPRSummary(categorizedPRs, 10);
// Output: [DRY RUN] Would post to Slack: {...}
// Toggle dry-run mode
client.setDryRun(false); // Disable dry-run
client.setDryRun(true); // Enable dry-runError Handling
import {
SlackClient,
SlackWebhookError,
NetworkError,
ConfigurationError,
} from '@lytics/slack-client';
try {
const client = new SlackClient({
webhook_url: process.env.SLACK_WEBHOOK_URL!,
});
await client.postPRSummary(categorizedPRs, 10);
} catch (error) {
if (error instanceof SlackWebhookError) {
console.error(`Slack API error: ${error.status} - ${error.response}`);
} else if (error instanceof NetworkError) {
console.error('Network failure:', error.message);
} else if (error instanceof ConfigurationError) {
console.error('Invalid configuration:', error.message);
}
}Custom Retry Configuration
const client = new SlackClient({
webhook_url: process.env.SLACK_WEBHOOK_URL!,
});
// Configure retry attempts and initial delay
client.setRetryConfig(5, 2000); // 5 attempts, 2000ms initial delay
// Retries will use exponential backoff: 2s, 4s, 8s, 16s, 32s
await client.postMessage({ text: 'Important message' });API Reference
SlackClient
Constructor
constructor(config: SlackClientConfig, dryRun?: boolean)Parameters:
config.webhook_url(string, required): Slack webhook URLconfig.default_channel(string, optional): Default channel for messagesdryRun(boolean, optional): Enable dry-run mode (default: false)
Methods
postPRSummary(categorizedPRs, totalCount, channel?)
Post a formatted PR summary with three-tier categorization.
async postPRSummary(
categorizedPRs: CategorizedPRs,
totalCount: number,
channel?: string
): Promise<void>Parameters:
categorizedPRs: PRs organized by category (seeking reviews, ready to merge, stale)totalCount: Total number of open PRschannel: Optional channel override
Throws: SlackWebhookError, NetworkError
postMessage(message)
Post a custom Slack message with blocks.
async postMessage(message: SlackMessage): Promise<void>Parameters:
message: Slack message with text and/or blocks
Throws: SlackWebhookError, NetworkError
setDryRun(enabled)
Enable or disable dry-run mode.
setDryRun(enabled: boolean): voidisDryRun()
Check if dry-run mode is enabled.
isDryRun(): booleansetRetryConfig(attempts, initialDelay)
Configure retry behavior.
setRetryConfig(attempts: number, initialDelay: number): voidParameters:
attempts: Number of retry attempts (default: 3)initialDelay: Initial delay in milliseconds (default: 1000)
MessageBuilder
Utility class for building Slack messages with fluent API or static helpers.
Fluent API Methods (Instance Methods)
setHeader(text, emoji?)
Set the header block.
setHeader(text: string, emoji?: boolean): thisParameters:
text: Header text (plain text)emoji: Enable emoji rendering (default: true)
setSummary(text)
Set the summary context block (appears below header). Automatically adds a divider.
setSummary(text: string): thisParameters:
text: Summary text (supports markdown)
addSection(title, description, items)
Add a section with title, description, and items. Sections with empty items are automatically skipped. Automatically adds a divider.
addSection(title: string, description: string, items: string[]): thisParameters:
title: Section titledescription: Section descriptionitems: Array of item strings (supports markdown)
setFooter(text)
Set the footer context block.
setFooter(text: string): thisParameters:
text: Footer text (supports markdown)
setFallbackText(text)
Set custom fallback text for notifications.
setFallbackText(text: string): thisParameters:
text: Fallback text (plain text)
build()
Build the final Slack message.
build(): SlackMessageReturns: Formatted Slack message ready to send
Static Helper Methods
buildPRSummary(categorizedPRs, totalCount, categoryFilter?)
Build a complete PR summary message with Block Kit formatting.
static buildPRSummary(
categorizedPRs: CategorizedPRs,
totalCount: number,
categoryFilter?: CategoryFilter
): SlackMessagebuildPlainTextSummary(categorizedPRs, totalCount, categoryFilter?)
Build a plain text version of the PR summary (for logging/dry-run).
static buildPlainTextSummary(
categorizedPRs: CategorizedPRs,
totalCount: number,
categoryFilter?: CategoryFilter
): stringTypes
CategorizedPRs
interface CategorizedPRs {
seeking_reviews: PRSummary[];
ready_to_merge: PRSummary[];
stale: PRSummary[];
}PRSummary
interface PRSummary {
number: number;
title: string;
url: string;
author: string;
approvals: number;
days_open: number;
repo: string;
}SlackMessage
interface SlackMessage {
text?: string;
blocks?: SlackBlock[];
channel?: string;
}Error Types
All errors extend SlackClientError:
ConfigurationError: Invalid configuration (missing or invalid webhook URL)SlackWebhookError: Slack API errors (includes status code and response)NetworkError: Network failures (connection issues, timeouts)
Retry Behavior
The client automatically retries failed requests with exponential backoff:
- Default: 3 attempts with 1000ms initial delay
- Backoff: Delay doubles each retry (1s → 2s → 4s)
- Configurable: Use
setRetryConfig()to customize
Testing
Run tests:
pnpm testRun tests in watch mode:
pnpm test:watchDevelopment
Build the package:
pnpm buildType check:
pnpm typecheckLint:
pnpm lintLicense
MIT
