api

package
v0.8.3 Latest Latest
Warning

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

Go to latest
Published: May 7, 2026 License: MIT Imports: 37 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ErrorCodeBadRequest       = "bad_request"
	ErrorCodeUnauthorized     = "unauthorized"
	ErrorCodeForbidden        = "forbidden"
	ErrorCodeNotFound         = "not_found"
	ErrorCodeMethodNotAllowed = "method_not_allowed"
	ErrorCodeConflict         = "conflict"
	ErrorCodeUnprocessable    = "unprocessable_entity"
	ErrorCodeRateLimited      = "rate_limited"
	ErrorCodeInternal         = "internal"
	ErrorCodeUnavailable      = "unavailable"
	ErrorCodeTimeout          = "timeout"

	ErrorCodeAliasInvalid           = "alias_invalid"
	ErrorCodeAliasTaken             = "alias_taken"
	ErrorCodeAliasConflictsWithName = "alias_conflicts_with_name"
	ErrorCodeAliasLimitReached      = "alias_limit_reached"
	ErrorCodeAliasForbiddenForInbox = "alias_forbidden_for_inbox"

	ErrorCodeInvalidAudio        = "invalid_audio"
	ErrorCodeInvalidMetadata     = "invalid_metadata"
	ErrorCodeDurationTooLong     = "duration_too_long"
	ErrorCodeProjectNotFound     = "project_not_found"
	ErrorCodeAudioTooLarge       = "audio_too_large"
	ErrorCodeUnsupportedMedia    = "unsupported_media_type"
	ErrorCodeTranscriberDisabled = "transcriber_disabled"
)

API error codes. String values are stable and sent to the client — they must not be changed without updating the OpenAPI specification.

View Source
const IdempotencyHeader = "Idempotency-Key"

IdempotencyHeader is the HTTP header name the client uses to request cached replay of a repeated request.

View Source
const Version = "0.2.0"

Version is the API version returned by GET /v1/me. Bumped manually on breaking changes to the OpenAPI contract.

Variables

This section is empty.

Functions

func AuthMiddleware

func AuthMiddleware(store model.DeviceStore, logger *slog.Logger) func(http.Handler) http.Handler

AuthMiddleware validates the Authorization: Bearer <token> header, compares SHA256(token) against the DeviceStore, and stores device_id in the request context. Returns 401 with a uniform JSON body for unauthenticated requests. Updating last_seen_at is best-effort: errors are logged but the request proceeds.

func ContextWithDeviceID

func ContextWithDeviceID(ctx context.Context, deviceID string) context.Context

ContextWithDeviceID returns a context with device_id set. Useful in tests that do not want to set up the full AuthMiddleware.

func DeviceIDFromContext

func DeviceIDFromContext(ctx context.Context) string

DeviceIDFromContext returns the device ID stored by AuthMiddleware. Returns an empty string if the middleware is not applied or the request is not authorised.

func IdempotencyMiddleware

func IdempotencyMiddleware(cfg IdempotencyConfig) func(http.Handler) http.Handler

IdempotencyMiddleware caches responses for mutating HTTP requests keyed on `device_id + Idempotency-Key`. A repeated request with the same key gets the previously stored status, headers, and body — the real handler is not called. Transparent for GET/HEAD/OPTIONS and requests without the header. Responses with 5xx status are not cached: the client must be able to retry after a transient error is resolved.

func OpenAPISpec

func OpenAPISpec() []byte

OpenAPISpec returns the embedded OpenAPI specification as bytes. Exported for tests to verify YAML validity and coverage of all registered routes.

func RequestIDFromContext

func RequestIDFromContext(ctx context.Context) string

RequestIDFromContext returns the request-id stored by requestIDMiddleware. Returns an empty string if the middleware is not applied.

func WriteError

func WriteError(w http.ResponseWriter, status int, code, message string)

WriteError serialises an error into the response.

Types

type Config

