semantic-release-bot
6aacb4f3a9
chore(release): 2.2.0 [skip ci]
...
# [2.2.0](https://github.com/snapotter-hq/snapotter/compare/v2.1.0...v2.2.0 ) (2026-07-29)
### Bug Fixes
* **a11y:** focus indicators meet the 3:1 non-text contrast bar ([#574 ](https://github.com/snapotter-hq/snapotter/issues/574 )) ([6339370 ](https://github.com/snapotter-hq/snapotter/commit/63393700939e34ad3d847043b03728e3c2907445 )), closes [#A85518](https://github.com/snapotter-hq/snapotter/issues/A85518 ) [#F0A766](https://github.com/snapotter-hq/snapotter/issues/F0A766 )
* **a11y:** WCAG AA contrast retune for the Otter Orange palette ([#567 ](https://github.com/snapotter-hq/snapotter/issues/567 )) ([5102262 ](https://github.com/snapotter-hq/snapotter/commit/51022628dc19d8a03525bab98473f3c23b1a2709 )), closes [#E07832](https://github.com/snapotter-hq/snapotter/issues/E07832 ) [#1A1814](https://github.com/snapotter-hq/snapotter/issues/1A1814 )
* **ai-bridge:** surface sidecar exit reasons in Sentry via SafeError ([#538 ](https://github.com/snapotter-hq/snapotter/issues/538 )) ([55e1e95 ](https://github.com/snapotter-hq/snapotter/commit/55e1e95f20792cae4f1f2257bafe839b83332c93 ))
* **ai-bundles:** stop CPU onnxruntime from clobbering onnxruntime-gpu ([#544 ](https://github.com/snapotter-hq/snapotter/issues/544 )) ([c8629c9 ](https://github.com/snapotter-hq/snapotter/commit/c8629c9d22b455b6deac206e3816ae0f730f06c6 )), closes [#490 ](https://github.com/snapotter-hq/snapotter/issues/490 )
* **ai:** advance the progress bar during upscale and background removal ([#608 ](https://github.com/snapotter-hq/snapotter/issues/608 )) ([e56edc6 ](https://github.com/snapotter-hq/snapotter/commit/e56edc659f742430798104b52a08806a8d8fbff2 )), closes [#591 ](https://github.com/snapotter-hq/snapotter/issues/591 )
* **ai:** warn that upscale and background removal are slow without a GPU ([#605 ](https://github.com/snapotter-hq/snapotter/issues/605 )) ([d43208b ](https://github.com/snapotter-hq/snapotter/commit/d43208b85e1ba1f0ac687970b8fb52ca1738ae15 )), closes [#591 ](https://github.com/snapotter-hq/snapotter/issues/591 )
* **api:** contain library stored-name path traversal ([#600 ](https://github.com/snapotter-hq/snapotter/issues/600 )) ([4333432 ](https://github.com/snapotter-hq/snapotter/commit/43334324c446c53eb1dc2f8ef14cbecca4e2a676 ))
* **api:** enforce job ownership on cancel endpoint ([#599 ](https://github.com/snapotter-hq/snapotter/issues/599 )) ([577d74b ](https://github.com/snapotter-hq/snapotter/commit/577d74bdb134d9a7d02c27ba976731839d071e63 ))
* **api:** gate every tool endpoint and stop ZIP streams failing quietly ([#646 ](https://github.com/snapotter-hq/snapotter/issues/646 )) ([2d8b57c ](https://github.com/snapotter-hq/snapotter/commit/2d8b57c57fad4e1d98ab7eb327198809aa64bd09 )), closes [#645 ](https://github.com/snapotter-hq/snapotter/issues/645 ) [#643 ](https://github.com/snapotter-hq/snapotter/issues/643 ) [#645 ](https://github.com/snapotter-hq/snapotter/issues/645 )
* **api:** wait for Postgres and Redis at startup instead of crash-looping ([#537 ](https://github.com/snapotter-hq/snapotter/issues/537 )) ([4ac89fe ](https://github.com/snapotter-hq/snapotter/commit/4ac89fe6505e50645174e8de5fcdc40c46420cc4 ))
* **audio:** expose sample rate setting in Convert Audio ([#561 ](https://github.com/snapotter-hq/snapotter/issues/561 )) ([d4eaa65 ](https://github.com/snapotter-hq/snapotter/commit/d4eaa655b24236da5633006871415afbf0c92d08 )), closes [#558 ](https://github.com/snapotter-hq/snapotter/issues/558 )
* **auth:** close the MFA policy lockout and add self-service enrollment ([#531 ](https://github.com/snapotter-hq/snapotter/issues/531 )) ([190d4c2 ](https://github.com/snapotter-hq/snapotter/commit/190d4c2a002c6d3d240ff18480e37217fcbeae12 )), closes [#529 ](https://github.com/snapotter-hq/snapotter/issues/529 ) [#515 ](https://github.com/snapotter-hq/snapotter/issues/515 )
* **auth:** give OIDC/SAML logins a real MFA challenge instead of a hard block ([#536 ](https://github.com/snapotter-hq/snapotter/issues/536 )) ([bbfcbe9 ](https://github.com/snapotter-hq/snapotter/commit/bbfcbe9c8212afb244bb2738a6e3643d06dcee68 )), closes [#533 ](https://github.com/snapotter-hq/snapotter/issues/533 )
* **background-removal:** surface failures with a diagnosable SafeError ([#535 ](https://github.com/snapotter-hq/snapotter/issues/535 )) ([43ddf96 ](https://github.com/snapotter-hq/snapotter/commit/43ddf96ccf7baf94416050ec6229efca68124679 ))
* **ci:** repair the chronically-failing nightly workflow ([#624 ](https://github.com/snapotter-hq/snapotter/issues/624 )) ([44f5aea ](https://github.com/snapotter-hq/snapotter/commit/44f5aea3268f022641832af4b8c60cbd2d5e2c7e ))
* **compress-pdf:** land close to the target size, honestly ([#522 ](https://github.com/snapotter-hq/snapotter/issues/522 )) ([7d938af ](https://github.com/snapotter-hq/snapotter/commit/7d938af1f9e601238fd49af4c2cd157d16616266 ))
* **deps:** patch 4 HIGH/CRITICAL transitive CVEs (fast-uri, svgo, sharp, tar) ([#619 ](https://github.com/snapotter-hq/snapotter/issues/619 )) ([10a2aab ](https://github.com/snapotter-hq/snapotter/commit/10a2aabe589b5afd470f6c47ccdb1bf8bca15c02 ))
* **doc-engine:** guard sidecar JSON parsing against non-JSON stdout ([#532 ](https://github.com/snapotter-hq/snapotter/issues/532 )) ([a2cb1a8 ](https://github.com/snapotter-hq/snapotter/commit/a2cb1a8261b2669ae7e656a418999b70a37f6b4f ))
* **docker:** harden Postgres readiness checks in compose and startup ([#595 ](https://github.com/snapotter-hq/snapotter/issues/595 )) ([4ba7503 ](https://github.com/snapotter-hq/snapotter/commit/4ba7503f15a4444c4937576dbcadafdb19a8848d )), closes [#592 ](https://github.com/snapotter-hq/snapotter/issues/592 )
* **docs:** keep the nav within the viewport on tablets and laptops ([#570 ](https://github.com/snapotter-hq/snapotter/issues/570 )) ([69f72a6 ](https://github.com/snapotter-hq/snapotter/commit/69f72a6c712512e8489b23bcf78a233d872d897c )), closes [#556 ](https://github.com/snapotter-hq/snapotter/issues/556 )
* **docs:** keep the translated locale trees out of the search index ([#662 ](https://github.com/snapotter-hq/snapotter/issues/662 )) ([42e1dc9 ](https://github.com/snapotter-hq/snapotter/commit/42e1dc9799f60c7dde46b9485e5f37a5a29630ae ))
* **docs:** localize the docs homepage, nav, and sidebar chrome across 20 languages ([#547 ](https://github.com/snapotter-hq/snapotter/issues/547 )) ([9247947 ](https://github.com/snapotter-hq/snapotter/commit/92479477042740d7026de9b9bb3c71eeb0668231 ))
* **download:** ask reverse proxies not to buffer file downloads ([#604 ](https://github.com/snapotter-hq/snapotter/issues/604 )) ([89d7585 ](https://github.com/snapotter-hq/snapotter/commit/89d75853f45c98d6e9cae661dbda02bc8285009b )), closes [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 )
* **download:** reset the socket when a stream is shorter than Content-Length ([#617 ](https://github.com/snapotter-hq/snapotter/issues/617 )) ([0467e87 ](https://github.com/snapotter-hq/snapotter/commit/0467e87bfe410b313fa21d9758f8c162b12113a6 )), closes [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 ) [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 ) [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 )
* **editor:** repair rotate/flip/resize, levels/curves, filters, and layer lock ([#597 ](https://github.com/snapotter-hq/snapotter/issues/597 )) ([a6bce68 ](https://github.com/snapotter-hq/snapotter/commit/a6bce6825ae27890951becf7c858d4626c513714 ))
* enforce role authority for user management ([#616 ](https://github.com/snapotter-hq/snapotter/issues/616 )) ([1f8a42e ](https://github.com/snapotter-hq/snapotter/commit/1f8a42e54822142132270df1aefa768f4626613f ))
* enforce settings authority boundaries ([#618 ](https://github.com/snapotter-hq/snapotter/issues/618 )) ([44d8109 ](https://github.com/snapotter-hq/snapotter/commit/44d8109486aa6efd9383e573f0a36deb4ffda460 ))
* **erase-object:** crop-based HD inpainting to remove ghosting and blur ([#501 ](https://github.com/snapotter-hq/snapotter/issues/501 )) ([380419d ](https://github.com/snapotter-hq/snapotter/commit/380419dd0603693ad542082bd6197e6505f9b1e9 )), closes [#491 ](https://github.com/snapotter-hq/snapotter/issues/491 ) [hi#res](https://github.com/hi/issues/res ) [#141 ](https://github.com/snapotter-hq/snapotter/issues/141 )
* **files:** decode CLI-decoded formats before URL-import preview generation ([#637 ](https://github.com/snapotter-hq/snapotter/issues/637 )) ([841f47f ](https://github.com/snapotter-hq/snapotter/commit/841f47f6ca25e79dc56dc1e735afa37f02023f99 )), closes [#634 ](https://github.com/snapotter-hq/snapotter/issues/634 )
* **files:** store null instead of 0x0 for undecoded upload dimensions ([#636 ](https://github.com/snapotter-hq/snapotter/issues/636 )) ([511633f ](https://github.com/snapotter-hq/snapotter/commit/511633fa1c76f00fe9c4e2a0935a02b5601cae6a )), closes [#635 ](https://github.com/snapotter-hq/snapotter/issues/635 )
* give remove-background job timeouts an actionable failure message ([#518 ](https://github.com/snapotter-hq/snapotter/issues/518 )) ([58121f2 ](https://github.com/snapotter-hq/snapotter/commit/58121f205f7ae2b34b3d789c80db37c8bf0950bf )), closes [#494 ](https://github.com/snapotter-hq/snapotter/issues/494 )
* **help:** render the help dialog from i18n instead of hardcoded English ([#647 ](https://github.com/snapotter-hq/snapotter/issues/647 )) ([2848dd0 ](https://github.com/snapotter-hq/snapotter/commit/2848dd0e53d8a7c1e19ee82c1a1f2d485380d356 )), closes [#644 ](https://github.com/snapotter-hq/snapotter/issues/644 )
* honor unlimited processing timeout ([#638 ](https://github.com/snapotter-hq/snapotter/issues/638 )) ([025851b ](https://github.com/snapotter-hq/snapotter/commit/025851beefaac6f8d12c1dbcdb69276965072ac9 ))
* **image-tools:** surface Sharp encode failures instead of "Error: Error" ([#534 ](https://github.com/snapotter-hq/snapotter/issues/534 )) ([9cccbc9 ](https://github.com/snapotter-hq/snapotter/commit/9cccbc957681f8d12547e87be0e335f98e789cb7 ))
* **image:** decode real iPhone HEIC files instead of rejecting them at validation ([#631 ](https://github.com/snapotter-hq/snapotter/issues/631 )) ([098ed50 ](https://github.com/snapotter-hq/snapotter/commit/098ed50d0693ba181fae6f934bf427079e1f8e9f )), closes [#622 ](https://github.com/snapotter-hq/snapotter/issues/622 )
* **image:** image-to-pdf presets no longer 404 on 2+ files ([#633 ](https://github.com/snapotter-hq/snapotter/issues/633 )) ([330cf55 ](https://github.com/snapotter-hq/snapotter/commit/330cf559e00b6e5f1ca8df199cabee4c0fa650d0 )), closes [#627 ](https://github.com/snapotter-hq/snapotter/issues/627 )
* **jobs:** classify BullMQ stall (UnrecoverableError) as operational ([#610 ](https://github.com/snapotter-hq/snapotter/issues/610 )) ([e537cb0 ](https://github.com/snapotter-hq/snapotter/commit/e537cb04013d7bf4fd0fb125fb72f42f5a51917f ))
* **jobs:** make timeout messages tool-agnostic and CPU-aware ([#596 ](https://github.com/snapotter-hq/snapotter/issues/596 )) ([37c915c ](https://github.com/snapotter-hq/snapotter/commit/37c915c3da6b2183b0befe1521a643bb36edcce6 )), closes [#591 ](https://github.com/snapotter-hq/snapotter/issues/591 )
* **landing-i18n:** commit missed landing-seo re-translation (remove.bg comparison) ([b8c3700 ](https://github.com/snapotter-hq/snapotter/commit/b8c3700c15333b2eb328cab0979f8d943c15d7ab ))
* **landing,docs:** use build-time GitHub star count, drop per-page api.github.com fetch ([#560 ](https://github.com/snapotter-hq/snapotter/issues/560 )) ([54073a7 ](https://github.com/snapotter-hq/snapotter/commit/54073a7c501788dea49f77f6e94bdebb9b8f0f65 ))
* **landing:** derive conversion-preset copy from real format differences ([#663 ](https://github.com/snapotter-hq/snapotter/issues/663 )) ([a75a22d ](https://github.com/snapotter-hq/snapotter/commit/a75a22dd3ff8e675002a13da0ec12d00f91136c8 ))
* **landing:** keep mixed-case locale casing in emitted URLs ([#562 ](https://github.com/snapotter-hq/snapotter/issues/562 )) ([67f5434 ](https://github.com/snapotter-hq/snapotter/commit/67f54347b2ca711f40495fa7fcb05e132ea8f3da )), closes [#554 ](https://github.com/snapotter-hq/snapotter/issues/554 )
* **landing:** link English-only tool-detail and self-hosted pages to un-prefixed URLs ([#553 ](https://github.com/snapotter-hq/snapotter/issues/553 )) ([6ecc598 ](https://github.com/snapotter-hq/snapotter/commit/6ecc598fc4fc8fa6da5db9d9d0c66e53d2f2376d ))
* **landing:** open Product dropdown below the navbar bottom line ([#571 ](https://github.com/snapotter-hq/snapotter/issues/571 )) ([e3a01b6 ](https://github.com/snapotter-hq/snapotter/commit/e3a01b6be6fa077fa00c6c7245be7ba18b6e913c ))
* **landing:** rework footer badge/switcher layout ([#514 ](https://github.com/snapotter-hq/snapotter/issues/514 )) ([74e7d23 ](https://github.com/snapotter-hq/snapotter/commit/74e7d23abad924f04b348f00edf34e67188c4f2e ))
* **landing:** stop mangling #hash fragments in localized links ([#516 ](https://github.com/snapotter-hq/snapotter/issues/516 )) ([5bd0522 ](https://github.com/snapotter-hq/snapotter/commit/5bd052286c5a7920161b21cb791cc122fe3a1616 )), closes [#hash](https://github.com/snapotter-hq/snapotter/issues/hash )
* make OCR portable and reliable across AMD64 and ARM64 ([#519 ](https://github.com/snapotter-hq/snapotter/issues/519 )) ([991c981 ](https://github.com/snapotter-hq/snapotter/commit/991c981529c81ebb719199aba084db4c2d9a7c6f ))
* **ocr:** unblock and harden accurate-OCR install ([#552 ](https://github.com/snapotter-hq/snapotter/issues/552 )) ([bda4db3 ](https://github.com/snapotter-hq/snapotter/commit/bda4db3f358eebd659a1f8b7892112061a82b000 ))
* **pdf:** flag scanned PDFs in pdf-to-text and serve text as UTF-8 ([#603 ](https://github.com/snapotter-hq/snapotter/issues/603 )) ([7d37f6e ](https://github.com/snapotter-hq/snapotter/commit/7d37f6e6f5aa68aa5954182d76bb6ccf1c6b0649 )), closes [#589 ](https://github.com/snapotter-hq/snapotter/issues/589 )
* **pdf:** pdf-to-image presets no longer 404 on 2+ files ([#643 ](https://github.com/snapotter-hq/snapotter/issues/643 )) ([a713795 ](https://github.com/snapotter-hq/snapotter/commit/a7137958a158309ff8128490de96313e517ae554 )), closes [#627 ](https://github.com/snapotter-hq/snapotter/issues/627 ) [#633 ](https://github.com/snapotter-hq/snapotter/issues/633 ) [#632 ](https://github.com/snapotter-hq/snapotter/issues/632 )
* **pdf:** restore downloads on PDF conversion preset pages ([#629 ](https://github.com/snapotter-hq/snapotter/issues/629 )) ([e0a7aec ](https://github.com/snapotter-hq/snapotter/commit/e0a7aecde8f194b6375747a5a5f8ea4c57053813 )), closes [#623 ](https://github.com/snapotter-hq/snapotter/issues/623 )
* **pdf:** stop page tools failing on short and encrypted PDFs ([#594 ](https://github.com/snapotter-hq/snapotter/issues/594 )) ([73df107 ](https://github.com/snapotter-hq/snapotter/commit/73df1077580904c37d159dafe51a294b250bb074 ))
* preserve colored blocks in PDF-to-Word ([#500 ](https://github.com/snapotter-hq/snapotter/issues/500 )) ([e7cfc00 ](https://github.com/snapotter-hq/snapotter/commit/e7cfc00fe1d294256a0a4663797b8a8cdf58d8c0 ))
* **readme:** self-host the star history chart ([#625 ](https://github.com/snapotter-hq/snapotter/issues/625 )) ([90483c9 ](https://github.com/snapotter-hq/snapotter/commit/90483c944a4d4c912d3c5e2c09b2ee61bed3d150 ))
* release QA hardening across processing, media, security, and CI gates ([#649 ](https://github.com/snapotter-hq/snapotter/issues/649 )) ([d10d0f5 ](https://github.com/snapotter-hq/snapotter/commit/d10d0f544f2a093d2adb13cbd69d54a31c0cbf7a ))
* **release:** resolve the release by id, and make the vulnerability gate cover HIGH ([#661 ](https://github.com/snapotter-hq/snapotter/issues/661 )) ([935861b ](https://github.com/snapotter-hq/snapotter/commit/935861bced95cd778ea77d5a3741ff1da1a2ffed )), closes [#649 ](https://github.com/snapotter-hq/snapotter/issues/649 )
* **security:** bump Pillow to 12.3.0, fixes 5 disclosed CVEs ([#517 ](https://github.com/snapotter-hq/snapotter/issues/517 )) ([30d36d7 ](https://github.com/snapotter-hq/snapotter/commit/30d36d7949817751b869916775138dc4fa7a34d2 ))
* **security:** close the gaps a full 2.0 re-audit left open ([#620 ](https://github.com/snapotter-hq/snapotter/issues/620 )) ([079fcd2 ](https://github.com/snapotter-hq/snapotter/commit/079fcd2631216147db4b68acbcaca58ac4f93fb4 ))
* **seo:** emit clean docs URLs and de-index the demo ([#598 ](https://github.com/snapotter-hq/snapotter/issues/598 )) ([e6718ad ](https://github.com/snapotter-hq/snapotter/commit/e6718ada719e8931f643e1184aee354d4698c1da ))
* **settings:** let admins relax the minimum password length to 1 ([#543 ](https://github.com/snapotter-hq/snapotter/issues/543 )) ([846044a ](https://github.com/snapotter-hq/snapotter/commit/846044a463f18f490f7752b0cb6b4b225b107367 )), closes [#136 ](https://github.com/snapotter-hq/snapotter/issues/136 )
* **sign-pdf:** surface PDF load failures instead of a blank canvas ([#545 ](https://github.com/snapotter-hq/snapotter/issues/545 )) ([1f4878a ](https://github.com/snapotter-hq/snapotter/commit/1f4878ac4df417331a8cff9b8d5ab4da2edc788a ))
* **telemetry:** classify environmental database errors as operational ([#540 ](https://github.com/snapotter-hq/snapotter/issues/540 )) ([631d82e ](https://github.com/snapotter-hq/snapotter/commit/631d82eaae36a15d401c7408182d52a0754b1e36 ))
* **telemetry:** data-quality pass (opt-in noise, onboarding split, file_count, OIDC) ([#614 ](https://github.com/snapotter-hq/snapotter/issues/614 )) ([b20bca3 ](https://github.com/snapotter-hq/snapotter/commit/b20bca3c3c4ef3a63aca6ba420986d49bbeb905b )), closes [hi#level](https://github.com/hi/issues/level )
* **telemetry:** fingerprint stackless uncaught errors so they stop collapsing ([#611 ](https://github.com/snapotter-hq/snapotter/issues/611 )) ([82f5708 ](https://github.com/snapotter-hq/snapotter/commit/82f5708193984e863b95319e0e0ec8be47e46075 ))
* **telemetry:** sharpen Sentry signal for v2.1.0 residual defects ([#498 ](https://github.com/snapotter-hq/snapotter/issues/498 )) ([b457596 ](https://github.com/snapotter-hq/snapotter/commit/b4575966495c1a022154149832aedcd727d411e2 ))
* **telemetry:** surface AI sidecar and DOMException failure reasons in Sentry ([#612 ](https://github.com/snapotter-hq/snapotter/issues/612 )) ([6a0768b ](https://github.com/snapotter-hq/snapotter/commit/6a0768b39da648d3b62b39f2370b97f9ce876da0 )), closes [#535 ](https://github.com/snapotter-hq/snapotter/issues/535 )
* **tools:** classify expected input and timeout errors, not bugs ([#539 ](https://github.com/snapotter-hq/snapotter/issues/539 )) ([39b89b9 ](https://github.com/snapotter-hq/snapotter/commit/39b89b9fbd4f67012b55ecdef35ddf369a3fb874 ))
* **video:** write faststart mp4/mov output from stabilize-video ([#593 ](https://github.com/snapotter-hq/snapotter/issues/593 )) ([df92f7e ](https://github.com/snapotter-hq/snapotter/commit/df92f7ee42b22b5b6cb3434a6b972851388c67ad )), closes [#588 ](https://github.com/snapotter-hq/snapotter/issues/588 )
* **web:** use h-dvh for app shells so mobile tool controls stay reachable ([#559 ](https://github.com/snapotter-hq/snapotter/issues/559 )) ([3f7214b ](https://github.com/snapotter-hq/snapotter/commit/3f7214bac22fe392eb7d179752e9c4583e4dbe0e ))
### Features
* add landing testimonial wall, unblock the onboarding survey ([#639 ](https://github.com/snapotter-hq/snapotter/issues/639 )) ([5cc0a85 ](https://github.com/snapotter-hq/snapotter/commit/5cc0a850c68e0af7a427b8442c24c55f6157416e ))
* **analytics:** instance census, full capture, richer error context ([#511 ](https://github.com/snapotter-hq/snapotter/issues/511 )) ([e1b8c24 ](https://github.com/snapotter-hq/snapotter/commit/e1b8c24e5d78153a62629972932a65cd1491ee77 ))
* clearer, disambiguated tool names across all surfaces ([#520 ](https://github.com/snapotter-hq/snapotter/issues/520 )) ([f858c4c ](https://github.com/snapotter-hq/snapotter/commit/f858c4cea00ae7165718509c8a78881fe6fc24fc ))
* **docs-i18n:** translate all documentation into 20 languages ([4963ab3 ](https://github.com/snapotter-hq/snapotter/commit/4963ab3bbd36fe86b856a3be791f192af4582142 ))
* **erase-object:** add freeform lasso selection mode ([#503 ](https://github.com/snapotter-hq/snapotter/issues/503 )) ([601557e ](https://github.com/snapotter-hq/snapotter/commit/601557edaed32f331b5271334923f1c010098d91 ))
* **erase-object:** optional high-quality diffusion inpainting bundle ([#566 ](https://github.com/snapotter-hq/snapotter/issues/566 )) ([1bac663 ](https://github.com/snapotter-hq/snapotter/commit/1bac663a2e76c98313a7a56c97231c2bbc1b36f2 )), closes [hi#quality](https://github.com/hi/issues/quality ) [#141 ](https://github.com/snapotter-hq/snapotter/issues/141 )
* **feedback:** gate onboarding survey on first processing, add prompt lifecycle events ([#615 ](https://github.com/snapotter-hq/snapotter/issues/615 )) ([129e42b ](https://github.com/snapotter-hq/snapotter/commit/129e42b95cd9c078eebcb3c52be10e8661dd7903 ))
* **files:** add save-as-new vs overwrite choice for library file edits ([#564 ](https://github.com/snapotter-hq/snapotter/issues/564 )) ([a23158d ](https://github.com/snapotter-hq/snapotter/commit/a23158d968c32e8cdf319225d73bf51120f20cbf )), closes [#495 ](https://github.com/snapotter-hq/snapotter/issues/495 )
* **i18n:** 21-language pipeline, landing/docs/API wiring, landing+API translations ([00b651c ](https://github.com/snapotter-hq/snapotter/commit/00b651c9f851a8754cac755f6929ba2eeac8602b ))
* **image:** add rounded-square and squircle crop tool ([#602 ](https://github.com/snapotter-hq/snapotter/issues/602 )) ([e7ffb37 ](https://github.com/snapotter-hq/snapotter/commit/e7ffb37e981c553cf17db88155ac12667f104062 )), closes [#601 ](https://github.com/snapotter-hq/snapotter/issues/601 )
* **landing-i18n:** recall a returning visitor's chosen language ([1bc9fe9 ](https://github.com/snapotter-hq/snapotter/commit/1bc9fe93ec4ca82295e77f2c8068bc700ef94367 ))
* **landing:** add a live system status indicator to the footer ([#641 ](https://github.com/snapotter-hq/snapotter/issues/641 )) ([d690a6e ](https://github.com/snapotter-hq/snapotter/commit/d690a6e26d82f9783cac154faa11f19481902a0e ))
* **landing:** add Twelve Tools and Wired Business footer badges ([#512 ](https://github.com/snapotter-hq/snapotter/issues/512 )) ([ce54d06 ](https://github.com/snapotter-hq/snapotter/commit/ce54d06e797c8f3fe25ed8c00ef42047ddf63882 ))
* **landing:** move language switcher from navbar to footer ([#513 ](https://github.com/snapotter-hq/snapotter/issues/513 )) ([2dee9ea ](https://github.com/snapotter-hq/snapotter/commit/2dee9ead0b1c84c02831c5e92082cd4598b7b8f5 ))
* **library:** wire save-mode into the five custom-client tool submitters ([#577 ](https://github.com/snapotter-hq/snapotter/issues/577 )) ([1113c76 ](https://github.com/snapotter-hq/snapotter/commit/1113c761ead67664e4a7120b8bdf1b8e9da52c43 ))
* **onboarding:** collect install method and friction area in the usage survey ([#499 ](https://github.com/snapotter-hq/snapotter/issues/499 )) ([430b87e ](https://github.com/snapotter-hq/snapotter/commit/430b87eda0078c9afe31aa49da1f2293c928a147 ))
* **resize:** add aspect-ratio proportion presets ([#530 ](https://github.com/snapotter-hq/snapotter/issues/530 )) ([d88999e ](https://github.com/snapotter-hq/snapotter/commit/d88999e7a91d65adb37ea4cb3f9f7fe5650ad6c5 ))
* **search:** start typing anywhere to fill the search box ([#644 ](https://github.com/snapotter-hq/snapotter/issues/644 )) ([0058fc6 ](https://github.com/snapotter-hq/snapotter/commit/0058fc610f4b88ddf0660889b2ea78bf33a527d1 ))
* **telemetry:** add a safe input_format tag to worker error reports ([#541 ](https://github.com/snapotter-hq/snapotter/issues/541 )) ([281b4a0 ](https://github.com/snapotter-hq/snapotter/commit/281b4a06e39756a3a2b981e93d033454eb494c8c ))
* **telemetry:** Sentry + PostHog quality pass ([#546 ](https://github.com/snapotter-hq/snapotter/issues/546 )) ([8625143 ](https://github.com/snapotter-hq/snapotter/commit/86251434b5858c63049c50dda44acb8e281a4cdf ))
* **tools:** remove background from animated GIFs (WebP, APNG) ([#502 ](https://github.com/snapotter-hq/snapotter/issues/502 )) ([cb5db59 ](https://github.com/snapotter-hq/snapotter/commit/cb5db59f77e6b77fd9a575996b8514d6760aaf5b ))
2026-07-29 13:08:27 +00:00
SnapOtter
b6373b864c
chore: reset the partial 2.2.0 release artifacts for a clean re-run
...
Second failed dispatch (verify-ocr, now fixed in #666 ) again left a
chore(release): 2.2.0 commit. Undo its artifacts so the re-dispatch regenerates
them once: restore .release-notes.md to root, drop the 2.2.0 entries from
CHANGELOG.md and the docs changelog. Tag and draft deleted, so the fresh run
re-tags on this commit, which includes the #666 fix the previous tag lacked.
Non-releasable type so the re-run stays 2.2.0.
2026-07-29 20:21:55 +08:00
semantic-release-bot
c2903872bb
chore(release): 2.2.0 [skip ci]
...
# [2.2.0](https://github.com/snapotter-hq/snapotter/compare/v2.1.0...v2.2.0 ) (2026-07-29)
### Bug Fixes
* **a11y:** focus indicators meet the 3:1 non-text contrast bar ([#574 ](https://github.com/snapotter-hq/snapotter/issues/574 )) ([6339370 ](https://github.com/snapotter-hq/snapotter/commit/63393700939e34ad3d847043b03728e3c2907445 )), closes [#A85518](https://github.com/snapotter-hq/snapotter/issues/A85518 ) [#F0A766](https://github.com/snapotter-hq/snapotter/issues/F0A766 )
* **a11y:** WCAG AA contrast retune for the Otter Orange palette ([#567 ](https://github.com/snapotter-hq/snapotter/issues/567 )) ([5102262 ](https://github.com/snapotter-hq/snapotter/commit/51022628dc19d8a03525bab98473f3c23b1a2709 )), closes [#E07832](https://github.com/snapotter-hq/snapotter/issues/E07832 ) [#1A1814](https://github.com/snapotter-hq/snapotter/issues/1A1814 )
* **ai-bridge:** surface sidecar exit reasons in Sentry via SafeError ([#538 ](https://github.com/snapotter-hq/snapotter/issues/538 )) ([55e1e95 ](https://github.com/snapotter-hq/snapotter/commit/55e1e95f20792cae4f1f2257bafe839b83332c93 ))
* **ai-bundles:** stop CPU onnxruntime from clobbering onnxruntime-gpu ([#544 ](https://github.com/snapotter-hq/snapotter/issues/544 )) ([c8629c9 ](https://github.com/snapotter-hq/snapotter/commit/c8629c9d22b455b6deac206e3816ae0f730f06c6 )), closes [#490 ](https://github.com/snapotter-hq/snapotter/issues/490 )
* **ai:** advance the progress bar during upscale and background removal ([#608 ](https://github.com/snapotter-hq/snapotter/issues/608 )) ([e56edc6 ](https://github.com/snapotter-hq/snapotter/commit/e56edc659f742430798104b52a08806a8d8fbff2 )), closes [#591 ](https://github.com/snapotter-hq/snapotter/issues/591 )
* **ai:** warn that upscale and background removal are slow without a GPU ([#605 ](https://github.com/snapotter-hq/snapotter/issues/605 )) ([d43208b ](https://github.com/snapotter-hq/snapotter/commit/d43208b85e1ba1f0ac687970b8fb52ca1738ae15 )), closes [#591 ](https://github.com/snapotter-hq/snapotter/issues/591 )
* **api:** contain library stored-name path traversal ([#600 ](https://github.com/snapotter-hq/snapotter/issues/600 )) ([4333432 ](https://github.com/snapotter-hq/snapotter/commit/43334324c446c53eb1dc2f8ef14cbecca4e2a676 ))
* **api:** enforce job ownership on cancel endpoint ([#599 ](https://github.com/snapotter-hq/snapotter/issues/599 )) ([577d74b ](https://github.com/snapotter-hq/snapotter/commit/577d74bdb134d9a7d02c27ba976731839d071e63 ))
* **api:** gate every tool endpoint and stop ZIP streams failing quietly ([#646 ](https://github.com/snapotter-hq/snapotter/issues/646 )) ([2d8b57c ](https://github.com/snapotter-hq/snapotter/commit/2d8b57c57fad4e1d98ab7eb327198809aa64bd09 )), closes [#645 ](https://github.com/snapotter-hq/snapotter/issues/645 ) [#643 ](https://github.com/snapotter-hq/snapotter/issues/643 ) [#645 ](https://github.com/snapotter-hq/snapotter/issues/645 )
* **api:** wait for Postgres and Redis at startup instead of crash-looping ([#537 ](https://github.com/snapotter-hq/snapotter/issues/537 )) ([4ac89fe ](https://github.com/snapotter-hq/snapotter/commit/4ac89fe6505e50645174e8de5fcdc40c46420cc4 ))
* **audio:** expose sample rate setting in Convert Audio ([#561 ](https://github.com/snapotter-hq/snapotter/issues/561 )) ([d4eaa65 ](https://github.com/snapotter-hq/snapotter/commit/d4eaa655b24236da5633006871415afbf0c92d08 )), closes [#558 ](https://github.com/snapotter-hq/snapotter/issues/558 )
* **auth:** close the MFA policy lockout and add self-service enrollment ([#531 ](https://github.com/snapotter-hq/snapotter/issues/531 )) ([190d4c2 ](https://github.com/snapotter-hq/snapotter/commit/190d4c2a002c6d3d240ff18480e37217fcbeae12 )), closes [#529 ](https://github.com/snapotter-hq/snapotter/issues/529 ) [#515 ](https://github.com/snapotter-hq/snapotter/issues/515 )
* **auth:** give OIDC/SAML logins a real MFA challenge instead of a hard block ([#536 ](https://github.com/snapotter-hq/snapotter/issues/536 )) ([bbfcbe9 ](https://github.com/snapotter-hq/snapotter/commit/bbfcbe9c8212afb244bb2738a6e3643d06dcee68 )), closes [#533 ](https://github.com/snapotter-hq/snapotter/issues/533 )
* **background-removal:** surface failures with a diagnosable SafeError ([#535 ](https://github.com/snapotter-hq/snapotter/issues/535 )) ([43ddf96 ](https://github.com/snapotter-hq/snapotter/commit/43ddf96ccf7baf94416050ec6229efca68124679 ))
* **ci:** repair the chronically-failing nightly workflow ([#624 ](https://github.com/snapotter-hq/snapotter/issues/624 )) ([44f5aea ](https://github.com/snapotter-hq/snapotter/commit/44f5aea3268f022641832af4b8c60cbd2d5e2c7e ))
* **compress-pdf:** land close to the target size, honestly ([#522 ](https://github.com/snapotter-hq/snapotter/issues/522 )) ([7d938af ](https://github.com/snapotter-hq/snapotter/commit/7d938af1f9e601238fd49af4c2cd157d16616266 ))
* **deps:** patch 4 HIGH/CRITICAL transitive CVEs (fast-uri, svgo, sharp, tar) ([#619 ](https://github.com/snapotter-hq/snapotter/issues/619 )) ([10a2aab ](https://github.com/snapotter-hq/snapotter/commit/10a2aabe589b5afd470f6c47ccdb1bf8bca15c02 ))
* **doc-engine:** guard sidecar JSON parsing against non-JSON stdout ([#532 ](https://github.com/snapotter-hq/snapotter/issues/532 )) ([a2cb1a8 ](https://github.com/snapotter-hq/snapotter/commit/a2cb1a8261b2669ae7e656a418999b70a37f6b4f ))
* **docker:** harden Postgres readiness checks in compose and startup ([#595 ](https://github.com/snapotter-hq/snapotter/issues/595 )) ([4ba7503 ](https://github.com/snapotter-hq/snapotter/commit/4ba7503f15a4444c4937576dbcadafdb19a8848d )), closes [#592 ](https://github.com/snapotter-hq/snapotter/issues/592 )
* **docs:** keep the nav within the viewport on tablets and laptops ([#570 ](https://github.com/snapotter-hq/snapotter/issues/570 )) ([69f72a6 ](https://github.com/snapotter-hq/snapotter/commit/69f72a6c712512e8489b23bcf78a233d872d897c )), closes [#556 ](https://github.com/snapotter-hq/snapotter/issues/556 )
* **docs:** keep the translated locale trees out of the search index ([#662 ](https://github.com/snapotter-hq/snapotter/issues/662 )) ([42e1dc9 ](https://github.com/snapotter-hq/snapotter/commit/42e1dc9799f60c7dde46b9485e5f37a5a29630ae ))
* **docs:** localize the docs homepage, nav, and sidebar chrome across 20 languages ([#547 ](https://github.com/snapotter-hq/snapotter/issues/547 )) ([9247947 ](https://github.com/snapotter-hq/snapotter/commit/92479477042740d7026de9b9bb3c71eeb0668231 ))
* **download:** ask reverse proxies not to buffer file downloads ([#604 ](https://github.com/snapotter-hq/snapotter/issues/604 )) ([89d7585 ](https://github.com/snapotter-hq/snapotter/commit/89d75853f45c98d6e9cae661dbda02bc8285009b )), closes [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 )
* **download:** reset the socket when a stream is shorter than Content-Length ([#617 ](https://github.com/snapotter-hq/snapotter/issues/617 )) ([0467e87 ](https://github.com/snapotter-hq/snapotter/commit/0467e87bfe410b313fa21d9758f8c162b12113a6 )), closes [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 ) [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 ) [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 )
* **editor:** repair rotate/flip/resize, levels/curves, filters, and layer lock ([#597 ](https://github.com/snapotter-hq/snapotter/issues/597 )) ([a6bce68 ](https://github.com/snapotter-hq/snapotter/commit/a6bce6825ae27890951becf7c858d4626c513714 ))
* enforce role authority for user management ([#616 ](https://github.com/snapotter-hq/snapotter/issues/616 )) ([1f8a42e ](https://github.com/snapotter-hq/snapotter/commit/1f8a42e54822142132270df1aefa768f4626613f ))
* enforce settings authority boundaries ([#618 ](https://github.com/snapotter-hq/snapotter/issues/618 )) ([44d8109 ](https://github.com/snapotter-hq/snapotter/commit/44d8109486aa6efd9383e573f0a36deb4ffda460 ))
* **erase-object:** crop-based HD inpainting to remove ghosting and blur ([#501 ](https://github.com/snapotter-hq/snapotter/issues/501 )) ([380419d ](https://github.com/snapotter-hq/snapotter/commit/380419dd0603693ad542082bd6197e6505f9b1e9 )), closes [#491 ](https://github.com/snapotter-hq/snapotter/issues/491 ) [hi#res](https://github.com/hi/issues/res ) [#141 ](https://github.com/snapotter-hq/snapotter/issues/141 )
* **files:** decode CLI-decoded formats before URL-import preview generation ([#637 ](https://github.com/snapotter-hq/snapotter/issues/637 )) ([841f47f ](https://github.com/snapotter-hq/snapotter/commit/841f47f6ca25e79dc56dc1e735afa37f02023f99 )), closes [#634 ](https://github.com/snapotter-hq/snapotter/issues/634 )
* **files:** store null instead of 0x0 for undecoded upload dimensions ([#636 ](https://github.com/snapotter-hq/snapotter/issues/636 )) ([511633f ](https://github.com/snapotter-hq/snapotter/commit/511633fa1c76f00fe9c4e2a0935a02b5601cae6a )), closes [#635 ](https://github.com/snapotter-hq/snapotter/issues/635 )
* give remove-background job timeouts an actionable failure message ([#518 ](https://github.com/snapotter-hq/snapotter/issues/518 )) ([58121f2 ](https://github.com/snapotter-hq/snapotter/commit/58121f205f7ae2b34b3d789c80db37c8bf0950bf )), closes [#494 ](https://github.com/snapotter-hq/snapotter/issues/494 )
* **help:** render the help dialog from i18n instead of hardcoded English ([#647 ](https://github.com/snapotter-hq/snapotter/issues/647 )) ([2848dd0 ](https://github.com/snapotter-hq/snapotter/commit/2848dd0e53d8a7c1e19ee82c1a1f2d485380d356 )), closes [#644 ](https://github.com/snapotter-hq/snapotter/issues/644 )
* honor unlimited processing timeout ([#638 ](https://github.com/snapotter-hq/snapotter/issues/638 )) ([025851b ](https://github.com/snapotter-hq/snapotter/commit/025851beefaac6f8d12c1dbcdb69276965072ac9 ))
* **image-tools:** surface Sharp encode failures instead of "Error: Error" ([#534 ](https://github.com/snapotter-hq/snapotter/issues/534 )) ([9cccbc9 ](https://github.com/snapotter-hq/snapotter/commit/9cccbc957681f8d12547e87be0e335f98e789cb7 ))
* **image:** decode real iPhone HEIC files instead of rejecting them at validation ([#631 ](https://github.com/snapotter-hq/snapotter/issues/631 )) ([098ed50 ](https://github.com/snapotter-hq/snapotter/commit/098ed50d0693ba181fae6f934bf427079e1f8e9f )), closes [#622 ](https://github.com/snapotter-hq/snapotter/issues/622 )
* **image:** image-to-pdf presets no longer 404 on 2+ files ([#633 ](https://github.com/snapotter-hq/snapotter/issues/633 )) ([330cf55 ](https://github.com/snapotter-hq/snapotter/commit/330cf559e00b6e5f1ca8df199cabee4c0fa650d0 )), closes [#627 ](https://github.com/snapotter-hq/snapotter/issues/627 )
* **jobs:** classify BullMQ stall (UnrecoverableError) as operational ([#610 ](https://github.com/snapotter-hq/snapotter/issues/610 )) ([e537cb0 ](https://github.com/snapotter-hq/snapotter/commit/e537cb04013d7bf4fd0fb125fb72f42f5a51917f ))
* **jobs:** make timeout messages tool-agnostic and CPU-aware ([#596 ](https://github.com/snapotter-hq/snapotter/issues/596 )) ([37c915c ](https://github.com/snapotter-hq/snapotter/commit/37c915c3da6b2183b0befe1521a643bb36edcce6 )), closes [#591 ](https://github.com/snapotter-hq/snapotter/issues/591 )
* **landing-i18n:** commit missed landing-seo re-translation (remove.bg comparison) ([b8c3700 ](https://github.com/snapotter-hq/snapotter/commit/b8c3700c15333b2eb328cab0979f8d943c15d7ab ))
* **landing,docs:** use build-time GitHub star count, drop per-page api.github.com fetch ([#560 ](https://github.com/snapotter-hq/snapotter/issues/560 )) ([54073a7 ](https://github.com/snapotter-hq/snapotter/commit/54073a7c501788dea49f77f6e94bdebb9b8f0f65 ))
* **landing:** derive conversion-preset copy from real format differences ([#663 ](https://github.com/snapotter-hq/snapotter/issues/663 )) ([a75a22d ](https://github.com/snapotter-hq/snapotter/commit/a75a22dd3ff8e675002a13da0ec12d00f91136c8 ))
* **landing:** keep mixed-case locale casing in emitted URLs ([#562 ](https://github.com/snapotter-hq/snapotter/issues/562 )) ([67f5434 ](https://github.com/snapotter-hq/snapotter/commit/67f54347b2ca711f40495fa7fcb05e132ea8f3da )), closes [#554 ](https://github.com/snapotter-hq/snapotter/issues/554 )
* **landing:** link English-only tool-detail and self-hosted pages to un-prefixed URLs ([#553 ](https://github.com/snapotter-hq/snapotter/issues/553 )) ([6ecc598 ](https://github.com/snapotter-hq/snapotter/commit/6ecc598fc4fc8fa6da5db9d9d0c66e53d2f2376d ))
* **landing:** open Product dropdown below the navbar bottom line ([#571 ](https://github.com/snapotter-hq/snapotter/issues/571 )) ([e3a01b6 ](https://github.com/snapotter-hq/snapotter/commit/e3a01b6be6fa077fa00c6c7245be7ba18b6e913c ))
* **landing:** rework footer badge/switcher layout ([#514 ](https://github.com/snapotter-hq/snapotter/issues/514 )) ([74e7d23 ](https://github.com/snapotter-hq/snapotter/commit/74e7d23abad924f04b348f00edf34e67188c4f2e ))
* **landing:** stop mangling #hash fragments in localized links ([#516 ](https://github.com/snapotter-hq/snapotter/issues/516 )) ([5bd0522 ](https://github.com/snapotter-hq/snapotter/commit/5bd052286c5a7920161b21cb791cc122fe3a1616 )), closes [#hash](https://github.com/snapotter-hq/snapotter/issues/hash )
* make OCR portable and reliable across AMD64 and ARM64 ([#519 ](https://github.com/snapotter-hq/snapotter/issues/519 )) ([991c981 ](https://github.com/snapotter-hq/snapotter/commit/991c981529c81ebb719199aba084db4c2d9a7c6f ))
* **ocr:** unblock and harden accurate-OCR install ([#552 ](https://github.com/snapotter-hq/snapotter/issues/552 )) ([bda4db3 ](https://github.com/snapotter-hq/snapotter/commit/bda4db3f358eebd659a1f8b7892112061a82b000 ))
* **pdf:** flag scanned PDFs in pdf-to-text and serve text as UTF-8 ([#603 ](https://github.com/snapotter-hq/snapotter/issues/603 )) ([7d37f6e ](https://github.com/snapotter-hq/snapotter/commit/7d37f6e6f5aa68aa5954182d76bb6ccf1c6b0649 )), closes [#589 ](https://github.com/snapotter-hq/snapotter/issues/589 )
* **pdf:** pdf-to-image presets no longer 404 on 2+ files ([#643 ](https://github.com/snapotter-hq/snapotter/issues/643 )) ([a713795 ](https://github.com/snapotter-hq/snapotter/commit/a7137958a158309ff8128490de96313e517ae554 )), closes [#627 ](https://github.com/snapotter-hq/snapotter/issues/627 ) [#633 ](https://github.com/snapotter-hq/snapotter/issues/633 ) [#632 ](https://github.com/snapotter-hq/snapotter/issues/632 )
* **pdf:** restore downloads on PDF conversion preset pages ([#629 ](https://github.com/snapotter-hq/snapotter/issues/629 )) ([e0a7aec ](https://github.com/snapotter-hq/snapotter/commit/e0a7aecde8f194b6375747a5a5f8ea4c57053813 )), closes [#623 ](https://github.com/snapotter-hq/snapotter/issues/623 )
* **pdf:** stop page tools failing on short and encrypted PDFs ([#594 ](https://github.com/snapotter-hq/snapotter/issues/594 )) ([73df107 ](https://github.com/snapotter-hq/snapotter/commit/73df1077580904c37d159dafe51a294b250bb074 ))
* preserve colored blocks in PDF-to-Word ([#500 ](https://github.com/snapotter-hq/snapotter/issues/500 )) ([e7cfc00 ](https://github.com/snapotter-hq/snapotter/commit/e7cfc00fe1d294256a0a4663797b8a8cdf58d8c0 ))
* **readme:** self-host the star history chart ([#625 ](https://github.com/snapotter-hq/snapotter/issues/625 )) ([90483c9 ](https://github.com/snapotter-hq/snapotter/commit/90483c944a4d4c912d3c5e2c09b2ee61bed3d150 ))
* release QA hardening across processing, media, security, and CI gates ([#649 ](https://github.com/snapotter-hq/snapotter/issues/649 )) ([d10d0f5 ](https://github.com/snapotter-hq/snapotter/commit/d10d0f544f2a093d2adb13cbd69d54a31c0cbf7a ))
* **release:** resolve the release by id, and make the vulnerability gate cover HIGH ([#661 ](https://github.com/snapotter-hq/snapotter/issues/661 )) ([935861b ](https://github.com/snapotter-hq/snapotter/commit/935861bced95cd778ea77d5a3741ff1da1a2ffed )), closes [#649 ](https://github.com/snapotter-hq/snapotter/issues/649 )
* **security:** bump Pillow to 12.3.0, fixes 5 disclosed CVEs ([#517 ](https://github.com/snapotter-hq/snapotter/issues/517 )) ([30d36d7 ](https://github.com/snapotter-hq/snapotter/commit/30d36d7949817751b869916775138dc4fa7a34d2 ))
* **security:** close the gaps a full 2.0 re-audit left open ([#620 ](https://github.com/snapotter-hq/snapotter/issues/620 )) ([079fcd2 ](https://github.com/snapotter-hq/snapotter/commit/079fcd2631216147db4b68acbcaca58ac4f93fb4 ))
* **seo:** emit clean docs URLs and de-index the demo ([#598 ](https://github.com/snapotter-hq/snapotter/issues/598 )) ([e6718ad ](https://github.com/snapotter-hq/snapotter/commit/e6718ada719e8931f643e1184aee354d4698c1da ))
* **settings:** let admins relax the minimum password length to 1 ([#543 ](https://github.com/snapotter-hq/snapotter/issues/543 )) ([846044a ](https://github.com/snapotter-hq/snapotter/commit/846044a463f18f490f7752b0cb6b4b225b107367 )), closes [#136 ](https://github.com/snapotter-hq/snapotter/issues/136 )
* **sign-pdf:** surface PDF load failures instead of a blank canvas ([#545 ](https://github.com/snapotter-hq/snapotter/issues/545 )) ([1f4878a ](https://github.com/snapotter-hq/snapotter/commit/1f4878ac4df417331a8cff9b8d5ab4da2edc788a ))
* **telemetry:** classify environmental database errors as operational ([#540 ](https://github.com/snapotter-hq/snapotter/issues/540 )) ([631d82e ](https://github.com/snapotter-hq/snapotter/commit/631d82eaae36a15d401c7408182d52a0754b1e36 ))
* **telemetry:** data-quality pass (opt-in noise, onboarding split, file_count, OIDC) ([#614 ](https://github.com/snapotter-hq/snapotter/issues/614 )) ([b20bca3 ](https://github.com/snapotter-hq/snapotter/commit/b20bca3c3c4ef3a63aca6ba420986d49bbeb905b )), closes [hi#level](https://github.com/hi/issues/level )
* **telemetry:** fingerprint stackless uncaught errors so they stop collapsing ([#611 ](https://github.com/snapotter-hq/snapotter/issues/611 )) ([82f5708 ](https://github.com/snapotter-hq/snapotter/commit/82f5708193984e863b95319e0e0ec8be47e46075 ))
* **telemetry:** sharpen Sentry signal for v2.1.0 residual defects ([#498 ](https://github.com/snapotter-hq/snapotter/issues/498 )) ([b457596 ](https://github.com/snapotter-hq/snapotter/commit/b4575966495c1a022154149832aedcd727d411e2 ))
* **telemetry:** surface AI sidecar and DOMException failure reasons in Sentry ([#612 ](https://github.com/snapotter-hq/snapotter/issues/612 )) ([6a0768b ](https://github.com/snapotter-hq/snapotter/commit/6a0768b39da648d3b62b39f2370b97f9ce876da0 )), closes [#535 ](https://github.com/snapotter-hq/snapotter/issues/535 )
* **tools:** classify expected input and timeout errors, not bugs ([#539 ](https://github.com/snapotter-hq/snapotter/issues/539 )) ([39b89b9 ](https://github.com/snapotter-hq/snapotter/commit/39b89b9fbd4f67012b55ecdef35ddf369a3fb874 ))
* **video:** write faststart mp4/mov output from stabilize-video ([#593 ](https://github.com/snapotter-hq/snapotter/issues/593 )) ([df92f7e ](https://github.com/snapotter-hq/snapotter/commit/df92f7ee42b22b5b6cb3434a6b972851388c67ad )), closes [#588 ](https://github.com/snapotter-hq/snapotter/issues/588 )
* **web:** use h-dvh for app shells so mobile tool controls stay reachable ([#559 ](https://github.com/snapotter-hq/snapotter/issues/559 )) ([3f7214b ](https://github.com/snapotter-hq/snapotter/commit/3f7214bac22fe392eb7d179752e9c4583e4dbe0e ))
### Features
* add landing testimonial wall, unblock the onboarding survey ([#639 ](https://github.com/snapotter-hq/snapotter/issues/639 )) ([5cc0a85 ](https://github.com/snapotter-hq/snapotter/commit/5cc0a850c68e0af7a427b8442c24c55f6157416e ))
* **analytics:** instance census, full capture, richer error context ([#511 ](https://github.com/snapotter-hq/snapotter/issues/511 )) ([e1b8c24 ](https://github.com/snapotter-hq/snapotter/commit/e1b8c24e5d78153a62629972932a65cd1491ee77 ))
* clearer, disambiguated tool names across all surfaces ([#520 ](https://github.com/snapotter-hq/snapotter/issues/520 )) ([f858c4c ](https://github.com/snapotter-hq/snapotter/commit/f858c4cea00ae7165718509c8a78881fe6fc24fc ))
* **docs-i18n:** translate all documentation into 20 languages ([4963ab3 ](https://github.com/snapotter-hq/snapotter/commit/4963ab3bbd36fe86b856a3be791f192af4582142 ))
* **erase-object:** add freeform lasso selection mode ([#503 ](https://github.com/snapotter-hq/snapotter/issues/503 )) ([601557e ](https://github.com/snapotter-hq/snapotter/commit/601557edaed32f331b5271334923f1c010098d91 ))
* **erase-object:** optional high-quality diffusion inpainting bundle ([#566 ](https://github.com/snapotter-hq/snapotter/issues/566 )) ([1bac663 ](https://github.com/snapotter-hq/snapotter/commit/1bac663a2e76c98313a7a56c97231c2bbc1b36f2 )), closes [hi#quality](https://github.com/hi/issues/quality ) [#141 ](https://github.com/snapotter-hq/snapotter/issues/141 )
* **feedback:** gate onboarding survey on first processing, add prompt lifecycle events ([#615 ](https://github.com/snapotter-hq/snapotter/issues/615 )) ([129e42b ](https://github.com/snapotter-hq/snapotter/commit/129e42b95cd9c078eebcb3c52be10e8661dd7903 ))
* **files:** add save-as-new vs overwrite choice for library file edits ([#564 ](https://github.com/snapotter-hq/snapotter/issues/564 )) ([a23158d ](https://github.com/snapotter-hq/snapotter/commit/a23158d968c32e8cdf319225d73bf51120f20cbf )), closes [#495 ](https://github.com/snapotter-hq/snapotter/issues/495 )
* **i18n:** 21-language pipeline, landing/docs/API wiring, landing+API translations ([00b651c ](https://github.com/snapotter-hq/snapotter/commit/00b651c9f851a8754cac755f6929ba2eeac8602b ))
* **image:** add rounded-square and squircle crop tool ([#602 ](https://github.com/snapotter-hq/snapotter/issues/602 )) ([e7ffb37 ](https://github.com/snapotter-hq/snapotter/commit/e7ffb37e981c553cf17db88155ac12667f104062 )), closes [#601 ](https://github.com/snapotter-hq/snapotter/issues/601 )
* **landing-i18n:** recall a returning visitor's chosen language ([1bc9fe9 ](https://github.com/snapotter-hq/snapotter/commit/1bc9fe93ec4ca82295e77f2c8068bc700ef94367 ))
* **landing:** add a live system status indicator to the footer ([#641 ](https://github.com/snapotter-hq/snapotter/issues/641 )) ([d690a6e ](https://github.com/snapotter-hq/snapotter/commit/d690a6e26d82f9783cac154faa11f19481902a0e ))
* **landing:** add Twelve Tools and Wired Business footer badges ([#512 ](https://github.com/snapotter-hq/snapotter/issues/512 )) ([ce54d06 ](https://github.com/snapotter-hq/snapotter/commit/ce54d06e797c8f3fe25ed8c00ef42047ddf63882 ))
* **landing:** move language switcher from navbar to footer ([#513 ](https://github.com/snapotter-hq/snapotter/issues/513 )) ([2dee9ea ](https://github.com/snapotter-hq/snapotter/commit/2dee9ead0b1c84c02831c5e92082cd4598b7b8f5 ))
* **library:** wire save-mode into the five custom-client tool submitters ([#577 ](https://github.com/snapotter-hq/snapotter/issues/577 )) ([1113c76 ](https://github.com/snapotter-hq/snapotter/commit/1113c761ead67664e4a7120b8bdf1b8e9da52c43 ))
* **onboarding:** collect install method and friction area in the usage survey ([#499 ](https://github.com/snapotter-hq/snapotter/issues/499 )) ([430b87e ](https://github.com/snapotter-hq/snapotter/commit/430b87eda0078c9afe31aa49da1f2293c928a147 ))
* **resize:** add aspect-ratio proportion presets ([#530 ](https://github.com/snapotter-hq/snapotter/issues/530 )) ([d88999e ](https://github.com/snapotter-hq/snapotter/commit/d88999e7a91d65adb37ea4cb3f9f7fe5650ad6c5 ))
* **search:** start typing anywhere to fill the search box ([#644 ](https://github.com/snapotter-hq/snapotter/issues/644 )) ([0058fc6 ](https://github.com/snapotter-hq/snapotter/commit/0058fc610f4b88ddf0660889b2ea78bf33a527d1 ))
* **telemetry:** add a safe input_format tag to worker error reports ([#541 ](https://github.com/snapotter-hq/snapotter/issues/541 )) ([281b4a0 ](https://github.com/snapotter-hq/snapotter/commit/281b4a06e39756a3a2b981e93d033454eb494c8c ))
* **telemetry:** Sentry + PostHog quality pass ([#546 ](https://github.com/snapotter-hq/snapotter/issues/546 )) ([8625143 ](https://github.com/snapotter-hq/snapotter/commit/86251434b5858c63049c50dda44acb8e281a4cdf ))
* **tools:** remove background from animated GIFs (WebP, APNG) ([#502 ](https://github.com/snapotter-hq/snapotter/issues/502 )) ([cb5db59 ](https://github.com/snapotter-hq/snapotter/commit/cb5db59f77e6b77fd9a575996b8514d6760aaf5b ))
2026-07-29 11:14:24 +00:00
SnapOtter
a76982da60
chore: reset the partial 2.2.0 release artifacts for a clean re-run
...
The first v2.2.0 dispatch failed at archive-security after semantic-release had
already committed its release artifacts (chore(release): 2.2.0). Undo those so
the re-dispatch regenerates them once instead of duplicating the CHANGELOG
section: restore .release-notes.md to the root, and drop the 2.2.0 entries from
CHANGELOG.md and the docs changelog. The tag and draft release were deleted, so
the fresh run re-tags on this commit, which includes the #665 fixes the previous
tag lacked. Non-releasable type so the re-run stays 2.2.0.
2026-07-29 19:08:52 +08:00
semantic-release-bot
4ae03b441b
chore(release): 2.2.0 [skip ci]
...
# [2.2.0](https://github.com/snapotter-hq/snapotter/compare/v2.1.0...v2.2.0 ) (2026-07-29)
### Bug Fixes
* **a11y:** focus indicators meet the 3:1 non-text contrast bar ([#574 ](https://github.com/snapotter-hq/snapotter/issues/574 )) ([6339370 ](https://github.com/snapotter-hq/snapotter/commit/63393700939e34ad3d847043b03728e3c2907445 )), closes [#A85518](https://github.com/snapotter-hq/snapotter/issues/A85518 ) [#F0A766](https://github.com/snapotter-hq/snapotter/issues/F0A766 )
* **a11y:** WCAG AA contrast retune for the Otter Orange palette ([#567 ](https://github.com/snapotter-hq/snapotter/issues/567 )) ([5102262 ](https://github.com/snapotter-hq/snapotter/commit/51022628dc19d8a03525bab98473f3c23b1a2709 )), closes [#E07832](https://github.com/snapotter-hq/snapotter/issues/E07832 ) [#1A1814](https://github.com/snapotter-hq/snapotter/issues/1A1814 )
* **ai-bridge:** surface sidecar exit reasons in Sentry via SafeError ([#538 ](https://github.com/snapotter-hq/snapotter/issues/538 )) ([55e1e95 ](https://github.com/snapotter-hq/snapotter/commit/55e1e95f20792cae4f1f2257bafe839b83332c93 ))
* **ai-bundles:** stop CPU onnxruntime from clobbering onnxruntime-gpu ([#544 ](https://github.com/snapotter-hq/snapotter/issues/544 )) ([c8629c9 ](https://github.com/snapotter-hq/snapotter/commit/c8629c9d22b455b6deac206e3816ae0f730f06c6 )), closes [#490 ](https://github.com/snapotter-hq/snapotter/issues/490 )
* **ai:** advance the progress bar during upscale and background removal ([#608 ](https://github.com/snapotter-hq/snapotter/issues/608 )) ([e56edc6 ](https://github.com/snapotter-hq/snapotter/commit/e56edc659f742430798104b52a08806a8d8fbff2 )), closes [#591 ](https://github.com/snapotter-hq/snapotter/issues/591 )
* **ai:** warn that upscale and background removal are slow without a GPU ([#605 ](https://github.com/snapotter-hq/snapotter/issues/605 )) ([d43208b ](https://github.com/snapotter-hq/snapotter/commit/d43208b85e1ba1f0ac687970b8fb52ca1738ae15 )), closes [#591 ](https://github.com/snapotter-hq/snapotter/issues/591 )
* **api:** contain library stored-name path traversal ([#600 ](https://github.com/snapotter-hq/snapotter/issues/600 )) ([4333432 ](https://github.com/snapotter-hq/snapotter/commit/43334324c446c53eb1dc2f8ef14cbecca4e2a676 ))
* **api:** enforce job ownership on cancel endpoint ([#599 ](https://github.com/snapotter-hq/snapotter/issues/599 )) ([577d74b ](https://github.com/snapotter-hq/snapotter/commit/577d74bdb134d9a7d02c27ba976731839d071e63 ))
* **api:** gate every tool endpoint and stop ZIP streams failing quietly ([#646 ](https://github.com/snapotter-hq/snapotter/issues/646 )) ([2d8b57c ](https://github.com/snapotter-hq/snapotter/commit/2d8b57c57fad4e1d98ab7eb327198809aa64bd09 )), closes [#645 ](https://github.com/snapotter-hq/snapotter/issues/645 ) [#643 ](https://github.com/snapotter-hq/snapotter/issues/643 ) [#645 ](https://github.com/snapotter-hq/snapotter/issues/645 )
* **api:** wait for Postgres and Redis at startup instead of crash-looping ([#537 ](https://github.com/snapotter-hq/snapotter/issues/537 )) ([4ac89fe ](https://github.com/snapotter-hq/snapotter/commit/4ac89fe6505e50645174e8de5fcdc40c46420cc4 ))
* **audio:** expose sample rate setting in Convert Audio ([#561 ](https://github.com/snapotter-hq/snapotter/issues/561 )) ([d4eaa65 ](https://github.com/snapotter-hq/snapotter/commit/d4eaa655b24236da5633006871415afbf0c92d08 )), closes [#558 ](https://github.com/snapotter-hq/snapotter/issues/558 )
* **auth:** close the MFA policy lockout and add self-service enrollment ([#531 ](https://github.com/snapotter-hq/snapotter/issues/531 )) ([190d4c2 ](https://github.com/snapotter-hq/snapotter/commit/190d4c2a002c6d3d240ff18480e37217fcbeae12 )), closes [#529 ](https://github.com/snapotter-hq/snapotter/issues/529 ) [#515 ](https://github.com/snapotter-hq/snapotter/issues/515 )
* **auth:** give OIDC/SAML logins a real MFA challenge instead of a hard block ([#536 ](https://github.com/snapotter-hq/snapotter/issues/536 )) ([bbfcbe9 ](https://github.com/snapotter-hq/snapotter/commit/bbfcbe9c8212afb244bb2738a6e3643d06dcee68 )), closes [#533 ](https://github.com/snapotter-hq/snapotter/issues/533 )
* **background-removal:** surface failures with a diagnosable SafeError ([#535 ](https://github.com/snapotter-hq/snapotter/issues/535 )) ([43ddf96 ](https://github.com/snapotter-hq/snapotter/commit/43ddf96ccf7baf94416050ec6229efca68124679 ))
* **ci:** repair the chronically-failing nightly workflow ([#624 ](https://github.com/snapotter-hq/snapotter/issues/624 )) ([44f5aea ](https://github.com/snapotter-hq/snapotter/commit/44f5aea3268f022641832af4b8c60cbd2d5e2c7e ))
* **compress-pdf:** land close to the target size, honestly ([#522 ](https://github.com/snapotter-hq/snapotter/issues/522 )) ([7d938af ](https://github.com/snapotter-hq/snapotter/commit/7d938af1f9e601238fd49af4c2cd157d16616266 ))
* **deps:** patch 4 HIGH/CRITICAL transitive CVEs (fast-uri, svgo, sharp, tar) ([#619 ](https://github.com/snapotter-hq/snapotter/issues/619 )) ([10a2aab ](https://github.com/snapotter-hq/snapotter/commit/10a2aabe589b5afd470f6c47ccdb1bf8bca15c02 ))
* **doc-engine:** guard sidecar JSON parsing against non-JSON stdout ([#532 ](https://github.com/snapotter-hq/snapotter/issues/532 )) ([a2cb1a8 ](https://github.com/snapotter-hq/snapotter/commit/a2cb1a8261b2669ae7e656a418999b70a37f6b4f ))
* **docker:** harden Postgres readiness checks in compose and startup ([#595 ](https://github.com/snapotter-hq/snapotter/issues/595 )) ([4ba7503 ](https://github.com/snapotter-hq/snapotter/commit/4ba7503f15a4444c4937576dbcadafdb19a8848d )), closes [#592 ](https://github.com/snapotter-hq/snapotter/issues/592 )
* **docs:** keep the nav within the viewport on tablets and laptops ([#570 ](https://github.com/snapotter-hq/snapotter/issues/570 )) ([69f72a6 ](https://github.com/snapotter-hq/snapotter/commit/69f72a6c712512e8489b23bcf78a233d872d897c )), closes [#556 ](https://github.com/snapotter-hq/snapotter/issues/556 )
* **docs:** keep the translated locale trees out of the search index ([#662 ](https://github.com/snapotter-hq/snapotter/issues/662 )) ([42e1dc9 ](https://github.com/snapotter-hq/snapotter/commit/42e1dc9799f60c7dde46b9485e5f37a5a29630ae ))
* **docs:** localize the docs homepage, nav, and sidebar chrome across 20 languages ([#547 ](https://github.com/snapotter-hq/snapotter/issues/547 )) ([9247947 ](https://github.com/snapotter-hq/snapotter/commit/92479477042740d7026de9b9bb3c71eeb0668231 ))
* **download:** ask reverse proxies not to buffer file downloads ([#604 ](https://github.com/snapotter-hq/snapotter/issues/604 )) ([89d7585 ](https://github.com/snapotter-hq/snapotter/commit/89d75853f45c98d6e9cae661dbda02bc8285009b )), closes [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 )
* **download:** reset the socket when a stream is shorter than Content-Length ([#617 ](https://github.com/snapotter-hq/snapotter/issues/617 )) ([0467e87 ](https://github.com/snapotter-hq/snapotter/commit/0467e87bfe410b313fa21d9758f8c162b12113a6 )), closes [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 ) [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 ) [#590 ](https://github.com/snapotter-hq/snapotter/issues/590 )
* **editor:** repair rotate/flip/resize, levels/curves, filters, and layer lock ([#597 ](https://github.com/snapotter-hq/snapotter/issues/597 )) ([a6bce68 ](https://github.com/snapotter-hq/snapotter/commit/a6bce6825ae27890951becf7c858d4626c513714 ))
* enforce role authority for user management ([#616 ](https://github.com/snapotter-hq/snapotter/issues/616 )) ([1f8a42e ](https://github.com/snapotter-hq/snapotter/commit/1f8a42e54822142132270df1aefa768f4626613f ))
* enforce settings authority boundaries ([#618 ](https://github.com/snapotter-hq/snapotter/issues/618 )) ([44d8109 ](https://github.com/snapotter-hq/snapotter/commit/44d8109486aa6efd9383e573f0a36deb4ffda460 ))
* **erase-object:** crop-based HD inpainting to remove ghosting and blur ([#501 ](https://github.com/snapotter-hq/snapotter/issues/501 )) ([380419d ](https://github.com/snapotter-hq/snapotter/commit/380419dd0603693ad542082bd6197e6505f9b1e9 )), closes [#491 ](https://github.com/snapotter-hq/snapotter/issues/491 ) [hi#res](https://github.com/hi/issues/res ) [#141 ](https://github.com/snapotter-hq/snapotter/issues/141 )
* **files:** decode CLI-decoded formats before URL-import preview generation ([#637 ](https://github.com/snapotter-hq/snapotter/issues/637 )) ([841f47f ](https://github.com/snapotter-hq/snapotter/commit/841f47f6ca25e79dc56dc1e735afa37f02023f99 )), closes [#634 ](https://github.com/snapotter-hq/snapotter/issues/634 )
* **files:** store null instead of 0x0 for undecoded upload dimensions ([#636 ](https://github.com/snapotter-hq/snapotter/issues/636 )) ([511633f ](https://github.com/snapotter-hq/snapotter/commit/511633fa1c76f00fe9c4e2a0935a02b5601cae6a )), closes [#635 ](https://github.com/snapotter-hq/snapotter/issues/635 )
* give remove-background job timeouts an actionable failure message ([#518 ](https://github.com/snapotter-hq/snapotter/issues/518 )) ([58121f2 ](https://github.com/snapotter-hq/snapotter/commit/58121f205f7ae2b34b3d789c80db37c8bf0950bf )), closes [#494 ](https://github.com/snapotter-hq/snapotter/issues/494 )
* **help:** render the help dialog from i18n instead of hardcoded English ([#647 ](https://github.com/snapotter-hq/snapotter/issues/647 )) ([2848dd0 ](https://github.com/snapotter-hq/snapotter/commit/2848dd0e53d8a7c1e19ee82c1a1f2d485380d356 )), closes [#644 ](https://github.com/snapotter-hq/snapotter/issues/644 )
* honor unlimited processing timeout ([#638 ](https://github.com/snapotter-hq/snapotter/issues/638 )) ([025851b ](https://github.com/snapotter-hq/snapotter/commit/025851beefaac6f8d12c1dbcdb69276965072ac9 ))
* **image-tools:** surface Sharp encode failures instead of "Error: Error" ([#534 ](https://github.com/snapotter-hq/snapotter/issues/534 )) ([9cccbc9 ](https://github.com/snapotter-hq/snapotter/commit/9cccbc957681f8d12547e87be0e335f98e789cb7 ))
* **image:** decode real iPhone HEIC files instead of rejecting them at validation ([#631 ](https://github.com/snapotter-hq/snapotter/issues/631 )) ([098ed50 ](https://github.com/snapotter-hq/snapotter/commit/098ed50d0693ba181fae6f934bf427079e1f8e9f )), closes [#622 ](https://github.com/snapotter-hq/snapotter/issues/622 )
* **image:** image-to-pdf presets no longer 404 on 2+ files ([#633 ](https://github.com/snapotter-hq/snapotter/issues/633 )) ([330cf55 ](https://github.com/snapotter-hq/snapotter/commit/330cf559e00b6e5f1ca8df199cabee4c0fa650d0 )), closes [#627 ](https://github.com/snapotter-hq/snapotter/issues/627 )
* **jobs:** classify BullMQ stall (UnrecoverableError) as operational ([#610 ](https://github.com/snapotter-hq/snapotter/issues/610 )) ([e537cb0 ](https://github.com/snapotter-hq/snapotter/commit/e537cb04013d7bf4fd0fb125fb72f42f5a51917f ))
* **jobs:** make timeout messages tool-agnostic and CPU-aware ([#596 ](https://github.com/snapotter-hq/snapotter/issues/596 )) ([37c915c ](https://github.com/snapotter-hq/snapotter/commit/37c915c3da6b2183b0befe1521a643bb36edcce6 )), closes [#591 ](https://github.com/snapotter-hq/snapotter/issues/591 )
* **landing-i18n:** commit missed landing-seo re-translation (remove.bg comparison) ([b8c3700 ](https://github.com/snapotter-hq/snapotter/commit/b8c3700c15333b2eb328cab0979f8d943c15d7ab ))
* **landing,docs:** use build-time GitHub star count, drop per-page api.github.com fetch ([#560 ](https://github.com/snapotter-hq/snapotter/issues/560 )) ([54073a7 ](https://github.com/snapotter-hq/snapotter/commit/54073a7c501788dea49f77f6e94bdebb9b8f0f65 ))
* **landing:** derive conversion-preset copy from real format differences ([#663 ](https://github.com/snapotter-hq/snapotter/issues/663 )) ([a75a22d ](https://github.com/snapotter-hq/snapotter/commit/a75a22dd3ff8e675002a13da0ec12d00f91136c8 ))
* **landing:** keep mixed-case locale casing in emitted URLs ([#562 ](https://github.com/snapotter-hq/snapotter/issues/562 )) ([67f5434 ](https://github.com/snapotter-hq/snapotter/commit/67f54347b2ca711f40495fa7fcb05e132ea8f3da )), closes [#554 ](https://github.com/snapotter-hq/snapotter/issues/554 )
* **landing:** link English-only tool-detail and self-hosted pages to un-prefixed URLs ([#553 ](https://github.com/snapotter-hq/snapotter/issues/553 )) ([6ecc598 ](https://github.com/snapotter-hq/snapotter/commit/6ecc598fc4fc8fa6da5db9d9d0c66e53d2f2376d ))
* **landing:** open Product dropdown below the navbar bottom line ([#571 ](https://github.com/snapotter-hq/snapotter/issues/571 )) ([e3a01b6 ](https://github.com/snapotter-hq/snapotter/commit/e3a01b6be6fa077fa00c6c7245be7ba18b6e913c ))
* **landing:** rework footer badge/switcher layout ([#514 ](https://github.com/snapotter-hq/snapotter/issues/514 )) ([74e7d23 ](https://github.com/snapotter-hq/snapotter/commit/74e7d23abad924f04b348f00edf34e67188c4f2e ))
* **landing:** stop mangling #hash fragments in localized links ([#516 ](https://github.com/snapotter-hq/snapotter/issues/516 )) ([5bd0522 ](https://github.com/snapotter-hq/snapotter/commit/5bd052286c5a7920161b21cb791cc122fe3a1616 )), closes [#hash](https://github.com/snapotter-hq/snapotter/issues/hash )
* make OCR portable and reliable across AMD64 and ARM64 ([#519 ](https://github.com/snapotter-hq/snapotter/issues/519 )) ([991c981 ](https://github.com/snapotter-hq/snapotter/commit/991c981529c81ebb719199aba084db4c2d9a7c6f ))
* **ocr:** unblock and harden accurate-OCR install ([#552 ](https://github.com/snapotter-hq/snapotter/issues/552 )) ([bda4db3 ](https://github.com/snapotter-hq/snapotter/commit/bda4db3f358eebd659a1f8b7892112061a82b000 ))
* **pdf:** flag scanned PDFs in pdf-to-text and serve text as UTF-8 ([#603 ](https://github.com/snapotter-hq/snapotter/issues/603 )) ([7d37f6e ](https://github.com/snapotter-hq/snapotter/commit/7d37f6e6f5aa68aa5954182d76bb6ccf1c6b0649 )), closes [#589 ](https://github.com/snapotter-hq/snapotter/issues/589 )
* **pdf:** pdf-to-image presets no longer 404 on 2+ files ([#643 ](https://github.com/snapotter-hq/snapotter/issues/643 )) ([a713795 ](https://github.com/snapotter-hq/snapotter/commit/a7137958a158309ff8128490de96313e517ae554 )), closes [#627 ](https://github.com/snapotter-hq/snapotter/issues/627 ) [#633 ](https://github.com/snapotter-hq/snapotter/issues/633 ) [#632 ](https://github.com/snapotter-hq/snapotter/issues/632 )
* **pdf:** restore downloads on PDF conversion preset pages ([#629 ](https://github.com/snapotter-hq/snapotter/issues/629 )) ([e0a7aec ](https://github.com/snapotter-hq/snapotter/commit/e0a7aecde8f194b6375747a5a5f8ea4c57053813 )), closes [#623 ](https://github.com/snapotter-hq/snapotter/issues/623 )
* **pdf:** stop page tools failing on short and encrypted PDFs ([#594 ](https://github.com/snapotter-hq/snapotter/issues/594 )) ([73df107 ](https://github.com/snapotter-hq/snapotter/commit/73df1077580904c37d159dafe51a294b250bb074 ))
* preserve colored blocks in PDF-to-Word ([#500 ](https://github.com/snapotter-hq/snapotter/issues/500 )) ([e7cfc00 ](https://github.com/snapotter-hq/snapotter/commit/e7cfc00fe1d294256a0a4663797b8a8cdf58d8c0 ))
* **readme:** self-host the star history chart ([#625 ](https://github.com/snapotter-hq/snapotter/issues/625 )) ([90483c9 ](https://github.com/snapotter-hq/snapotter/commit/90483c944a4d4c912d3c5e2c09b2ee61bed3d150 ))
* release QA hardening across processing, media, security, and CI gates ([#649 ](https://github.com/snapotter-hq/snapotter/issues/649 )) ([d10d0f5 ](https://github.com/snapotter-hq/snapotter/commit/d10d0f544f2a093d2adb13cbd69d54a31c0cbf7a ))
* **release:** resolve the release by id, and make the vulnerability gate cover HIGH ([#661 ](https://github.com/snapotter-hq/snapotter/issues/661 )) ([935861b ](https://github.com/snapotter-hq/snapotter/commit/935861bced95cd778ea77d5a3741ff1da1a2ffed )), closes [#649 ](https://github.com/snapotter-hq/snapotter/issues/649 )
* **security:** bump Pillow to 12.3.0, fixes 5 disclosed CVEs ([#517 ](https://github.com/snapotter-hq/snapotter/issues/517 )) ([30d36d7 ](https://github.com/snapotter-hq/snapotter/commit/30d36d7949817751b869916775138dc4fa7a34d2 ))
* **security:** close the gaps a full 2.0 re-audit left open ([#620 ](https://github.com/snapotter-hq/snapotter/issues/620 )) ([079fcd2 ](https://github.com/snapotter-hq/snapotter/commit/079fcd2631216147db4b68acbcaca58ac4f93fb4 ))
* **seo:** emit clean docs URLs and de-index the demo ([#598 ](https://github.com/snapotter-hq/snapotter/issues/598 )) ([e6718ad ](https://github.com/snapotter-hq/snapotter/commit/e6718ada719e8931f643e1184aee354d4698c1da ))
* **settings:** let admins relax the minimum password length to 1 ([#543 ](https://github.com/snapotter-hq/snapotter/issues/543 )) ([846044a ](https://github.com/snapotter-hq/snapotter/commit/846044a463f18f490f7752b0cb6b4b225b107367 )), closes [#136 ](https://github.com/snapotter-hq/snapotter/issues/136 )
* **sign-pdf:** surface PDF load failures instead of a blank canvas ([#545 ](https://github.com/snapotter-hq/snapotter/issues/545 )) ([1f4878a ](https://github.com/snapotter-hq/snapotter/commit/1f4878ac4df417331a8cff9b8d5ab4da2edc788a ))
* **telemetry:** classify environmental database errors as operational ([#540 ](https://github.com/snapotter-hq/snapotter/issues/540 )) ([631d82e ](https://github.com/snapotter-hq/snapotter/commit/631d82eaae36a15d401c7408182d52a0754b1e36 ))
* **telemetry:** data-quality pass (opt-in noise, onboarding split, file_count, OIDC) ([#614 ](https://github.com/snapotter-hq/snapotter/issues/614 )) ([b20bca3 ](https://github.com/snapotter-hq/snapotter/commit/b20bca3c3c4ef3a63aca6ba420986d49bbeb905b )), closes [hi#level](https://github.com/hi/issues/level )
* **telemetry:** fingerprint stackless uncaught errors so they stop collapsing ([#611 ](https://github.com/snapotter-hq/snapotter/issues/611 )) ([82f5708 ](https://github.com/snapotter-hq/snapotter/commit/82f5708193984e863b95319e0e0ec8be47e46075 ))
* **telemetry:** sharpen Sentry signal for v2.1.0 residual defects ([#498 ](https://github.com/snapotter-hq/snapotter/issues/498 )) ([b457596 ](https://github.com/snapotter-hq/snapotter/commit/b4575966495c1a022154149832aedcd727d411e2 ))
* **telemetry:** surface AI sidecar and DOMException failure reasons in Sentry ([#612 ](https://github.com/snapotter-hq/snapotter/issues/612 )) ([6a0768b ](https://github.com/snapotter-hq/snapotter/commit/6a0768b39da648d3b62b39f2370b97f9ce876da0 )), closes [#535 ](https://github.com/snapotter-hq/snapotter/issues/535 )
* **tools:** classify expected input and timeout errors, not bugs ([#539 ](https://github.com/snapotter-hq/snapotter/issues/539 )) ([39b89b9 ](https://github.com/snapotter-hq/snapotter/commit/39b89b9fbd4f67012b55ecdef35ddf369a3fb874 ))
* **video:** write faststart mp4/mov output from stabilize-video ([#593 ](https://github.com/snapotter-hq/snapotter/issues/593 )) ([df92f7e ](https://github.com/snapotter-hq/snapotter/commit/df92f7ee42b22b5b6cb3434a6b972851388c67ad )), closes [#588 ](https://github.com/snapotter-hq/snapotter/issues/588 )
* **web:** use h-dvh for app shells so mobile tool controls stay reachable ([#559 ](https://github.com/snapotter-hq/snapotter/issues/559 )) ([3f7214b ](https://github.com/snapotter-hq/snapotter/commit/3f7214bac22fe392eb7d179752e9c4583e4dbe0e ))
### Features
* add landing testimonial wall, unblock the onboarding survey ([#639 ](https://github.com/snapotter-hq/snapotter/issues/639 )) ([5cc0a85 ](https://github.com/snapotter-hq/snapotter/commit/5cc0a850c68e0af7a427b8442c24c55f6157416e ))
* **analytics:** instance census, full capture, richer error context ([#511 ](https://github.com/snapotter-hq/snapotter/issues/511 )) ([e1b8c24 ](https://github.com/snapotter-hq/snapotter/commit/e1b8c24e5d78153a62629972932a65cd1491ee77 ))
* clearer, disambiguated tool names across all surfaces ([#520 ](https://github.com/snapotter-hq/snapotter/issues/520 )) ([f858c4c ](https://github.com/snapotter-hq/snapotter/commit/f858c4cea00ae7165718509c8a78881fe6fc24fc ))
* **docs-i18n:** translate all documentation into 20 languages ([4963ab3 ](https://github.com/snapotter-hq/snapotter/commit/4963ab3bbd36fe86b856a3be791f192af4582142 ))
* **erase-object:** add freeform lasso selection mode ([#503 ](https://github.com/snapotter-hq/snapotter/issues/503 )) ([601557e ](https://github.com/snapotter-hq/snapotter/commit/601557edaed32f331b5271334923f1c010098d91 ))
* **erase-object:** optional high-quality diffusion inpainting bundle ([#566 ](https://github.com/snapotter-hq/snapotter/issues/566 )) ([1bac663 ](https://github.com/snapotter-hq/snapotter/commit/1bac663a2e76c98313a7a56c97231c2bbc1b36f2 )), closes [hi#quality](https://github.com/hi/issues/quality ) [#141 ](https://github.com/snapotter-hq/snapotter/issues/141 )
* **feedback:** gate onboarding survey on first processing, add prompt lifecycle events ([#615 ](https://github.com/snapotter-hq/snapotter/issues/615 )) ([129e42b ](https://github.com/snapotter-hq/snapotter/commit/129e42b95cd9c078eebcb3c52be10e8661dd7903 ))
* **files:** add save-as-new vs overwrite choice for library file edits ([#564 ](https://github.com/snapotter-hq/snapotter/issues/564 )) ([a23158d ](https://github.com/snapotter-hq/snapotter/commit/a23158d968c32e8cdf319225d73bf51120f20cbf )), closes [#495 ](https://github.com/snapotter-hq/snapotter/issues/495 )
* **i18n:** 21-language pipeline, landing/docs/API wiring, landing+API translations ([00b651c ](https://github.com/snapotter-hq/snapotter/commit/00b651c9f851a8754cac755f6929ba2eeac8602b ))
* **image:** add rounded-square and squircle crop tool ([#602 ](https://github.com/snapotter-hq/snapotter/issues/602 )) ([e7ffb37 ](https://github.com/snapotter-hq/snapotter/commit/e7ffb37e981c553cf17db88155ac12667f104062 )), closes [#601 ](https://github.com/snapotter-hq/snapotter/issues/601 )
* **landing-i18n:** recall a returning visitor's chosen language ([1bc9fe9 ](https://github.com/snapotter-hq/snapotter/commit/1bc9fe93ec4ca82295e77f2c8068bc700ef94367 ))
* **landing:** add a live system status indicator to the footer ([#641 ](https://github.com/snapotter-hq/snapotter/issues/641 )) ([d690a6e ](https://github.com/snapotter-hq/snapotter/commit/d690a6e26d82f9783cac154faa11f19481902a0e ))
* **landing:** add Twelve Tools and Wired Business footer badges ([#512 ](https://github.com/snapotter-hq/snapotter/issues/512 )) ([ce54d06 ](https://github.com/snapotter-hq/snapotter/commit/ce54d06e797c8f3fe25ed8c00ef42047ddf63882 ))
* **landing:** move language switcher from navbar to footer ([#513 ](https://github.com/snapotter-hq/snapotter/issues/513 )) ([2dee9ea ](https://github.com/snapotter-hq/snapotter/commit/2dee9ead0b1c84c02831c5e92082cd4598b7b8f5 ))
* **library:** wire save-mode into the five custom-client tool submitters ([#577 ](https://github.com/snapotter-hq/snapotter/issues/577 )) ([1113c76 ](https://github.com/snapotter-hq/snapotter/commit/1113c761ead67664e4a7120b8bdf1b8e9da52c43 ))
* **onboarding:** collect install method and friction area in the usage survey ([#499 ](https://github.com/snapotter-hq/snapotter/issues/499 )) ([430b87e ](https://github.com/snapotter-hq/snapotter/commit/430b87eda0078c9afe31aa49da1f2293c928a147 ))
* **resize:** add aspect-ratio proportion presets ([#530 ](https://github.com/snapotter-hq/snapotter/issues/530 )) ([d88999e ](https://github.com/snapotter-hq/snapotter/commit/d88999e7a91d65adb37ea4cb3f9f7fe5650ad6c5 ))
* **search:** start typing anywhere to fill the search box ([#644 ](https://github.com/snapotter-hq/snapotter/issues/644 )) ([0058fc6 ](https://github.com/snapotter-hq/snapotter/commit/0058fc610f4b88ddf0660889b2ea78bf33a527d1 ))
* **telemetry:** add a safe input_format tag to worker error reports ([#541 ](https://github.com/snapotter-hq/snapotter/issues/541 )) ([281b4a0 ](https://github.com/snapotter-hq/snapotter/commit/281b4a06e39756a3a2b981e93d033454eb494c8c ))
* **telemetry:** Sentry + PostHog quality pass ([#546 ](https://github.com/snapotter-hq/snapotter/issues/546 )) ([8625143 ](https://github.com/snapotter-hq/snapotter/commit/86251434b5858c63049c50dda44acb8e281a4cdf ))
* **tools:** remove background from animated GIFs (WebP, APNG) ([#502 ](https://github.com/snapotter-hq/snapotter/issues/502 )) ([cb5db59 ](https://github.com/snapotter-hq/snapotter/commit/cb5db59f77e6b77fd9a575996b8514d6760aaf5b ))
2026-07-29 09:50:41 +00:00