custom

package
v1.20.1 Latest Latest
Warning

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

Go to latest
Published: Jul 27, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package custom implements user-defined mod sources configured declaratively via YAML files in <configDir>/sources/. See the design doc: docs/plans/2026-07-13-custom-sources-design.md

Index

Constants

View Source
const (
	TypeDirectory = "directory"
	TypeManifest  = "manifest"
	TypeAPI       = "api"
)

Source type identifiers for SourceDefinition.Type.

Variables

This section is empty.

Functions

func New

New constructs a ModSource from a validated definition. The default case is defensive: SourceDefinition.Validate already rejects unknown type strings, so it should be unreachable in practice, but New still returns a clear error instead of panicking if it is ever reached.

Types

type API added in v1.9.0

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

API is a ModSource backed by a declaratively-described GET+JSON REST API (design §4). Endpoints that the definition omits surface as ErrNotSupported capability gaps rather than errors at load time.

func NewAPI added in v1.9.0

func NewAPI(def SourceDefinition) (*API, error)

NewAPI constructs an api source from a validated definition. It performs no I/O — a valid definition always registers; request problems surface as operation errors.

func (*API) AuthURL added in v1.9.0

func (a *API) AuthURL() string

AuthURL implements source.ModSource; api sources use API keys, not OAuth.

func (*API) Capabilities added in v1.9.0

func (a *API) Capabilities() source.Capabilities

Capabilities implements source.CapabilityReporter: an undefined endpoint is an unsupported capability (design §4/§7).

func (*API) CheckUpdates added in v1.9.0

func (a *API) CheckUpdates(ctx context.Context, installed []domain.InstalledMod) ([]domain.Update, error)

CheckUpdates implements source.ModSource generically via get_mod + version comparison (design §4). Per-mod fetch failures are collected and returned alongside partial results so a single flaky mod page doesn't hide the rest — and doesn't get silently skipped either.

func (*API) DownloadHeaders added in v1.9.0

func (a *API) DownloadHeaders(fileURL string) map[string]string

DownloadHeaders implements source.DownloadHeaderProvider: header-mode keys go only to downloads on the API's own origin (design §9).

func (*API) ExchangeToken added in v1.9.0

func (a *API) ExchangeToken(ctx context.Context, code string) (*source.Token, error)

ExchangeToken implements source.ModSource.

func (*API) GetDependencies added in v1.9.0

func (a *API) GetDependencies(ctx context.Context, mod *domain.Mod) ([]domain.ModReference, error)

GetDependencies implements source.ModSource; always unsupported in v1 (design §4).

func (*API) GetDownloadURL added in v1.9.0

func (a *API) GetDownloadURL(ctx context.Context, mod *domain.Mod, fileID string) (string, error)

GetDownloadURL implements source.ModSource via the download_url endpoint. Query-mode keys are appended only for same-origin download URLs (design §9).

func (*API) GetMod added in v1.9.0

func (a *API) GetMod(ctx context.Context, gameID, modID string) (*domain.Mod, error)

GetMod implements source.ModSource via the get_mod endpoint. gameID feeds the {game_id} placeholder and is echoed onto the returned mod for downstream attribution (the persisted row is normalized by the installer).

func (*API) GetModFiles added in v1.9.0

func (a *API) GetModFiles(ctx context.Context, mod *domain.Mod) ([]domain.DownloadableFile, error)

GetModFiles implements source.ModSource via the mod_files endpoint.

func (*API) ID added in v1.9.0

func (a *API) ID() string

ID implements source.ModSource.

func (*API) IsAuthenticated added in v1.9.0

func (a *API) IsAuthenticated() bool

IsAuthenticated reports whether an API key is configured.

func (*API) Name added in v1.9.0

func (a *API) Name() string

Name implements source.ModSource.

func (*API) Search added in v1.9.0

func (a *API) Search(ctx context.Context, query source.SearchQuery) (source.SearchResult, error)

Search implements source.ModSource by executing the search endpoint template and mapping the results (design §4). An undefined search endpoint is an unsupported capability.

func (*API) SetAPIKey added in v1.9.0

func (a *API) SetAPIKey(key string)

SetAPIKey provides the API key resolved at startup (env var or token store).

type APIConfig

type APIConfig struct {
	BaseURL   string       `yaml:"base_url"`
	PageStart *int         `yaml:"page_start"` // nil = default 1; explicit 0 respected
	Auth      *AuthConfig  `yaml:"auth"`
	Endpoints APIEndpoints `yaml:"endpoints"`
	Mappings  APIMappings  `yaml:"mappings"`
}

APIConfig configures a declarative REST source (expanded in Phase 4).

type APIEndpoints added in v1.9.0