type Config struct {
	ListenAddr     string
	RequestTimeout time.Duration
	Logger         *slog.Logger
	DB             *sql.DB
	// Devices is the device store for AuthMiddleware. Required to mount protected
	// /v1/* routes; if nil only /healthz, /readyz, and 404 are served.
	Devices model.DeviceStore
	// Projects is the use-case for /v1/projects. Optional; nil — routes not mounted.
	Projects model.ProjectService
	// Tasks is the use-case for /v1/tasks. Optional; nil — routes not mounted.
	Tasks model.TaskService
	// Chat is the use-case for /v1/chat. Optional; nil — routes not mounted.
	Chat model.ChatService
	// History is the history store for /v1/chat/history. Optional; nil — returns empty history.
	History model.History
	// ChatTimeout is the agent processing timeout for /v1/chat (0 means no timeout).
	ChatTimeout time.Duration
	// Owner holds owner data published at /v1/me.
	Owner OwnerInfo
	// IdempotencyTTL/IdempotencyMaxEntries are the idempotency cache parameters;
	// zero uses IdempotencyMiddleware defaults.
	IdempotencyTTL        time.Duration
	IdempotencyMaxEntries int
	// Events is the domain event store for SSE replay and /v1/sync/snapshot.
	// If nil, /v1/events and /v1/sync/snapshot routes are not registered.
	Events model.EventStore
	// Broker is the in-memory SSE broker. If nil, /v1/events is not registered.
	Broker model.Broker
	// SSEHeartbeatInterval is the SSE keepalive comment interval. 0 → 15 seconds.
	SSEHeartbeatInterval time.Duration
	// PairingService is the use-case for /v1/pair/* and /pair/confirm/*. If nil — routes not mounted.
	PairingService model.PairingService
	// PairingRateLimit is the POST /v1/pair/request rate limit per IP per hour. 0 → default 5.
	PairingRateLimit int
	// PairingSecure: if true, the CSRF cookie is set as __Host-csrf with Secure:true (HTTPS);
	// if false — as csrf without Secure (HTTP, dev environment).
	PairingSecure bool
	// Relay is the push relay client for syncing registrations on patchMe and revoke.
	// Defaults to NilRelayClient (push disabled) when nil.
	Relay push.RelayClient
	// DateTime holds date/time configuration served at GET /v1/datetime/config.
	DateTime config.DateTimeConfig
	// VoiceQueue is the voice job queue for POST /v1/chat/voice. If nil, the route is not mounted.
	VoiceQueue model.VoiceQueue
	// UploadsDir is the base directory for client audio file storage.
	UploadsDir string
	// VoiceMaxBytes is the max audio upload size in bytes (default 10 MiB).
	VoiceMaxBytes int64
	// VoiceDuration is the max allowed audio duration (default: no limit).
	VoiceDuration time.Duration
	// Transcriber is the speech-to-text backend. Used by Task 9b to return 503 when nil.
	Transcriber model.Transcriber
	// TaskStore is the task/project store used by POST /v1/chat/voice to validate projectId.
	TaskStore model.TaskStore
	// VoiceRateLimit is the per-device rate limit for POST /v1/chat/voice, per minute. 0 → default 10.
	VoiceRateLimit int
	// BuildVersion is the binary version string injected via ldflags. Falls back to
	// the package-level Version constant when empty.
	BuildVersion string
}

Config holds HTTP server parameters. DB is required for /readyz; Logger for middleware. ListenAddr is required for Run but not for Handler().

type ErrorBody

type ErrorBody struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

ErrorBody is the payload of a single error.

type ErrorResponse

type ErrorResponse struct {
	Error ErrorBody `json:"error"`
}

ErrorResponse wraps the error body. The format `{"error": {"code": "...", "message": "..."}}` is fixed in the OpenAPI specification.

type IdempotencyConfig

type IdempotencyConfig struct {
	// TTL is how long to keep a cached response. Default: 1 hour.
	TTL time.Duration
	// MaxEntries is the LRU size limit. Oldest entries are evicted when
	// exceeded. Default: 1024.
	MaxEntries int
	// Now is the time extension point for tests that need to "shift" time.
	// Default: time.Now.
	Now func() time.Time
}

IdempotencyConfig controls the middleware parameters. Any zero field receives a safe default.

type OwnerInfo

type OwnerInfo struct {
	UserName       string
	TelegramUserID int64
}

OwnerInfo is a snapshot of the instance owner's data, published at /v1/me.

type Server

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

Server wraps http.Server and a chi router.

func New

func New(cfg Config) *Server

New builds the server with applied middleware and base endpoints.

func (*Server) Handler

func (s *Server) Handler() http.Handler

Handler returns the root http.Handler — convenient for httptest.

func (*Server) Run

func (s *Server) Run(ctx context.Context) error

Run starts http.Server and blocks until ctx is cancelled, then performs a graceful shutdown with a timeout.

Jump to

Keyboard shortcuts

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