Commit Graph
100 Commits
Author SHA1 Message Date
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
SnapOtterandGitHub 395b93214e fix: increase timeout for AVIF conversion integration tests (#152)
AVIF encoding is slow in CI without hardware acceleration, causing
SVG->AVIF and WebP->AVIF tests to timeout at 30s. Set 120s timeout
for all AVIF output tests, matching the existing exotic format timeout.
2026-05-18 17:48:21 +08:00
SnapOtterandGitHub 436576fe15 fix: resolve features-store test timeouts and dynamic icon-map test (#151)
- Fix installAll tests timing out by returning installed status from
  refreshBundles mock (prevents infinite retry loop) and increasing
  waitFor/test timeouts to accommodate the 2s inter-install delay
- Fix zustand-stores installAll test with same refreshBundles mock fix
- Icon-map test already fixed to derive from shared constants
2026-05-18 17:24:36 +08:00
SnapOtterandGitHub 8b85a8c386 fix: update all renamed Lucide icons and make icon test dynamic (#150)
- FileEdit -> FilePen (bulk-rename tool)
- Wand2 -> Wand (object eraser)
- Columns -> Columns2 (stitch tool)
- Add Expand to ICON_MAP (ai-canvas-expand)
- Make icon-map test derive icon lists from shared constants instead
  of hardcoding names, preventing future breakage on icon renames
2026-05-18 17:09:14 +08:00
SnapOtterandGitHub 27bbdb6e8a fix: update renamed Lucide icons (Wand2 -> Wand, Columns -> Columns2) (#149)
Lucide v0.577 dropped Wand2 and Columns from the icons object used
for dynamic lookup. Named exports still exist as aliases, but the
landing site and tools index use icons[name] which fails silently.

Updates shared constants and web app icon-map to use the current names.
2026-05-18 16:50:30 +08:00
SnapOtterandGitHub dfddaef260 feat: add /tools index page and fix navbar links on subpages (#148)
- Add /tools hub page listing all 52 tools grouped by category with
  CollectionPage + ItemList schema markup
- Include /tools in dynamic sitemap at priority 0.9
- Fix Features and Pricing nav links using relative anchors (#features,
  #pricing) that broke on subpages by prefixing with /
2026-05-18 16:46:58 +08:00
SnapOtterandGitHub 9941a1db03 feat: add 52 per-tool SEO landing pages and public changelog (#145)
* feat: add 52 per-tool SEO landing pages and public changelog

- Create individual landing pages for all 52 tools at /tools/{slug}
  with search-intent title tags, unique FAQs (156 Q&As), per-tool
  features, and rich schema markup (BreadcrumbList, WebApplication,
  HowTo, FAQPage)
- Replace static sitemap.xml with dynamic generation including all
  tool URLs
- Refactor bento grid to import from @snapotter/shared (eliminates
  330 lines of duplicated tool data) and link cards to tool pages
- Add @snapotter/shared as workspace dependency to landing site
- Add public changelog page to docs site with curated release notes
  from v1.8 through v1.17
- Update docs nav and sidebar with changelog link

* feat: enhance SEO and performance with updated metadata, robots.txt, and llms.txt
2026-05-18 16:39:54 +08:00
SnapOtterandGitHub 6c47f292af docs: add OpenSSF Best Practices passing badge to README (#146) 2026-05-18 16:04:07 +08:00
SnapOtterandGitHub ec6ff3d8a8 chore: harden OpenSSF Scorecard from 4.3 to ~7.0 (#142)
Token-Permissions (0 -> 10): Set permissions: {} at workflow top level
across all 7 workflows, moved write scopes to per-job minimum.

SAST (0 -> 10): Added CodeQL workflow for JavaScript/TypeScript and
Python analysis on push, PR, and weekly schedule.

Vulnerabilities (0 -> ~8): Added 13 pnpm overrides to patch transitive
dependency vulnerabilities (38 -> 2 remaining, both in dev-only tools).

Pinned-Dependencies (5 -> 8-9): Pinned all Docker FROM images to SHA
digests, pinned pip-audit version in CI, pinned pip version in
Dockerfile.
2026-05-18 15:57:17 +08:00
SnapOtter 697566d00e fix: pre-decode HEIC/HEIF in info tool to prevent stats failure
Sharp can read HEIF container headers (metadata succeeds) but cannot
decode HEVC pixels (stats fails with "No decoding plugin installed").
Unconditionally pre-decode HEIF files via heif-dec CLI before any Sharp
operations, matching the createToolRoute factory behavior.
2026-05-18 14:44:21 +08:00
SnapOtter 475af753bf chore: add pre-push hook guard and test scene fixture 2026-05-18 10:20:12 +08:00
SnapOtter 398f65cd3f chore: add demo dir to gitignore and local wiki dev scripts 2026-05-18 10:20:04 +08:00
SnapOtter 6843ae98b4 fix: translate AI features settings section to Italian 2026-05-18 10:19:55 +08:00
SnapOtter 73842ded92 fix: remove duplicate privacy policy link from main content area 2026-05-18 10:19:51 +08:00
SnapOtter 6a2b19919d feat: add background preview support to before-after slider
Render custom background layers (solid color, image, checkerboard) and
drop shadow in the after panel, constrained to the actual image content
area. Supports remove-bg tool preview effects.
2026-05-18 10:19:47 +08:00
SnapOtter 36431bce48 fix: improve AI feature install error handling and resource limits
Handle OOM kills (exit code 137) with actionable memory guidance,
filter ANSI/progress noise from error output, add --no-cache-dir to
pip installs, reduce download concurrency to 2, and bump default
container memory from 4g to 6g.
2026-05-18 10:19:43 +08:00
SnapOtter d978ae211b fix: hide size comparison percentage on non-compression tools
Only show "X% smaller/larger" badges on compress and optimize-for-web
where file size reduction is the goal. All other tools no longer display
irrelevant size percentage data in the results pane.
2026-05-18 10:08:19 +08:00
SnapOtter 8ea4399739 feat: replace editor icon with custom PNG using CSS mask 2026-05-17 11:47:39 +08:00
SnapOtter d693d5e762 fix: update OG images from 45+ to 50+ tools 2026-05-17 10:13:27 +08:00
SnapOtter 4eb07ae2fd fix: allow demo indexing and update navbar test for Try Demo CTA
Remove noindex meta tag from demo so Google can index demo.snapotter.com.
Update navbar test to match renamed "Try Demo" button (was "Book a Demo").
2026-05-17 09:33:46 +08:00
SnapOtter 228f70d011 feat: add static demo site at demo.snapotter.com
- New apps/demo/ that reuses apps/web components with mocked API layer
- Full UI shell: login, change password, analytics consent, dashboard, all tool pages
- Stateful mock tracks session flow (password change, analytics consent)
- Demo banner with link to GitHub repo
- Processing attempts show info message with GitHub link
- Deployed to Cloudflare Pages as static site (no backend)

Also links demo across all surfaces:
- README: "Live Demo" badge
- Landing navbar: "Try Demo" CTA button (replaces "Book a Demo")
- Landing hero: "No sign-ups. No credit card." tagline
- Docs getting-started: "Try before installing" tip box

Other changes:
- Docs: move NVIDIA GPU section above GHCR, demote GHCR to collapsed details
- Fix before-after slider checkerboard background for transparency
- Fix remove-bg preview reset when no effects applied
2026-05-17 09:25:12 +08:00
SnapOtter df2d1286d6 fix(seo): add structured data for sitelinks and fix OG image
Replace Organization schema with WebSite schema, add SiteNavigationElement
for Documentation/FAQ/GitHub/Contact/Discord. Add BreadcrumbList to FAQ
and Contact pages. Remove outdated og-image.svg (source already uses PNG).
Update sitemap with lastmod and changefreq.
2026-05-16 23:11:39 +08:00
SnapOtter 148118d969 feat: add generate strong password button to Add Members form
Add a "Generate strong password" button with Sparkles icon to the
Add Members form in Settings > People. Generated passwords are shown
in plain text with a copy button and an amber warning to copy before
creating the user. Also upgraded the button style on the change
password page to match. Translated copy/warning strings for all 21
locales.

Closes #139
2026-05-16 23:08:19 +08:00
SnapOtter e316dff294 docs: add dedicated sponsor section with full-width banner to README 2026-05-16 22:51:13 +08:00
SnapOtter 2951161414 fix: prevent dropdown clipping in settings People and Teams tables
Remove overflow-hidden from table wrappers that was clipping the
actions dropdown menu. Apply rounded corners directly to header and
last-row elements to preserve the visual appearance.

Closes #139
2026-05-16 22:45:51 +08:00
SnapOtter fd69a60e48 feat: add "Hello from the otter side" easter eggs
Custom 404 pages for landing and docs sites, otter greeting on the
first-login sidebar, and a one-time welcome toast after password change.
2026-05-16 22:45:22 +08:00
SnapOtter b5db8f3192 docs: restructure README sponsor section and add pink fund button to docs
Fold the sponsor call-to-action into the Contributing section as a
natural bullet point instead of a standalone heavy section. Remove
the large badge buttons. Keep star history chart under Contributing.

Add a pink "Fund Development" button component to the docs site nav
bar (left of Star on GitHub), matching the landing page style.
Remove the plain-text nav link that replaced the heart icon.
2026-05-16 21:14:06 +08:00
SnapOtter 6e103d31f8 docs: add Fund Development button to landing navbar and docs nav
Add pink heart-styled "Fund Development" button to landing page
navbar (left of Star on GitHub) and mobile menu. Rename "Sponsor"
to "Fund Development" in the open-source section. Replace icon-only
heart in docs socialLinks with a named "Fund Development" nav link.
2026-05-16 20:00:25 +08:00
SnapOtter 50a25691d9 docs: add GitHub Sponsors CTAs across README, landing, and docs
Remove Ko-fi from FUNDING.yml since GitHub Sponsors is now active.
Add sponsor badge to README badge row and support section. Add
sponsor button to landing page open-source section and footer.
Add heart icon social link to docs site nav bar.
2026-05-16 19:38:12 +08:00
SnapOtter 6717207c48 fix(ci): add system deps to unit test job for exiftool/heic tests 2026-05-16 19:35:05 +08:00
SnapOtter 1fb2802eea fix(ci): split unit/integration tests and fix landing test failures
- Separate unit tests (fast, no system deps) from integration test
  shards to prevent vi.mock db leakage across test types
- Fix hero test: update expected subtitle to match current copy
- Fix FAQ test: add missing json-ld alias in vitest config and mock
- Integration tests run in 4 parallel shards (30min timeout each)
2026-05-16 19:12:43 +08:00
SnapOtter d886cc2486 fix(ci): parallelize tests into 4 shards to avoid timeout
The full test suite takes ~100 minutes sequentially. Split into 4
parallel shards using Vitest's --shard flag so each completes in
~25 minutes. Removed coverage from CI (was causing overhead without
being reported anywhere). 30-minute timeout per shard as safety net.
2026-05-16 18:41:15 +08:00
SnapOtter 6b79184a93 fix(ci): downsize remaining oversized test fixtures (JXL + HEIF)
- sample.jxl: 6000x4000 (1.1MB) -> 1440x960 (70KB)
- motorcycle.heif: 8736x5856 (2.5MB) -> 1440x960 (224KB)
- Bump test job timeout to 20 minutes for headroom
2026-05-16 18:17:58 +08:00
SnapOtter 5a355aa2ec fix(ci): downsize HEIF test fixture to prevent timeout
The sample.heif was 8736x5856 (2.5MB), causing each processing
operation to take 17-38s in CI. Resized to 1432x960 (224KB) and added
a 15-minute timeout to the test job.
2026-05-16 17:59:26 +08:00
SnapOtter 799cb86229 chore: update dashboard images with and without details toggle 2026-05-16 17:26:48 +08:00