npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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 fetch API

Installation

npm install @lytics/slack-client
# or
pnpm add @lytics/slack-client
# or
yarn add @lytics/slack-client

Usage

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-run

Error 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 URL
  • config.default_channel (string, optional): Default channel for messages
  • dryRun (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 PRs
  • channel: 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): void
isDryRun()

Check if dry-run mode is enabled.

isDryRun(): boolean
setRetryConfig(attempts, initialDelay)

Configure retry behavior.

setRetryConfig(attempts: number, initialDelay: number): void

Parameters:

  • 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): this

Parameters:

  • 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): this

Parameters:

  • 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[]): this

Parameters:

  • title: Section title
  • description: Section description
  • items: Array of item strings (supports markdown)
setFooter(text)

Set the footer context block.

setFooter(text: string): this

Parameters:

  • text: Footer text (supports markdown)
setFallbackText(text)

Set custom fallback text for notifications.

setFallbackText(text: string): this

Parameters:

  • text: Fallback text (plain text)
build()

Build the final Slack message.

build(): SlackMessage

Returns: 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
): SlackMessage
buildPlainTextSummary(categorizedPRs, totalCount, categoryFilter?)

Build a plain text version of the PR summary (for logging/dry-run).

static buildPlainTextSummary(
  categorizedPRs: CategorizedPRs,
  totalCount: number,
  categoryFilter?: CategoryFilter
): string

Types

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 test

Run tests in watch mode:

pnpm test:watch

Development

Build the package:

pnpm build

Type check:

pnpm typecheck

Lint:

pnpm lint

License

MIT