Releases: stamat/poops-images
Release list
v1.4.0
A 900-line README is where a fact goes to hide. Everything was in it and nothing
was findable: no search, no table of contents, and a crop anchor grid eleven
screens below the flag that needs it.
Added
- A documentation site at https://stamat.info/poops-images/, built with
Poops fromsite/srcand published by a
GitHub Actions workflow on every push tomain. Same content as the README,
one page per topic, with search and a table of contents.npm run docs
serves it locally on port 4041;npm run docs:buildwritessite/dist. - A Quick examples page on that site — a recipe per job, runnable as
written: a responsive srcset set, square thumbnails, an anchored hero crop, an
LQIP placeholder, a watermark, watch mode. It is the only page without a
README counterpart, because it composes documented facts rather than adding
any.
Security
sharpmoved from^0.33.0to^0.35.0, which closes four libvips
vulnerabilities inherited by every 0.33 and 0.34 release
(GHSA-f88m-g3jw-g9cj:
CVE-2026-33327, CVE-2026-33328, CVE-2026-35590, CVE-2026-35591). There is no
patched 0.33 line, so the upgrade is the only fix.
Changed
- The default
includeglob now namessvgandgifalongside the raster
formats, becauseincludegoverns every pipeline. If your config sets a
custominclude— say"**/*.jpg"— SVGs and GIFs are no longer processed
unless the glob covers them; add them to the pattern to keep the old
behavior. - Node ≥ 20.9 is now the minimum, because sharp 0.35 dropped Node 18. On
Node 18 the install now fails outright rather than half-working;enginesin
package.jsonsays so, so npm warns before anything is written. - AVIF output is not byte-for-byte what it was. sharp 0.35 retuned lossy AVIF
around SSIMULACRA2 quality metrics, so the samequalitynumber lands on a
different file size — usually smaller. Nothing in the config changed; if you
have a size budget pinned to a byte count, re-measure it.
Fixed
- An output never overwrites its own source. With
inandoutpointing at
the same directory — the default is both"."— a conversion-only variant,
a minified SVG or a copied GIF landed on the file it came from, and because
the cache kept the pre-write mtime, every run recompressed the previous
run's recompression. Such writes are now refused and counted as errors;
suffixed variants (photo-300w.jpg) are unaffected. - The tool no longer eats its own output. With
outinsidein— say
-i . -o dist— every run re-ingested the previous run's variants, producing
dist/dist/dist/a-100w-100w-100w.jpgby the third build. The output subtree
is now excluded from discovery, and anything the cache records as a written
variant is dropped from the source list, in build and watch mode both. - Pointing at one file means one file.
--in photo.jpgused to run the raster
pipeline on that file and then minify every SVG and copy every GIF found
beside it, recursively, because SVG and GIF discovery ignoredinclude. All
three pipelines now read the sameincludeglob. - Watch mode obeys
includeandexclude. It used to process any supported
extension anywhere underin— the exclude globs were handed to the watcher
in a form it never matched, and the include glob was not consulted at all. A
watch event now runs through the same discovery predicate as a build, so a
file is processed on change exactly when a build would have picked it up. - The custom-handler cache holds one entry per handler file instead of one per
edit, so a long watch session editing handlers no longer grows it without
bound. Edited handlers still reload on the next run. - Preprocessor
sizesare validated like top-levelsizes. A typo in a crop
anchor —"crop": ["middle", "top"]— used to surface as a sharp error per
image at process time; it is now one config error at startup. - The CLI exits
1when any file failed to process. It used to exit0no
matter how many errors were logged, so a CI build over corrupt sources came
up green. A run that merely contains failures still completes — the exit
code is how CI hears about them. verbose: falsemeans quiet. The SVGMinified:line and the format
normalization notices (Opaque PNG → JPEG:and friends) printed for every
file regardless of the setting; they are per-file progress and now obey it.- Editing an SVG under watch regenerates its preprocessor variants. Watch mode
used to only re-minify the SVG, leaving variants from"svg": true
preprocessors stale until the next full build; both modes now share one SVG
processing path. - SVG failures count. An unreadable SVG or an SVGO parse error was logged but
leftstats.errorsat zero, so a build full of broken SVGs still reported
itself clean to any caller reading the stats. They now land in the same
error count as raster failures, in build and watch mode both. - One truncated image no longer kills the whole build. A source whose header
reads fine but whose body fails to decode used to abortprocessAll()— the
remaining images went unprocessed and the cache unsaved. It is now counted in
stats.errorslike any other bad file, and a failed decode leaves the
previous run's outputs and cache entry for that file untouched instead of
sweeping them as stale. - The
poops.jsonexample under Poops Integration in the README was missing
a comma between two size objects, so copying it out produced invalid JSON. The
test that checks every README config example against the schema parses each
fence and skips what will not parse, which is exactly how a syntax error hid
from it; it now reports on the docs site's examples as well.
Full Changelog: v1.3.0...v1.4.0
v1.3.0
A misspelt key was silently ignored: "quailty": 60 meant the default quality,
with nothing said about it, and the first sign was output that looked wrong.
Added
- A JSON Schema for the config, shipped in the
package atschema/poops-images.schema.json. Point$schemaat it and the
editor completes and checks the whole config as you type — see the Config
file section of the README for both the local and the GitHub URL. - Unknown config keys are named as they load:
[info] unknown key "quailty" — ignored. Valid: …, with the path for nested ones (in sizes[0]). Key names
only; a wrong type still throws where it always did. A schema file that
cannot be read leaves the config to load unadvised rather than taking the run
down over a warning.
Changed
- The config is validated once, in the
ImageProcessorconstructor, which is
the one place that cannot trust what it is handed — a library caller can
build a config without going through the file loader at all.loadConfig()
now returns the file as read, so anything reading a default off its result
before handing it to the processor seesundefinedwhere it used to see the
default. The CLI and the documentednew ImageProcessor(config)path behave
as they did, minus the duplicate warnings.
Full Changelog: v1.2.1...v1.3.0
v1.2.1
named sizes default image and cropping not enough pixels mitigation
Full Changelog: v1.2.0...v1.2.1
v1.2.0
⚠️ Breaking change
CLI options changed
--verboseCLI option introduced,falseby default, replaces-q, --quietwhich had an opposite functionality.-qis now a shorthand for--qualityinstead of-Q
Added
verboseconfig option (default:false).processAll()stats now include anerrorscount.- New tests for:
- error counting on corrupt images
- verbose log gating behavior
- README docs for the
asciipreprocessor outputs (.txtandsvgsidecars).
Fixed
- Corrupt/unsupported image inputs are now counted as errors without stopping processing of valid files.
- Windows test stability improvements:
- disabled
sharpcache during tests - retry-based fixture cleanup to avoid EBUSY unlink failures.
- disabled
- Test script now runs Jest via explicit Node invocation for more reliable VM modules usage.
Full Changelog: v1.1.0...v1.2.0
v1.1.0
enhance resizeFirst, additional testing - regression tests and exif tests, CI, windows path support
Full Changelog: v1.0.0...v1.1.0
v1.0.0
initial release
Full Changelog: https://github.com/stamat/poops-images/commits/v1.0.0