Help us shape the future of Go! Take the 2026 Go Developer Survey

store

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Oct 1, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// MaxPushSubscriptionsPerUser caps how many devices one account keeps.
	// The oldest is evicted, so reinstalling a browser repeatedly cannot grow
	// the table without bound.
	MaxPushSubscriptionsPerUser = 10

	// MaxPushRetryDelay caps the backoff after a push service refuses a
	// delivery. A device that has been unreachable for a day is retried daily,
	// not abandoned: a row is removed when the service says the subscription
	// is gone, or by PrunePushSubscriptions, never for one failure.
	MaxPushRetryDelay = 24 * time.Hour
	// PushFailingPruneAfter is how long a push service may refuse a device
	// before its row is pruned. An outage is shorter than a week.
	PushFailingPruneAfter = 7 * 24 * time.Hour
	// PushFailingPruneRefusedWithin is how recent the latest refusal of that
	// week must be. Retries ride on messages, so two refusals in one short
	// outage and then a quiet week are not a week of refusals: the run must
	// still be refusing at its end.
	PushFailingPruneRefusedWithin = 24 * time.Hour
	// PushFailingPruneMinFailures is how many refusals that week must hold,
	// so one refusal never removes a device.
	PushFailingPruneMinFailures = 2
	// PushRetiredKeyPruneAfter is how long a device registered under a
	// retired key may go without registering again before its row is pruned.
	// Opening the app replaces its subscription; a month without that means
	// nobody is opening it.
	PushRetiredKeyPruneAfter = 30 * 24 * time.Hour
)
View Source
const (
	DefaultSearchPageLimit = 50
	MaxSearchPageLimit     = 100
	MaxSearchQueryRunes    = 500
)
View Source
const (
	ChannelNotifyAll      = "all"
	ChannelNotifyMentions = "mentions"
	ChannelNotifyMuted    = "muted"
)
View Source
const (
	MessageKindMessage         = "message"
	MessageKindAgentCommentary = "agent_commentary"
	MessageKindAgentTool       = "agent_tool"
)

Message kinds. 'message' is an ordinary human/bot message and is the default for any row created before this column existed. The agent_* kinds are durable agent activity rows: they ride the normal message stream (channel sequence, message.created fan-out, scrollback) but are excluded from full-text search and from unread/notification accounting.

View Source
const (
	WorkspaceRoleOwner           = "owner"
	WorkspaceRoleModerator       = "moderator"
	WorkspaceRoleMember          = "member"
	WorkspaceRoleGuest           = "guest"
	WorkspaceRoleBot             = "bot"
	GuestChannelName             = "guest"
	GuestPostLimit               = 3
	MaxDirectConversationMembers = 32

	UploadQuotaBytesPerUserWorkspace int64 = 512 << 20
	UploadQuotaCountPerUserWorkspace int64 = 64
)
View Source
const (
	OAuthModeBrowser = "browser"
	OAuthModeDesktop = "desktop"
)
View Source
const AgentActivityWriteScope = "agent_activity:write"

AgentActivityWriteScope is the dedicated, non-inherited bot scope required to create an agent activity message (kind != 'message'). It is deliberately EXCLUDED from the bot:* bundles so existing deployments' capability surface is unchanged: a bot must be granted it explicitly.

View Source
const BotCommandsWriteScope = "commands:write"

BotCommandsWriteScope allows a bot token to replace its bot user's command menu in the token's bound workspace.

View Source
const MaxPinnedMessagesPerChannel = 100
View Source
const MaxSidebarChannelOrderIDs = 500

MaxSidebarChannelOrderIDs bounds one workspace's saved channel order. A client with more channels than this saves the leading window and lets the server's default ordering carry the rest.

View Source
const MaxSidebarChannelOrderWorkspaces = 100

MaxSidebarChannelOrderWorkspaces bounds how many workspaces one patch may rewrite, so a single request cannot fan out into unbounded membership work.

Variables

View Source
var (
	// ErrPushSessionEnded reports that the session a device was registered
	// under has been signed out, revoked, or expired since the push was queued.
	ErrPushSessionEnded = errors.New("push subscription session has ended")
	// ErrPushSubscriptionBackingOff reports that the push service asked for a
	// pause that the next attempt has not waited out yet.
	ErrPushSubscriptionBackingOff = errors.New("push subscription is backing off")
	// ErrPushSubscriptionKeyRetired reports that the device registered under
	// an application server key the server no longer signs with, so its push
	// service refuses every push.
	ErrPushSubscriptionKeyRetired = errors.New("push subscription is under a retired key")
)
View Source
var (
	ErrPushChannelMuted = errors.New("the recipient muted the channel")
	ErrPushNotMentioned = errors.New("the message does not mention the recipient")
)
View Source
var (
	ErrAlreadyPinned         = errors.New("message is already pinned")
	ErrPinnedMessageNotFound = errors.New("pinned message not found")
	ErrPinnedMessageLimit    = errors.New("channel pin limit reached (maximum 100)")
)
View Source
var (
	ErrOAuthTransactionInvalid  = errors.New("invalid or expired oauth transaction")
	ErrOAuthCapacityExceeded    = errors.New("too many pending oauth requests")
	ErrDesktopOAuthGrantInvalid = errors.New("invalid or expired desktop oauth grant")
)
View Source
var DurableEventTypes = []string{
	"channel.created",
	"channel.read",
	"channel.updated",
	"dm.read",
	"member.moderation_updated",
	"message.created",
	"message.deleted",
	"message.updated",
	"pin.added",
	"pin.removed",
	"reaction.added",
	"reaction.removed",
	"thread.reply_created",
	"thread.state_updated",
	"workspace.ownership_transferred",
	"workspace.updated",
}

DurableEventTypes enumerates every event type persisted to the event log and eligible for outgoing event subscriptions.

View Source
var ErrAmbiguousUserEmail = errors.New("multiple users have this identity email")

ErrAmbiguousUserEmail is returned when a case-insensitive identity email lookup resolves to more than one user. Callers must use an unambiguous user ID rather than guessing which account should receive access.

View Source
var ErrAmbiguousUserIdentifier = errors.New("multiple users match this identifier")

ErrAmbiguousUserIdentifier is returned when a password login identifier matches more than one account. Signing in would have to guess which account the caller meant, so the lookup fails instead.

View Source
var ErrBotOwnerCreateRequired = errors.New("only the bot owner can create a user-owned bot")

ErrBotOwnerCreateRequired is returned when someone other than the owner tries to create a user-owned bot.

View Source
var ErrBotOwnerMembershipRequired = errors.New("bot owner must be a workspace member")

ErrBotOwnerMembershipRequired is returned when a user-owned bot operation is attempted after the owner has lost membership in that workspace.

View Source
var ErrBotOwnerRequired = errors.New("only the bot owner can manage this bot")

ErrBotOwnerRequired is returned when a user-owned bot operation is attempted by someone other than the bot owner.

View Source
var ErrClientNonceConflict = errors.New("client nonce was already used for a different message")

ErrClientNonceConflict is returned when a client reuses an idempotency nonce for a different message request.

View Source
var ErrDirectConversationNoActivePeer = errors.New("direct conversation has no active recipient")

ErrDirectConversationNoActivePeer is returned when a sender is the only active workspace member left in a retained direct conversation.

View Source
var ErrInvalidEventDeliveryCursor = errors.New("invalid or stale event delivery cursor")

ErrInvalidEventDeliveryCursor is returned when a delivery-attempt cursor does not exist for the requested subscription.

View Source
var ErrInvalidMessageKind = errors.New("invalid message kind")

ErrInvalidMessageKind is returned when a caller supplies a message kind that is not one of the recognised values. HTTP callers surface it as a 400.

View Source
var ErrInvalidMessagePage = errors.New("invalid message page request")

ErrInvalidMessagePage is returned when a message-history request combines mutually exclusive cursors or uses an invalid cursor value.

View Source
var ErrInvalidSearch = errors.New("invalid search request")
View Source
var ErrInvalidWorkspaceMemberPage = errors.New("invalid workspace member page request")

ErrInvalidWorkspaceMemberPage is returned when a workspace-member listing request uses an invalid limit, filter, or cursor.

View Source
var ErrMessageNotWritable = errors.New("message is not writable")

ErrMessageNotWritable is returned when a user can read a message but cannot mutate it.

View Source
var ErrModerationRestricted = errors.New("moderation restriction")

ErrModerationRestricted is returned when a workspace moderation rule blocks a write. HTTP callers surface it as a 403 or 429 depending on the rule.

View Source
var ErrNotWorkspaceManager = errors.New("workspace manager permission required")

ErrNotWorkspaceManager is returned when a workspace operation requires an owner or moderator.

View Source
var ErrNotWorkspaceMember = errors.New("workspace membership required")

ErrNotWorkspaceMember is returned when a workspace operation requires any membership and the caller has none.

View Source
var ErrPasswordVerificationStale = errors.New("stored password changed while this request was verifying it")

ErrPasswordVerificationStale is returned when a password operation reaches its commit and finds the stored hash is no longer the one it verified. The expensive key derivation runs outside the transaction, so another change can land in between; the write is refused rather than applied to a credential the caller never proved.

View Source
var ErrPostRateLimited = errors.New("waiting room post limit reached")

ErrPostRateLimited is returned when a waiting-room guest exhausts the small daily post budget.

View Source
var ErrPushSubscriptionNeedsSession = errors.New("push registration needs a signed-in session")

ErrPushSubscriptionNeedsSession refuses a device registration that has no session to follow. Such a row could never be stopped by signing out.

View Source
var ErrQuotedMessageOutOfScope = errors.New("quoted message is not in this channel, conversation, or thread")

ErrQuotedMessageOutOfScope is returned when a message tries to quote another message that does not belong to the same channel, direct conversation, or thread. It is surfaced to API callers as a 400.

View Source
var ErrSessionExpired = errors.New("session expired")
View Source
var ErrSessionRevoked = errors.New("this session is no longer valid")

ErrSessionRevoked is returned when a request that authenticated with a session reaches its commit and finds that session is no longer live. A password change that revoked it must not be overwritten by the request it signed out.

View Source
var ErrSetupCodeInvalid = errors.New("setup code is invalid or expired")

ErrSetupCodeInvalid is returned for any unusable bot setup code — unknown, expired, already claimed, or pointing at a bot that is no longer eligible. The single error keeps claim responses uniform so callers cannot probe which condition failed.

View Source
var ErrSetupNonceConflict = errors.New("setup nonce was already used for a different request")

ErrSetupNonceConflict is returned when a retry-safe integration setup nonce is reused with different inputs or after its credential was revoked.

View Source
var ErrSlashCommandScopeMismatch = errors.New("slash command invocation scope does not match command and channel")

ErrSlashCommandScopeMismatch is returned when an invocation's supplied workspace does not match the registered command and channel workspaces.

View Source
var ErrTurnIDNotAllowed = errors.New("turn_id is only valid for agent activity messages")

ErrTurnIDNotAllowed is returned when an ordinary ('message') row is created with a non-empty turn_id. turn_id correlates a sequence of agent activity rows belonging to one turn; an ordinary message carrying one contradicts the documented "must be empty for ordinary messages" contract. HTTP callers surface it as a 400 so a client bug fails closed instead of silently persisting a contradictory turn_id.

View Source
var ErrUploadNonceConflict = errors.New("upload nonce was already used in another workspace")

ErrUploadNonceConflict is returned when a client reuses an upload nonce in another workspace.

View Source
var ErrUploadNonceInProgress = errors.New("upload nonce is already in progress")

ErrUploadNonceInProgress is returned while another request owns the same upload nonce claim and has not committed or released it yet.

View Source
var ErrUploadQuotaExceeded = errors.New("upload quota exceeded")

ErrUploadQuotaExceeded is returned when a user has exhausted their upload budget in a workspace.

View Source
var ErrWorkspaceOwnerRequired = errors.New("workspace owner permission required")

ErrWorkspaceOwnerRequired is returned when a workspace operation requires the current owner, not just a moderator.

Functions

func AppearancePreferencesPatchEmpty added in v0.3.0

func AppearancePreferencesPatchEmpty(patch AppearancePreferencesPatch) bool

func ChannelPushAllowed added in v0.6.0

func ChannelPushAllowed(preference string, mentioned bool) error

ChannelPushAllowed is the push policy for a channel message: a recipient who muted the channel gets nothing, one who chose mentions gets only messages that mention them, and everyone else gets every message. Recipient selection applies it when a message is posted, and the web push worker applies it again to the message as it reads when a queued push is sent.

func CheckPushDelivery added in v0.6.0

func CheckPushDelivery(state PushDeliveryState, currentKeyID string, now time.Time) error

CheckPushDelivery applies the rules recipient selection uses a second time, at send time, because a push can sit in the delivery queue after the session behind it ends. It answers ErrPushSessionEnded when the registering session is gone, revoked, expired, or belongs to someone else, ErrPushSubscriptionKeyRetired when the device registered under a key other than currentKeyID, and ErrPushSubscriptionBackingOff when the backoff has not elapsed.

func CompileSQLiteSearchQuery added in v0.2.0

func CompileSQLiteSearchQuery(workspaceID, query string) string

func DirectConversationMemberSetKey

func DirectConversationMemberSetKey(memberIDs []string) string

DirectConversationMemberSetKey returns a stable key for canonical one-to-one conversations. Group conversations intentionally remain non-canonical.

func EncodeSearchCursor added in v0.2.0

func EncodeSearchCursor(req SearchPageRequest, rank float64, createdAt, messageID string) (string, error)

func EncodeWorkspaceMemberCursor added in v0.2.0

func EncodeWorkspaceMemberCursor(cursor WorkspaceMemberCursor) (string, error)

func EventCursorAfter added in v0.4.0

func EventCursorAfter(candidate, frontier string) (string, error)

EventCursorAfter keeps the candidate's entropy while placing it above the persisted workspace frontier. Callers must serialize appends through commit.

func FilterSidebarChannelOrder added in v0.7.0

func FilterSidebarChannelOrder(order []string, workspaceChannelIDs []string) []string

FilterSidebarChannelOrder keeps only ids that are channels of the workspace, in the caller's order. A channel that was deleted since the client last read the sidebar is dropped instead of failing the save.

func IsActivityMessageKind

func IsActivityMessageKind(kind string) bool

IsActivityMessageKind reports whether kind is one of the durable agent activity kinds (anything other than the ordinary 'message').

func IsDurableEventType added in v0.2.0

func IsDurableEventType(value string) bool

func NewRouteID added in v0.4.0

func NewRouteID(prefix byte) (string, error)

NewRouteID returns a byte prefix followed by 16 base32 characters from 80 random bits.

func NormalizeAvatarURL added in v0.5.1

func NormalizeAvatarURL(value string) (string, error)

func NormalizeClientNonce added in v0.5.1

func NormalizeClientNonce(value string) (string, error)

func NormalizeHandle added in v0.5.1

func NormalizeHandle(value string) (string, error)

func NormalizeMessageKind

func NormalizeMessageKind(kind string) (string, error)

NormalizeMessageKind validates a caller-supplied kind. An empty value defaults to 'message'. Unknown values return ErrInvalidMessageKind.

func NormalizeUserProfile added in v0.5.1

func NormalizeUserProfile(displayNameInput, handleInput, avatarURLInput string) (string, string, string, error)

func NormalizeUserProfilePatch added in v0.5.1

func NormalizeUserProfilePatch(displayNameInput, handleInput, avatarURLInput *string) (*string, *string, *string, error)

func ParseMessageMentions added in v0.3.0

func ParseMessageMentions(body string) []string

ParseMessageMentions returns unique, normalized handles referenced with an @ at a token boundary. Email addresses and Markdown link labels are ignored.

func PlanIdentitySync added in v0.4.0

func PlanIdentitySync(input IdentitySyncInput, rows []IdentitySyncRow) ([]IdentitySyncChange, IdentitySyncReport, error)

PlanIdentitySync validates every match before either SQL backend writes. A source identity is authoritative after linking; aliases may confirm it, never move it.

func PushEndpointKey added in v0.6.0

func PushEndpointKey(endpoint string) string

PushEndpointKey is the unpadded base64url SHA-256 of a subscription endpoint. A browser computes the same digest of the subscription it holds, so the server can say whether that browser is one of an account's devices without either side sending the endpoint.

func PushKeyRetired added in v0.6.0

func PushKeyRetired(keyID, currentKeyID string) bool

PushKeyRetired reports whether a device registered under keyID can no longer receive from a server signing with currentKeyID. An empty id on either side is unknown, never retired: a row from before the key was recorded is not condemned on a guess.

func PushRetryDelay added in v0.6.0

func PushRetryDelay(failureCount int64, retryAfter time.Duration) time.Duration

PushRetryDelay reports how long to wait before the next delivery attempt after failureCount consecutive failures, honoring a longer Retry-After from the push service.

func PushSubscriptionReady added in v0.6.0

func PushSubscriptionReady(nextAttemptAt, sessionExpiresAt string, now time.Time) bool

PushSubscriptionReady reports whether a stored subscription may be used for a delivery now: its backoff has elapsed, and the session that registered it is still live. An empty session timestamp means the row was registered without a session, which only development authentication can do.

func ResolveAvatarURL added in v0.3.0

func ResolveAvatarURL(avatarURL, email string) string

func SidebarPreferencesPatchEmpty added in v0.7.0

func SidebarPreferencesPatchEmpty(patch SidebarPreferencesPatch) bool

func ValidWorkspaceMemberRole added in v0.2.0

func ValidWorkspaceMemberRole(role string) bool

func WorkspaceMemberRoleSort added in v0.2.0

func WorkspaceMemberRoleSort(role string) int

Types

type AddWorkspaceMemberInput added in v0.3.0

type AddWorkspaceMemberInput struct {
	WorkspaceID string
	UserID      string
	ActorUserID string
	Role        string
}

type AddWorkspaceMemberResult added in v0.3.0

type AddWorkspaceMemberResult struct {
	Role  string
	Added bool
}

type AppInstallation

type AppInstallation struct {
	ID          string         `json:"id"`
	WorkspaceID string         `json:"workspace_id"`
	AppSlug     string         `json:"app_slug"`
	DisplayName string         `json:"display_name"`
	BotUserID   string         `json:"bot_user_id"`
	Config      map[string]any `json:"config"`
	CreatedBy   string         `json:"created_by,omitempty"`
	CreatedAt   string         `json:"created_at"`
	RevokedAt   *string        `json:"revoked_at,omitempty"`
}

type AppInstallationRevokedCounts added in v0.2.0

