Documentation
¶
Index ¶
- Constants
- func IsCode(err error, code string) bool
- func RedactToken(token string) string
- type APIError
- type Authenticator
- type Bool
- type Client
- func (c *Client) AuthTest(ctx context.Context) (*Identity, error)
- func (c *Client) BaseURL() string
- func (c *Client) Call(ctx context.Context, method string, params map[string]any, idempotent bool) (json.RawMessage, error)
- func (c *Client) CallAllPages(ctx context.Context, method string, params map[string]any, resultKey string, ...) (json.RawMessage, error)
- func (c *Client) CallInto(ctx context.Context, method string, params map[string]any, idempotent bool, ...) error
- func (c *Client) Close() error
- func (c *Client) DialHeaders() http.Header
- func (c *Client) FetchAuthed(ctx context.Context, url string, w io.Writer) (int64, error)
- func (c *Client) OpenRTMURL(ctx context.Context) (string, error)
- func (c *Client) OpenSocketURL(ctx context.Context) (string, error)
- func (c *Client) UploadFile(ctx context.Context, path string, opts UploadOptions) (*UploadResult, error)
- type ID
- type Identity
- type Int
- type Option
- func WithBaseURL(u string) Option
- func WithDryRun(v bool) Option
- func WithDryRunWriter(w io.Writer) Option
- func WithHTTPClient(h *http.Client) Option
- func WithRPS(rps float64) Option
- func WithRecorder(r Recorder) Option
- func WithRetryPolicy(p retryPolicy) Option
- func WithShowToken(v bool) Option
- func WithVerbose(v bool) Option
- type Recorder
- type SessionAuth
- type TokenAuth
- type UploadOptions
- type UploadResult
Constants ¶
const DefaultBaseURL = "https://slack.com/api"
DefaultBaseURL is the public Web API root. Method URLs are <base>/<method>.
Variables ¶
This section is empty.
Functions ¶
func RedactToken ¶
RedactToken masks a Slack token, keeping only the kind prefix (e.g. "xoxb-****").
Types ¶
type APIError ¶
type APIError struct {
StatusCode int // HTTP status (usually 200 even on failure; 429 on rate limit)
Code string // Slack error code, e.g. "channel_not_found"
Warning string // Slack's non-fatal warning, when present
Needed string // missing_scope: the scope the call needed
Provided string // missing_scope: the scopes the token actually has
Body string // raw body, for --verbose debugging
Method string // the Web API method that failed, for context
RetryAfter int // seconds from the Retry-After header on a 429, or 0
}
APIError is a typed Slack Web API failure. Slack answers HTTP 200 with {"ok":false,"error":"snake_case_code",...} for almost every failure — the HTTP status only matters for 429s and infrastructure errors — so the string Code is the primary key. We surface all of it and, crucially, append an actionable hint keyed by the code so the user knows the next move instead of staring at a bare "request failed" (GOAL.md §1).
type Authenticator ¶
type Authenticator interface {
// Apply sets the credential on the request.
Apply(req *http.Request)
// Redacted returns the Authorization value masked, for --dry-run and logs.
Redacted() string
// Raw returns the Authorization value for --show-token dry-runs. Never log it elsewhere.
Raw() string
// ExtraHeaders returns credential headers beyond Authorization (the session cookie),
// masked unless redact is false — so the --dry-run curl reproduces the real request.
ExtraHeaders(redact bool) map[string]string
// Method is the non-secret auth method name recorded in the profile.
Method() string
}
Authenticator applies a credential to an outgoing Web API request. Slack has one primary wire scheme (an `Authorization: Bearer` header) carried by several token kinds — bot (xoxb-), user (xoxp-), app-level (xapp-, Socket Mode only) — plus the browser-session scheme (an xoxc- bearer token + a `Cookie: d=xoxd-…` header) that Slack's own web client uses. We keep the interface from the cliwright standard so redaction lives in one place and the design scales across kinds (GOAL.md §1 "auth providers").
type Bool ¶
type Bool bool
Bool accepts a real JSON bool or the strings "true"/"false"/"1"/"0"/"yes"/"no".
func (Bool) MarshalJSON ¶
func (*Bool) UnmarshalJSON ¶
type Client ¶
type Client struct {
DryRun bool
ShowToken bool
Verbose bool
// contains filtered or unexported fields
}
Client is the single typed gateway to the Slack Web API. Every command goes through it, so auth, retries, rate limiting, and dry-run live in exactly one place (GOAL.md §2).
func New ¶
func New(auth Authenticator, opts ...Option) *Client
New builds a Client for the given authenticator. Sensible defaults are applied; override with Options.
func (*Client) AuthTest ¶
AuthTest verifies the token against auth.test and returns who it belongs to. It is the verification step behind `auth login`, `auth status`, and `doctor`.
func (*Client) Call ¶
func (c *Client) Call(ctx context.Context, method string, params map[string]any, idempotent bool) (json.RawMessage, error)
Call invokes a Web API method and returns the raw response body (the full envelope, since Slack nests payloads as siblings of ok). idempotent marks read methods: they are sent as GET with query params — which also lets the retry policy safely replay them — while writes go as a form-encoded POST and are never auto-retried except on 429 (rejected, not processed). In dry-run mode it prints the equivalent curl and returns (nil, nil).
func (*Client) CallAllPages ¶
func (c *Client) CallAllPages(ctx context.Context, method string, params map[string]any, resultKey string, max int) (json.RawMessage, error)
CallAllPages follows Slack's cursor pagination (response_metadata.next_cursor; empty string = done) and returns the pages' resultKey arrays merged into a single JSON array. max caps the total items collected; max <= 0 means all. The per-request limit is set by the caller via params["limit"] (Slack recommends 100-200).
func (*Client) CallInto ¶
func (c *Client) CallInto(ctx context.Context, method string, params map[string]any, idempotent bool, out any) error
CallInto is Call plus a JSON decode of the response into out.
func (*Client) Close ¶ added in v0.3.0
Close releases resources an attached Recorder holds (e.g. the store's SQLite handle) if it implements io.Closer. Safe to defer unconditionally: a nil or non-Closer recorder is a no-op. This matters on Windows, where an open handle blocks deleting/renaming the file.
func (*Client) DialHeaders ¶
DialHeaders returns the credential headers a WebSocket handshake must carry beyond the URL ticket. For a browser-session credential this is the `Cookie: d=<xoxd>` header, which the RTM gateway re-validates on the WebSocket UPGRADE (not just on the rtm.connect HTTP call) — without it the gateway answers invalid_auth. For a plain token it is empty (the URL ticket authenticates), so this is safe to apply for every transport.
func (*Client) FetchAuthed ¶ added in v0.2.0
FetchAuthed streams a Slack-hosted private URL (url_private / url_private_download) to w, applying the credential. Slack file URLs require the same Authorization header as the API.
func (*Client) OpenRTMURL ¶
OpenRTMURL asks rtm.connect for a fresh Real Time Messaging wss:// URL. RTM works with a user/session token (xoxc+xoxd) — a browser web-client credential — so it backs `slackctl listen` when no app-level token is available. RTM is a legacy API and is not officially supported for xoxc tokens; a workspace may return method_deprecated or not_allowed_token_type, which the caller surfaces with its hint. URLs are single-use and must be connected within ~30s, so callers fetch one per (re)connection.
func (*Client) OpenSocketURL ¶
OpenSocketURL asks apps.connections.open for a fresh Socket Mode wss:// URL. It requires an app-level token (xapp-, scope connections:write); Slack's URLs are single-use tickets, so callers fetch one per (re)connection attempt.
func (*Client) UploadFile ¶ added in v0.2.0
func (c *Client) UploadFile(ctx context.Context, path string, opts UploadOptions) (*UploadResult, error)
UploadFile runs Slack's three-step external upload flow (files.upload was sunset Nov 2025):
- files.getUploadURLExternal — reserve an upload URL + file id for (filename, length);
- POST the file bytes to that URL (multipart, field "file");
- files.completeUploadExternal — finalize and share the file.
It returns the completed file id. path must be a readable regular file.
type ID ¶
type ID string
ID unmarshals from a JSON string OR number and always marshals as a string. Telegram chat/user/message IDs are int64 that overflow JS's 2^53 safe integer, so we never let them round-trip through float64 and we render them consistently in tables.
func (ID) MarshalJSON ¶
MarshalJSON always emits a quoted string so tables and JSON output are stable.
func (*ID) UnmarshalJSON ¶
UnmarshalJSON accepts `123`, `"123"`, or null.
type Identity ¶
type Identity struct {
URL string `json:"url"`
Team string `json:"team"`
User string `json:"user"`
TeamID string `json:"team_id"`
UserID string `json:"user_id"`
BotID string `json:"bot_id,omitempty"`
EnterpriseID string `json:"enterprise_id,omitempty"`
}
Identity is auth.test's answer — the whoami payload. A bot token adds bot_id; Enterprise Grid orgs add enterprise_id.
type Int ¶
type Int int64
Int accepts a JSON number or a numeric string and stores an exact int64. It decodes the integer form before any float path so values above 2^53 keep full precision, and it rejects NaN/Inf and non-integer numbers.
func (Int) MarshalJSON ¶
func (*Int) UnmarshalJSON ¶
type Option ¶
type Option func(*Client)
Option configures a Client.
func WithBaseURL ¶
func WithDryRun ¶
func WithDryRunWriter ¶
func WithHTTPClient ¶
func WithRecorder ¶ added in v0.3.0
WithRecorder attaches an observer notified after every successful, non-dry-run call — the local message-history hook. internal/api stays generic (it knows nothing about SQLite) by depending only on this narrow interface.
func WithRetryPolicy ¶
func WithRetryPolicy(p retryPolicy) Option
func WithShowToken ¶
func WithVerbose ¶
type Recorder ¶ added in v0.3.0
type Recorder interface {
Record(ctx context.Context, method string, params map[string]any, result json.RawMessage)
}
Recorder observes successful Web API calls so a caller can persist a local message history (the `slackctl log` store) without internal/api depending on internal/store — the client stays a generic HTTP core (GOAL.md §2). Record is called once per successful, non-dry-run call with the same context the command passed in.
Record must not block the caller on its own failures: an implementation filters to the methods it cares about and swallows/logs its own errors — a broken store must never fail a command.
type SessionAuth ¶
SessionAuth authenticates as a real Slack user with browser-session credentials: an xoxc- token in the Authorization header plus the paired xoxd- cookie. This is the scheme Slack's web client uses; an xoxc token WITHOUT its cookie is rejected by Slack with invalid_auth. It carries the user's own identity, so it satisfies user-token-only methods (search.*, stars.*) too.
func NewSessionAuth ¶
func NewSessionAuth(token, cookie string) (*SessionAuth, error)
NewSessionAuth validates the pair's shape: both halves are required.
func (*SessionAuth) Apply ¶
func (a *SessionAuth) Apply(req *http.Request)
func (*SessionAuth) ExtraHeaders ¶
func (a *SessionAuth) ExtraHeaders(redact bool) map[string]string
func (*SessionAuth) Method ¶
func (a *SessionAuth) Method() string
Method reports "session-token": user-grade identity from a browser session.
func (*SessionAuth) Raw ¶
func (a *SessionAuth) Raw() string
func (*SessionAuth) Redacted ¶
func (a *SessionAuth) Redacted() string
type TokenAuth ¶
type TokenAuth struct {
Token string
}
TokenAuth authenticates with a Slack token via the Authorization header.
func NewTokenAuth ¶
NewTokenAuth validates the token shape loosely: Slack tokens start with "xox" (xoxb-, xoxp-, xoxe.xoxp-, ...) or "xapp-". Reject only the obviously wrong, not unknown future prefixes.
func (*TokenAuth) ExtraHeaders ¶
ExtraHeaders is empty for plain tokens — the bearer header is the whole credential.
type UploadOptions ¶ added in v0.2.0
type UploadOptions struct {
Filename string // defaults to the base name of the path
Title string
Channels string // comma-separated channel ids to share into
InitialComment string
ThreadTS string
SnippetType string // for code snippets (e.g. "text", "python")
}
UploadOptions carries the sharing parameters for a file upload.
type UploadResult ¶ added in v0.2.0
type UploadResult struct {
FileID string `json:"file_id"`
Raw json.RawMessage
}
UploadResult is the outcome of a completed external file upload.