slack

package
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package slack implements the Slack adapter for the pigo chat gateway: Events API ingress over HTTP (v0 request signing, url_verification handshake, echo filtering), Web API delivery with a bot token (streamed preview edits via chat.update, mrkdwn finalization with chunking), and authenticated file download.

The adapter speaks the Events API webhook, not Socket Mode, so it needs a public endpoint plus the app's signing secret. Slack has no typing indicator for bot messages: the streamed preview message is the activity signal and Typing is a no-op.

Index

Constants

View Source
const DefaultBaseURL = "https://slack.com"

DefaultBaseURL is the production Web API endpoint.

Variables

This section is empty.

Functions

func ChunkText

func ChunkText(text string, limit int) []string

ChunkText splits text into chunks of at most limit characters, at line boundaries where possible (long lines split at spaces, then hard). Code fences are chunk-aware: a split inside a fence closes it with ``` and reopens ``` at the start of the next chunk. Empty input yields no chunks.

func FormatText

func FormatText(markdown string) string

FormatText converts standard markdown to Slack mrkdwn: `**b**`/`__b__` → `*b*`, `*i*` → `_i_`, `~~s~~` → `~s~`, `[t](u)` → `<u|t>`, headings → `*bold*` lines, `- ` bullets → `• `, with `&`, `<`, `>` escaped in body text before any `<...>` construct is inserted. Fenced code blocks keep their triple-backtick markers (language tokens are dropped — mrkdwn would display them literally); fence content is escaped but otherwise untouched.

ponytail: line/regex transform, not a goldmark AST walk; inline-code contents are transformed like normal text, and spaced single asterisks can over-italicize — accepted ceilings.

Types

type APIError

type APIError struct {
	Method string
	Status int
	Code   string
	// RetryAfter is the server-requested pause (Retry-After header on 429,
	// a default 1s on a body-level "ratelimited"), zero otherwise.
	RetryAfter time.Duration
}

APIError is a decoded Web API failure: either an HTTP 429 or an ok:false envelope. Code carries the Slack error token ("ratelimited", "edit_window_closed", ...).

func (*APIError) Error

func (e *APIError) Error() string

type Adapter

type Adapter struct {
	// contains filtered or unexported fields
}

Adapter is the Slack implementation of chat.Adapter.

func New

func New(opts Options) (*Adapter, error)

New builds the adapter. It refuses to construct without Token and SigningSecret. When Options.BotUserID is empty, the bot identity is resolved (and cached for the adapter's lifetime) via one auth.test call — the id drives echo filtering, so the adapter cannot run without it.

func (*Adapter) Account

func (a *Adapter) Account() string

Account returns the bot user id (auth.test user_id), matching the Account set on every normalized message.

func (*Adapter) Download

func (a *Adapter) Download(ctx context.Context, ref chat.AttachmentRef) (io.ReadCloser, string, error)

Download implements chat.Adapter: the attachment id is the file's url_private_download, fetched with the Bearer token (kept across the slack.com → files.slack.com redirect). The MIME type is the one carried on the ref (the download response is generic).

func (*Adapter) NewDelivery

func (a *Adapter) NewDelivery(key chat.ConversationKey, replyTo, resumePreviewID string) chat.Delivery

NewDelivery implements chat.Adapter. The conversation ThreadID (thread_ts or "" for top-level DM replies) threads every outbound message; a non-empty resumePreviewID makes Finalize edit that message instead of posting a new one (crash recovery).

func (*Adapter) Platform

func (a *Adapter) Platform() string

Platform implements chat.Adapter.

func (*Adapter) Webhook

func (a *Adapter) Webhook(publish func(chat.Message) error) http.Handler

Webhook returns the Events API ingress handler. Every request — including url_verification — is authenticated by the v0 signature over the raw body (constant-time compare, replay window enforced), 401 on failure. Events are normalized and published synchronously, then acked: publish is a durable-enqueue seam and must never wait on turn processing (Slack requires a 2xx within 3 seconds). A publish failure answers 500 so Slack redelivers; the "sl:<channel>:<ts>" EventID dedupes downstream — the same key also collapses the app_mention/message.channels double delivery of one mention (their event_ids differ, channel+ts do not).

type Options

type Options struct {
	// Token is the bot token (xoxb-...). Required.
	Token string
	// SigningSecret verifies inbound Events API requests (v0 signature).
	// Required: unsigned webhooks are not an option.
	SigningSecret string
	// BaseURL overrides the Web API endpoint (tests). Default
	// https://slack.com.
	BaseURL string
	// BotUserID pre-seeds the bot user identity used for echo filtering and
	// mention gating; resolved via auth.test in [New] when empty.
	BotUserID string
	// HTTPClient overrides the HTTP client. Default: 30s timeout.
	HTTPClient *http.Client
	// PreviewMinInterval rate-limits chat.update preview edits per channel.
	// Default 1s (chat.update is Tier 3, ~1/sec sustained).
	PreviewMinInterval time.Duration
	// ReplayWindow bounds |now - X-Slack-Request-Timestamp| on inbound
	// events. Default 5m (Slack's documented replay window).
	ReplayWindow time.Duration
	// Logger receives non-fatal diagnostics. Optional.
	Logger *slog.Logger
}

Options configures New.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL