client

package
v0.19.930 Latest Latest
Warning

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

Go to latest
Published: May 13, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package client is a thin Slack Web API client scoped to the surface area the Nuon slackbot integration needs:

  • oauth.v2.access — exchange OAuth code for a workspace bot token
  • chat.postMessage — post lifecycle / approval messages
  • chat.update — edit a previously posted message (e.g. mark approved)
  • conversations.list — enumerate channels for the /nuon subscribe flow
  • auth.test — probe a token (used after install to capture bot_user_id, app_id, etc.)

We avoid pulling in a third-party Slack SDK because the surface area is small, easy to review, and we want full control over JSON shape, retry behavior, and observability.

Index

Constants

View Source
const BaseURL = "https://slack.com/api"

BaseURL is the public Slack Web API endpoint. Tests override this.

Variables

This section is empty.

Functions

This section is empty.

Types

type AuthTestResponse

type AuthTestResponse 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"`
	EnterpriseID string `json:"enterprise_id,omitempty"`
	// contains filtered or unexported fields
}

AuthTestResponse is the response from auth.test.

type Client

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

Client is a Slack Web API client. Construct via New.

func New

func New(opts ...Option) *Client

New constructs a Slack Web API client with sensible defaults.

func (*Client) AuthTest

func (c *Client) AuthTest(ctx context.Context, botToken string) (*AuthTestResponse, error)

AuthTest probes a bot token. Useful immediately after install to verify scope grants and capture the bot user id / team id from the token itself.

func (*Client) ConversationsList

func (c *Client) ConversationsList(ctx context.Context, botToken string, req ConversationsListRequest) (*ConversationsListResponse, error)

ConversationsList enumerates channels visible to the bot.

func (*Client) OAuthV2Access

func (c *Client) OAuthV2Access(ctx context.Context, req OAuthV2AccessRequest) (*OAuthV2AccessResponse, error)

OAuthV2Access exchanges an OAuth code for a workspace access token.

func (*Client) PostMessage

func (c *Client) PostMessage(ctx context.Context, botToken string, req PostMessageRequest) (*PostMessageResponse, error)

PostMessage posts a message to a channel as the supplied bot token.

func (*Client) UpdateMessage

func (c *Client) UpdateMessage(ctx context.Context, botToken string, req UpdateMessageRequest) (*UpdateMessageResponse, error)

UpdateMessage edits a previously posted message.

func (*Client) ViewsOpen

func (c *Client) ViewsOpen(ctx context.Context, botToken string, req ViewsOpenRequest) (*ViewsResponse, error)

ViewsOpen opens a new modal anchored to the given trigger_id. Trigger ids are short-lived (~3s) so callers must not block before invoking this.

func (*Client) ViewsPush

func (c *Client) ViewsPush(ctx context.Context, botToken string, req ViewsPushRequest) (*ViewsResponse, error)

ViewsPush stacks a new modal on top of the current one.

func (*Client) ViewsUpdate

func (c *Client) ViewsUpdate(ctx context.Context, botToken string, req ViewsUpdateRequest) (*ViewsResponse, error)

ViewsUpdate edits a previously opened modal in place. Used by the unsubscribe modal's Remove buttons (re-render after each delete) and by the subscribe modal's scope/install pivots.

type Conversation

type Conversation struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	IsChannel  bool   `json:"is_channel"`
	IsPrivate  bool   `json:"is_private"`
	IsArchived bool   `json:"is_archived"`
	IsMember   bool   `json:"is_member"`
}

Conversation is a single channel entry from conversations.list.

type ConversationsListRequest

type ConversationsListRequest struct {
	Cursor          string
	Limit           int
	Types           string // e.g. "public_channel,private_channel"
	ExcludeArchived bool
}

ConversationsListRequest paginates through channel listings.

type ConversationsListResponse

type ConversationsListResponse struct {
	Channels         []Conversation `json:"channels"`
	ResponseMetadata struct {
		NextCursor string `json:"next_cursor"`
	} `json:"response_metadata"`
	// contains filtered or unexported fields
}

ConversationsListResponse is the response from conversations.list.

type OAuthV2AccessRequest

type OAuthV2AccessRequest struct {
	ClientID     string
	ClientSecret string
	Code         string
	RedirectURI  string
}

OAuthV2AccessRequest contains the inputs for an OAuth code exchange.

