api

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 23, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GzipMiddleware

func GzipMiddleware(next http.Handler) http.Handler

GzipMiddleware compresses responses when the client accepts gzip. SSE (/api/events) is excluded because EventSource cannot handle compressed streams.

Types

type Broker

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

Broker manages SSE client channels.

Each Notify call broadcasts a "source" tag (`claude`, `codex`, or `all`) so the web UI can selectively refresh the active tab. Notify() (no args) is kept for backward compatibility and tags the event as "claude".

func NewBroker

func NewBroker() *Broker

func (*Broker) ClientCount

func (b *Broker) ClientCount() int

func (*Broker) LastNotifyUnix

func (b *Broker) LastNotifyUnix() int64

func (*Broker) LastSource

func (b *Broker) LastSource() string

LastSource returns the source tag of the most recent broadcast, or "" if no broadcast has happened yet.

func (*Broker) Notify

func (b *Broker) Notify()

Notify broadcasts a Claude-tagged update. Equivalent to NotifySource("claude").

func (*Broker) NotifyCount

func (b *Broker) NotifyCount() int64

func (*Broker) NotifySource

func (b *Broker) NotifySource(source string)

NotifySource broadcasts an update tagged with the given source.

func (*Broker) Subscribe

func (b *Broker) Subscribe() chan string

func (*Broker) Unsubscribe

func (b *Broker) Unsubscribe(ch chan string)

type CalendarResponse

type CalendarResponse struct {
	Data []db.CalendarDay `json:"data"`
}

type Handler

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

Handler serves the REST API and SSE endpoints for the cc-otel web dashboard.

func NewHandler

func NewHandler(repo *db.Repository, broker *Broker, cfg *config.Config, configPath string) *Handler

NewHandler creates a Handler with the given database repository, SSE broker, config, and the absolute path of the config file the daemon actually loaded.

func (*Handler) Calendar

func (h *Handler) Calendar(w http.ResponseWriter, r *http.Request)

Calendar returns compact per-day aggregates for the dashboard usage calendar.

func (*Handler) Close

func (h *Handler) Close()

Close cancels active inspection/import work and waits for file users to exit.

func (*Handler) CodexCalendar

func (h *Handler) CodexCalendar(w http.ResponseWriter, r *http.Request)

CodexCalendar returns compact per-day aggregates for the Codex usage calendar.

func (*Handler) CodexDaily

func (h *Handler) CodexDaily(w http.ResponseWriter, r *http.Request)

CodexDaily returns paged per-(date, model) rollup rows for the Codex tab.

func (*Handler) CodexDashboard

func (h *Handler) CodexDashboard(w http.ResponseWriter, r *http.Request)

CodexDashboard returns aggregated KPI cards for the Codex tab.

func (*Handler) CodexDurations

func (h *Handler) CodexDurations(w http.ResponseWriter, r *http.Request)

CodexDurations returns per-model latency stats. Token-throughput columns are always zero since Codex does not emit per-request token rates.

func (*Handler) CodexIntraday

func (h *Handler) CodexIntraday(w http.ResponseWriter, r *http.Request)

CodexIntraday returns per-(time-bucket, model) Codex stats.

func (*Handler) CodexModels

func (h *Handler) CodexModels(w http.ResponseWriter, r *http.Request)

CodexModels returns the distinct list of Codex models seen so far.

func (*Handler) CodexRequests

func (h *Handler) CodexRequests(w http.ResponseWriter, r *http.Request)

CodexRequests returns paged Codex API request rows.

func (*Handler) CodexSessions

func (h *Handler) CodexSessions(w http.ResponseWriter, r *http.Request)

CodexSessions returns paged session aggregates.

func (*Handler) DailyModel

func (h *Handler) DailyModel(w http.ResponseWriter, r *http.Request)

DailyModel returns per-day, per-model token usage and cost with pagination.

func (*Handler) Dashboard

func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request)

Dashboard returns aggregated token usage and cost KPIs for a date range.

func (*Handler) Durations

func (h *Handler) Durations(w http.ResponseWriter, r *http.Request)

Durations returns per-model average duration stats for the selected date range. Query:

  • from=YYYY-MM-DD&to=YYYY-MM-DD (preferred)
  • or range=today|week|month|all
  • optional: model=<name> to filter down to a single model
  • optional: limit=<n> (default 2000, max 2000)

func (*Handler) Events

func (h *Handler) Events(w http.ResponseWriter, r *http.Request)

Events streams Server-Sent Events to the client, pushing "update" on each new OTEL record.

func (*Handler) Health

func (h *Handler) Health(w http.ResponseWriter, r *http.Request)

Health reports database connectivity (200 ok, 503 error).

func (*Handler) HourlyModel

func (h *Handler) HourlyModel(w http.ResponseWriter, r *http.Request)

