* 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
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.
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.
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.
Math.random() is not cryptographically secure. Replace with
crypto.getRandomValues() in both generatePassword() functions
to resolve CodeQL js/insecure-randomness alerts.
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.
- 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 /
* 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
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.
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.
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.
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.
- 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
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.
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
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
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.
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.
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.
Rewrite contributing page to match new CONTRIBUTING.md with PR types,
CLA process, and good-first-issue links. Update translation guide to
encourage direct PRs instead of issue-only workflow.
The <img src> tag cannot send Authorization headers, so thumbnail
requests returned 401 and browsers displayed the alt text (filename)
instead of the image. Replaced with AuthImage component that fetches
via fetch() with proper auth headers and renders blob URLs.
- Bump all workspace package versions to 1.17.0
- Update APP_VERSION constant and OpenAPI spec
- Update AI tool count from 15 to 16 across docs and i18n
- Update tool table with AI Canvas Expand, Meme Generator, Beautify
- Add image editor, OIDC, and 20 languages to README features
- Add release notes for v1.17.0
- Add JSON-LD structured data and SEO improvements to landing/docs
- Grant admin role to anonymous user when AUTH_ENABLED=false
- Add DEFAULT_TOOL_VIEW env var (sidebar|fullscreen)
- Hide auth-dependent settings sections when auth disabled
- Fix session endpoint to return admin role consistently
- Seed anonymous user row in DB to satisfy FK constraints
- Add 25 new tests covering anonymous mode behavior
Closes#135
When AUTH_ENABLED=false, seed an "anonymous" user row in the users
table so API keys, pipelines, and user files don't fail with FK
constraint violations. Previously, the synthetic anonymous user only
existed in memory (attached by the middleware), but any DB operation
referencing userId "anonymous" would violate foreign key constraints.
Also adds 25 new tests covering:
- Integration: ensureAnonymousUser, FK constraints, settings save,
API key and pipeline operations for anonymous mode
- Frontend: useAuth hook anonymous happy path (role, permissions,
hasPermission, session endpoint bypass)
- Frontend: settings dialog nav filtering (authRequired hides
security/people/teams/roles when auth disabled)
- Backend: session endpoint returns admin role when auth disabled
The GET /api/auth/session endpoint still returned role "user" and
user-level permissions when AUTH_ENABLED=false, inconsistent with the
middleware which now assigns role "admin". Fix the session endpoint to
match so API clients get the correct role.
- Filter known client-error noise (rate limit, empty body, unsupported
media type, content-length mismatch, premature close) from Sentry
via beforeSend to stop 644 events of non-actionable noise
- Sanitize x-output-filename header to prevent TypeError on non-ASCII
filenames in optimize-for-web preview (23 events)
- Handle EPIPE on Python dispatcher stdin write with graceful fallback
to per-request spawning instead of crashing (NODE-W)
- Map EACCES on storage directory/file write to proper 503 status
instead of generic 500 (NODE-P, 3 events)
Security, People, Teams, and Roles sections are meaningless without
auth and could cause problems (e.g., creating orphan users that block
admin bootstrap on re-enable). Hide them via an authRequired flag on
nav items, checked alongside the existing requiredPermission filter.
When AUTH_ENABLED=false, the anonymous user was assigned the "user" role
which lacks settings:write permission, making all settings saves return
403. Since no admin exists when auth is disabled, settings were
permanently read-only. Promote the anonymous user to "admin" so the
single user has full control of the instance.
Also adds DEFAULT_TOOL_VIEW env var (sidebar|fullscreen) following the
existing DEFAULT_THEME pattern, seeded via ensureDefaultSettings() on
first boot.
Closes#135
ai-canvas-expand was added to constants.ts and route files but never
added to the landing page bento grid, causing all hardcoded counts
to remain at 51. This updates all references across source, docs,
i18n, and tests to reflect the correct count of 52 tools.
- Change "52 tools" to "51 tools" in 6 places (bento-grid heading,
typing cursor, pricing, meta description, OG description, Twitter)
- Change "14 AI models" to "15" in FAQ page
- Add "Available in 21 languages" to pricing feature list
- fix(db): migration 0012 column order mismatch causing NOT NULL
constraint failure on existing databases; use explicit column
mapping instead of SELECT *
- fix(db): disable FK checks during migrations to allow SQLite
table-recreation pattern (DROP + RENAME)
- fix(security): filter cookie_secret and instance_id from settings
API response for non-admin users
- fix(lint): resolve all 7 API lint warnings (noParameterAssign,
noImplicitAnyLet) in compose, image-enhancement, and workspace
- fix(docs): correct permission count from 16 to 14 in CLAUDE.md
- fix(e2e): resolve 44 Playwright test failures across 8 spec files
including locator specificity, compress mode defaults, format count,
restore-photo UI drift, stitch image count, GIF animated fixtures,
submit button timing, and processing timeouts
Add complete i18n infrastructure with 21 supported languages:
English, Simplified Chinese, Traditional Chinese, Japanese, Korean,
Spanish, French, Italian, Brazilian Portuguese, German, Dutch, Swedish,
Russian, Polish, Ukrainian, Arabic (RTL), Turkish, Hindi, Vietnamese,
Indonesian, and Thai.
- I18nProvider context with three-tier locale detection
(user preference > navigator.languages > instance default > English)
- ~1500 translation keys per locale with TypeScript-enforced completeness
- Dynamic code-splitting: only the active locale is loaded at runtime
- Language selectors in footer, login page, settings, and mobile sidebar
- Arabic RTL support with CSS logical properties across all components
- Tool names, descriptions, and categories translated via i18n helpers
- Public API endpoint GET /api/v1/config/locale for instance default
- Multi-script font stack (CJK, Arabic, Devanagari, Thai, Cyrillic)
- format() and plural() helpers for interpolation and pluralization
- API error translation mapping (translateApiError)
- 36 Playwright e2e tests verifying all 21 locales load correctly
- 25 unit tests for format, plural, locale detection, and completeness
- Updated translations.md docs and CLAUDE.md conventions
- LOGIN_ATTEMPT_LIMIT: 500 -> 30 in Dockerfile (matching code default)
- RATE_LIMIT_PER_MIN=0 now means no global limit (50K ceiling) instead
of 1 req/min, preserving backward compatibility with existing deploys
while keeping per-route limits (login brute-force) active