type OAuthV2AccessResponse

type OAuthV2AccessResponse struct {
	AccessToken string `json:"access_token"`
	TokenType   string `json:"token_type"`
	Scope       string `json:"scope"`
	BotUserID   string `json:"bot_user_id"`
	AppID       string `json:"app_id"`

	Team struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	} `json:"team"`

	Enterprise *struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	} `json:"enterprise"`

	// IsEnterpriseInstall is true for org-wide (Enterprise Grid) installs.
	// We reject these at the OAuth callback in v1 — see Phase 4.
	IsEnterpriseInstall bool `json:"is_enterprise_install"`

	AuthedUser struct {
		ID string `json:"id"`
	} `json:"authed_user"`
	// contains filtered or unexported fields
}

OAuthV2AccessResponse is the subset of oauth.v2.access we care about.

Slack returns far more fields (incoming_webhook, authed_user, etc.) but we only persist what's needed to drive the bot: the bot token, the workspace identity, and the install-time scope grant.

type Option

type Option func(*Client)

Option mutates Client during construction.

func WithBaseURL

func WithBaseURL(u string) Option

WithBaseURL overrides the default Slack API base URL (used in tests).

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

WithHTTPClient overrides the default HTTP client.

type PostMessageRequest

type PostMessageRequest struct {
	Channel  string         `json:"channel"`
	Text     string         `json:"text,omitempty"`
	Blocks   []any          `json:"blocks,omitempty"`
	ThreadTS string         `json:"thread_ts,omitempty"`
	Metadata map[string]any `json:"metadata,omitempty"`
}

PostMessageRequest is the input for chat.postMessage.

type PostMessageResponse

type PostMessageResponse struct {
	Channel string `json:"channel"`
	TS      string `json:"ts"`
	// contains filtered or unexported fields
}

PostMessageResponse mirrors chat.postMessage's response.

type UpdateMessageRequest

type UpdateMessageRequest struct {
	Channel string `json:"channel"`
	TS      string `json:"ts"`
	Text    string `json:"text,omitempty"`
	Blocks  []any  `json:"blocks,omitempty"`
}

UpdateMessageRequest mutates a previously posted message.

type UpdateMessageResponse

type UpdateMessageResponse struct {
	Channel string `json:"channel"`
	TS      string `json:"ts"`
	// contains filtered or unexported fields
}

UpdateMessageResponse mirrors chat.update's response.

type ViewsOpenRequest

type ViewsOpenRequest struct {
	TriggerID string         `json:"trigger_id"`
	View      map[string]any `json:"view"`
}

ViewsOpenRequest opens a modal in response to a trigger_id from an interactive surface (slash command, button click, etc.). View is the Block-Kit modal definition; we accept it as a generic map so callers can build whatever shape they need without us schema-locking the modal here.

type ViewsPushRequest

type ViewsPushRequest struct {
	TriggerID string         `json:"trigger_id"`
	View      map[string]any `json:"view"`
}

ViewsPushRequest pushes a new modal onto an already-open modal stack. We don't currently use push (everything fits in a single root modal) but expose it for parity with views.open / views.update.

type ViewsResponse

type ViewsResponse struct {
	View struct {
		ID         string `json:"id"`
		CallbackID string `json:"callback_id"`
		Hash       string `json:"hash"`
	} `json:"view"`

	// ResponseMetadata.Messages carries Block-Kit validation errors when
	// Slack rejects a view payload (e.g. an unknown block type). Surfaces
	// in error messages so misshapen modals are debuggable.
	ResponseMetadata struct {
		Messages []string `json:"messages,omitempty"`
	} `json:"response_metadata,omitempty"`
	// contains filtered or unexported fields
}

ViewsResponse is the shared response shape for views.open / views.update / views.push. Slack returns the persisted view (with its allocated id) on success.

type ViewsUpdateRequest

type ViewsUpdateRequest struct {
	ViewID     string         `json:"view_id,omitempty"`
	ExternalID string         `json:"external_id,omitempty"`
	Hash       string         `json:"hash,omitempty"`
	View       map[string]any `json:"view"`
}

ViewsUpdateRequest replaces the contents of an already-open modal. Exactly one of ViewID / ExternalID identifies the view; ViewID is the standard case (Slack provides it on every view payload).

Jump to

Keyboard shortcuts

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