New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

effect-slack

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

effect-slack

An Effect-native Slack SDK

latest
Source
npmnpm
Version
0.3.0
Version published
Weekly downloads
6
-73.91%
Maintainers
1
Weekly downloads
 
Created
Source

effect-slack

An Effect-native Slack SDK ✨

Features

  • 100% Type-safe — Full TypeScript types for all 272 methods, arguments, and responses
  • Typed errors — Discriminated unions with catchTag/catchTags for precise error handling
  • Observability built-in — OpenTelemetry spans with rich attributes (method, channel, user, timestamps)
  • Smart retries — Rate limit aware with exponential backoff and jitter
  • Testable by design — Dependency injection via Effect layers, easily mockable
  • Always up-to-date — Auto-generated from official @slack/web-api types

Installation

bun add effect-slack effect
# or
npm install effect-slack effect

Quick Start

import { Effect } from "effect"
import { SlackService } from "effect-slack"

// Using environment variables (SLACK_TOKEN)
const program = Effect.gen(function* () {
  const slack = yield* SlackService

  const result = yield* slack.postMessage({
    channel: "C1234567890",
    text: "Hello from Effect!"
  })

  console.log("Message sent:", result.ts)
}).pipe(Effect.provide(SlackService.Live))

Effect.runPromise(program)

Examples

Check out the examples folder for complete, runnable examples:

ExampleDescription
with-effect-platformFull Effect stack using @effect/platform-bun with Events API, slash commands, and Swagger docs
with-expressExpress + Effect integration showing gradual Effect adoption for Slack API calls

Custom Configuration

import { Effect, Layer, Redacted } from "effect"
import { SlackService, SlackConfig, SlackClient } from "effect-slack"

const customConfig = SlackConfig.make({
  token: Redacted.make(process.env.MY_SLACK_TOKEN!),
  options: {
    retryConfig: { retries: 5 }
  }
})

const CustomSlackLayer = SlackService.Default.pipe(
  Layer.provide(SlackClient.Default),
  Layer.provide(customConfig)
)

const program = Effect.gen(function* () {
  const slack = yield* SlackService
  // ... use slack methods
}).pipe(Effect.provide(CustomSlackLayer))

Error Handling

All Slack API errors are mapped to typed Effect errors that can be handled with catchTag or catchTags:

import { Effect } from "effect"
import { SlackService } from "effect-slack"

const program = Effect.gen(function* () {
  const slack = yield* SlackService
  return yield* slack.postMessage({ channel: "C123", text: "Hi" })
}).pipe(
  Effect.catchTags({
    SlackRateLimitedError: (e) => Effect.log(`Rate limited, retry in ${e.retryAfter}s`),
    SlackPlatformError: (e) =>
      e.isAuthError
        ? Effect.logError(`Auth failed: ${e.error}`)
        : Effect.logError(`API error: ${e.error}`),
    SlackHttpError: (e) => Effect.logError(`HTTP ${e.statusCode}: ${e.statusMessage}`)
  }),
  Effect.provide(SlackService.Live)
)

Error Types

Error TypeDescription
SlackRequestErrorNetwork failures, DNS errors
SlackHttpErrorNon-200 HTTP responses with statusCode and body
SlackPlatformErrorSlack API errors with error code (e.g., channel_not_found)
SlackRateLimitedErrorRate limit exceeded, includes retryAfter (seconds)
SlackFileUploadInvalidArgumentsErrorInvalid file upload arguments
SlackFileUploadReadErrorFailed to read file data
SlackUnknownErrorUnexpected errors

SlackPlatformError includes an isAuthError getter that returns true for auth-related errors (invalid_auth, not_authed, token_revoked, token_expired, account_inactive).

Retry Support

The library provides two approaches to retry handling:

SDK-Level Retries (Default)

The underlying @slack/web-api SDK handles retries automatically. You can configure it via SlackConfig:

import { Redacted } from "effect"
import { SlackConfig } from "effect-slack"

const config = SlackConfig.make({
  token: Redacted.make("xoxb-..."),
  options: {
    retryConfig: { retries: 5 }
  }
})

Disabling SDK Retries

To use Effect-level retries exclusively, disable SDK retries:

import { Redacted } from "effect"
import { SlackConfig } from "effect-slack"

const config = SlackConfig.make({
  token: Redacted.make("xoxb-..."),
  options: {
    retryConfig: { retries: 0 }, // Disable SDK retries
    rejectRateLimitedCalls: true // Don't auto-handle rate limits
  }
})

Effect-Level Retries

For more control, use the Effect-native retry utilities:

import { Effect, pipe } from "effect"
import {
  SlackService,
  withDefaultRetry,
  withRateLimitRetry,
  rapidRetryPolicy,
  isRetryableError
} from "effect-slack"

// Apply default retry policy (10 retries with exponential backoff)
const program = pipe(
  Effect.flatMap(SlackService, (slack) =>
    slack.postMessage({ channel: "#general", text: "Hello!" })
  ),
  withDefaultRetry
)

// Or use a custom schedule
const programWithCustomRetry = pipe(
  Effect.flatMap(SlackService, (slack) =>
    slack.postMessage({ channel: "#general", text: "Hello!" })
  ),
  Effect.retry(rapidRetryPolicy)
)

Pre-built Schedules

ScheduleDescription
tenRetriesInAboutThirtyMinutes10 retries with exponential backoff + jitter
fiveRetriesInFiveMinutes5 retries with exponential backoff + jitter
rapidRetryPolicy3 retries with 100ms delay (for testing)
rateLimitAwareSchedule(opts)Configurable retries with exponential backoff

Retryable Errors

The isRetryableError function determines which errors are safe to retry:

Error TypeRetryableReason
SlackRateLimitedErrorYesTransient, has retryAfter
SlackRequestErrorYesNetwork failures
SlackHttpError (5xx)YesServer errors
SlackHttpError (4xx)NoClient errors
SlackPlatformErrorPartialOnly service_unavailable
Auth errorsNoWon't resolve with retry

Observability

All SlackService methods are instrumented with OpenTelemetry-compatible spans.

Span Attributes

AttributeDescription
slack.methodSlack API method (e.g., chat.postMessage)
slack.channelChannel ID (where applicable)
slack.userUser ID (for user operations)
slack.tsMessage timestamp (for updates/deletes)
slack.reactionReaction name (for reaction operations)
error.typeError tag on failures (e.g., SlackPlatformError)
slack.errorPlatform error code (e.g., channel_not_found)
http.status_codeHTTP status code on HTTP errors
slack.retry_afterRetry-After seconds on rate limit errors

Exporting Traces

Use @effect/opentelemetry to export traces to your observability backend:

import { Effect } from "effect"
import { NodeSdk } from "@effect/opentelemetry"
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base"
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http"
import { SlackService } from "effect-slack"

const TracingLive = NodeSdk.layer(() => ({
  resource: { serviceName: "my-slack-app" },
  spanProcessor: new BatchSpanProcessor(new OTLPTraceExporter())
}))

const program = Effect.gen(function* () {
  const slack = yield* SlackService
  yield* slack.postMessage({ channel: "#general", text: "Hello!" })
})

Effect.runPromise(program.pipe(Effect.provide(SlackService.Live), Effect.provide(TracingLive)))

Available Methods

The library provides 272 methods across 33 services, auto-generated from the official @slack/web-api types. Services include:

  • ChatService - Messages, threads, scheduled messages
  • ConversationsService - Channels, DMs, group conversations
  • UsersService - User profiles, presence, identity
  • ReactionsService - Emoji reactions
  • FilesService - File uploads and management
  • AdminService - Workspace administration (100+ methods)
  • AppsService, AuthService, BookmarksService, CallsService, ViewsService, and more...

Each service is available as an Effect service with full TypeScript types. See src/generated/ for the complete API.

Testing

The library is designed to be easily testable by providing mock implementations:

import { Effect, Layer } from "effect"
import { SlackService, SlackClient } from "effect-slack"
import type { WebClient } from "@slack/web-api"

// Create a mock WebClient
const mockClient = {
  chat: {
    postMessage: async () => ({ ok: true, ts: "1234.5678" })
  }
} as unknown as WebClient

// Create test layer
const TestLayer = SlackService.Default.pipe(Layer.provide(SlackClient.make(mockClient)))

// Use in tests
const testProgram = Effect.gen(function* () {
  const slack = yield* SlackService
  const result = yield* slack.postMessage({
    channel: "C123",
    text: "Test message"
  })
  return result
}).pipe(Effect.provide(TestLayer))

Architecture

Services are auto-generated from the @slack/web-api TypeScript definitions:

  • Parse — Extract method signatures from @slack/web-api/dist/methods.d.ts
  • Generate — Create Effect-wrapped services with typed arguments and responses
  • Instrument — Add OpenTelemetry spans and error mapping to each method
@slack/web-api types → Parser → Code Generator → Effect Services

Generated services follow a consistent pattern:

// Each method is wrapped with Effect.tryPromise, error mapping, and tracing
const postMessage = (
  args: ChatPostMessageArguments
): Effect.Effect<ChatPostMessageResponse, SlackError> =>
  Effect.tryPromise({
    try: () => client.chat.postMessage(args),
    catch: mapSlackError
  }).pipe(
    Effect.tapError(annotateSpanWithError),
    Effect.withSpan("ChatService.postMessage", {
      attributes: { "slack.method": "chat.postMessage" }
    })
  )

Run bun run generate to regenerate services when updating @slack/web-api.

License

MIT

Keywords

api

FAQs

Package last updated on 13 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts