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

@fluojs/slack

v1.1.3

Published

Webhook-first, transport-agnostic Slack delivery core for Fluo with notifications integration.

Readme

@fluojs/slack

Webhook-first, transport-agnostic Slack delivery core for fluo. It provides a Nest-like module API, an injectable SlackService for standalone usage, and a first-party SlackChannel for @fluojs/notifications integration without assuming a Node-only SDK.

Table of Contents

Installation

npm install @fluojs/slack @fluojs/notifications

This package follows the repo-wide Node.js 20+ install baseline reflected in published package metadata, while keeping its delivery contract transport-agnostic at runtime through explicit fetch-compatible boundaries.

When to Use

  • When you want one package that can send Slack messages directly and also plug into @fluojs/notifications.
  • When transport choice must stay explicit and portable across Node, Bun, Deno, and Cloudflare-compatible application boundaries.
  • When Slack delivery should prefer incoming webhooks while still allowing richer API integrations through a custom transport contract.
  • When configuration must enter through DI or explicit options instead of process.env reads inside the package.

Quick Start

Register the module

import { Module } from '@fluojs/core';
import { SlackModule, createSlackWebhookTransport } from '@fluojs/slack';

@Module({
  imports: [
    SlackModule.forRoot({
      defaultChannel: '#ops',
      transport: createSlackWebhookTransport({
        fetch: globalThis.fetch.bind(globalThis),
        webhookUrl: 'https://hooks.slack.com/services/T000/B000/XXXX',
      }),
    }),
  ],
})
export class AppModule {}

Send Slack messages directly

import { Inject } from '@fluojs/core';
import { SlackService } from '@fluojs/slack';

@Inject(SlackService)
export class DeployNotifier {
  constructor(private readonly slack: SlackService) {}

  async announce(version: string) {
    await this.slack.send({
      text: `Deploy ${version} finished successfully.`,
    });
  }
}

Common Patterns

Manual provider composition with createSlackProviders

createSlackProviders(...) is the supported manual-composition helper when applications need the same provider normalization outside SlackModule.forRoot(...).

import { Module } from '@fluojs/core';
import { createSlackProviders, createSlackWebhookTransport } from '@fluojs/slack';

@Module({
  providers: [
    ...createSlackProviders({
      defaultChannel: '#ops',
      notifications: { channel: 'alerts' },
      transport: createSlackWebhookTransport({
        fetch: globalThis.fetch.bind(globalThis),
        webhookUrl: 'https://hooks.slack.com/services/T000/B000/XXXX',
      }),
    }),
  ],
  exports: [],
})
export class SlackProvidersModule {}

Behavioral contract notes:

  • The helper preserves the same SLACK, SLACK_CHANNEL, and SlackService wiring that SlackModule.forRoot(...) installs.
  • createSlackProviders(...) applies the same option normalization as SlackModule.forRoot(...), including trimmed default channels, notification channel fallback, and transport ownership defaults.
  • The helper still requires an explicit transport; it does not weaken the package's runtime-portable, no-implicit-env contract.

Standalone delivery with SlackService

Use SlackService when your application wants direct Slack delivery without routing through the notifications foundation.

SlackModule.forRootAsync({
  inject: [ConfigService],
  useFactory: (config) => ({
    defaultChannel: config.slack.defaultChannel,
    transport: createSlackWebhookTransport({
      fetch: config.runtime.fetch,
      webhookUrl: config.slack.webhookUrl,
    }),
  }),
});

Behavioral contract notes:

  • SlackService.send(...) resolves defaultChannel before delivery.
  • SlackService.sendMany(...) sends messages sequentially and supports continueOnError when callers need a batch result instead of fail-fast behavior.
  • SlackService.send(...), SlackService.sendMany(...), and SlackService.sendNotification(...) honor already-aborted signals before provider handoff, and the same signal is propagated to transport calls.
  • The service initializes the configured transport during module bootstrap and closes factory-owned resources during application shutdown.
  • Once shutdown starts, SlackService.send(...) and SlackService.sendNotification(...) fail with SlackLifecycleError instead of reusing or lazily creating transports; any in-flight factory-owned transport creation is awaited and closed by shutdown.
  • SlackService.createPlatformStatusSnapshot() reports lifecycle, readiness, and transport ownership without requiring callers to reach into internal options.
  • The package never reads process.env directly. All configuration must enter through explicit options or DI.

Integration with @fluojs/notifications

Inject SLACK_CHANNEL into NotificationsModule.forRootAsync(...) so the Slack package remains the only place that understands Slack-specific payload fields and recipient-to-channel translation.

import { Module } from '@fluojs/core';
import { NotificationsModule } from '@fluojs/notifications';
import {
  SLACK_CHANNEL,
  SlackModule,
  createSlackWebhookTransport,
} from '@fluojs/slack';

@Module({
  imports: [
    SlackModule.forRoot({
      transport: createSlackWebhookTransport({
        fetch: globalThis.fetch.bind(globalThis),
        webhookUrl: 'https://hooks.slack.com/services/T000/B000/XXXX',
      }),
    }),
    NotificationsModule.forRootAsync({
      inject: [SLACK_CHANNEL],
      useFactory: (channel) => ({
        channels: [channel],
      }),
    }),
  ],
})
export class AppModule {}

Supported notification payload fields:

  • text, blocks, attachments
  • channel, threadTs, replyBroadcast
  • username, iconEmoji, iconUrl
  • mrkdwn, unfurlLinks, unfurlMedia, metadata

Behavioral contract notes:

  • One notification dispatch maps to exactly one Slack destination. Use payload.channel or a single entry in recipients.
  • If payload.channel is omitted, SlackService.sendNotification(...) uses the first recipients entry or falls back to defaultChannel.
  • Notification metadata is merged from payload metadata, dispatch metadata, and subject/template markers before delivery.
  • If a notification needs fan-out across multiple Slack destinations, call sendMany(...) instead of one multi-recipient dispatch.

Webhook-first delivery with explicit fetch injection

Use createSlackWebhookTransport(...) when you want a portable first-party transport that only depends on a fetch-compatible HTTP boundary.

const transport = createSlackWebhookTransport({
  fetch: runtime.fetch,
  webhookUrl: slackWebhookUrl,
});

await slack.send({
  blocks: [{ type: 'section', text: { type: 'mrkdwn', text: '*Deploy finished*' } }],
  text: 'Deploy finished',
});

For richer API integrations such as chat.postMessage, implement the exported SlackTransport contract and inject it through SlackModule.forRoot(...) or forRootAsync(...).

Behavioral contract notes:

  • Passing fetch explicitly is the portable path and is recommended for all supported runtimes. For backward compatibility, omitting fetch falls back to globalThis.fetch when that ambient runtime API exists; runtimes without globalThis.fetch fail fast with SlackConfigurationError.
  • The built-in webhook transport retries transient 408, 429, and 5xx failures with bounded exponential backoff before surfacing an error.
  • Abort signals are passed to the injected fetch boundary and cancel retry backoff without wrapping AbortError values as SlackTransportError.
  • Caller-visible SlackTransportError messages omit raw upstream response bodies by default.

Intentional limitations

The Slack package intentionally does not:

  • read credentials or webhook URLs from process.env
  • ship a Node-only Slack SDK inside the shared root package boundary
  • force one provider strategy beyond the webhook-first helper and exported transport contract
  • translate one notification into multi-channel fan-out inside a single dispatch call

These limitations are part of the package contract so runtime choice, provider capability, and rollout strategy stay explicit at the application boundary.

Public API Overview

Core

  • SlackModule.forRoot(options) / SlackModule.forRootAsync(options)
  • SlackModuleOptions
  • SlackAsyncModuleOptions
  • createSlackProviders(options)
  • SlackService
  • SlackService.send(message, options)
  • SlackService.sendMany(messages, options)
  • SlackService.sendNotification(notification, options)
  • SlackService.createPlatformStatusSnapshot()
  • SlackChannel
  • SLACK
  • SLACK_CHANNEL

Service facade and result contracts

  • Slack
  • SlackSendOptions
  • SlackSendManyOptions
  • SlackSendResult
  • SlackSendBatchResult
  • SlackSendFailure

Contracts and helpers

  • SlackMessage
  • NormalizedSlackMessage
  • SlackNotificationPayload
  • SlackNotificationDispatchRequest
  • SlackBlock
  • SlackAttachment
  • SlackTransport
  • SlackTransportFactory
  • SlackTransportContext
  • SlackTransportReceipt
  • SlackFetchLike
  • SlackFetchResponse
  • SlackWebhookTransportOptions
  • createSlackWebhookTransport(options)
  • SlackTemplateRenderer
  • SlackTemplateRenderInput
  • SlackTemplateRenderResult

Status and errors

  • createSlackPlatformStatusSnapshot(...)
  • SlackPlatformStatusSnapshot
  • SlackLifecycleState
  • SlackStatusAdapterInput
  • SlackConfigurationError
  • SlackLifecycleError: thrown by lifecycle-gated delivery, transport initialization, and owned-resource shutdown failures. Catch this error when sends can race with application teardown.
  • SlackMessageValidationError
  • SlackTransportError

Related Packages

  • @fluojs/notifications: Shared orchestration layer that consumes SLACK_CHANNEL.
  • @fluojs/config: Recommended for resolving webhook URLs or tokens without direct environment access.
  • @fluojs/event-bus: Useful when Slack notifications are one side effect among several event-driven workflows.

Example Sources

  • packages/slack/src/module.test.ts: Module registration, createSlackProviders(...) helper coverage, async wiring, webhook transport, and notifications integration examples.
  • packages/slack/src/public-surface.test.ts: Public export and TypeScript contract verification.
  • packages/slack/src/status.test.ts: Health/readiness contract examples.