type AppInstallationRevokedCounts struct {
	SlashCommands      int `json:"slash_commands"`
	EventSubscriptions int `json:"event_subscriptions"`
	BotTokens          int `json:"bot_tokens"`
}

type AppearancePreferences added in v0.3.0

type AppearancePreferences struct {
	ColorMode     string `json:"color_mode,omitempty"`
	BoardTheme    string `json:"board_theme,omitempty"`
	MessageLayout string `json:"message_layout,omitempty"`
	Density       string `json:"density,omitempty"`
}

type AppearancePreferencesPatch added in v0.3.0

type AppearancePreferencesPatch struct {
	ColorMode     *string `json:"color_mode,omitempty"`
	BoardTheme    *string `json:"board_theme,omitempty"`
	MessageLayout *string `json:"message_layout,omitempty"`
	Density       *string `json:"density,omitempty"`
}

func NormalizeAppearancePreferencesPatch added in v0.3.0

func NormalizeAppearancePreferencesPatch(input AppearancePreferencesPatch) (AppearancePreferencesPatch, error)

type AttachUploadInput

type AttachUploadInput struct {
	MessageID string
	UploadID  string
	UserID    string
}

type AuditLogEntry

type AuditLogEntry struct {
	ID          string         `json:"id"`
	WorkspaceID string         `json:"workspace_id"`
	ActorUserID string         `json:"actor_user_id"`
	Action      string         `json:"action"`
	TargetType  string         `json:"target_type"`
	TargetID    string         `json:"target_id"`
	Metadata    map[string]any `json:"metadata"`
	CreatedAt   string         `json:"created_at"`
}

type BotCommand added in v0.2.0

type BotCommand struct {
	ID          string `json:"id"`
	WorkspaceID string `json:"workspace_id"`
	BotUserID   string `json:"bot_user_id"`
	Command     string `json:"command"`
	Description string `json:"description"`
	ArgsHint    string `json:"args_hint"`
	CreatedAt   string `json:"created_at"`
	UpdatedAt   string `json:"updated_at"`
}

type BotCommandBot added in v0.2.0

type BotCommandBot struct {
	ID          string `json:"id"`
	Handle      string `json:"handle"`
	DisplayName string `json:"display_name"`
	AvatarURL   string `json:"avatar_url"`
}

type BotCommandInput added in v0.2.0

type BotCommandInput struct {
	Command     string `json:"command"`
	Description string `json:"description"`
	ArgsHint    string `json:"args_hint"`
}

type BotSetupCode added in v0.2.0

type BotSetupCode struct {
	ID          string               `json:"id"`
	BotUserID   string               `json:"bot_user_id"`
	WorkspaceID string               `json:"workspace_id"`
	TokenName   string               `json:"token_name"`
	Scopes      []string             `json:"scopes"`
	Defaults    BotSetupCodeDefaults `json:"defaults"`
	CreatedBy   string               `json:"created_by,omitempty"`
	CreatedAt   string               `json:"created_at"`
	ExpiresAt   string               `json:"expires_at"`
	Code        string               `json:"code,omitempty"`
}

type BotSetupCodeClaim added in v0.2.0

type BotSetupCodeClaim struct {
	BotToken  BotToken             `json:"bot_token"`
	Bot       User                 `json:"bot"`
	Workspace Workspace            `json:"workspace"`
	Defaults  BotSetupCodeDefaults `json:"defaults"`
}

BotSetupCodeClaim is the result of claiming a setup code: the freshly minted token (plaintext included once) plus the context an installer needs to write its configuration.

type BotSetupCodeDefaults added in v0.2.0

type BotSetupCodeDefaults struct {
	DefaultTo     string   `json:"defaultTo,omitempty"`
	AllowFrom     []string `json:"allowFrom,omitempty"`
	AgentActivity *bool    `json:"agentActivity,omitempty"`
}

BotSetupCode is a pending bot-token grant. Creating one does not mint a token; the token is minted when the code is claimed. Code carries the plaintext only in the mint response — at rest only the hash is stored.

func NormalizeBotSetupCodeDefaults added in v0.2.0

func NormalizeBotSetupCodeDefaults(defaults BotSetupCodeDefaults, scopes []string) (BotSetupCodeDefaults, error)

NormalizeBotSetupCodeDefaults validates the small configuration payload carried by a setup-code grant. It is consumed by another trusted client, but still crosses the public API boundary and must remain bounded.

type BotToken

type BotToken struct {
	ID          string   `json:"id"`
	BotUserID   string   `json:"bot_user_id"`
	WorkspaceID string   `json:"workspace_id"`
	OwnerUserID string   `json:"owner_user_id,omitempty"`
	Name        string   `json:"name"`
	Scopes      []string `json:"scopes"`
	CreatedBy   string   `json:"created_by,omitempty"`
	CreatedAt   string   `json:"created_at"`
	LastUsedAt  *string  `json:"last_used_at,omitempty"`
	RevokedAt   *string  `json:"revoked_at,omitempty"`
	Token       string   `json:"token,omitempty"`
}

type BotTokenAuth

type BotTokenAuth struct {
	User        User
	TokenID     string
	WorkspaceID string
	Scopes      []string
}

type BotWithTokens

type BotWithTokens struct {
	Bot    User       `json:"bot"`
	Tokens []BotToken `json:"tokens"`
}

type ChangeUserPasswordInput added in v0.4.0

type ChangeUserPasswordInput struct {
	UserID           string
	VerifiedHash     string
	NewHash          string
	KeepSessionToken string
}

ChangeUserPasswordInput describes one password rotation. VerifiedHash is the stored hash the caller checked the current password against, and the store commits nothing unless that is still the hash on file. KeepSessionToken is the caller's own session token: the account's other sessions are revoked, and the write is refused if that session has itself been revoked in the meantime. An empty KeepSessionToken belongs to a caller the server cannot place in a session, such as a trusted-proxy assertion, and revokes every session.

type Channel

type Channel struct {
	ID              string  `json:"id"`
	RouteID         string  `json:"route_id"`
	WorkspaceID     string  `json:"workspace_id"`
	Name            string  `json:"name"`
	DisplayTitle    *string `json:"display_title,omitempty"`
	Kind            string  `json:"kind"`
	CreatedAt       string  `json:"created_at"`
	ArchivedAt      *string `json:"archived_at,omitempty"`
	ExternalManaged bool    `json:"external_managed"`
	ExternalRef     *string `json:"external_ref,omitempty"`
	ExternalURL     *string `json:"external_url,omitempty"`
	SidebarSection  *string `json:"sidebar_section,omitempty"`
	LastSeq         int64   `json:"last_seq"`
	LastReadSeq     int64   `json:"last_read_seq"`
	UnreadCount     int64   `json:"unread_count"`
}

type ChannelNotificationInput added in v0.3.0

type ChannelNotificationInput struct {
	ChannelID  string
	UserID     string
	Preference string
}

type ConnectedAccount

type ConnectedAccount struct {
	ID                string         `json:"id"`
	WorkspaceID       string         `json:"workspace_id"`
	UserID            string         `json:"user_id"`
	Provider          string         `json:"provider"`
	ProviderAccountID string         `json:"provider_account_id"`
	DisplayName       string         `json:"display_name"`
	Scopes            []string       `json:"scopes"`
	Metadata          map[string]any `json:"metadata"`
	CreatedAt         string         `json:"created_at"`
	RevokedAt         *string        `json:"revoked_at,omitempty"`
}

type CreateAppInstallationInput

type CreateAppInstallationInput struct {
	WorkspaceID string
	AppSlug     string
	DisplayName string
	BotUserID   string
	Config      map[string]any
	SetupNonce  string
	CreatedBy   string
}

type CreateAuditLogEntryInput

type CreateAuditLogEntryInput struct {
	WorkspaceID string
	ActorUserID string
	Action      string
	TargetType  string
	TargetID    string
	Metadata    map[string]any
}

type CreateBotInput

type CreateBotInput struct {
	WorkspaceID string
	OwnerUserID string
	DisplayName string
	Handle      string
	AvatarURL   string
	TokenName   string
	Scopes      []string
	SetupNonce  string
	CreatedBy   string
	// SkipInitialToken creates the bot without minting a token, for
	// installs that hand credentials over via a setup code instead.
	SkipInitialToken bool
}

type CreateBotSetupCodeInput added in v0.2.0

type CreateBotSetupCodeInput struct {
	WorkspaceID string
	BotUserID   string
	Name        string
	Scopes      []string
	Defaults    BotSetupCodeDefaults
	CreatedBy   string
}

type CreateBotTokenInput

type CreateBotTokenInput struct {
	WorkspaceID string
	BotUserID   string
	Name        string
	Scopes      []string
	SetupNonce  string
	CreatedBy   string
}

type CreateChannelInput

type CreateChannelInput struct {
	WorkspaceID     string
	Name            string
	DisplayTitle    string
	Kind            string
	UserID          string
	ExternalManaged bool
	ExternalRef     string
	ExternalURL     string
	SidebarSection  string
}

type CreateConnectedAccountInput

type CreateConnectedAccountInput struct {
	WorkspaceID       string
	UserID            string
	Provider          string
	ProviderAccountID string
	DisplayName       string
	Scopes            []string
	Metadata          map[string]any
	CreatedBy         string
}

type CreateDirectConversationInput

type CreateDirectConversationInput struct {
	WorkspaceID string
	UserID      string
	MemberIDs   []string
}

type CreateDirectMessageInput

