Documentation
¶
Overview ¶
Package api is the composition root's one dependency: an http.Handler satisfying api/openapi.yaml, serving the aggregated dashboard snapshot and the static frontend. It lives under internal/ because the API this service offers is its endpoints, not its Go packages — see go.md's "a server keeps everything in internal/ and its commands in cmd/".
Index ¶
- func NewMux(deps Deps) http.Handler
- type AdminInvite
- type AdminInviteCreateResponse
- type AdminRequestLogEntry
- type AdminUser
- type CredentialInfo
- type DatabasePinger
- type Deps
- type Drain
- type FirstRefreshGate
- type Health
- type Ready
- type SessionUser
- type SettingsResponse
- type SharedUser
- type SharingResponse
- type ThemeResponse
- type TimezoneResponse
- type Token
- type Version
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewMux ¶
NewMux wires the handlers registered against api/openapi.yaml: liveness, readiness, passkey registration/login/session, per-user settings, the aggregated dashboard snapshot, and the static frontend that consumes it.
The dashboard itself, and the page that renders it, require a valid session; registration, login and the handful of static assets a login page needs (its own HTML/JS, the shared stylesheet, the favicon) don't.
Types ¶
type AdminInvite ¶ added in v0.86.0
type AdminInvite struct {
ID string `json:"id"`
Username string `json:"username"`
DisplayName string `json:"displayName"`
ExpiresAt string `json:"expiresAt"`
}
AdminInvite matches components.schemas.AdminInvite — an outstanding invite's own metadata for the admin area's list. ID is the invite's own stable identifier (its stored token hash — see auth.Invite's own doc comment for why that's safe to hand back), never the raw token itself; it's what a revoke call passes back in the {token} path segment.
type AdminInviteCreateResponse ¶ added in v0.86.0
type AdminInviteCreateResponse struct {
Token string `json:"token"`
Username string `json:"username"`
DisplayName string `json:"displayName"`
ExpiresAt string `json:"expiresAt"`
}
AdminInviteCreateResponse matches components.schemas.AdminInviteCreateResponse — the one and only response that ever carries the raw invite token, shown once at creation time; only its hash is stored, so it can't be recovered from here again (the same "show once" handling APITokenCreateResponse's own token field gets).
type AdminRequestLogEntry ¶ added in v0.90.0
type AdminRequestLogEntry struct {
LoggedAt string `json:"loggedAt"`
Forge string `json:"forge"`
Account string `json:"account,omitempty"`
Method string `json:"method"`
Endpoint string `json:"endpoint"`
StatusCode int `json:"statusCode,omitempty"`
Outcome string `json:"outcome"`
RateLimit *dashboard.RateLimit `json:"rateLimit,omitempty"`
}
AdminRequestLogEntry matches components.schemas.RequestLogEntry.
type AdminUser ¶ added in v0.9.0
type AdminUser struct {
Username string `json:"username"`
DisplayName string `json:"displayName"`
IsAdmin bool `json:"isAdmin"`
CreatedAt string `json:"createdAt"`
}
AdminUser matches components.schemas.AdminUser in api/openapi.yaml.
type CredentialInfo ¶ added in v0.73.0
type CredentialInfo struct {
ID string `json:"id"`
Label string `json:"label"`
CreatedAt time.Time `json:"createdAt"`
}
CredentialInfo matches components.schemas.Credential — one passkey's own display metadata, never the credential itself.
type DatabasePinger ¶ added in v0.109.0
DatabasePinger is the slice of *sql.DB readiness needs. Deps.Database is satisfied by cmd/forge-dashboard's schema-aware wrapper in production.
type Deps ¶ added in v0.8.0
type Deps struct {
// Version is the release tag this binary was built from ("dev" for a
// build outside the release pipeline) — see cmd/forge-dashboard's own
// version var for how it's set.
Version string
AuthService *auth.Service
AuthStore *auth.Store
SettingsStore *settings.Store
SharingStore *sharing.Store
// Database and Dashboard back GET /readyz. Either may be nil, in which
// case that check is skipped.
Database DatabasePinger
Dashboard FirstRefreshGate
// ReadyProbeTimeout bounds the database ping and ReadyCacheTTL is how
// long its result is reused; zero means the defaults (2s and 3s).
ReadyProbeTimeout time.Duration
ReadyCacheTTL time.Duration
// Drain, once started, makes /readyz answer 503 so a router stops
// sending traffic before shutdown. Nil never drains.
Drain *Drain
// Manager holds each signed-in user's own Aggregator, built from
// their saved Credentials via BuildSources.
Manager *dashboard.Manager
// BuildSources takes the signed-in user's own ID (#482: threaded
// through so the forge clients it builds can record outbound
// requests under the right account) alongside their saved
// Credentials.
BuildSources func(userID []byte, c settings.Credentials) []dashboard.Source
// RequestLog is the admin-only outbound-request log's own read path
// — every account's forge clients record into the same underlying
// store (see cmd/forge-dashboard's buildSourcesForUser), so this one
// instance, with no account bound to it, is enough to list or export
// across all of them.
RequestLog *requestlog.SQLiteRecorder
// PublicOrigin is this instance's own externally-reachable origin
// (RP_ORIGIN — the same value WebAuthn's relying-party config
// already requires be set correctly, reused rather than adding a
// second "what's my own address" env var). handleWebhookEnsure uses
// it to build the exact URL a webhook it creates should target;
// nothing else here needs it, since matching an existing hook
// (dashboard.WebhookTargetsPath) only ever compares by path.
PublicOrigin string
// GitHubAppConfigured is whether this deployment has a GitHub App set
// up at all (#620) — server-wide GITHUB_APP_ID/
// GITHUB_APP_PRIVATE_KEY_BASE64, read once at startup, never a
// per-user setting. handleSettingsGet/handleSettingsPut use it to
// explain and enforce why a saved githubAppInstallationId can't work
// on a server with no App configured.
GitHubAppConfigured bool
// AppContext is the process's own long-lived context (canceled on
// shutdown), not any one request's — a handler that starts a
// Manager-owned background refresh goroutine has to root it here, not
// in the *http.Request context that dies the moment that handler
// returns.
AppContext context.Context
}
Deps is everything NewMux needs — passed as one struct rather than a long parameter list, since it's grown one dependency per feature slice (auth, then per-user settings) and reads better named than positional.
type Drain ¶ added in v0.130.0
type Drain struct {
// contains filtered or unexported fields
}
Drain flips /readyz to 503 once shutdown starts, before the server stops accepting connections, so a router that polls /readyz stops sending traffic first. The zero value isn't draining.
type FirstRefreshGate ¶ added in v0.109.0
type FirstRefreshGate interface {
FirstRefreshComplete() bool
}
FirstRefreshGate reports whether the dashboard has finished its first refresh. *dashboard.Manager satisfies it.
type Health ¶
type Health struct {
Status string `json:"status"`
}
Health matches components.schemas.Health in api/openapi.yaml.
type Ready ¶ added in v0.135.0
type Ready struct {
Status string `json:"status"`
Goroutines int `json:"goroutines"`
// Threads is left out where the process can't count its own, which is
// anywhere without /proc.
Threads int `json:"threads,omitempty"`
}
Ready matches components.schemas.Ready in api/openapi.yaml: Health plus how many goroutines and OS threads the process holds (#902).
type SessionUser ¶ added in v0.7.0
type SessionUser struct {
Username string `json:"username"`
DisplayName string `json:"displayName"`
IsAdmin bool `json:"isAdmin"`
}
SessionUser matches components.schemas.SessionUser in api/openapi.yaml.
type SettingsResponse ¶ added in v0.8.0
type SettingsResponse struct {
GitHubUsername string `json:"githubUsername"`
GitHubTokenSet bool `json:"githubTokenSet"`
// GitHubAppInstallationID and GitHubAppConfigured (#620) — see their
// SettingsResponse doc comments in api/openapi.yaml for the full
// precedence/validation story.
GitHubAppInstallationID int64 `json:"githubAppInstallationId"`
GitHubAppConfigured bool `json:"githubAppConfigured"`
ForgejoURL string `json:"forgejoUrl"`
ForgejoUsername string `json:"forgejoUsername"`
ForgejoTokenSet bool `json:"forgejoTokenSet"`
// WebhookToken and WebhookSecret, unlike the forge tokens above, are
// ours to hand back in the clear — the user has to paste them into
// the forge's own webhook setup, so a "set" flag alone wouldn't do.
WebhookToken string `json:"webhookToken"`
WebhookSecret string `json:"webhookSecret"`
// RenovateRebaseLabel — see settings.Credentials' own doc comment;
// round-trips as a plain value, unlike the forge tokens above, since
// it isn't a secret.
RenovateRebaseLabel string `json:"renovateRebaseLabel"`
// RenovateAuthors — see settings.Credentials' own doc comment. Always a
// list on the wire, never null.
RenovateAuthors []string `json:"renovateAuthors"`
// Theme — see settings.Credentials' own doc comment. Round-tripped
// here too so the Settings page's own save confirms what it just set,
// even though the lightweight GET /api/settings/theme below is what
// every other page actually polls on load.
Theme string `json:"theme"`
// Timezone — see settings.Credentials' own doc comment. Round-tripped
// here so the Settings page shows what is saved; every other page reads
// the lightweight GET /api/settings/timezone.
Timezone string `json:"timezone"`
}
SettingsResponse matches components.schemas.SettingsResponse in api/openapi.yaml. Tokens are never sent back to the browser once saved — *Set reports whether one is on file, not what it is.
type SharedUser ¶ added in v0.10.0
type SharedUser struct {
}
SharedUser matches components.schemas.SharedUser in api/openapi.yaml.
type SharingResponse ¶ added in v0.10.0
type SharingResponse struct {
}
SharingResponse matches components.schemas.SharingResponse.
type ThemeResponse ¶ added in v0.73.0
type ThemeResponse struct {
Theme string `json:"theme"`
}
ThemeResponse matches components.schemas.ThemeResponse. Every page needs this on load, and none of them should trigger EnsureWebhookCredentials just to read one field — the same reasoning that gave Theme its own dedicated GET rather than folding it into handleSettingsGet.
type TimezoneResponse ¶ added in v0.134.0
type TimezoneResponse struct {
Timezone string `json:"timezone"`
}
TimezoneResponse matches components.schemas.TimezoneResponse. Every page needs it on load to show times in the user's zone, so it has its own cheap GET like Theme does.
type Token ¶ added in v0.64.0
type Token struct {
ID string `json:"id"`
Label string `json:"label"`
CreatedAt time.Time `json:"createdAt"`
ExpiresAt time.Time `json:"expiresAt"`
LastUsedAt *time.Time `json:"lastUsedAt,omitempty"`
}
Token matches components.schemas.APIToken — a token's own metadata, never the raw value. Named Token, not APIToken, to avoid stuttering as api.APIToken from outside the package; auth.APIToken (a different package) keeps its own fuller name since auth.Token would collide with nothing here but reads less clearly on its own.
Source Files
¶
- access_log.go
- action_error.go
- admin.go
- auth.go
- auto_update_branch.go
- credentials.go
- dashboard.go
- doc.go
- error_pages.go
- filter_state.go
- health.go
- mcp.go
- pull_request_action.go
- pull_request_auto_merge.go
- pull_request_checks.go
- pull_request_close.go
- pull_request_dependabot.go
- pull_request_merge.go
- pull_request_renovate_rebase.go
- pull_request_rerun_checks.go
- pull_request_update_branch.go
- queued_actions.go
- repo_ignore.go
- repo_setting.go
- request_limits.go
- server.go
- settings.go
- sharing.go
- static.go
- tokens.go
- tzdata.go
- webhook_ensure.go
- webhooks.go