HourlyModel returns per-hour, per-model token usage and cost for a single local day. Query params: - date=YYYY-MM-DD (optional; defaults to today) - model=<name> (optional filter)

func (*Handler) ImportDelete

func (h *Handler) ImportDelete(w http.ResponseWriter, r *http.Request)

func (*Handler) ImportInspect

func (h *Handler) ImportInspect(w http.ResponseWriter, r *http.Request)

func (*Handler) ImportStart

func (h *Handler) ImportStart(w http.ResponseWriter, r *http.Request)

func (*Handler) ImportStatus

func (h *Handler) ImportStatus(w http.ResponseWriter, r *http.Request)

func (*Handler) InitImports

func (h *Handler) InitImports() error

InitImports initializes the singleton database-import manager. Initialization failure does not prevent the dashboard from starting; import endpoints report the stored error as unavailable.

func (*Handler) Intraday

func (h *Handler) Intraday(w http.ResponseWriter, r *http.Request)

Intraday returns per-(time-bucket, model) stats across a [from, to] window of at most 7 local days, bucketed at 5/10/15/30/60 minutes. Designed for the Intraday bar-chart view; defaults to today + 30-min buckets.

Query params:

  • from=YYYY-MM-DD, to=YYYY-MM-DD (optional; default = today)
  • range=<today|week|month|all> (used only if from/to omitted)
  • bucket=5|10|15|30|60 (default 30)
  • model=<name> (optional filter)

func (*Handler) Models

func (h *Handler) Models(w http.ResponseWriter, r *http.Request)

Models returns the distinct model names seen in the database.

func (*Handler) PricingCollection

func (h *Handler) PricingCollection(w http.ResponseWriter, r *http.Request)

PricingCollection handles GET (list), POST (upsert), DELETE over model_pricing. Prices are USD/Mtok on the wire and USD/token in storage, so POST divides by perMtokFactor and GET multiplies back.

func (*Handler) PricingLookup

func (h *Handler) PricingLookup(w http.ResponseWriter, r *http.Request)

PricingLookup answers "why does cc-otel think model X costs Y?". Useful when a row's cost_usd looks wrong: hit /api/pricing/lookup?model=glm-4.6 to confirm whether the registry resolved at all and which entry won.

func (*Handler) PricingRecompute

func (h *Handler) PricingRecompute(w http.ResponseWriter, r *http.Request)

PricingRecompute handles GET (status) / POST (start) for the background full-table recompute. State is server-side and singleton: GET never starts a job; POST while a job is already running is a no-op that returns the current status. One job at a time.

func (*Handler) PricingSuggest

func (h *Handler) PricingSuggest(w http.ResponseWriter, r *http.Request)

PricingSuggest handles GET /api/pricing/suggest — a user-initiated OpenRouter price lookup used to prefill the manual-entry form. It never writes. The response carries the default one-click price (first-party "Official" provider when OpenRouter lists one, else the blended minimum) plus a "providers" list + "providers_total" for the picker. A non-match returns a zero-valued SuggestResult (Matched=false).

func (*Handler) Rate

func (h *Handler) Rate(w http.ResponseWriter, r *http.Request)

Rate returns per-(bucket, model) token throughput over time for the rate chart.

func (*Handler) Register

func (h *Handler) Register(mux *http.ServeMux)

Register wires all API and static-file routes onto the given ServeMux.

func (*Handler) Requests

func (h *Handler) Requests(w http.ResponseWriter, r *http.Request)

Requests returns individual API request records with optional model and date filters.

func (*Handler) SessionRate

func (h *Handler) SessionRate(w http.ResponseWriter, r *http.Request)

SessionRate returns token throughput for the most recent 1-minute window in which the given session had API activity (duration_ms > 0).

func (*Handler) Sessions

func (h *Handler) Sessions(w http.ResponseWriter, r *http.Request)

Sessions returns per-session aggregated stats with pagination.

func (*Handler) SetOTLPHTTPBound

func (h *Handler) SetOTLPHTTPBound(f func() bool)

SetOTLPHTTPBound supplies the predicate /api/status uses to report OTLP/HTTP receiver health. Pass the daemon's own bind state, not a port probe.

func (*Handler) SetPricer

func (h *Handler) SetPricer(p pricing.Registry)

SetPricer injects the pricing registry used by /api/status and /api/pricing/lookup. Done via setter (rather than another constructor argument) to avoid churning every existing call site.

func (*Handler) SetPricingWriter

func (h *Handler) SetPricingWriter(w pricing.Writer)

SetPricingWriter injects the pricing Writer used by /api/pricing CRUD. nil (the default) makes the collection endpoint return 503.

func (*Handler) SetShutdownContext

func (h *Handler) SetShutdownContext(ctx context.Context)

SetShutdownContext supplies the context used to cancel a background recompute goroutine when the daemon shuts down. If unset, the recompute runs against context.Background.

func (*Handler) Status

