Commit Graph
100 Commits
Author SHA1 Message Date
SnapOtter 0b90c62dae docs: add security page to docs sidebar 2026-06-08 17:48:48 +08:00
SnapOtter bfd6d25786 docs: add security and hardening guide
Container hardening, network isolation, Docker secrets, Kubernetes
deployment, backup strategy, and compliance artifacts reference.
2026-06-08 17:48:20 +08:00
SnapOtter ac39557b42 feat(ci): add Trivy JSON report as release artifact
Full vulnerability scan (all severities) uploaded to each GitHub
Release for enterprise customers to review before deployment.
2026-06-08 17:45:40 +08:00
SnapOtter 6a5e7f3389 feat(ci): add SBOM generation to release workflow
Syft generates CycloneDX and SPDX SBOMs from the amd64 production
image and uploads both to the GitHub Release.
2026-06-08 17:44:15 +08:00
SnapOtter d2fff1f87d fix(security): bump Go 1.25 and Pillow 12.2.0 for new Trivy CVEs
- Go 1.24 -> 1.25: fixes CVE-2026-25679 (HIGH: net/url IPv6 parsing)
- Pillow 12.1.1 -> 12.2.0: fixes CVE-2026-40192 (HIGH: decompression bomb DoS)
2026-06-08 17:32:34 +08:00
SnapOtter 61c587d024 docs: credit @electricmessiah and @florentineprinzessinzusachsen in release notes 2026-06-08 17:26:43 +08:00
SnapOtter 0c58db2417 fix(security): update Go 1.24 and Pillow 12.1.1 for Trivy CVEs
- Bump Go from 1.23 to 1.24 to fix CVE-2025-68121 (CRITICAL:
  crypto/tls certificate validation) and CVE-2025-61726 (HIGH:
  net/url memory exhaustion) in the caire binary.
- Bump Pillow from 11.1.0 to 12.1.1 to fix CVE-2026-25990 (HIGH:
  out-of-bounds write via crafted image).
2026-06-08 17:06:07 +08:00
SnapOtter 1846d1c7c9 fix(security): add pnpm bundled dependency CVEs to trivyignore
All 13 HIGH CVEs (glob, minimatch, picomatch, tar) are bundled
inside pnpm 9.x itself, not in our application dependencies.
pnpm overrides only affect our app's dependency tree, not pnpm's
internal modules. All require upgrading to pnpm 10.x.
2026-06-08 16:44:38 +08:00
SnapOtter 012e2136ee fix(security): resolve 13 HIGH Trivy CVEs in npm dependencies
- Override glob>=10.5.0 (CVE-2025-64756 command injection)
- Override minimatch>=9.0.6 (CVE-2026-26996/27903/27904 ReDoS)
- Override tar>=7.5.11 (CVE-2026-23745/23950/24842/26960/29786/31802
  path traversal and arbitrary file overwrite)
- picomatch>=4.0.4 already overridden (CVE-2026-33671 ReDoS)
- Add .trivyignore for pnpm 9.x CVEs (CVE-2025-69262/69263) that
  require a major version bump to pnpm 10.x
- Restore Trivy as a blocking gate with trivyignore support
- Restore scan dependency in manifest job
2026-06-08 16:32:52 +08:00
SnapOtter 2c0a04c195 fix(ci): make Trivy scan non-blocking for manifest creation
The Trivy scan finds HIGH CVEs in pnpm's own transitive dependencies
(glob, minimatch, tar, picomatch) which are build-time only and not
in the runtime image. These block manifest creation unnecessarily.
Scan results still upload to GitHub Security tab via SARIF.
2026-06-08 16:30:24 +08:00
SnapOtter 31e5f81a55 feat(docs): add v1.17.2 changelog and auto-update in release workflow
- Add v1.17.2 entry to docs/changelog.md
- Add "Update docs changelog" step to release workflow that
  auto-prepends .release-notes.md to the docs changelog on
  each release, then commits and pushes to trigger docs deploy
2026-06-08 16:21:29 +08:00
SnapOtter e0eb2e2075 fix(ci): add curl retry for libheif download and update release notes
- Add --retry 3 --retry-delay 5 to libheif curl in Dockerfile to
  handle transient GitHub CDN 504 errors on arm64 CI runners.
- Update release notes: use @ mentions, remove double-dash separators.
2026-06-08 16:17:28 +08:00
SnapOtter 37bc623dec fix(ci): exclude .git/.github from archive instead of deleting
Deleting .github breaks the Post Run cleanup for composite actions,
causing the entire job to fail. Use tar --exclude instead so the
working directory stays intact for GitHub Actions cleanup.
2026-06-08 16:11:34 +08:00
SnapOtter d43aa2f1b6 fix(ci): add --repo flag to gh release upload after .git removal
The archive step removes .git before creating the tarball, but
gh release upload needs git context to resolve the repo. Pass
--repo explicitly to avoid "not a git repository" errors.
2026-06-08 16:07:23 +08:00
SnapOtter 6dcbb9f122 docs: add release notes for v1.17.2 2026-06-08 15:55:55 +08:00
SnapOtter 9f26f0d733 test: increase GIF conversion timeout to 120s on CI
WebP->GIF conversion is slow on GitHub Actions runners and
intermittently exceeds the 30s default. Match the AVIF timeout.
2026-06-08 15:49:47 +08:00
SnapOtter 9e345bf37f fix: update APP_VERSION constant to 1.17.2 2026-06-08 15:19:24 +08:00
SnapOtter 24baf18746 test: update TypingCursor tests for new hero copy and 5s interval 2026-06-08 14:57:58 +08:00
SnapOtter 9931d6899c chore(release): 1.17.2 2026-06-08 14:45:44 +08:00
SnapOtter 1680344f9d revert(docs): restore original homepage layout
Reverts all docs homepage CSS and content changes back to the
state before the compact layout experiments.
2026-06-08 14:45:12 +08:00
SnapOtterandalbanobattistella c629fb3893 feat(i18n): update Italian translation with ~145 newly translated strings
Co-authored-by: albanobattistella <albanobattistella@users.noreply.github.com>

Closes #206
2026-06-08 14:44:16 +08:00
SnapOtter 1d7bc00d2d fix(docker): use CUDA 12.6 index for PaddlePaddle GPU and revert version
- fix(ocr): change paddlepaddle-gpu from --extra-index-url to --index-url
  for the CUDA 12.6 package index. With --extra-index-url, pip could
  resolve from PyPI (CUDA 11 build) instead of the cu126 index, causing
  "libcusolver.so.11: undefined symbol" errors on CUDA 12 containers.

- revert version to 1.17.1 (v1.17.2 release was deleted)
2026-06-08 14:36:59 +08:00
SnapOtter d33844d9c8 docs: shorten feature descriptions to two sentences max 2026-06-08 14:34:54 +08:00
SnapOtter 9a1d3d25f4 fix(docker): resolve 4 release-blocking issues from validation
- fix(rate-limit): treat RATE_LIMIT_PER_MIN=0 as unlimited (50k/min)
  instead of blocking all requests. @fastify/rate-limit interprets
  max:0 as "allow zero requests," breaking fresh container startups.

- fix(docker): add libgles2 for MediaPipe face detection tools.
  blur-faces, red-eye-removal, enhance-faces, and passport-photo
  failed with "libGLESv2.so.2 not found" on all headless containers.

- fix(docker/arm64): remove conflicting system libheif1 to avoid
  ABI symbol mismatch with our custom libheif 1.21.2 build.
  heif-convert failed with "undefined symbol: heif_get_plugin_directories."

- fix(docker/arm64): pre-install wheel+setuptools in base Python venv
  so basicsr can build from source on arm64 (no pre-built wheel).
  This unblocks upscale-enhance and photo-restoration bundles.
2026-06-08 14:07:55 +08:00
SnapOtter 7cb8d912e8 fix(docs): rewrite homepage layout with proper visual hierarchy
Rewrote all homepage CSS overrides from scratch:
- Brand name at 44px with gradient, subtitle at 34px (clear hierarchy)
- Feature cards at 14px/13px with 20px padding (readable, not cramped)
- 3-column feature grid with equal-height rows
- Removed VitePress 128px default gap before footer
- Trimmed Local AI feature description to balance card heights

Entire page fits in one viewport without scrolling.
2026-06-08 13:29:15 +08:00
SnapOtter acee5a6651 fix(landing): slow hero message rotation from 3s to 5s 2026-06-08 13:27:08 +08:00
SnapOtter 25e7c79982 fix(landing): move docker command into hero section
Relocate the terminal mockup from the separate HowItWorks section
into the hero so the install command is visible immediately without
scrolling. Remove the now-empty HowItWorks component from the page.
2026-06-08 13:23:53 +08:00
SnapOtter 143feadb49 fix(docs): fix hero name size and eliminate remaining scroll
The .name and .clip are the same element (class="name clip"), not
nested, so .name .clip selector never matched. Use .name.clip instead.
Also remove VitePress default 128px margin-bottom on .VPHome that was
pushing the footer below the viewport.
2026-06-08 13:20:08 +08:00
SnapOtter 1e44963f68 fix(landing): replace hero messages with personality-driven copy
Swap 25 dry feature bullets for 15 messages with voice -- mix of
cheeky, warm, and playful tones across privacy, simplicity, open
source, use cases, and capability themes. Interleaved rotation order
ensures theme variety for any viewing window.
2026-06-08 13:18:17 +08:00
SnapOtter 8e44c55d32 fix(docs): center hero title and refine homepage spacing
The hero title was left-aligned while tagline/buttons were centered,
creating a visual mismatch. Use flexbox centering on .VPHero .main to
align all hero elements. Bump font sizes slightly and equalize feature
card heights with height: 100%.
2026-06-08 13:15:52 +08:00
SnapOtter 2fb37f0fb6 fix(docs): compact homepage layout to fit in single viewport
Reduce hero padding and font sizes, center tagline and action buttons,
switch feature cards from 2-column to 3-column grid, and tighten all
section spacing so the entire docs homepage is visible without scrolling.
2026-06-08 12:21:51 +08:00
SnapOtter 7db6bb97da docs: add per-tool API documentation and fix parity gaps
- Create 53 per-tool VitePress documentation pages with accurate
  parameters from Zod schemas, example requests, and response formats