type APIEndpoints struct {
	Search      *EndpointConfig `yaml:"search"`
	GetMod      *EndpointConfig `yaml:"get_mod"`
	ModFiles    *EndpointConfig `yaml:"mod_files"`
	DownloadURL *EndpointConfig `yaml:"download_url"`
}

APIEndpoints defines optional endpoint configurations for an API source.

type APIKeyConfig added in v1.7.0

type APIKeyConfig struct {
	In   string `yaml:"in"`   // "header" or "query"
	Name string `yaml:"name"` // header name or query parameter name
}

APIKeyConfig says where the API key is attached on requests.

type APIMappings added in v1.9.0

type APIMappings struct {
	Mod  map[string]string `yaml:"mod"` // domain field key -> JSON dot-path
	File map[string]string `yaml:"file"`
}

APIMappings maps domain field keys to JSON dot-paths.

type AuthConfig added in v1.7.0

type AuthConfig struct {
	APIKey *APIKeyConfig `yaml:"api_key"`
}

AuthConfig configures optional API-key authentication for a custom source. The key itself is never stored in the definition; it comes from the LMM_<ID>_API_KEY env var or the DB token store at startup.

type Directory

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

Directory is a ModSource backed by a local directory: each subdirectory (or .zip/.jar archive) is one mod. The directory is rescanned on each operation so edits show up without restarting lmm; scans are local and cheap.

func NewDirectory

func NewDirectory(def SourceDefinition) (*Directory, error)

NewDirectory constructs a directory source from a validated definition. The configured path must exist and be a directory.

func (*Directory) AuthURL

func (d *Directory) AuthURL() string

AuthURL implements source.ModSource; directory sources need no auth.

func (*Directory) Capabilities

func (d *Directory) Capabilities() source.Capabilities

Capabilities implements source.CapabilityReporter.

func (*Directory) CheckUpdates

func (d *Directory) CheckUpdates(ctx context.Context, installed []domain.InstalledMod) ([]domain.Update, error)

CheckUpdates implements source.ModSource by comparing installed versions to the current scan.

func (*Directory) ExchangeToken

func (d *Directory) ExchangeToken(ctx context.Context, code string) (*source.Token, error)

ExchangeToken implements source.ModSource.

func (*Directory) GetDependencies

func (d *Directory) GetDependencies(ctx context.Context, mod *domain.Mod) ([]domain.ModReference, error)

GetDependencies implements source.ModSource; directory mods declare none.

func (*Directory) GetDownloadURL

func (d *Directory) GetDownloadURL(ctx context.Context, mod *domain.Mod, fileID string) (string, error)

GetDownloadURL implements source.ModSource, returning a file:// URL that Service.DownloadModToCache ingests by local copy instead of HTTP download.

func (*Directory) GetMod

func (d *Directory) GetMod(ctx context.Context, gameID, modID string) (*domain.Mod, error)

GetMod implements source.ModSource. gameID is accepted from any game and not used to look up the mod (see Search); it is echoed onto the returned mod so downstream installs are attributed to the correct game.

func (*Directory) GetModFiles

func (d *Directory) GetModFiles(ctx context.Context, mod *domain.Mod) ([]domain.DownloadableFile, error)

GetModFiles implements source.ModSource: every mod has exactly one synthetic file ("main") representing its directory or archive.

func (*Directory) ID

func (d *Directory) ID() string

ID implements source.ModSource.

func (*Directory) Name

func (d *Directory) Name() string

Name implements source.ModSource.

func (*Directory) Search

Search implements source.ModSource with client-side matching: case-insensitive substring on name and summary; name matches rank first, then alphabetical. GameID is accepted from any game (a directory source applies to any game that maps it — it does not filter by GameID) but is echoed onto every returned mod so downstream installs are attributed to the correct game.

type DirectoryConfig

type DirectoryConfig struct {
	Path string `yaml:"path"`
}

DirectoryConfig configures a local-directory source.

type EndpointConfig added in v1.9.0

type EndpointConfig struct {
	Path  string `yaml:"path"`  // required; may contain {placeholders}
	List  string `yaml:"list"`  // dot-path to results array (required for search & mod_files)
	Total string `yaml:"total"` // optional dot-path to total count (search only)
	Field string `yaml:"field"` // dot-path to a scalar (required for download_url)
}

EndpointConfig configures a single API endpoint.

type Manifest added in v1.7.0

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

Manifest is a ModSource backed by a published mod-list document (design §3). Remote manifests are fetched on demand and cached in memory for the configured TTL; local paths are read on every operation (cheap). Construction is pure: a valid definition always registers, and fetch/parse problems surface as operation errors naming the manifest URL.

func NewManifest added in v1.7.0

func NewManifest(def SourceDefinition) (*Manifest, error)

NewManifest constructs a manifest source from a validated definition. It performs no I/O — the manifest is first fetched when an operation needs it.

func (*Manifest) AuthURL added in v1.7.0