func (h *Handler) Status(w http.ResponseWriter, r *http.Request)

Status returns server health details: DB, SSE, OTEL receiver, ports, and last update time.

type HourlyResponse

type HourlyResponse struct {
	Date string                  `json:"date"`
	Data []db.HourlyModelSummary `json:"data"`
}

type ImportFileStatus

type ImportFileStatus struct {
	Name      string `json:"name"`
	SizeBytes int64  `json:"size_bytes"`
	SHA256    string `json:"sha256"`
}

type ImportJobError

type ImportJobError struct {
	Code      string `json:"code"`
	Message   string `json:"message"`
	Table     string `json:"table,omitempty"`
	RowNumber int64  `json:"row_number,omitempty"`
}

type ImportJobStatus

type ImportJobStatus struct {
	JobID     string              `json:"job_id"`
	State     importState         `json:"state"`
	Phase     dbmerge.Phase       `json:"phase"`
	CreatedAt int64               `json:"created_at"`
	UpdatedAt int64               `json:"updated_at"`
	ExpiresAt int64               `json:"expires_at,omitempty"`
	Retryable bool                `json:"retryable"`
	File      ImportFileStatus    `json:"file"`
	Progress  dbmerge.Progress    `json:"progress"`
	Preview   *dbmerge.Inspection `json:"preview"`
	Result    *dbmerge.Result     `json:"result"`
	Error     *ImportJobError     `json:"error"`
}

type IntradayResponse

type IntradayResponse struct {
	From          string                    `json:"from"`
	To            string                    `json:"to"`
	BucketMinutes int                       `json:"bucket_minutes"`
	Data          []db.IntradayModelSummary `json:"data"`
}

IntradayResponse wraps Intraday for the JSON envelope; From/To are inclusive local YYYY-MM-DD; BucketMinutes echoes back the granularity actually used so the client can label its axis without re-deriving it.

type PagedResponse

type PagedResponse struct {
	Data     interface{} `json:"data"`
	Total    int64       `json:"total"`
	Page     int         `json:"page"`
	PageSize int         `json:"page_size"`
}

type PricingLookupResponse

type PricingLookupResponse struct {
	Query      string  `json:"query"`
	Found      bool    `json:"found"`
	Kind       string  `json:"kind"` // "exact" | "alias" | "prefix" | "miss"
	MatchedKey string  `json:"matched_key,omitempty"`
	Source     string  `json:"source,omitempty"`
	Input      float64 `json:"input,omitempty"`
	Output     float64 `json:"output,omitempty"`
	CacheRead  float64 `json:"cache_read,omitempty"`
	CacheWrite float64 `json:"cache_creation,omitempty"`
	IsClaude   bool    `json:"is_claude"` // Claude is intentionally absent — surfaced so callers know why
}

PricingLookupResponse describes one model lookup against the registry. Returned by /api/pricing/lookup.

type PricingStatus

type PricingStatus struct {
	TableSize     int      `json:"table_size"`
	UserOverrides int      `json:"user_overrides"`
	LastEditAt    int64    `json:"last_edit_at"`
	MissCount24h  int      `json:"miss_count_24h"`
	MissModelsTop []string `json:"miss_models_top"`
}

PricingStatus mirrors pricing.Snapshot with JSON-friendly names. Kept separate so the api package doesn't expose the internal struct directly.

type RateResponse

type RateResponse struct {
	From          string          `json:"from"`
	To            string          `json:"to"`
	BucketMinutes int             `json:"bucket_minutes"`
	Data          []db.RateBucket `json:"data"`
}

RateResponse wraps the rate-over-time buckets in a JSON envelope. From/To are inclusive local YYYY-MM-DD; BucketMinutes echoes the granularity actually used.

type StatusResponse

type StatusResponse struct {
	ServerTimeUnix int64 `json:"server_time_unix"`

	DBOK bool `json:"db_ok"`

	SSEClients  int   `json:"sse_clients"`
	LastUpdate  int64 `json:"last_update_unix"`
	NotifyCount int64 `json:"notify_count"`

	WebPort      int `json:"web_port"`
	OTELPort     int `json:"otel_port"`
	OTLPHTTPPort int `json:"otlp_http_port"`

	OTELReceiverListening     bool `json:"otel_receiver_listening"`
	OTLPHTTPReceiverListening bool `json:"otlp_http_receiver_listening"`

	// ConfigPath is the absolute path of the config file this daemon loaded at startup.
	// DBPath is the resolved SQLite path after yaml + CC_OTEL_DB_PATH env override.
	ConfigPath string `json:"config_path"`
	DBPath     string `json:"db_path"`

	// Pricing is omitted when no pricing registry is wired (legacy callers /
	// tests). The frontend Server Status popup keys off the presence of this
	// block to decide whether to render the Pricing row.
	Pricing *PricingStatus `json:"pricing,omitempty"`
}

Jump to

Keyboard shortcuts

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