type CreateDirectMessageInput struct {
	ConversationID  string
	AuthorID        string
	Body            string
	QuotedMessageID *string
	Nonce           string
	UploadID        string
	Kind            string
	TurnID          string
}

type CreateEventDeliveryAttemptInput

type CreateEventDeliveryAttemptInput struct {
	SubscriptionID string
	EventID        string
	WorkspaceID    string
	EventType      string
	RequestJSON    string
	ResponseStatus int
	ResponseBody   string
	Error          string
}

type CreateEventSubscriptionInput

type CreateEventSubscriptionInput struct {
	WorkspaceID       string
	AppInstallationID string
	EventTypes        []string
	CallbackURL       string
	CreatedBy         string
}

type CreateMessageInput

type CreateMessageInput struct {
	ChannelID       string
	AuthorID        string
	Body            string
	QuotedMessageID *string
	Nonce           string
	TopicID         string
	UploadID        string
	// Kind defaults to 'message' when empty. Activity kinds are gated at the
	// API layer by AgentActivityWriteScope.
	Kind   string
	TurnID string
}

type CreateReactionInput

type CreateReactionInput struct {
	MessageID string
	UserID    string
	Emoji     string
}

type CreateSlashCommandInput

type CreateSlashCommandInput struct {
	WorkspaceID       string
	AppInstallationID string
	Command           string
	Description       string
	CallbackURL       string
	BotUserID         string
	CreatedBy         string
}

type CreateSlashCommandInvocationInput

type CreateSlashCommandInvocationInput struct {
	CommandID   string
	WorkspaceID string
	ChannelID   string
	UserID      string
	Text        string
	PayloadJSON string
}

type CreateThreadReplyInput

type CreateThreadReplyInput struct {
	RootMessageID   string
	AuthorID        string
	Body            string
	QuotedMessageID *string
	Nonce           string
}

type CreateTopicInput

type CreateTopicInput struct {
	WorkspaceID string
	ChannelID   string
	Name        string
	CreatedBy   string
}

type CreateUploadInput

type CreateUploadInput struct {
	WorkspaceID string
	OwnerID     string
	Nonce       string
	Filename    string
	ContentType string
	ByteSize    int64
	Width       int
	Height      int
	DurationMS  int
	StoragePath string
}

type CreateUserInput

type CreateUserInput struct {
	DisplayName string
	Email       string
}

type CreateWorkspaceInput

type CreateWorkspaceInput struct {
	Name string
	Slug string
}

type CurrentUserState added in v0.3.0

type CurrentUserState struct {
	User                  User
	AppearancePreferences *AppearancePreferences
	SidebarPreferences    *SidebarPreferences
}

type DeleteMessageInput

type DeleteMessageInput struct {
	MessageID string
	UserID    string
}

type DeletedBot added in v0.2.0

type DeletedBot struct {
	ID           string   `json:"id"`
	DisplayName  string   `json:"display_name"`
	FormerHandle string   `json:"former_handle"`
	DeletedAt    string   `json:"deleted_at"`
	WorkspaceIDs []string `json:"-"`
}

type DesktopOAuthGrant added in v0.2.0

type DesktopOAuthGrant struct {
	ID               string
	GrantHash        string
	UserID           string
	DesktopChallenge string
	CreatedAt        time.Time
	ExpiresAt        time.Time
}

type DirectConversation

type DirectConversation struct {
	ID          string `json:"id"`
	RouteID     string `json:"route_id"`
	WorkspaceID string `json:"workspace_id"`
	CreatedAt   string `json:"created_at"`
	Members     []User `json:"members"`
	LastSeq     int64  `json:"last_seq"`
	LastReadSeq int64  `json:"last_read_seq"`
	UnreadCount int64  `json:"unread_count"`
	CanSend     bool   `json:"can_send"`
}

type Event

type Event struct {
	ID               string   `json:"id"`
	Cursor           string   `json:"cursor"`
	Type             string   `json:"type"`
	WorkspaceID      string   `json:"workspace_id"`
	ChannelID        string   `json:"channel_id,omitempty"`
	Seq              *int64   `json:"seq,omitempty"`
	CreatedAt        string   `json:"created_at"`
	PayloadJSON      string   `json:"-"`
	Payload          any      `json:"payload"`
	RecipientUserIDs []string `json:"-"`
	MentionedUserIDs []string `json:"mentioned_user_ids,omitempty"`
}

type EventDeliveryAttempt

type EventDeliveryAttempt struct {
	ID             string `json:"id"`
	SubscriptionID string `json:"subscription_id"`
	EventID        string `json:"event_id"`
	WorkspaceID    string `json:"workspace_id"`
	EventType      string `json:"event_type"`
	Attempt        int    `json:"attempt"`
	RequestJSON    string `json:"request_json,omitempty"`
	ResponseStatus int    `json:"response_status"`
	ResponseBody   string `json:"response_body,omitempty"`
	Error          string `json:"error,omitempty"`
	CreatedAt      string `json:"created_at"`
	CompletedAt    string `json:"completed_at"`
}

type EventSubscription

type EventSubscription struct {
	ID                string   `json:"id"`
	WorkspaceID       string   `json:"workspace_id"`
	AppInstallationID string   `json:"app_installation_id,omitempty"`
	EventTypes        []string `json:"event_types"`
	CallbackURL       string   `json:"callback_url"`
	SigningSecret     string   `json:"signing_secret,omitempty"`
	CreatedBy         string   `json:"created_by,omitempty"`
	CreatedAt         string   `json:"created_at"`
	RevokedAt         *string  `json:"revoked_at,omitempty"`
}

type IdentitySyncChange added in v0.4.0

type IdentitySyncChange struct {
	User
	ProfileID string
	Link      bool
	Update    bool
}

type IdentitySyncInput added in v0.4.0

type IdentitySyncInput struct {
	Source   string
	Profiles []IdentitySyncProfile
}

func NormalizeIdentitySync added in v0.4.0

func NormalizeIdentitySync(input IdentitySyncInput) (IdentitySyncInput, error)

type IdentitySyncProfile added in v0.4.0

type IdentitySyncProfile struct {
	ID          string   `json:"id"`
	DisplayName string   `json:"displayName"`
	Emails      []string `json:"emails"`
	MergedInto  *string  `json:"mergedInto"`
}

IdentitySyncProfile accepts the profile fields from OpenClaw's users.list export.

type IdentitySyncReport added in v0.4.0

type IdentitySyncReport struct {
	Linked    int      `json:"linked"`
	Updated   int      `json:"updated"`
	Unchanged int      `json:"unchanged"`
	Unmatched []string `json:"unmatched_profile_ids"`
	Merged    int      `json:"merged_skipped"`
}

type IdentitySyncRow added in v0.4.0

type IdentitySyncRow struct {
	User
	Provider, Subject, Email string
}

IdentitySyncRow is an existing identity and its user, read in the write transaction.

type Invite

type Invite struct {
	ID          string  `json:"id"`
	WorkspaceID string  `json:"workspace_id"`
	Token       string  `json:"token"`
	CreatedBy   string  `json:"created_by"`
	CreatedAt   string  `json:"created_at"`
	AcceptedAt  *string `json:"accepted_at,omitempty"`
}
type MagicLink struct {
	ID          string  `json:"id"`
	Token       string  `json:"token"`
	Email       string  `json:"email"`
	DisplayName string  `json:"display_name"`
	CreatedAt   string  `json:"created_at"`
	ExpiresAt   string  `json:"expires_at"`
	UsedAt      *string `json:"used_at,omitempty"`
}

type MemberModeration

type MemberModeration struct {
	WorkspaceID    string  `json:"workspace_id"`
	User           User    `json:"user"`
	Role           string  `json:"role"`
	PostsRemaining int     `json:"posts_remaining"`
	PostLimit      int     `json:"post_limit"`
	TimeoutUntil   *string `json:"timeout_until,omitempty"`
	BlockedAt      *string `json:"blocked_at,omitempty"`
	ModerationNote string  `json:"moderation_note,omitempty"`
	ModerationBy   string  `json:"moderation_by,omitempty"`
	ModerationAt   string  `json:"moderation_at,omitempty"`
}

type Message

type Message struct {
	ID                   string  `json:"id"`
	RouteID              string  `json:"route_id,omitempty"`
	WorkspaceID          string  `json:"workspace_id"`
	ChannelID            string  `json:"channel_id,omitempty"`
	DirectConversationID string  `json:"direct_conversation_id,omitempty"`
	AuthorID             string  `json:"author_id"`
	ParentMessageID      *string `json:"parent_message_id,omitempty"`
	ThreadRootID         string  `json:"thread_root_id"`
	TopicID              string  `json:"topic_id,omitempty"`
	ChannelSeq           *int64  `json:"channel_seq,omitempty"`
	ThreadSeq            *int64  `json:"thread_seq,omitempty"`
	Body                 string  `json:"body"`
	BodyFormat           string  `json:"body_format"`
	CreatedAt            string  `json:"created_at"`
	EditedAt             *string `json:"edited_at,omitempty"`
	DeletedAt            *string `json:"deleted_at,omitempty"`
	// Kind discriminates ordinary messages from durable agent activity rows.
	// Empty in JSON means the default 'message'.
	Kind string `json:"kind,omitempty"`
	// TurnID correlates a sequence of agent activity rows belonging to one
	// agent turn. It must be empty for ordinary messages (kind="message"): the
	// create path enforces this and rejects a non-empty turn_id on a 'message'
	// kind with a 400 ErrTurnIDNotAllowed. It is optional for agent activity
	// kinds (agent_commentary/agent_tool), which may carry one.
	TurnID             string       `json:"turn_id,omitempty"`
	Author             *User        `json:"author,omitempty"`
	Attachments        []Upload     `json:"attachments,omitempty"`
	QuotedMessageID    *string      `json:"quoted_message_id,omitempty"`
	QuotedBodySnapshot string       `json:"quoted_body_snapshot,omitempty"`
	QuotedAuthorID     *string      `json:"quoted_author_id,omitempty"`
	QuotedAuthor       *User        `json:"quoted_author,omitempty"`
	ThreadState        *ThreadState `json:"thread_state,omitempty"`
	// Nonce is a client-supplied idempotency key used by optimistic UIs to match
	// the server response to a pending placeholder and safely retry after a lost
	// response.
	Nonce     string            `json:"nonce,omitempty"`
	Reactions []ReactionSummary `json:"reactions,omitempty"`
}