func (m *Manifest) AuthURL() string

AuthURL implements source.ModSource; manifest sources use API keys, not OAuth.

func (*Manifest) Capabilities added in v1.7.0

func (m *Manifest) Capabilities() source.Capabilities

Capabilities implements source.CapabilityReporter. Auth reflects whether the definition declares an auth block.

func (*Manifest) CheckUpdates added in v1.7.0

func (m *Manifest) CheckUpdates(ctx context.Context, installed []domain.InstalledMod) ([]domain.Update, error)

CheckUpdates implements source.ModSource by comparing installed versions to the current manifest.

func (*Manifest) DownloadHeaders added in v1.7.0

func (m *Manifest) DownloadHeaders(fileURL string) map[string]string

DownloadHeaders implements source.DownloadHeaderProvider. Header-mode auth applies the same key to file downloads as to manifest fetches (design §6), but for remote manifests only when the file URL is same-origin (scheme and host, via sameOrigin) with the manifest — a manifest pointing files at a third-party CDN, or downgrading from https to http on the same host, must not ship the repo's key there. Local-path manifests are user-authored and trusted, so their configured key attaches regardless of host.

func (*Manifest) ExchangeToken added in v1.7.0

func (m *Manifest) ExchangeToken(ctx context.Context, code string) (*source.Token, error)

ExchangeToken implements source.ModSource.

func (*Manifest) GetDependencies added in v1.7.0

func (m *Manifest) GetDependencies(ctx context.Context, mod *domain.Mod) ([]domain.ModReference, error)

GetDependencies implements source.ModSource: manifest dependencies are IDs within this source, returned as ModReferences for the resolver.

func (*Manifest) GetDownloadURL added in v1.7.0

func (m *Manifest) GetDownloadURL(ctx context.Context, mod *domain.Mod, fileID string) (string, error)

GetDownloadURL implements source.ModSource. Query-mode auth is appended here — for remote manifests, only when the file URL is same-origin with the manifest (see sameOrigin); a manifest pointing files at a third-party CDN must not ship the repo's key there via the URL either. Header-mode auth rides via DownloadHeaders (see DownloadHeaderProvider) under the same rule.

func (*Manifest) GetMod added in v1.7.0

func (m *Manifest) GetMod(ctx context.Context, gameID, modID string) (*domain.Mod, error)

GetMod implements source.ModSource. gameID does not filter (install-by-ID works from any game); it is echoed onto the returned mod for attribution.

func (*Manifest) GetModFiles added in v1.7.0

func (m *Manifest) GetModFiles(ctx context.Context, mod *domain.Mod) ([]domain.DownloadableFile, error)

GetModFiles implements source.ModSource, mapping manifest file entries — including declared sha256 checksums — onto DownloadableFiles.

func (*Manifest) ID added in v1.7.0

func (m *Manifest) ID() string

ID returns the source ID.

func (*Manifest) IsAuthenticated added in v1.7.0

func (m *Manifest) IsAuthenticated() bool

IsAuthenticated reports whether an API key is configured. Only meaningful when the definition declares auth (Capabilities().Auth).

func (*Manifest) Name added in v1.7.0

func (m *Manifest) Name() string

Name returns the source name.

func (*Manifest) Search added in v1.7.0

Search implements source.ModSource with the shared client-side semantics (design §5), filtered by the manifest's per-mod game_ids.

func (*Manifest) SetAPIKey added in v1.7.0

func (m *Manifest) SetAPIKey(key string)

SetAPIKey provides the API key resolved at startup (env var or token store).

type ManifestConfig

type ManifestConfig struct {
	URL     string      `yaml:"url"`
	Refresh string      `yaml:"refresh"` // Go duration string, e.g. "15m"; empty = default
	Auth    *AuthConfig `yaml:"auth"`
}

ManifestConfig configures a manifest source (Phase 3).

type SourceDefinition

type SourceDefinition struct {
	ID        string           `yaml:"id"`
	Name      string           `yaml:"name"`
	Type      string           `yaml:"type"`
	AllowHTTP bool             `yaml:"allow_http"`
	Directory *DirectoryConfig `yaml:"directory"`
	Manifest  *ManifestConfig  `yaml:"manifest"`
	API       *APIConfig       `yaml:"api"`
}

SourceDefinition is one user-defined source, parsed from a YAML file in <configDir>/sources/. Exactly one of Directory/Manifest/API must be set, matching Type.

func (*SourceDefinition) Validate

func (d *SourceDefinition) Validate() error

Validate checks the definition for structural errors. It does not touch the filesystem or network; existence checks happen when the source is constructed.

Directories

Path Synopsis
Package metadata extracts mod metadata from well-known files inside a mod directory (e.g.
Package metadata extracts mod metadata from well-known files inside a mod directory (e.g.

Jump to

Keyboard shortcuts

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