Documentation
¶
Index ¶
- Variables
- func ByCategory() map[Category][]Integration
- func Categories() []struct{ ... }
- func Register(i Integration)
- func SetCreator(c Creator)
- func SetCredentialStore(v interface{ ... })
- func SetCredentialWriter(w CredentialWriter)
- func SetPlanner(p Planner)
- type Auth
- type AuthState
- type Category
- type Creator
- type CredentialWriter
- type Integration
- type OAuthStore
- type Planner
- type Provider
- type SQLOAuthStore
- type Service
- type SessionPlanner
- type State
- type Status
- type Terminal
- type Text
- type Tmux
- type Token
- type Tokens
Constants ¶
This section is empty.
Variables ¶
var ErrNotConnected = errors.New("not connected — authorize this integration first")
ErrNotConnected means no token is stored for this integration.
Distinct from a refresh failure on purpose: this one is fixed by a human pressing Authorize, and a collector that says "not connected" sends them there instead of into logs.
Functions ¶
func ByCategory ¶
func ByCategory() map[Category][]Integration
ByCategory groups the catalogue for the gallery.
func Categories ¶
func Categories() []struct {
Key Category `json:"key"`
Title Text `json:"title"`
Help Text `json:"help"`
}
Categories in display order, with their labels.
func Register ¶
func Register(i Integration)
Register adds an integration. Called from init() in the per-category files.
func SetCreator ¶
func SetCreator(c Creator)
SetCreator installs the connection creator. Called once during boot.
func SetCredentialStore ¶
func SetCredentialStore(v interface {
RevealSystem(ctx context.Context, name, reason string) (string, error)
HasSecret(ctx context.Context, name string) bool
})
SetCredentialStore installs the vault reader. Called once during boot.
func SetCredentialWriter ¶
func SetCredentialWriter(w CredentialWriter)
SetCredentialWriter installs the vault writer. Called once during boot.
func SetPlanner ¶
func SetPlanner(p Planner)
SetPlanner installs the model client. Called once during boot.
Types ¶
type Auth ¶
type Auth string
Auth is HOW an operator connects, and it decides what the Connect button does.
const ( // AuthTerminal opens an interactive session and runs the vendor's login. // // The important property: we never see or store the credential. `gh auth // login` writes gh's own config file; `claude login` writes Claude Code's. // That is why these integrations are not blocked by SF-001 — there is no // secret of ours to grant. AuthTerminal Auth = "terminal" // AuthToken stores a named secret in the vault (SF-001 applies). AuthToken Auth = "token" // AuthDSN stores a connection string in the vault (SF-001 applies). AuthDSN Auth = "dsn" // AuthOAuth is a redirect dance. Not implemented yet; declared so the // gallery can show "coming soon" honestly rather than offering a button // that fails. AuthOAuth Auth = "oauth" // AuthNone needs no credential at all — a public RSS feed, a self-hosted // SearXNG with anonymous access. AuthNone Auth = "none" )
type AuthState ¶
AuthState is one in-flight authorization.
func NewAuthState ¶
NewAuthState mints the CSRF state and the PKCE pair.
type Category ¶
type Category string
Category groups integrations in the gallery.
const ( // CatTerminal — connect by running the vendor's own login in a terminal. CatTerminal Category = "terminal" // CatAPI — token or OAuth; can usually both receive and send. CatAPI Category = "api" // CatDatabase — a DSN we connect with directly. CatDatabase Category = "database" // CatReader — read-only collectors. No actions, by nature not by omission. CatReader Category = "reader" // CatAnalytics — measurement properties and submission endpoints. CatAnalytics Category = "analytics" )
type Creator ¶
type Creator interface {
CreateFromPlan(ctx context.Context, kind, name string, config json.RawMessage) (string, error)
TestConnection(ctx context.Context, id string) error
}
Creator makes a connection once the plan is validated.
Satisfied by *sources.Store. Narrow on purpose: this package may create a connection and test it, and nothing else.
type CredentialWriter ¶
type CredentialWriter interface {
PutSystem(ctx context.Context, name, value, reason string) error
}
CredentialWriter stores installation-owned credentials.
type Integration ¶
type Integration struct {
Slug string `json:"slug"`
Title Text `json:"title"`
Summary Text `json:"summary"`
Category Category `json:"category"`
Auth Auth `json:"auth"`
// Icon is a glyph name from the shell's inlined set.
Icon string `json:"icon"`
Color string `json:"color"`
// Collects: can pull content into the brain.
Collects bool `json:"collects"`
// Acts: can send outward. False here is a STATEMENT — see the package doc.
Acts bool `json:"acts"`
// ActorKind links to internal/actors when Acts is true. Empty otherwise.
ActorKind string `json:"actorKind,omitempty"`
// SourceKind links to internal/sources when Collects is true.
SourceKind string `json:"sourceKind,omitempty"`
// Inputs is a JSON Schema for this integration's own configuration. One
// schema, two consumers: the form the operator fills, and server-side
// validation. Two copies is how a field ends up optional in one and
// required in the other.
Inputs json.RawMessage `json:"inputs"`
// Terminal is set when Auth is AuthTerminal.
Terminal *Terminal `json:"terminal,omitempty"`
// DocsURL is the vendor's own setup page.
DocsURL string `json:"docsUrl,omitempty"`
// Beta marks an integration that is declared but not finished. The gallery
// shows it as unavailable rather than hiding it, so "is X supported?" has a
// visible answer.
Beta bool `json:"beta,omitempty"`
}
Integration is one entry in the catalogue.
func All ¶
func All() []Integration
All returns the catalogue, ordered for display: by category in the order the gallery shows them, then alphabetically within a category.
type OAuthStore ¶
type OAuthStore interface {
SaveState(ctx context.Context, st AuthState, integration, createdBy string) error
// TakeState consumes a state, returning it exactly once. A replayed
// callback must not succeed twice.
TakeState(ctx context.Context, state string) (AuthState, string, error)
SaveToken(ctx context.Context, integration string, tok Token) error
}
OAuthStore persists in-flight states and issued tokens.
type Planner ¶
Planner runs one bounded model call and returns its text.
An interface rather than a concrete session so this package does not depend on the runner, and so a test can plan without spending money.
type Provider ¶
type Provider struct {
// AuthURL and TokenURL are the vendor's endpoints.
AuthURL string
TokenURL string
// Scopes are what we ask for. Least privilege: read-only wherever the
// vendor offers a read-only scope, because an integration that collects
// analytics has no business being able to change them.
Scopes []string
// ClientIDEnv / ClientSecretEnv name the env vars holding the app
// credentials. The NAMES are declared; the values are never in code.
ClientIDEnv string
ClientSecretEnv string
// Extra query parameters on the authorize leg. Google needs
// access_type=offline to issue a refresh token at all, and prompt=consent
// to reissue one when the user has authorised before — without both, a
// second authorization silently returns no refresh token and the
// integration dies an hour later.
AuthParams map[string]string
// UsesPKCE — send a code challenge. Harmless where supported.
UsesPKCE bool
// AccountFrom names the field in the token or userinfo response that
// identifies the account, so the UI can say whose it is.
AccountFrom string
}
Provider is the per-vendor half of an OAuth flow — all data.
func ProviderFor ¶
ProviderFor returns the OAuth provider an integration authorises against.
func (Provider) AuthorizeURL ¶
AuthorizeURL builds the redirect the operator's browser follows.
func (Provider) Configured ¶
Configured reports whether the operator has supplied this provider's app credentials.
Checked BEFORE showing a Connect button: an OAuth button that redirects to a vendor error page because no client id is set is worse than a card that says what is missing.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func (*Service) OAuthAppRoutes ¶
OAuthAppRoutes mounts the provider-configuration surface.
func (*Service) OAuthRoutes ¶
OAuthRoutes registers the flow. Mounted alongside the rest of the service.
func (*Service) SmartRoutes ¶
type SessionPlanner ¶
type SessionPlanner struct {
Log *slog.Logger
// Model is optional; empty uses whatever the CLI is configured with.
Model string
// Dir is where the session runs. It reads nothing, but the CLI wants a
// working directory that exists.
Dir string
}
SessionPlanner runs the plan prompt through the Claude Code CLI.
type State ¶
type State string
State is what the badge shows.
const ( // StateConnected — the tool answered yes. StateConnected State = "connected" // StateDisconnected — the tool is installed and says it is not signed in. StateDisconnected State = "disconnected" // StateMissing — the binary is not on PATH. Distinct from disconnected on // purpose: one is fixed by signing in, the other by installing, and telling // an operator to sign in to something they have not installed is the kind // of advice that wastes an afternoon. StateMissing State = "missing" // StateUnknown — the check itself failed to run or timed out. StateUnknown State = "unknown" )
type Status ¶
type Status struct {
Slug string `json:"slug"`
State State `json:"state"`
Version string `json:"version,omitempty"`
// Detail is a short, already-scrubbed line for the UI.
Detail string `json:"detail,omitempty"`
// Install is populated when State is StateMissing.
//
// omitzero, not omitempty: omitempty has no effect on a struct, so this
// would have serialised {"en":"","ar":""} on every status the UI renders —
// and a truthy-looking empty object is exactly what makes a client show an
// install hint to someone who has the tool installed.
Install Text `json:"install,omitzero"`
}
type Terminal ¶
type Terminal struct {
// Bin is the executable, checked for presence before anything else. A
// missing binary is the most common reason a connect does nothing, and it
// deserves "gh is not installed" rather than a blank terminal.
Bin string `json:"bin"`
// Install is what to tell the operator when Bin is absent.
Install Text `json:"install"`
// Login is the interactive command. It runs in a tmux session the operator
// attaches to, because these prompts ask questions — a device code to
// paste, a browser to approve, a project to pick — and answering them is
// the whole point.
Login []string `json:"login"`
// Status is a NON-interactive command whose exit code answers "is this
// connected?". It must never block waiting for input; a status check that
// hangs looks identical to one that failed.
Status []string `json:"status"`
// Version reports the installed version for display.
Version []string `json:"version"`
// Logout undoes it, so an operator can disconnect from the same screen.
Logout []string `json:"logout"`
}
Terminal describes how a CatTerminal integration logs in and reports status.
type Tmux ¶
type Tmux interface {
// Ensure creates the session if absent, and reports the name.
Ensure(ctx context.Context, name string) error
// SendKeys types a command into it, as if the operator had.
SendKeys(ctx context.Context, name string, args ...string) error
}
Tmux is the slice of terminal control this package needs.
type Tokens ¶
Tokens hands out valid access tokens, refreshing as needed.
func (*Tokens) AccessToken ¶
AccessToken returns a token good for at least refreshMargin.
Takes an INTEGRATION slug and resolves it to the provider that issued the token, because one Google grant serves five Google integrations — see the note on SaveToken in the callback.