api

package
v0.94.1 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2026 License: AGPL-3.0 Imports: 22 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewMux

func NewMux(deps Deps) http.Handler

NewMux wires the handlers registered against api/openapi.yaml: liveness, 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 BotPrUpdatesResponse added in v0.67.0

type BotPrUpdatesResponse struct {
	AllowBotPrUpdates bool `json:"allowBotPrUpdates"`
}

BotPrUpdatesResponse matches components.schemas.BotPrUpdatesResponse. Deliberately not folded into SettingsResponse's own GET: the dashboard page (app.js) needs only this one field on every load, and reusing handleSettingsGet for that would carry its EnsureWebhookCredentials side effect along too — silently provisioning webhook credentials (and flipping GET /api/dashboard/stream from 404 to 200) for a user who only ever visited the dashboard and never opened Settings at all. This handler reads the saved row without ever creating one.

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 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

	// 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

	// 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 Health

type Health struct {
	Status string `json:"status"`
}

Health matches components.schemas.Health in api/openapi.yaml.

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"`
	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"`
	// AllowBotPrUpdates and RenovateRebaseLabel — see settings.Credentials'
	// own doc comments; both round-trip as plain values, unlike the forge
	// tokens above, since neither is a secret.
	AllowBotPrUpdates   bool   `json:"allowBotPrUpdates"`
	RenovateRebaseLabel string `json:"renovateRebaseLabel"`
	// 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"`
}

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 {
	Username    string `json:"username"`
	DisplayName string `json:"displayName"`
}

SharedUser matches components.schemas.SharedUser in api/openapi.yaml.

type SharingResponse added in v0.10.0

type SharingResponse struct {
	SharedWith   []SharedUser `json:"sharedWith"`
	SharedWithMe []SharedUser `json:"sharedWithMe"`
}

SharingResponse matches components.schemas.SharingResponse.

type ThemeResponse added in v0.73.0

type ThemeResponse struct {
	Theme string `json:"theme"`
}

ThemeResponse matches components.schemas.ThemeResponse. Same reasoning as BotPrUpdatesResponse above: every page needs this on load, and none of them should trigger EnsureWebhookCredentials just to read one field.

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.

type Version added in v0.15.0

type Version struct {
	Version string `json:"version"`
}

Version matches components.schemas.Version in api/openapi.yaml.

Jump to

Keyboard shortcuts

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