Typed config section adapters¶
Reusable packages no longer read config.Containable inside their cores. Each
extraction-candidate package now owns a typed settings struct (with
mapstructure tags), and GTB reads config into that struct at an adapter
boundary. The practical rule for callers:
- Core constructors take typed settings (and a
*slog.Logger— see Logger slog-first boundary). - Framework callers that read GTB config use the
*FromContainable/*FromConfig/*FromPropsadapter, which preserves the existing config keys, precedence, env binding, and hot-reload behaviour.
This is an intentional pre-1.0 breaking change. The config keys themselves are unchanged — only the Go API moved.
New pkg/config APIs (for adapter authors)¶
If you write your own adapters, these read a resolved config section into a typed struct:
// one-shot
section, err := config.UnmarshalSection[http.ServerSettings](cfg, "server.http")
_ = section.Value // T
_ = section.Exists // was the section present?
// long-lived / reload-aware: re-unmarshals on each successful reload,
// retains the last valid snapshot on a rejected reload, exposes Version()
observed, err := config.ObserveSection[http.ServerSettings](cfg, "server.http",
config.WithSectionValidator(validate),
config.WithSectionApply(apply),
)
// source-aware existence, distinct from a defaulted zero value
if cfg.SectionExists("telemetry") { ... }
config.WithLogger and config.NewContainerFromViper now take a *slog.Logger.
Transports (pkg/http, pkg/grpc)¶
Core Register/Start now take a typed ServerSettings and a *slog.Logger;
the config-reading forms were renamed. Rename the call, keep the arguments:
// before
srv, _ := grpc.Register(ctx, "grpc", controller, cfg, log)
controls.WithStart(grpc.Start(cfg, log, srv))
// after
srv, _ := grpc.RegisterFromContainable(ctx, "grpc", controller, cfg, log)
controls.WithStart(grpc.StartFromContainable(cfg, log, srv))
The same applies to http.Register → http.RegisterFromContainable and
http.Start* → http.StartFromContainable. Stop keeps its name but now takes a
*slog.Logger (grpc.Stop(logger.ToSlog(log), srv)). For reload-aware
composition, bind long-lived servers with ObserveServerSettingsFromConfig
(exposes Current() / Version()); NewServerFromContainable remains for
one-shot construction.
Gateway (pkg/gateway)¶
gateway.Register core takes typed http.ServerSettings + a prepared
*grpc.ClientConn; the config-driven entrypoints are
gateway.RegisterFromContainable (raw config.Containable) and
gateway.RegisterFromConfig. ObserveSettingsFromConfig backs reload-aware
gateways.
TLS (pkg/tls)¶
TLS resolution is now typed. The core is tls.ResolvePair(shared, transport,
overrides) Pair and Pair.ServerConfig(...); GTB reads it with the adapter:
VCS release providers (pkg/vcs/*)¶
Provider constructors take typed settings instead of config.Containable:
// before
p, err := gitlab.NewReleaseProvider(cfg) // config.Containable subtree
// after
settings := gitlab.SettingsFromConfig(src, tokenCfg) // GTB adapter builds it
p, err := gitlab.NewReleaseProvider(settings)
The same shape applies to the github, gitea, bitbucket, and direct
providers.
Related notes (same refactor, package-specific)¶
- Chat settings constructors —
chat.New(ctx, Settings)/chat.NewFromProps. - Telemetry observability settings —
telemetry.Setup(ObservabilitySettings)/SetupFromProps;otelcoreObserveSettingsFromConfig. - Telemetry value types moved to
pkg/telemetrytypes. - Logger slog-first boundary — the
*slog.Loggerside of the same core/adapter split.