type MessagePage

type MessagePage struct {
	Messages  []Message `json:"messages"`
	OldestSeq int64     `json:"oldest_seq"`
	NewestSeq int64     `json:"newest_seq"`
	HasOlder  bool      `json:"has_older"`
	HasNewer  bool      `json:"has_newer"`
}

type MessagePageRequest

type MessagePageRequest struct {
	Limit     int
	BeforeSeq *int64
	AfterSeq  *int64
	AroundSeq *int64
	TopicID   string
}

type NotificationSettings

type NotificationSettings struct {
	PushoverEnabled bool   `json:"pushover_enabled"`
	PushoverUserKey string `json:"pushover_user_key"`
}

type OAuthTransaction added in v0.2.0

type OAuthTransaction struct {
	ID                 string
	StateHash          string
	BrowserBindingHash string
	Mode               string
	PKCEVerifier       string
	DesktopChallenge   string
	DesktopProtocol    int64
	CreatedAt          time.Time
	ExpiresAt          time.Time
}

type OwnedBotEntry added in v0.2.0

type OwnedBotEntry struct {
	Bot              User              `json:"bot"`
	Workspace        OwnedBotWorkspace `json:"workspace"`
	ActiveTokenCount int               `json:"active_token_count"`
}

type OwnedBotWorkspace added in v0.2.0

type OwnedBotWorkspace struct {
	ID      string `json:"id"`
	RouteID string `json:"route_id"`
	Name    string `json:"name"`
}

type PasswordLogin added in v0.4.0

type PasswordLogin struct {
	User         User
	PasswordHash string
}

PasswordLogin carries the account a password identifier resolved to together with its stored hash. PasswordHash is empty when the account exists but has no password set, which callers must reject the same way they reject a wrong password so the response does not disclose which accounts are enrolled.

type PendingUploadCleanup added in v0.2.0

type PendingUploadCleanup struct {
	ID          string `json:"id"`
	WorkspaceID string `json:"workspace_id"`
	StoragePath string `json:"storage_path"`
	Attempts    int64  `json:"attempts"`
	LastError   string `json:"last_error"`
	CreatedAt   string `json:"created_at"`
	UpdatedAt   string `json:"updated_at"`
}

type PinnedMessage added in v0.3.0

type PinnedMessage struct {
	ID          string `json:"id"`
	WorkspaceID string `json:"workspace_id"`
	ChannelID   string `json:"channel_id"`
	MessageID   string `json:"message_id"`
	PinnedBy    string `json:"pinned_by"`
	CreatedAt   string `json:"created_at"`
}

type PushDeliveryState added in v0.6.0

type PushDeliveryState struct {
	UserID           string
	NextAttemptAt    string
	KeyID            string
	SessionTokenHash string
	SessionUserID    string
	SessionExpiresAt string
	SessionRevokedAt string
}

PushDeliveryState is a stored subscription as the delivery worker re-reads it immediately before sending: the device's own row, and the session it was registered under, which is absent when that session no longer exists.

type PushNotificationRecipient

type PushNotificationRecipient struct {
	UserID          string
	DisplayName     string
	PushoverUserKey string
	Subscriptions   []PushSubscriptionTarget
}

type PushPruneCutoffs added in v0.6.0

type PushPruneCutoffs struct {
	// FailingBefore and LastFailureSince: a device refused since before
	// FailingBefore, most recently at or after LastFailureSince, at least
	// PushFailingPruneMinFailures times, is pruned.
	FailingBefore string
	// LastFailureSince is compared the other way, a stored time at or after
	// it, so it is the next whole second after the instant, written with no
	// fraction: a stored time sorts at or after it only when it is no
	// earlier than the instant.
	LastFailureSince string
	// RetiredKeyUpdatedBefore: a device under a retired key last written
	// before this is pruned.
	RetiredKeyUpdatedBefore string
	// SessionExpiredBy: a session expiring at or before this has ended.
	SessionExpiredBy string
}

PushPruneCutoffs are the instants PrunePushSubscriptions compares stored timestamps against, as text. Stored timestamps are RFC 3339 with trailing fraction zeros trimmed, so each cutoff is written with all nine fraction digits: a stored time then sorts before a cutoff only when it is earlier. The reverse can fail inside the cutoff's own second, which only leaves a removal to the next pass and never makes one early.

func NewPushPruneCutoffs added in v0.6.0

func NewPushPruneCutoffs(now time.Time) PushPruneCutoffs

NewPushPruneCutoffs derives the cutoffs from one reading of the clock.

type PushPruneResult added in v0.6.0

type PushPruneResult struct {
	Failing      int64
	RetiredKey   int64
	SessionEnded int64
}

PushPruneResult counts the devices one PrunePushSubscriptions pass removed, by the rule that removed each. A device matching more than one is counted once, under the first.

func (PushPruneResult) Total added in v0.6.0

func (r PushPruneResult) Total() int64

Total is every device the pass removed.

type PushSubscription added in v0.6.0

type PushSubscription struct {
	ID            string  `json:"id"`
	UserID        string  `json:"-"`
	UserAgent     string  `json:"user_agent"`
	CreatedAt     string  `json:"created_at"`
	UpdatedAt     string  `json:"updated_at"`
	LastSuccessAt *string `json:"last_success_at,omitempty"`
	FailureCount  int64   `json:"failure_count"`
	// EndpointKey identifies the device without the endpoint: see
	// PushEndpointKey. It is compared on the server and never serialized.
	EndpointKey string `json:"-"`
	// KeyID names the application server key the device registered under;
	// empty for a device registered before the server recorded it.
	KeyID string `json:"-"`
}

PushSubscription is the summary of a registered device. It deliberately omits the endpoint and the client keys: those are delivery secrets and never leave the server.

type PushSubscriptionInput added in v0.6.0

type PushSubscriptionInput struct {
	UserID           string
	Endpoint         string
	P256dh           string
	Auth             string
	UserAgent        string
	SessionToken     string
	DevelopmentActor bool
	KeyID            string
}

PushSubscriptionInput is one browser PushSubscription being registered. SessionToken binds the device to the session that registered it, so signing out stops that device receiving message text. A registration without one is refused unless DevelopmentActor says the caller is the local development fallback, the only way to be signed in without a session. KeyID names the application server key the server signs with now. A new device records it; the same endpoint registered again keeps the one it was first registered under, because it is the same browser subscription.

func NormalizePushSubscriptionInput added in v0.6.0

func NormalizePushSubscriptionInput(input PushSubscriptionInput) (PushSubscriptionInput, error)

NormalizePushSubscriptionInput validates a subscription the way both stores need it: a well formed endpoint URL, client keys that look like base64url, and a short device label. Which endpoint hosts the server is willing to call is a transport question, decided before the store is reached.

type PushSubscriptionTarget added in v0.6.0

type PushSubscriptionTarget struct {
	Endpoint string
	P256dh   string
	Auth     string
	KeyID    string
}

PushSubscriptionTarget carries what a delivery needs, and the key the device registered under so a sender can skip one it no longer signs with.

type ReactionSummary added in v0.3.0

type ReactionSummary struct {
	Emoji       string `json:"emoji"`
	Count       int64  `json:"count"`
	ReactedByMe bool   `json:"reacted_by_me"`
}

type ReadReceipt

type ReadReceipt struct {
	ScopeID     string `json:"scope_id"`
	UserID      string `json:"user_id"`
	LastReadSeq int64  `json:"last_read_seq"`
	LastReadAt  string `json:"last_read_at"`
}

type RevokeAppInstallationOptions added in v0.2.0

type RevokeAppInstallationOptions struct {
	RevokeSlashCommands      bool
	RevokeEventSubscriptions bool
	RevokeBotTokens          bool
	DeleteBot                bool
}

type RevokeAppInstallationResult added in v0.2.0

type RevokeAppInstallationResult struct {
	Installation AppInstallation              `json:"installation"`
	Revoked      AppInstallationRevokedCounts `json:"revoked"`
	DeletedBot   *DeletedBot                  `json:"deleted_bot,omitempty"`
}

type RouteTarget

type RouteTarget struct {
	WorkspaceID      string `json:"workspace_id"`
	WorkspaceRouteID string `json:"workspace_route_id"`
	TargetType       string `json:"target_type"`
	TargetID         string `json:"target_id"`
	TargetRouteID    string `json:"target_route_id"`
	ParentType       string `json:"parent_type,omitempty"`
	ParentID         string `json:"parent_id,omitempty"`
	ParentRouteID    string `json:"parent_route_id,omitempty"`
	CanonicalPath    string `json:"canonical_path"`
}