- Add root llms.txt for LLM-friendly repo browsing
- Fix OpenAPI spec: add auth and 422 error schemas to
  edit-metadata/inspect and strip-metadata/inspect sub-routes
- Fix tool count inconsistency (52 -> 53) across landing site,
  e2e tests, and local docs
- Rename color-adjustments.ts to adjust-colors.ts to match tool ID
- Update VitePress sidebar with all 8 tool categories and top nav
2026-06-08 11:52:28 +08:00
SnapOtter ed177e7cc1 fix(landing): simplify footer copyright to product name only
Drop verbose company registration details (entity name, UEN, country)
from the footer -- legal entity info already lives in the Terms page.
2026-06-08 11:51:49 +08:00
SnapOtter 862ff172ef fix(landing): correct API reference link in footer
Footer linked to /api which has no index page, causing a 404.
Point to /api/rest to match the docs site navigation.
2026-06-08 11:51:05 +08:00
SnapOtter 82a444dcaf fix: set MAX_PIPELINE_STEPS=0 in test env to match unlimited assumption
Two pipeline tests ("accepts pipeline with more than 20 steps when
limit is unlimited") expected unlimited steps but the test env didn't
set MAX_PIPELINE_STEPS, falling back to the default of 20.
2026-06-08 10:12:01 +08:00
SnapOtterandGitHub 6f276b4ef0 feat(a11y): WCAG 2.2 AA accessibility compliance (#209)
* feat(a11y): add i18n keys for ARIA labels and screen reader text

* fix(security): harden API against pentest findings

- Default TRUST_PROXY=false to prevent XFF rate limit bypass (PT-01)
- Return 400 instead of 500 on malformed JSON input (PT-03)
- Default MAX_PIPELINE_STEPS=20 to prevent DoS (PT-04)
- Validate clientJobId length (max 128) across all routes (PT-06)
- Add security headers to all reply.hijack() streaming responses (PT-07)
- Sanitize usernames in audit log to prevent stored XSS (PT-08)
- Block TRACE method with 405 response (PT-10)
- Add 429 RateLimited response to OpenAPI spec (PT-12)
- Default MAX_SVG_SIZE_MB=50 to limit SVGZ decompression (PT-13)
- Pin Dockerfile base images by digest
- Sanitize OIDC IdP error and sub claim in audit log
- Sync Docker compose/Dockerfile defaults with env.ts

* feat(a11y): convert all hardcoded aria-labels to i18n keys

Replace 49 hardcoded aria-label="..." strings across 25 files with
their corresponding t.a11y.* and t.common.* i18n references. Add
useTranslation import and hook call to 15 components that lacked it.
Zero hardcoded aria-labels remain in the codebase.

* feat(a11y): add aria-labels to icon-only buttons, aria-hidden on decorative icons, sr-only status text

* feat(a11y): add aria-live regions for processing status announcements

* feat(a11y): add skip-nav link, route announcer, main content landmark, and page h1 elements

* feat(a11y): add prefers-reduced-motion support, preserve functional spinners

* feat(a11y): add useFocusTrap hook for modal focus management

* feat(a11y): add focus trapping and dialog roles to all modals

* feat(a11y): add toggle switch roles, form labels, and error association

* fix(a11y): fix contrast failures, touch targets, and add nav landmark to sidebar

* fix(a11y): add role=switch to remaining toggle buttons found in verification sweep
2026-06-07 23:32:41 +08:00
SnapOtter ace41168bc fix(security): harden API against pentest findings
- Default TRUST_PROXY=false to prevent XFF rate limit bypass (PT-01)
- Return 400 instead of 500 on malformed JSON input (PT-03)
- Default MAX_PIPELINE_STEPS=20 to prevent DoS (PT-04)
- Validate clientJobId length (max 128) across all routes (PT-06)
- Add security headers to all reply.hijack() streaming responses (PT-07)
- Sanitize usernames in audit log to prevent stored XSS (PT-08)
- Block TRACE method with 405 response (PT-10)
- Add 429 RateLimited response to OpenAPI spec (PT-12)
- Default MAX_SVG_SIZE_MB=50 to limit SVGZ decompression (PT-13)
- Pin Dockerfile base images by digest
- Sanitize OIDC IdP error and sub claim in audit log
- Sync Docker compose/Dockerfile defaults with env.ts
2026-06-07 21:54:27 +08:00
SnapOtter 19f40f58c9 feat(a11y): add i18n keys for ARIA labels and screen reader text 2026-06-07 21:48:08 +08:00
SnapOtterandGitHub 73b259462a fix: resolve 7 bugs from QA sweep (#208)
- Fix selective metadata stripping (P1): use Sharp's keepExif()/keepIccProfile()
  instead of broken withMetadata({}) that preserved everything
- Fix meme font mapping (P1): add ArchivoBlack and ComicNeue fonts, map
  arial-black and comic-sans to correct TTF files instead of Anton
- Fix meme contentType (P2): detect actual output format from Sharp metadata
  instead of hardcoding image/png
- Fix info/text-overlay/color-palette i18n (P2): wire up existing translation
  keys that were imported but never used
- Fix info and color-palette displayMode (P2): change from before-after to
  no-comparison since neither tool produces a processed image
- Add missing i18n keys across all 21 locales
- Update displayMode test assertions
2026-06-07 18:27:09 +08:00
SnapOtter 59c9df3f0d fix: add missing SVG XXE security test fixtures
The adversarial-security integration test reads two SVG fixture files
that were never committed, causing CI to fail with ENOENT.
2026-06-07 12:33:15 +08:00
SnapOtterandGitHub 5a32e29b8c fix(security): security audit and hardening (#207)
* fix(security): harden SVG sanitizer, rate limiting, and analytics defaults

- SVG: add control-char stripping in href values to block whitespace/null-byte
  obfuscated javascript: URIs; block <feImage> with external href (SSRF via
  SVG filter primitives); expand test suite to 32 inline bypass payloads
- Rate limiting: add per-route limits on tool endpoints (60/min) and batch
  (20/min); fix compose files defaulting RATE_LIMIT_PER_MIN to 0 which mapped
  to 50,000 in code; simplify rate limit registration to use env.ts default
- Analytics: default ANALYTICS_ENABLED to false so self-hosters do not
  unknowingly send telemetry
- Docker: add --max-time 5 and -s flags to compose healthcheck curl commands

* fix: remove stale login limit bypass, reduce error log noise, clean up fixtures

- Fix getLoginAttemptLimit() ignoring LOGIN_ATTEMPT_LIMIT when global rate
  limit exceeded 1000/min, which let the global limit override the stricter
  per-route login brute-force protection
- Downgrade rate limit 429 responses from error to warn level in the global
  error handler to avoid log noise and unnecessary Sentry reports
- Log 4xx client errors at warn level instead of error level
- Remove 11 orphaned SVG attack fixture files replaced by inline test payloads
2026-06-07 10:43:52 +08:00
SnapOtter 46bb09f03a fix: resolve CI lint and test failures
- Apply biome formatting fixes to web app components
- Add required S3 credentials to loadEnv test when STORAGE_MODE=s3
- Update bento-grid test tool counts from 52 to 53 for html-to-image
2026-06-06 21:51:43 +08:00
SnapOtter 6b037e3abc feat: add html file upload mode to html-to-image tool 2026-06-06 21:45:39 +08:00
SnapOtter 8512c518b2 chore: use snapotter.com as placeholder URL for html-to-image tool 2026-06-06 21:45:39 +08:00
SnapOtter 5bcc357725 chore: update tool counts and references for html-to-image (53 tools) 2026-06-06 21:45:39 +08:00
SnapOtter 041ac3dc56 test: add e2e tests for html-to-image tool 2026-06-06 21:45:39 +08:00
SnapOtter a8b79f9da5 docs: add html-to-image tool to API docs, OpenAPI, and LLM docs 2026-06-06 21:45:39 +08:00
SnapOtter 4d7f67d2af feat: add playwright chromium to docker image for html-to-image 2026-06-06 21:45:39 +08:00
SnapOtter f8cfa17bd6 feat: register html-to-image in frontend tool registry 2026-06-06 21:45:39 +08:00
SnapOtter af1220cab1 feat: add frontend store and components for html-to-image tool 2026-06-06 21:45:38 +08:00
SnapOtter 5760d6723f feat: add browser service shutdown to server lifecycle 2026-06-06 21:45:38 +08:00
SnapOtter d9959d6686 feat: implement html-to-image API route with SSRF protection 2026-06-06 21:45:38 +08:00
SnapOtter b4eec49103 test: add integration tests for html-to-image tool 2026-06-06 21:45:38 +08:00
SnapOtter da5b248582 feat: add browser service singleton for html-to-image captures 2026-06-06 21:45:38 +08:00
SnapOtter 0e850ba5e0 feat: add playwright dependency for html-to-image tool
Install playwright in apps/api for the browser-based screenshot
service that will power the HTML to Image tool.
2026-06-06 21:45:38 +08:00
SnapOtter d1b0afd2e6 feat: add html-to-image tool definition and i18n strings
Add tool metadata to shared constants and i18n entries across all 21
locales for the new HTML to Image screenshot tool.
2026-06-06 21:45:38 +08:00
SnapOtterandGitHub 10a85cf37e feat: add Docker _FILE secret convention for sensitive env vars (#205)
Support reading secrets from mounted files instead of plain-text
environment variables, following the standard Docker/Kubernetes
convention used by MariaDB, Postgres, and Stirling-PDF.

Supported vars: DEFAULT_PASSWORD, S3_ACCESS_KEY_ID,
S3_SECRET_ACCESS_KEY, OIDC_CLIENT_SECRET, COOKIE_SECRET,
SNAPOTTER_LICENSE_KEY.
2026-06-06 21:18:14 +08:00
SnapOtter f64cbdda4e fix: block hex IPv4-mapped IPv6 in SSRF guard
The WHATWG URL parser canonicalizes dotted IPv4-mapped IPv6 literals
(e.g. ::ffff:127.0.0.1) to hex form (::ffff:7f00:1). The SSRF guard
only checked the dotted form, so hex literals bypassed the private-IP
classifier and allowed access to loopback, cloud metadata, and RFC1918
addresses.

Decode hex IPv4-mapped suffixes to dotted IPv4 before the private-range
check.

Reported-by: tonghuaroot
2026-06-06 20:27:48 +08:00
SnapOtter 3b84fab765 feat: add enterprise licensing and S3 storage backend
Add the enterprise package with Ed25519 license key validation and
feature gating. Enterprise code lives in the public repo under a
proprietary license (Cal.com/PostHog model), protected legally, not
by code hiding.

Implement S3-compatible storage backend as the first enterprise
feature. The file-storage module now delegates to either local
filesystem or S3 based on STORAGE_MODE env var. Works with AWS S3,
Cloudflare R2, DigitalOcean Spaces, MinIO, and any S3-compatible
provider. Workspace files remain local (ephemeral processing).

New env vars: STORAGE_MODE, S3_BUCKET, S3_REGION, S3_ENDPOINT,
S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_FORCE_PATH_STYLE,
S3_PREFIX, SNAPOTTER_LICENSE_KEY.

Tested against MinIO: 10 S3 integration tests + 82 existing tests
pass with zero regressions.
2026-06-06 20:17:49 +08:00
SnapOtter 06d1822491 test: expand test coverage across all layers (+1,157 tests)
Fix 2 failing unit tests (landing hero text mismatch) and broken
coverage tooling (brace-expansion v5 override breaking minimatch).
Add ~1,097 new test cases via 14-agent parallel expansion:

- Unit: +290 tests (AI bridge, image-engine, stores, API helpers)
- Integration: +504 tests (all tools, cross-format matrix, adversarial)
- E2E: +363 tests (navigation, tool UI, batch/pipeline, settings,
  visual regression, accessibility, performance, cross-browser)

Total: 4,223 unit + 6,057 integration + 1,563 E2E = 11,843 tests
2026-06-06 19:37:29 +08:00
SnapOtter 66e503730d fix: resolve 6 production Sentry errors
- Prevent @fastify/static double-registration crash via decorateReply guard
- Fix non-ASCII filename header encoding (X-Output-Filename + RFC 5987 Content-Disposition)
- Add EACCES error handling to all startup mkdir calls with actionable messages
- Add WAL autocheckpoint and journal size limit to prevent unbounded SQLite growth
- Fix Python sidecar EPIPE handling to reject pending requests and trigger restart
- Ensure Docker entrypoint creates all subdirectories before chown
2026-06-06 16:05:59 +08:00
SnapOtter cad6a7618c fix: add SHA256 checksums to prebuilt archives and retain LICENSE
Generate .sha256 checksum files alongside each prebuilt tarball for
download integrity verification. Stop stripping the LICENSE file from
archives to comply with AGPL-3.0 distribution requirements.
2026-06-06 12:35:55 +08:00
SnapOtter 9f2498f0d2 docs: add legal entity info to landing footer, terms, and privacy pages
SnapOtter is a product of Chocolate Wafers General Trading Pte. Ltd.
(UEN 202527149C), registered in Singapore. Surfaces company identity
in the footer copyright, a "Who We Are" section on the terms page,
and a "Data Controller" section on the privacy page.
2026-06-06 12:06:27 +08:00
SnapOtter 357f39ed7b fix: update landing word cloud with current tool list
Add Meme, Erase Object, Text Overlay, AI Expand, Compose, Split,
Enhance Faces, Replace Color, Beautify, Closeup. Remove Flip
(not a standalone tool) and Open Source (not a tool).
2026-06-06 11:41:10 +08:00
SnapOtter cfe3c1a2b3 fix: refine landing hero layout and spacing
Clean headline break, two-tier subtitle with tool list and lighter
attributes line, more vertical breathing room.
2026-06-06 11:38:48 +08:00
SnapOtter fa897148a4 docs: update hero copy across landing page and docs
Clearer messaging: "50+ image tools. One Docker container." on landing,
"Self-Hosted Image Toolkit" on docs.
2026-06-06 11:22:30 +08:00
SnapOtter 60e4d7b02f test: update settings dialog e2e test for dvh unit change
The settings dialog height class changed from h-[85vh] to h-[85dvh]
as part of the dynamic viewport height migration.
2026-06-06 11:10:27 +08:00
SnapOtter 26465cd844 test: add Playwright e2e tests for QA fixes
11 tests covering: login, tool pages, /tools/:toolId redirect,
invalid slug handling, 404 page, privacy page, automate/files/editor
pages, settings dialog, and dropzone i18n. The 404 catch-all test
gracefully skips on pre-fix builds.
2026-06-06 10:58:23 +08:00
SnapOtter fe0cbd32b2 fix: use correct i18n key path for noToolsFound in tool palette 2026-06-06 10:38:34 +08:00
SnapOtter 91c66eb4be fix: resolve all QA report issues from 2026-06-05 sweep
Merges 77 QA issue fixes across routing, editor, i18n, pipeline,
and settings. Includes catch-all 404 page, keyboard shortcuts,
export filename, password validation, selection masking, brush flow,
eraser modes, feather control, pipeline persistence, RTL properties,
license info, and i18n for all 21 locales.
2026-06-06 10:37:36 +08:00
SnapOtter 643df59ca1 fix: add missing i18n keys to en.ts and all locale files
Ensures all 21 locale files have: pageNotFound, licenseLabel,
noStepsHeading, searchToolsPlaceholder, and expanded files section
with 20 keys. Updates passwordTooShort to match backend validation.
2026-06-06 10:37:23 +08:00
SnapOtter d373ac83dc feat: mobile-responsive settings dialog, homepage, nav, and toast
- Settings dialog: full-screen on mobile with horizontal pill nav,
  card-based user/team tables, compact audit log, stacked SettingRow
- HomePage: stacked mobile layout with horizontal quick actions,
  tablet-friendly panel widths (w-64 lg:w-80)
- Extract MobileBottomNav component with safe-area-inset padding
- Add MobileBottomNav to fullscreen grid page
- Larger touch targets on hamburger, sidebar close, bottom nav items
- Toast repositioned to top-center on mobile (avoids bottom nav overlap)
- PWA viewport-fit=cover for notch devices
- Fix useMediaQuery null guard for test environment compatibility
2026-06-05 23:18:55 +08:00
SnapOtter 190d5c84bf fix: resolve remaining QA issues -- editor features, masking, persistence, Playwright tests
Phase 1 quick fixes:
- Add isInputFocused() guard to Cmd+A/D/T/J shortcuts (P1-7)
- Add Go Home button to tool-not-found page (P2-30)
- Fix hardcoded "Import from Library" string in file library modal (P2-28)
- Fix TeamEntry.id type from number to string to match API (P2-6)
- Add eye toggle to confirm password field (P2-10)
- Add Apply/Cancel buttons to Free Transform options bar (P2-14)

Phase 2 state fixes:
- Add sessionStorage persistence to pipeline store (P1-26)
- Fix Free Transform 0 dimensions by falling back to selection bounds (P1-6)

Phase 3 editor features:
- Constrain brush/eraser drawing within active selection bounds (P1-5)
- Add feather radius control to selection options (P2-21)
- Add flow control slider to brush options (P2-22)
- Add brush/block mode selector to eraser options (P2-23)
- Add estimated file size display to export dialog (P2-18)

Phase 4:
- Add Playwright e2e tests for key fixes (404 page, routing, pipeline persistence, export dialog)
2026-06-05 23:14:57 +08:00
SnapOtter 37f8ebcf66 Merge branch 'feat/remove-bg-improvements' 2026-06-05 23:05:33 +08:00
SnapOtter 80957f6e10 feat: improve remove background with edge smoothing, color decontamination, output formats
- Expose birefnet-hr-matting in UI (People/Ultra) and fix model defaults
  (People/Max now uses birefnet-matting for true alpha matting)
- Add output format selector (PNG/WebP/AVIF) with lossless alpha support
- Add edge smoothing post-processing (Off/Light/Medium/Strong) via
  morphological mask refinement to reduce gray halo artifacts
- Add color decontamination to remove background color spill from
  semi-transparent edge pixels
- Thread new settings through full stack: frontend -> API schema ->
  Python sidecar -> Sharp effects pipeline
- Add i18n keys for all 21 locales
- Add unit tests for new option serialization (3 tests)
- Add integration tests for new settings validation (4 tests)
2026-06-05 23:05:25 +08:00
SnapOtter 07e12754ba fix: resolve QA report issues across routing, editor, i18n, and pipeline
- Add /tools/:toolId legacy redirect and catch-all 404 page (P1-12, P1-13)
- Add Shift+O dodge/burn/sponge cycle and Ctrl+Y redo shortcut (P1-3, P1-4)
- Fix Fit on Screen menu action to properly compute fit zoom (P1-8)
- Add filename input to editor export dialog (P1-2)
- Fix password validation mismatch: frontend now requires 8 chars (P1-11)
- Add license info to Settings About section (P1-9)
- Replace hardcoded strings in dropzone, files, pipeline with i18n keys (P1-17 to P1-25)
- Add 20+ missing i18n keys to all 21 locale files
- Translate Japanese editor.shapes and settings.aiFeatures sections (P1-19, P1-20)
- Fix RTL: use logical CSS properties in sidebar, files, app-layout (P2-24 to P2-26)
- Add single-file download button to pipeline results (P1-28)
- Fix compress step settings restoration on pipeline load (P1-27)
- Increase mobile nav touch targets to 44px minimum (P2-29)
2026-06-05 22:31:28 +08:00
SnapOtter 6a8d9dcd8d feat: implement 6 research-backed mobile responsive features
- Bottom sheet for mobile tool settings (replaces top-collapsible panel)
- Pinch-to-zoom and wheel zoom on image viewer via @use-gesture/react
- Replace all vh units with dvh for dynamic viewport height
- Vertical before-after comparison on mobile devices
- Konva multi-touch pinch-to-zoom on editor canvas
- Container queries for adaptive tool settings + touch-friendly CSS
2026-06-05 22:30:43 +08:00
SnapOtterandGitHub 91e90b390e fix: recover SSE connections on mobile tab visibility change (#204)
* fix: extend SSE result retention from 2 to 10 minutes for mobile recovery

* fix: check server health on tab visibility change for mobile recovery

* fix: recover feature install SSE on tab visibility change

* fix: reconnect SSE on tab visibility change in tool processor

* fix: reconnect SSE on tab visibility change in pipeline processor

* test: add visibility recovery tests for connection monitor
2026-06-05 22:28:24 +08:00
SnapOtter f7282afe92 test: add visibility recovery tests for connection monitor 2026-06-05 21:52:10 +08:00
SnapOtter 807bd0cf85 fix: reconnect SSE on tab visibility change in pipeline processor 2026-06-05 21:51:34 +08:00
SnapOtter 4d8cc2dcf7 fix: reconnect SSE on tab visibility change in tool processor 2026-06-05 21:49:23 +08:00
SnapOtter 2b92109aee fix: recover feature install SSE on tab visibility change 2026-06-05 21:45:32 +08:00
SnapOtter fbc70272dd fix: check server health on tab visibility change for mobile recovery 2026-06-05 21:45:27 +08:00
SnapOtter 005fe1d982 fix: extend SSE result retention from 2 to 10 minutes for mobile recovery 2026-06-05 21:43:55 +08:00
SnapOtterandGitHub 01421640b5 fix: resolve file library Open File bug, upload reliability, and SSE proxy timeouts (#203)
The Open File button in the Files section did nothing due to a race
condition where the home page reset the file store on mount before files
from handleOpenFile could render. Upload on the files page used fetch
with no timeout, progress, or retry, causing silent failures on mobile
and slow connections. SSE connections for job progress had no keepalive
pings, allowing reverse proxies to kill idle streams.
2026-06-05 19:01:40 +08:00
SnapOtterandGitHub f1aae73397 feat: pre-built release archives + AI install fixes (#202)
Add pre-built release archives (Linux amd64/arm64) to the release
workflow, published as GitHub Release assets. Each archive is a
self-contained tar.gz (~240MB) with built frontend, API source,
and production node_modules. Users extract and run without needing
pnpm build.

Also includes AI install manifest fixes for Proxmox/bare-metal users:
- Pin setuptools<75 for Python 3.13 basicsr compatibility
- Pre-install basicsr with --no-build-isolation before realesrgan
- Loosen mediapipe pins from == to >= for Python 3.13 wheels
- Add retry logic to HuggingFace model downloads
2026-06-05 18:42:30 +08:00
SnapOtterandGitHub abd1efb46d fix: add retry logic to HuggingFace model downloads (#201)
HuggingFace snapshot_download had no retry logic, causing lama-onnx and
codeformer-onnx installs to fail on transient network errors. Direct URL
downloads already had 3 retries with exponential backoff -- this adds
the same pattern to HF downloads (3 attempts, 10s/20s backoff).
2026-06-05 17:53:34 +08:00
SnapOtterandGitHub 074c96e8c3 fix: enable tiling in Real-ESRGAN to prevent CUDA OOM on 8GB GPUs (#200)
Process images in 512px tiles instead of all at once, drastically
reducing peak VRAM usage. If OOM still occurs, retry with 256px tiles
after clearing the CUDA cache. Covers both upscale and face enhance.

Closes #191
2026-06-05 17:29:56 +08:00
SnapOtterandGitHub c365fde599 fix: build libheif 1.21.2 from source for iPhone HEIC support (#183) (#199)
iPhone 15 Pro (iOS 18+) HEIC files include HDR gain maps as auxiliary
image references. Distro-packaged libheif (1.15-1.17) rejects these
with "Too many auxiliary image references". Build libheif v1.21.2 from
source in a new Dockerfile stage to fix decoding.

- Add libheif-builder stage with platform-matched bases (debian:bookworm
  for arm64, ubuntu:24.04 for amd64) to avoid shared-library ABI
  mismatches
- Replace libheif-examples distro package with source-built binaries
- Update Dockerfile.test with same libheif source build
- No application code changes needed (heic-converter.ts CLI interface
  is stable across versions)

Closes #183
2026-06-05 17:05:01 +08:00
SnapOtterandGitHub 32055e0b32 fix: correct Docker image name in compose files (#198)
Closes #182
2026-06-05 17:04:52 +08:00
SnapOtter bec3b1e289 feat: add shape fill/stroke transparency, RGBA color picker, and dash styles
Closes #193. Shapes now support no-fill and no-stroke toggles for drawing
outlines or fill-only shapes. Adds RGBA color picker with opacity control,
stroke dash styles (solid/dashed/dotted), and i18n for all shape labels.
2026-06-05 16:40:57 +08:00
SnapOtter e03c6089af feat: support downloadFn-based model manifests and improve install error messages
Add support for models defined via downloadFn/args (rembg_session,
hf_snapshot) in bundle verification, recovery, and uninstall paths.
Previously only path-based models were tracked, so bundles using
rembg or HF snapshot downloads appeared broken after install.

Also improve pip install error messages with user-friendly hints for
common failures (basicsr build issues, OOM, disk full) and add better
error context for rembg session download failures.
2026-06-04 22:27:44 +08:00
SnapOtterGitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1616ad1a5a chore(deps-dev): bump dev-deps group + fix vitest 3.2.6 mock resolution (#197)
* chore(deps-dev): bump the dev-deps group across 1 directory with 7 updates

Bumps the dev-deps group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.15` | `2.4.16` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `3.2.4` | `3.2.6` |
| [turbo](https://github.com/vercel/turborepo) | `2.9.14` | `2.9.16` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `3.2.4` | `3.2.6` |
| [@types/opentype.js](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/opentype.js) | `1.3.9` | `1.3.10` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `6.4.2` | `6.4.3` |
| [vitepress-plugin-llms](https://github.com/okineadev/vitepress-plugin-llms) | `1.12.2` | `1.13.1` |

Updates `@biomejs/biome` from 2.4.15 to 2.4.16
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.16/packages/@biomejs/biome)

Updates `@vitest/coverage-v8` from 3.2.4 to 3.2.6
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v3.2.6/packages/coverage-v8)

Updates `turbo` from 2.9.14 to 2.9.16
- [Release notes](https://github.com/vercel/turborepo/releases)
- [Changelog](https://github.com/vercel/turborepo/blob/main/RELEASE.md)
- [Commits](https://github.com/vercel/turborepo/compare/v2.9.14...v2.9.16)

Updates `vitest` from 3.2.4 to 3.2.6
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v3.2.6/packages/vitest)

Updates `@types/opentype.js` from 1.3.9 to 1.3.10
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/opentype.js)

Updates `vite` from 6.4.2 to 6.4.3
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.4.3/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.4.3/packages/vite)

Updates `vitepress-plugin-llms` from 1.12.2 to 1.13.1
- [Release notes](https://github.com/okineadev/vitepress-plugin-llms/releases)
- [Commits](https://github.com/okineadev/vitepress-plugin-llms/compare/v1.12.2...v1.13.1)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.4.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-deps
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 3.2.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-deps
- dependency-name: turbo
  dependency-version: 2.9.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-deps
- dependency-name: vitest
  dependency-version: 3.2.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-deps
- dependency-name: "@types/opentype.js"
  dependency-version: 1.3.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-deps
- dependency-name: vite
  dependency-version: 6.4.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-deps
- dependency-name: vitepress-plugin-llms
  dependency-version: 1.13.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-deps
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(test): resolve vitest 3.2.6 mock path breakage for posthog-node and @sentry/node

Add posthog-node and @sentry/node to vitest resolve aliases (matching
the existing pattern for all other api-workspace packages) and switch
the analytics test mocks from fragile relative node_modules paths to
bare specifiers. Vitest 3.2.6 changed how it matches mock paths through
pnpm symlinks after vi.resetModules(), causing 9 analytics test failures.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-04 22:22:40 +08:00
SnapOtterandGitHub 8decb6b8d8 fix(i18n): use correct Italian abbreviation "IA" instead of "AI" (#196)
In Italian, "Artificial Intelligence" is "Intelligenza Artificiale",
abbreviated as "IA". Updates all 17 occurrences across tool names,
descriptions, and UI strings.

Closes #192
2026-06-04 21:44:56 +08:00
SnapOtter 7fe1007810 fix(ci): ignore new torch/joblib/markdown CVEs in pip-audit
No fixed versions available yet for:
- torch 2.12.0: 11 PYSEC advisories (transitive dep from ML packages)
- joblib 1.5.3: PYSEC-2024-277
- markdown 3.10.2: PYSEC-2026-89
2026-05-20 16:27:54 +08:00
SnapOtter 59bbe2b5e0 fix: use crypto.getRandomValues() for password generation
Math.random() is not cryptographically secure. Replace with
crypto.getRandomValues() in both generatePassword() functions
to resolve CodeQL js/insecure-randomness alerts.
2026-05-20 16:04:57 +08:00
SnapOtter 8706d8555d feat: add community roadmap infrastructure
- Discussion templates for feature requests and roadmap updates
- Roadmap labels (now/next/later, community-request)
- Fix security audit report path in .gitignore
2026-05-20 14:59:25 +08:00
SnapOtter e70fca054a fix: replace hardcoded "52 tools" with "50+" across all copy
Future-proofs marketing text so it doesn't need updating every time
a tool is added.
2026-05-20 14:45:45 +08:00
SnapOtter dfbc4cfd59 chore(release): 1.17.1
Bump version across all workspaces, update changelog, release notes,
OpenAPI spec, bug report template, and OpenSSF badge answers.
2026-05-18 19:10:56 +08:00
SnapOtterandGitHub b571165315 fix: increase timeout for remaining AVIF conversion tests (#153)
Extends the 120s AVIF timeout fix to format-matrix-comprehensive and
format-matrix-expanded test files (Integration shard 4/4 failures).
2026-05-18 18:16:07 +08:00