Hwaro::Core::Build::RemoteData
Constants
Overall wall-clock budget for one entry, spanning every redirect hop and every body read. READ_TIMEOUT bounds a single read OPERATION, so a source dripping one byte just inside it never trips a timeout at all and stalls the build indefinitely.
20 MiB: generous for a data payload, small enough that a misconfigured URL (a tarball, a video) can't balloon the build.
The braced no-default form of an env reference. Deliberately the
ONLY form checked: ${VAR:-fallback} was already resolved to its
fallback by the file-wide pass, and bare $WORD keeps its
warn-only behavior so a literal dollar sign in a URL can't break a
build.
Instance methods
Load one [[data.remote]] entry: serve it from a fresh disk cache
when the TTL allows, otherwise fetch it. Returns nil only for
on_error = "warn-and-skip" failures; fail (and an unusable
cache under warn-and-use-cache) raise a classified HwaroError.
now, max_bytes and deadline are parameters for the specs;
production callers use the defaults.
Parse a payload the same way data/ files parse, so a key can move
between a local file and a remote source without templates noticing —
both routes go through the one shared dispatcher. The BOM strip is
this caller's, matching data/: JSON and TOML both reject a leading
BOM outright.
The identity of the request entry makes, for the same two caches.
Headers are part of it: Accept-Language = "ko", a tenant header or
a rotated token asks the same url for a different payload, and a
fresh cache of the old one kept answering until the TTL ran out.
Header-less entries keep the plain url digest, so caches written
before headers counted stay valid.
${VAR} interpolation runs file-wide BEFORE config.toml is parsed,
so an unset variable simply leaves the literal ${VAR} text in the
value — which is what this detects.
It used to be a hard error inside Config.load, which meant
hwaro deploy, hwaro new and hwaro tool ... — none of which ever
fetch — aborted on a remote source they would never touch, while
serve (which rescues a failed config load) silently skipped its
[build] merge instead. Config load now validates shape only and
defers to here, the moment the entry is actually about to be used:
same code, same wording, same hint, blast radius of one entry.
Never echoes the value — header values hold credentials. Public so the serve-session memo can run it before deciding to reuse a payload: unsetting a header's variable mid-session is a config mistake, not a flaky source, and must not be papered over.
Explicit format wins; otherwise the response Content-Type, then
the URL's path extension. Returns nil when nothing matches.