type SearchAuthor added in v0.2.0

type SearchAuthor struct {
	ID           string  `json:"id"`
	Kind         string  `json:"kind"`
	OwnerUserID  string  `json:"owner_user_id,omitempty"`
	DisplayName  string  `json:"display_name"`
	Handle       string  `json:"handle"`
	FormerHandle string  `json:"former_handle,omitempty"`
	AvatarURL    string  `json:"avatar_url"`
	CreatedAt    string  `json:"created_at"`
	DeletedAt    *string `json:"deleted_at,omitempty"`
}

type SearchCursor added in v0.2.0

type SearchCursor struct {
	Version     int        `json:"v"`
	Fingerprint string     `json:"f"`
	Sort        SearchSort `json:"s"`
	Rank        float64    `json:"r,omitempty"`
	CreatedAt   string     `json:"t"`
	MessageID   string     `json:"m"`
}

func DecodeSearchCursor added in v0.2.0

func DecodeSearchCursor(value string, req SearchPageRequest) (SearchCursor, bool, error)

type SearchHighlight added in v0.2.0

type SearchHighlight struct {
	Start int `json:"start"`
	End   int `json:"end"`
}

func ParseSearchSnippetWithMarkers added in v0.2.0

func ParseSearchSnippetWithMarkers(marked string, markers SearchMarkers) (string, []SearchHighlight, error)

type SearchHit added in v0.2.0

type SearchHit struct {
	ID                   string            `json:"id"`
	WorkspaceID          string            `json:"workspace_id"`
	ChannelID            string            `json:"channel_id,omitempty"`
	ChannelName          string            `json:"channel_name,omitempty"`
	DirectConversationID string            `json:"direct_conversation_id,omitempty"`
	Author               SearchAuthor      `json:"author"`
	ParentMessageID      *string           `json:"parent_message_id,omitempty"`
	ThreadRootID         string            `json:"thread_root_id"`
	ChannelSeq           *int64            `json:"channel_seq,omitempty"`
	ThreadSeq            *int64            `json:"thread_seq,omitempty"`
	CreatedAt            string            `json:"created_at"`
	EditedAt             *string           `json:"edited_at,omitempty"`
	ReplyCount           int               `json:"reply_count"`
	LastReplyAt          *string           `json:"last_reply_at,omitempty"`
	Snippet              string            `json:"snippet"`
	Highlights           []SearchHighlight `json:"highlights"`
}

type SearchMarkers added in v0.2.0

type SearchMarkers struct {
	Start string
	End   string
}

func NewSearchMarkers added in v0.2.0

func NewSearchMarkers() (SearchMarkers, error)

type SearchPage added in v0.2.0

type SearchPage struct {
	Results    []SearchHit `json:"results"`
	NextCursor *string     `json:"next_cursor"`
}

func BuildSearchPage added in v0.2.0

func BuildSearchPage(req SearchPageRequest, entries []SearchPageEntry) (SearchPage, error)

type SearchPageEntry added in v0.2.0

type SearchPageEntry struct {
	Hit             SearchHit
	Rank            float64
	CursorCreatedAt string
}

type SearchPageRequest added in v0.2.0

type SearchPageRequest struct {
	WorkspaceID          string
	ChannelID            string
	DirectConversationID string
	UserID               string
	Query                string
	Sort                 SearchSort
	Limit                int
	Cursor               string
}

func NormalizeSearchPageRequest added in v0.2.0

func NormalizeSearchPageRequest(req SearchPageRequest) (SearchPageRequest, error)

type SearchSort added in v0.2.0

type SearchSort string
const (
	SearchSortRelevance SearchSort = "relevance"
	SearchSortNewest    SearchSort = "newest"
)

type Session

type Session struct {
	ID        string `json:"id"`
	Token     string `json:"token"`
	UserID    string `json:"user_id"`
	CreatedAt string `json:"created_at"`
	ExpiresAt string `json:"expires_at"`
}

type SidebarPreferences added in v0.7.0

type SidebarPreferences struct {
	ChannelOrder map[string][]string `json:"channel_order,omitempty"`
}

SidebarPreferences is the caller's complete roaming sidebar snapshot. Workspaces with no saved channel order are absent from the map.

type SidebarPreferencesPatch added in v0.7.0

type SidebarPreferencesPatch struct {
	ChannelOrder map[string][]string `json:"channel_order,omitempty"`
}

SidebarPreferencesPatch replaces the channel order of every workspace it lists and leaves the rest untouched. An empty list clears that workspace.

func NormalizeSidebarPreferencesPatch added in v0.7.0

func NormalizeSidebarPreferencesPatch(input SidebarPreferencesPatch) (SidebarPreferencesPatch, error)

NormalizeSidebarPreferencesPatch collapses repeated ids to their first position and drops ids that cannot name a channel. Ids that are well formed but unknown survive here and are filtered against the workspace's channels in the store, where the workspace is known.

type SlashCommand

type SlashCommand struct {
	ID                string  `json:"id"`
	WorkspaceID       string  `json:"workspace_id"`
	AppInstallationID string  `json:"app_installation_id,omitempty"`
	Command           string  `json:"command"`
	Description       string  `json:"description"`
	CallbackURL       string  `json:"callback_url"`
	SigningSecret     string  `json:"signing_secret,omitempty"`
	BotUserID         string  `json:"bot_user_id"`
	CreatedBy         string  `json:"created_by,omitempty"`
	CreatedAt         string  `json:"created_at"`
	RevokedAt         *string `json:"revoked_at,omitempty"`
}

type SlashCommandInvocation

type SlashCommandInvocation struct {
	ID             string  `json:"id"`
	CommandID      string  `json:"command_id"`
	WorkspaceID    string  `json:"workspace_id"`
	ChannelID      string  `json:"channel_id"`
	UserID         string  `json:"user_id"`
	Text           string  `json:"text"`
	PayloadJSON    string  `json:"payload_json,omitempty"`
	ResponseStatus int     `json:"response_status"`
	ResponseBody   string  `json:"response_body,omitempty"`
	Error          string  `json:"error,omitempty"`
	CreatedAt      string  `json:"created_at"`
	CompletedAt    *string `json:"completed_at,omitempty"`
}

type Store

type Store interface {
	Close() error
	Ping(ctx context.Context) error
	Migrate(ctx context.Context) error
	EnsureBootstrap(ctx context.Context, name, email string) (User, error)
	CreateUser(ctx context.Context, input CreateUserInput) (User, error)
	CreateBot(ctx context.Context, input CreateBotInput) (User, BotToken, error)
	ListBots(ctx context.Context, workspaceID, requesterID string) ([]BotWithTokens, error)
	CreateBotToken(ctx context.Context, input CreateBotTokenInput) (BotToken, error)
	CreateBotSetupCode(ctx context.Context, input CreateBotSetupCodeInput) (BotSetupCode, error)
	ClaimBotSetupCode(ctx context.Context, code string) (BotSetupCodeClaim, error)
	ListBotTokens(ctx context.Context, botUserID, requesterID string) ([]BotToken, error)
	ListBotTokensForWorkspace(ctx context.Context, workspaceID, botUserID, requesterID string) ([]BotToken, error)
	RevokeBotToken(ctx context.Context, tokenID, requesterID string) (BotToken, error)
	RemoveBotFromWorkspace(ctx context.Context, workspaceID, botUserID, requesterID string) error
	DeleteBot(ctx context.Context, botUserID, requesterID string) (DeletedBot, error)
	ListBotsOwnedBy(ctx context.Context, ownerUserID string) ([]OwnedBotEntry, error)
	SetBotCommands(ctx context.Context, workspaceID, botUserID string, commands []BotCommandInput) ([]BotCommand, error)
	ListBotCommands(ctx context.Context, workspaceID, requesterID string) ([]WorkspaceBotCommand, error)
	ListAppInstallations(ctx context.Context, workspaceID, requesterID string) ([]AppInstallation, error)
	CreateAppInstallation(ctx context.Context, input CreateAppInstallationInput) (AppInstallation, error)
	RevokeAppInstallation(ctx context.Context, installationID, requesterID string, options RevokeAppInstallationOptions) (RevokeAppInstallationResult, error)
	ListSlashCommands(ctx context.Context, workspaceID, requesterID string) ([]SlashCommand, error)
	CreateSlashCommand(ctx context.Context, input CreateSlashCommandInput) (SlashCommand, error)
	RevokeSlashCommand(ctx context.Context, commandID, requesterID string) (SlashCommand, error)
	RotateSlashCommandSecret(ctx context.Context, commandID, requesterID string) (SlashCommand, error)
	GetSlashCommandForChannel(ctx context.Context, channelID, command, requesterID string) (SlashCommand, error)
	CreateSlashCommandInvocation(ctx context.Context, input CreateSlashCommandInvocationInput) (SlashCommandInvocation, error)
	CompleteSlashCommandInvocation(ctx context.Context, invocationID string, status int, responseBody, invokeError string) (SlashCommandInvocation, error)
	ListEventSubscriptions(ctx context.Context, workspaceID, requesterID string) ([]EventSubscription, error)
	CreateEventSubscription(ctx context.Context, input CreateEventSubscriptionInput) (EventSubscription, error)
	RevokeEventSubscription(ctx context.Context, subscriptionID, requesterID string) (EventSubscription, error)
	RotateEventSubscriptionSecret(ctx context.Context, subscriptionID, requesterID string) (EventSubscription, error)
	ListEventSubscriptionsForEvent(ctx context.Context, event Event) ([]EventSubscription, error)
	CreateEventDeliveryAttempt(ctx context.Context, input CreateEventDeliveryAttemptInput) (EventDeliveryAttempt, error)
	ListEventDeliveryAttempts(ctx context.Context, subscriptionID, requesterID string, limit int, before string) ([]EventDeliveryAttempt, error)
	CreateAuditLogEntry(ctx context.Context, input CreateAuditLogEntryInput) (AuditLogEntry, error)
	ListAuditLogEntries(ctx context.Context, workspaceID, requesterID string, limit int) ([]AuditLogEntry, error)
	ListConnectedAccounts(ctx context.Context, workspaceID, requesterID string) ([]ConnectedAccount, error)
	CreateConnectedAccount(ctx context.Context, input CreateConnectedAccountInput) (ConnectedAccount, error)
	RevokeConnectedAccount(ctx context.Context, accountID, requesterID string) (ConnectedAccount, error)
	UpsertIdentityUser(ctx context.Context, input UpsertIdentityUserInput) (User, error)
	UpdateUserProfile(ctx context.Context, input UpdateUserProfileInput) (User, error)
	UpdateCurrentUser(ctx context.Context, input UpdateCurrentUserInput) (CurrentUserState, error)
	GetAppearancePreferences(ctx context.Context, userID string) (*AppearancePreferences, error)
	GetSidebarPreferences(ctx context.Context, userID string) (*SidebarPreferences, error)
	ListPushNotificationRecipients(ctx context.Context, messageID string, mentionedUserIDs []string) ([]PushNotificationRecipient, error)
	ListMentionedUserIDs(ctx context.Context, workspaceID, body string) ([]string, error)
	UpsertPushSubscription(ctx context.Context, input PushSubscriptionInput) (PushSubscription, error)
	ListPushSubscriptions(ctx context.Context, userID string) ([]PushSubscription, error)
	DeletePushSubscription(ctx context.Context, userID, endpoint string) error
	GetPushSubscriptionDelivery(ctx context.Context, userID, endpoint, currentKeyID string) (PushSubscriptionTarget, error)
	MarkPushSubscriptionSuccess(ctx context.Context, userID, endpoint string) error
	MarkPushSubscriptionFailure(ctx context.Context, userID, endpoint string, retryAfter time.Duration) (int64, error)
	PrunePushSubscriptions(ctx context.Context, currentKeyID string, now time.Time) (PushPruneResult, error)
	UpsertChannelNotificationSettings(ctx context.Context, input ChannelNotificationInput) error
	GetChannelNotificationPreference(ctx context.Context, channelID, userID string) (string, error)
	AddWorkspaceMember(ctx context.Context, workspaceID, userID, role string) error
	AddWorkspaceMemberByActor(ctx context.Context, input AddWorkspaceMemberInput) (AddWorkspaceMemberResult, error)
	EnsureDefaultWorkspaceMember(ctx context.Context, userID string) (Workspace, error)
	EnsureDefaultGuestWorkspaceMember(ctx context.Context, userID, role string) (Workspace, error)
	ListWorkspaceMemberPage(ctx context.Context, workspaceID, actorUserID string, page WorkspaceMemberPageRequest) (WorkspaceMemberPage, error)
	ListWorkspaceMembers(ctx context.Context, workspaceID, actorUserID string) ([]MemberModeration, error)
	UpdateMemberModeration(ctx context.Context, input UpdateMemberModerationInput) (MemberModeration, Event, error)
	UserHasNonGuestMembership(ctx context.Context, userID string) (bool, error)
	UploadQuota(ctx context.Context, workspaceID, userID string) (UploadQuota, error)
	ReserveUploadQuota(ctx context.Context, workspaceID, userID, nonce string, byteSize int64) (UploadQuotaReservation, error)
	CreateReservedUpload(ctx context.Context, reservationID string, input CreateUploadInput) (Upload, error)
	ReleaseUploadQuotaReservation(ctx context.Context, reservationID, userID string) error
	FirstUser(ctx context.Context) (User, error)
	GetUser(ctx context.Context, id string) (User, error)
	GetUserByEmail(ctx context.Context, email string) (User, error)
	ListWorkspaces(ctx context.Context, userID string) ([]Workspace, error)
	CreateWorkspace(ctx context.Context, input CreateWorkspaceInput, ownerID string) (Workspace, error)
	GetWorkspace(ctx context.Context, workspaceID, userID string) (Workspace, error)
	UpdateWorkspace(ctx context.Context, input UpdateWorkspaceInput) (Workspace, Event, error)
	TransferWorkspaceOwnership(ctx context.Context, input TransferWorkspaceOwnershipInput) (Workspace, Event, error)
	DeleteWorkspace(ctx context.Context, workspaceID, actorUserID string) ([]PendingUploadCleanup, error)
	ListPendingUploadCleanups(ctx context.Context, limit int) ([]PendingUploadCleanup, error)
	DeletePendingUploadCleanup(ctx context.Context, cleanupID string) error
	RecordPendingUploadCleanupFailure(ctx context.Context, cleanupID, message string) error
	CanPublishEphemeral(ctx context.Context, workspaceID, channelID, directConversationID, userID string) error
	ResolveRouteTarget(ctx context.Context, userID, workspaceRouteID, targetRouteID string) (RouteTarget, error)
	ResolveLegacyRouteTarget(ctx context.Context, userID, workspaceID, targetID string) (RouteTarget, error)
	ListChannels(ctx context.Context, workspaceID, userID string) ([]Channel, error)
	GetChannel(ctx context.Context, channelID, userID string) (Channel, error)
	CreateChannel(ctx context.Context, input CreateChannelInput) (Channel, Event, error)
	UpdateChannel(ctx context.Context, input UpdateChannelInput) (Channel, Event, error)
	ListTopics(ctx context.Context, workspaceID, requesterID string) ([]Topic, error)
	CreateTopic(ctx context.Context, input CreateTopicInput) (Topic, error)
	ListMessages(ctx context.Context, channelID, userID string, page MessagePageRequest) (MessagePage, error)
	GetMessage(ctx context.Context, messageID, userID string) (Message, error)
	GetMessageByNonce(ctx context.Context, authorID, nonce string) (Message, error)
	EnsureMessageRouteID(ctx context.Context, userID, rootMessageID string) (Message, error)
	EnsureThreadRouteID(ctx context.Context, userID, rootMessageID string) (Message, error)
	CreateMessage(ctx context.Context, input CreateMessageInput) (Message, Event, error)
	UpdateMessage(ctx context.Context, input UpdateMessageInput) (Message, Event, error)
	DeleteMessage(ctx context.Context, input DeleteMessageInput) (Message, []Event, error)
	GetThreadPage(ctx context.Context, rootMessageID, userID string, req ThreadPageRequest) (ThreadPage, error)
	CreateThreadReply(ctx context.Context, input CreateThreadReplyInput) (Message, ThreadState, []Event, error)
	AddReaction(ctx context.Context, input CreateReactionInput) (Event, error)
	RemoveReaction(ctx context.Context, input CreateReactionInput) (Event, error)
	PinMessage(ctx context.Context, channelID, messageID, userID string) (PinnedMessage, Event, error)
	UnpinMessage(ctx context.Context, channelID, messageID, userID string) (Event, error)
	ListPinnedMessages(ctx context.Context, channelID, userID string, limit int) ([]Message, error)
	LatestEventCursor(ctx context.Context, workspaceID, userID string) (string, error)
	EventCursorExists(ctx context.Context, workspaceID, userID, cursor string) (bool, error)
	ListEventsAfter(ctx context.Context, workspaceID, userID, cursor string, limit int) ([]Event, error)
	GetUpload(ctx context.Context, uploadID, userID string) (Upload, error)
	GetUploadByNonce(ctx context.Context, ownerID, nonce string) (Upload, error)
	UploadHasDirectMessageAttachment(ctx context.Context, uploadID string) (bool, error)
	UploadHasOtherDirectMessageAttachment(ctx context.Context, uploadID, messageID string) (bool, error)
	AttachUpload(ctx context.Context, input AttachUploadInput) (Event, error)
	SearchMessagePage(ctx context.Context, page SearchPageRequest) (SearchPage, error)
	ListDirectConversations(ctx context.Context, workspaceID, userID string) ([]DirectConversation, error)
	GetDirectConversation(ctx context.Context, conversationID, userID string) (DirectConversation, error)
	CreateDirectConversation(ctx context.Context, input CreateDirectConversationInput) (DirectConversation, error)
	HideDirectConversation(ctx context.Context, conversationID, userID string) error
	ReopenDirectConversation(ctx context.Context, conversationID, userID string) (DirectConversation, error)
	ListDirectMessages(ctx context.Context, conversationID, userID string, page MessagePageRequest) (MessagePage, error)
	CreateDirectMessage(ctx context.Context, input CreateDirectMessageInput) (Message, Event, error)
	MarkChannelRead(ctx context.Context, channelID, userID string, seq int64) (ReadReceipt, Event, error)
	MarkDirectRead(ctx context.Context, conversationID, userID string, seq int64) (ReadReceipt, Event, error)
	CreateInvite(ctx context.Context, workspaceID, createdBy string) (Invite, error)
	CreateMagicLink(ctx context.Context, email, displayName string) (MagicLink, error)
	ConsumeMagicLink(ctx context.Context, token string) (User, Session, error)
	GetOrCreateUserByEmail(ctx context.Context, provider, email, displayName string) (User, error)
	CreateSession(ctx context.Context, userID string) (Session, error)
	GetSessionUser(ctx context.Context, token string) (User, error)
	RevokeSession(ctx context.Context, token string) error
	GetPasswordLogin(ctx context.Context, identifier string) (PasswordLogin, error)
	CreateSessionForVerifiedPassword(ctx context.Context, userID, verifiedHash string) (Session, error)
	GetUserPasswordHash(ctx context.Context, userID string) (string, error)
	SetUserPassword(ctx context.Context, userID, passwordHash string) error
	ChangeUserPassword(ctx context.Context, input ChangeUserPasswordInput) (int64, error)
	ClearUserPassword(ctx context.Context, userID string) error
	CreateOAuthTransaction(ctx context.Context, transaction OAuthTransaction) error
	ConsumeOAuthTransaction(ctx context.Context, stateHash, browserBindingHash string, now time.Time) (OAuthTransaction, error)
	CreateDesktopOAuthGrant(ctx context.Context, grant DesktopOAuthGrant) error
	ConsumeDesktopOAuthGrant(ctx context.Context, grantHash, desktopChallenge string, now time.Time) (Session, error)
	GetBotTokenAuth(ctx context.Context, token string) (BotTokenAuth, error)
	RecordBotTokenUse(ctx context.Context, tokenID string) error
}

