// Package config loads service configuration from environment variables. package config import ( "errors" "fmt" "os" "time" ) // Config holds all runtime configuration for the service. type Config struct { APIKey string StacksRoot string Port string LogLevel string UpdateTimeout time.Duration OptInLabel string } // Load reads configuration from environment variables, applies defaults, // and validates required fields. Returns an error if validation fails so // the service can fail-fast at startup. func Load() (*Config, error) { cfg := &Config{ APIKey: os.Getenv("UPDATER_API_KEY"), StacksRoot: getenvDefault("STACKS_ROOT", "/home/shcizo/self-hosted"), Port: getenvDefault("PORT", "8080"), LogLevel: getenvDefault("LOG_LEVEL", "info"), OptInLabel: getenvDefault("OPT_IN_LABEL", "se.shcizo.auto-update"), } if cfg.APIKey == "" { return nil, errors.New("UPDATER_API_KEY is required") } timeoutStr := getenvDefault("UPDATE_TIMEOUT", "5m") d, err := time.ParseDuration(timeoutStr) if err != nil { return nil, fmt.Errorf("UPDATE_TIMEOUT %q is not a valid duration: %w", timeoutStr, err) } cfg.UpdateTimeout = d return cfg, nil } func getenvDefault(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback }