Node's ESM resolver does not consult NODE_PATH (unlike CJS require), so
an ESM postcss.config.js shipped by a Hugo theme fails when loaded from
the module cache: bare imports like `import x from "postcss-import"`
have no node_modules to walk up to.
Install a synchronous resolver hook (module.registerHooks) via
--import=data:... on every Node invocation. On ERR_MODULE_NOT_FOUND for
a bare specifier it resolves the package from each NODE_PATH entry via
createRequire().resolve(). No-op for relative, absolute, URL-scheme and
non-MODULE_NOT_FOUND failures. Synchronous hooks run on the main thread,
so no --allow-worker is needed under the Node permission model.
Fixes#13987
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
If a non-default-name file in the config folder parses to a map with a
single top-level key matching the file's basename, unwrap it. This lets
TOML/YAML express slice-typed roots (cascade, permalinks), which can't
have a headless top-level array, and also lets users copy-paste docs
examples that include the root container (e.g. params.yaml with a
top-level params: block).
Fixes#12899Fixes#14882
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A stale or removed resource used by js.Batch could panic while the esbuild import loader read its content during a rebuild. Return the read error through the loader so esbuild reports a normal build error and a later rebuild can recover when the file returns.
Closes#13737
Smartcrop can return a crop rectangle that is smaller than the requested dimensions after prescaling and rounding. Expand that rectangle within the source image bounds before applying Hugo's crop/fill pipeline, so smart crops keep the requested size without stretching the image.
Bump the smart crop cache version for crop/fill only.
Fixes#13688
Co-Authored-By: Joe Mooring <joe.mooring@veriphor.com>
* Note for themes, this is only an issue for themes stored locally, e.g. below `themes/...`. Themes mounted as modules from GitHub gets symlinks stripped away.
* Thas was also not an issue for file reading walking one or more directories.
* This is an regression introduced in `v0.123.0`.
A server allowed by security.http.urls could redirect resources.GetRemote
to a host that is not. Re-run the check on each hop via CheckRedirect.
Fixes#14871
When CSS imports assets via the file loader (fonts, images), the emitted
URLs were relative to the CSS output directory. That broke when the CSS
was inlined into HTML, since browsers then resolved the URLs against the
page rather than the CSS file.
Set esbuild's PublicPath to the CSS output directory joined with the
site base path so URLs work whether the CSS is published as a file or
inlined.
Fixes#14849
These keys are reserved at the top level of front matter, but are
legitimate user params under cascade.params. Only fire the deprecation
when the key was actually set at the top level of the original front
matter.
Fixes#14848
Fall back to global resources via resources.Get when page resources
don't match for named images in the images front matter parameter.
This aligns get-page-images.html with the existing behavior in
render-image.html, render-link.html, and figure.html.
Fixes#14062
Domains like 1password.com and 37signals.com were blocked by the default
allow rule '^https?://[a-z]'. Allow [a-z0-9] for the first hostname char
and add an explicit deny for hosts whose first label is all-digit (IP
literals like 127.0.0.1) to retain the prior SSRF protections.
Fixes#14837
When the server returns a temporary HTTP error (e.g. 429 or 503)
together with a Retry-After header, use that value as the next sleep
duration instead of the default exponential backoff. The Retry-After
value is also surfaced in the retry-timeout error message.
Fixes#14828
And be specific about which commit we use.
Hugo treat this as an upstream dependency, so we would appreciate that any bugs will be reported and fixed upstream.
See #14823
Some Linux setups trigger detect-libc's spawnSync('getconf') fallback
when process.report does not expose glibcVersionRuntime, breaking
tailwindcss under the Node permission model. Add AllowChildProcess
mirroring AllowAddons/AllowWorker, default to ["tailwindcss"], and
emit --allow-child-process accordingly.
Fixes#14824
Allow CSS variables to be grouped under sub-paths and imported via
@import "hugo:vars/mobile" (or @use for Dart Sass), so callers can pass
nested dicts like:
{{ dict "primary-color" "blue" "mobile" (dict "primary-color" "red") }}
Top-level "hugo:vars" now skips nested map entries instead of emitting
garbage for them.
Fixes#14705
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Whitelist now treats any pattern prefixed with "! " (the same negation
prefix used by hglob/predicate) as a deny rule. Deny matches take
precedence over allow, and a whitelist made up exclusively of deny
rules implicitly allows everything it does not deny.
The default security.http.urls now reads:
urls = ['(?i)^https?://[a-z]', '! (?i)localhost', '! @']
i.e. allow URLs whose host starts with a letter (the common
"https://example.com" shape), deny anything that looks like localhost,
and deny URLs with userinfo to foil "http://user@127.0.0.1/" bypasses.
Public IP literals are collateral blocks; users who need them (or their
own private hosts) override security.http.urls as before, mixing allow
and deny rules with the same "! " prefix, e.g.
[security.http]
urls = ['.*', '! ^https?://evil\.example\.com']
Fixes#14792