type ThreadPage added in v0.4.0

type ThreadPage struct {
	Root        Message     `json:"root"`
	Replies     []Message   `json:"replies"`
	ThreadState ThreadState `json:"thread_state"`
	OldestSeq   int64       `json:"oldest_seq"`
	NewestSeq   int64       `json:"newest_seq"`
	HasOlder    bool        `json:"has_older"`
	HasNewer    bool        `json:"has_newer"`
}

type ThreadPageRequest added in v0.4.0

type ThreadPageRequest struct {
	MessagePageRequest
	Latest bool
}

type ThreadState

type ThreadState struct {
	RootMessageID          string   `json:"root_message_id"`
	ReplyCount             int64    `json:"reply_count"`
	LastReplyAt            *string  `json:"last_reply_at,omitempty"`
	LastReplyAuthorIDs     []string `json:"last_reply_author_ids"`
	LastReplyAuthorIDsJSON string   `json:"-"`
}

type Topic

type Topic struct {
	ID          string  `json:"id"`
	WorkspaceID string  `json:"workspace_id"`
	ChannelID   string  `json:"channel_id,omitempty"`
	Name        string  `json:"name"`
	CreatedBy   string  `json:"created_by,omitempty"`
	CreatedAt   string  `json:"created_at"`
	ArchivedAt  *string `json:"archived_at,omitempty"`
}

type TransferWorkspaceOwnershipInput added in v0.2.0

type TransferWorkspaceOwnershipInput struct {
	WorkspaceID    string
	ActorUserID    string
	NewOwnerUserID string
}

type UpdateChannelInput

type UpdateChannelInput struct {
	ChannelID       string
	UserID          string
	Name            string
	DisplayTitle    *string
	Kind            string
	Archived        *bool
	ExternalManaged *bool
	ExternalRef     *string
	ExternalURL     *string
	SidebarSection  *string
}

type UpdateCurrentUserInput added in v0.3.0

type UpdateCurrentUserInput struct {
	UserID                string
	DisplayName           *string
	Handle                *string
	AvatarURL             *string
	NotificationSettings  *NotificationSettings
	AppearancePreferences *AppearancePreferencesPatch
	SidebarPreferences    *SidebarPreferencesPatch
}

type UpdateMemberModerationInput

type UpdateMemberModerationInput struct {
	WorkspaceID    string
	TargetUserID   string
	ActorUserID    string
	Role           string
	TimeoutUntil   *string
	ClearTimeout   bool
	Blocked        *bool
	ModerationNote *string
}

type UpdateMessageInput

type UpdateMessageInput struct {
	MessageID string
	UserID    string
	Body      string
}

type UpdateNotificationSettingsInput

type UpdateNotificationSettingsInput struct {
	UserID          string
	PushoverEnabled bool
	PushoverUserKey string
}

type UpdateUserProfileInput

type UpdateUserProfileInput struct {
	UserID      string
	DisplayName string
	Handle      string
	AvatarURL   string
}

type UpdateWorkspaceInput added in v0.2.0

type UpdateWorkspaceInput struct {
	WorkspaceID string
	ActorUserID string
	Name        *string
	Slug        *string
	IconURL     *string
}

type Upload

type Upload struct {
	ID          string `json:"id"`
	WorkspaceID string `json:"workspace_id"`
	OwnerID     string `json:"owner_id"`
	Nonce       string `json:"nonce,omitempty"`
	Filename    string `json:"filename"`
	ContentType string `json:"content_type"`
	ByteSize    int64  `json:"byte_size"`
	Width       int    `json:"width"`
	Height      int    `json:"height"`
	DurationMS  int    `json:"duration_ms"`
	StoragePath string `json:"-"`
	CreatedAt   string `json:"created_at"`
}

type UploadQuota

type UploadQuota struct {
	MaxBytes       int64
	UsedBytes      int64
	RemainingBytes int64
	MaxCount       int64
	UsedCount      int64
	RemainingCount int64
}

func (UploadQuota) CanFit

func (q UploadQuota) CanFit(byteSize int64) error

type UploadQuotaReservation

type UploadQuotaReservation struct {
	ID          string
	WorkspaceID string
	OwnerID     string
	Nonce       string
	ByteSize    int64
	CreatedAt   string
	ExpiresAt   string
}

type UpsertIdentityUserInput

type UpsertIdentityUserInput struct {
	Provider        string
	ProviderSubject string
	Email           string
	DisplayName     string
	AvatarURL       string
}

type User

type User struct {
	ID                   string                `json:"id"`
	Kind                 string                `json:"kind"`
	OwnerUserID          string                `json:"owner_user_id,omitempty"`
	DisplayName          string                `json:"display_name"`
	Handle               string                `json:"handle"`
	FormerHandle         string                `json:"former_handle,omitempty"`
	AvatarURL            string                `json:"avatar_url"`
	CreatedAt            string                `json:"created_at"`
	DeletedAt            *string               `json:"deleted_at,omitempty"`
	NotificationSettings *NotificationSettings `json:"notification_settings,omitempty"`
}

type Workspace

type Workspace struct {
	ID        string `json:"id"`
	RouteID   string `json:"route_id"`
	Name      string `json:"name"`
	Slug      string `json:"slug"`
	IconURL   string `json:"icon_url"`
	CreatedAt string `json:"created_at"`
	Role      string `json:"role,omitempty"`
}

type WorkspaceBotCommand added in v0.2.0

type WorkspaceBotCommand struct {
	ID          string        `json:"id"`
	Command     string        `json:"command"`
	Description string        `json:"description"`
	ArgsHint    string        `json:"args_hint"`
	Bot         BotCommandBot `json:"bot"`
	CreatedAt   string        `json:"created_at"`
	UpdatedAt   string        `json:"updated_at"`
}

type WorkspaceMember added in v0.2.0

type WorkspaceMember struct {
	WorkspaceID string `json:"workspace_id"`
	User        User   `json:"user"`
	Role        string `json:"role"`
	JoinedAt    string `json:"joined_at"`
}

type WorkspaceMemberCursor added in v0.2.0

type WorkspaceMemberCursor struct {
	Version    int    `json:"v"`
	RoleSort   int    `json:"r"`
	SortName   string `json:"n"`
	SortHandle string `json:"h"`
	UserID     string `json:"u"`
	Query      string `json:"q,omitempty"`
	Role       string `json:"role,omitempty"`
}

func DecodeWorkspaceMemberCursor added in v0.2.0

func DecodeWorkspaceMemberCursor(value string) (WorkspaceMemberCursor, bool, error)

type WorkspaceMemberPage added in v0.2.0

type WorkspaceMemberPage struct {
	Members     []WorkspaceMember          `json:"members"`
	NextCursor  string                     `json:"next_cursor,omitempty"`
	HasMore     bool                       `json:"has_more"`
	TotalCount  *int                       `json:"total_count,omitempty"`
	TotalByRole *WorkspaceMemberRoleCounts `json:"total_by_role,omitempty"`
}

type WorkspaceMemberPageRequest added in v0.2.0

type WorkspaceMemberPageRequest struct {
	Limit  int
	Cursor string
	Query  string
	Role   string
}

func NormalizeWorkspaceMemberPageRequest added in v0.2.0

func NormalizeWorkspaceMemberPageRequest(req WorkspaceMemberPageRequest) (WorkspaceMemberPageRequest, error)

type WorkspaceMemberRoleCounts added in v0.2.0

type WorkspaceMemberRoleCounts struct {
	Owner     int `json:"owner"`
	Moderator int `json:"moderator"`
	Member    int `json:"member"`
	Bot       int `json:"bot"`
	Guest     int `json:"guest"`
}

Directories

Path Synopsis
Package identitysynctest proves the same import contract against each SQL backend.
Package identitysynctest proves the same import contract against each SQL backend.
Package workspacetest checks workspace settings against each SQL backend.
Package workspacetest checks workspace settings against each SQL backend.

Jump to

Keyboard shortcuts

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