diff --git a/.env.example b/.env.example index 0ccb9811..433733ef 100644 --- a/.env.example +++ b/.env.example @@ -35,9 +35,9 @@ LOGIN_ATTEMPT_LIMIT=10 # Set to true in CI/dev to skip the forced password-change on the default admin # SKIP_MUST_CHANGE_PASSWORD=false -DB_PATH=./data/ashim.db +DB_PATH=./data/snapotter.db WORKSPACE_PATH=./tmp/workspace FILES_STORAGE_PATH=./data/files DEFAULT_THEME=light DEFAULT_LOCALE=en -APP_NAME=ashim +APP_NAME=snapotter diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index d2d44f2a..2d22651f 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,2 @@ -github: ashim-hq -ko_fi: ashim-hq +github: snapotter-hq +ko_fi: snapotter-hq diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 3319630e..18334f13 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -9,7 +9,7 @@ body: options: - label: I searched existing issues and didn't find a duplicate required: true - - label: I'm running the latest version of ashim + - label: I'm running the latest version of SnapOtter required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3a505367..74a2db04 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,8 @@ blank_issues_enabled: false contact_links: - name: Documentation - url: https://ashim-hq.github.io/ashim/ + url: https://docs.snapotter.com/ about: Check the docs for setup guides, configuration, and API reference. - name: Security vulnerability - url: https://github.com/ashim-hq/ashim/security/advisories/new + url: https://github.com/snapotter-hq/snapotter/security/advisories/new about: Report security issues privately through GitHub Security Advisories. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 6aaa3c36..08077924 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,12 +1,12 @@ -**This project does not accept pull requests.** Please close this PR and [open an issue](https://github.com/ashim-hq/ashim/issues/new/choose) instead. See [CONTRIBUTING.md](CONTRIBUTING.md) for details. +**This project does not accept pull requests.** Please close this PR and [open an issue](https://github.com/snapotter-hq/snapotter/issues/new/choose) instead. See [CONTRIBUTING.md](CONTRIBUTING.md) for details. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f276e651..7d35c7ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ on: - "CONTRIBUTING.md" - "images/**" - "apps/docs/**" + - "apps/landing/**" - "docs/**" pull_request: branches: [main] @@ -16,6 +17,7 @@ on: - "CONTRIBUTING.md" - "images/**" - "apps/docs/**" + - "apps/landing/**" - "docs/**" concurrency: @@ -111,7 +113,7 @@ jobs: context: . file: docker/Dockerfile push: false - tags: ashim:ci + tags: snapotter:ci build-args: SKIP_MODEL_DOWNLOADS=true cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:cache-linux-amd64 cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:cache-ci,mode=max diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index f8792f8a..531c9f2c 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -1,4 +1,4 @@ -name: Deploy Docs to GitHub Pages +name: Deploy Docs to Cloudflare Pages on: push: @@ -7,48 +7,32 @@ on: - "apps/docs/**" workflow_dispatch: -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. concurrency: - group: pages - cancel-in-progress: false + group: deploy-docs + cancel-in-progress: true jobs: - build: + deploy: + name: Deploy runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup pnpm - uses: pnpm/action-setup@v4 - - name: Setup Node - uses: actions/setup-node@v4 + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - - name: Install dependencies - run: pnpm install --frozen-lockfile - - name: Build Docs - run: pnpm --filter @ashim/docs docs:build - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: apps/docs/.vitepress/dist - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - needs: build - runs-on: ubuntu-latest - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 + - run: pnpm install --frozen-lockfile + + - name: Build Docs + run: pnpm --filter @snapotter/docs docs:build + + - name: Deploy to Cloudflare Pages + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: pages deploy apps/docs/.vitepress/dist --project-name snapotter-docs --branch main --commit-dirty=true diff --git a/.github/workflows/deploy-landing.yml b/.github/workflows/deploy-landing.yml new file mode 100644 index 00000000..af08186d --- /dev/null +++ b/.github/workflows/deploy-landing.yml @@ -0,0 +1,38 @@ +name: Deploy Landing to Cloudflare Pages + +on: + push: + branches: [main] + paths: + - "apps/landing/**" + workflow_dispatch: + +concurrency: + group: deploy-landing + cancel-in-progress: true + +jobs: + deploy: + name: Deploy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Build Landing Page + run: pnpm --filter @snapotter/landing build + + - name: Deploy to Cloudflare Pages + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: pages deploy apps/landing/out --project-name snapotter-landing --branch main --commit-dirty=true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b5aa403f..28d01ec2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,7 +109,7 @@ jobs: uses: docker/metadata-action@v5 with: images: | - ashimhq/ashim + snapotterhq/snapotter ghcr.io/${{ github.repository }} - name: Build and push by digest @@ -120,7 +120,7 @@ jobs: file: docker/Dockerfile platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,"name=ashimhq/ashim,ghcr.io/${{ github.repository }}",push-by-digest=true,name-canonical=true,push=true + outputs: type=image,"name=snapotterhq/snapotter,ghcr.io/${{ github.repository }}",push-by-digest=true,name-canonical=true,push=true cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:cache-${{ env.PLATFORM_PAIR }} cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:cache-${{ env.PLATFORM_PAIR }},mode=max @@ -168,7 +168,7 @@ jobs: uses: docker/metadata-action@v5 with: images: | - ashimhq/ashim + snapotterhq/snapotter ghcr.io/${{ github.repository }} tags: | type=semver,pattern={{version}},value=v${{ needs.release.outputs.new_version }} @@ -180,8 +180,8 @@ jobs: working-directory: /tmp/digests run: | docker buildx imagetools create \ - $(jq -cr '.tags | map(select(startswith("ashimhq/")) | "-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf 'ashimhq/ashim@sha256:%s ' *) + $(jq -cr '.tags | map(select(startswith("snapotterhq/")) | "-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf 'snapotterhq/snapotter@sha256:%s ' *) - name: Create GHCR manifest working-directory: /tmp/digests diff --git a/.gitignore b/.gitignore index 35b66488..5ea690c0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ data/ tmp/ .env .env.local +.env.cloudflare +.env.* .DS_Store .playwright-mcp/ .vite/ @@ -22,6 +24,7 @@ __pycache__/ # Build artifacts .next/ +.vitepress/cache/ out/ coverage/ *.tsbuildinfo diff --git a/CHANGELOG.md b/CHANGELOG.md index 78c7ad49..ec52d351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,805 +1,805 @@ -## [1.15.8](https://github.com/ashim-hq/ashim/compare/v1.15.7...v1.15.8) (2026-04-17) +## [1.15.8](https://github.com/snapotter-hq/snapotter/compare/v1.15.7...v1.15.8) (2026-04-17) ### Bug Fixes -* copy Node.js from official image instead of apt-get install ([536125e](https://github.com/ashim-hq/ashim/commit/536125ec9fbc5758bdd3e8f0f4c44253de2231c7)) +* copy Node.js from official image instead of apt-get install ([536125e](https://github.com/snapotter-hq/snapotter/commit/536125ec9fbc5758bdd3e8f0f4c44253de2231c7)) -## [1.15.7](https://github.com/ashim-hq/ashim/compare/v1.15.6...v1.15.7) (2026-04-17) +## [1.15.7](https://github.com/snapotter-hq/snapotter/compare/v1.15.6...v1.15.7) (2026-04-17) ### Bug Fixes -* add retry with backoff for apt-get update on CUDA base image ([3d6db5a](https://github.com/ashim-hq/ashim/commit/3d6db5a32d3f9292d5476e9bd80c1f06624fa316)) +* add retry with backoff for apt-get update on CUDA base image ([3d6db5a](https://github.com/snapotter-hq/snapotter/commit/3d6db5a32d3f9292d5476e9bd80c1f06624fa316)) -## [1.15.6](https://github.com/ashim-hq/ashim/compare/v1.15.5...v1.15.6) (2026-04-17) +## [1.15.6](https://github.com/snapotter-hq/snapotter/compare/v1.15.5...v1.15.6) (2026-04-17) ### Performance Improvements -* parallelize model downloads and switch to registry cache ([79c4ed6](https://github.com/ashim-hq/ashim/commit/79c4ed6a359b008dedeb154a55e2764ee0e3d9fa)) +* parallelize model downloads and switch to registry cache ([79c4ed6](https://github.com/snapotter-hq/snapotter/commit/79c4ed6a359b008dedeb154a55e2764ee0e3d9fa)) -## [1.15.5](https://github.com/ashim-hq/ashim/compare/v1.15.4...v1.15.5) (2026-04-17) +## [1.15.5](https://github.com/snapotter-hq/snapotter/compare/v1.15.4...v1.15.5) (2026-04-17) ### Bug Fixes -* exclude e2e-docker tests from Vitest runner ([8df18c5](https://github.com/ashim-hq/ashim/commit/8df18c56a6c69e2a188cf0e7c97e692cd4c0e7ec)) +* exclude e2e-docker tests from Vitest runner ([8df18c5](https://github.com/snapotter-hq/snapotter/commit/8df18c56a6c69e2a188cf0e7c97e692cd4c0e7ec)) -## [1.15.4](https://github.com/ashim-hq/ashim/compare/v1.15.3...v1.15.4) (2026-04-17) +## [1.15.4](https://github.com/snapotter-hq/snapotter/compare/v1.15.3...v1.15.4) (2026-04-17) ### Bug Fixes -* verbose error handling, batch processing, and multi-file support ([3223960](https://github.com/ashim-hq/ashim/commit/32239600ae6ce30628e77e61a805ca0a167b5068)) -* verbose errors, batch processing, multi-file support ([#1](https://github.com/ashim-hq/ashim/issues/1)) ([8b87cf8](https://github.com/ashim-hq/ashim/commit/8b87cf888c6194e2af427a180607d7c53a1d15b9)) +* verbose error handling, batch processing, and multi-file support ([3223960](https://github.com/snapotter-hq/snapotter/commit/32239600ae6ce30628e77e61a805ca0a167b5068)) +* verbose errors, batch processing, multi-file support ([#1](https://github.com/snapotter-hq/snapotter/issues/1)) ([8b87cf8](https://github.com/snapotter-hq/snapotter/commit/8b87cf888c6194e2af427a180607d7c53a1d15b9)) -## [1.15.3](https://github.com/ashim-hq/ashim/compare/v1.15.2...v1.15.3) (2026-04-16) +## [1.15.3](https://github.com/snapotter-hq/snapotter/compare/v1.15.2...v1.15.3) (2026-04-16) ### Bug Fixes -* retry apt-get update on transient mirror sync errors (Acquire::Retries=3) ([cec7163](https://github.com/ashim-hq/ashim/commit/cec71632d0c868c3a413b813ff15baccc8fa8cdd)) +* retry apt-get update on transient mirror sync errors (Acquire::Retries=3) ([cec7163](https://github.com/snapotter-hq/snapotter/commit/cec71632d0c868c3a413b813ff15baccc8fa8cdd)) -## [1.15.2](https://github.com/ashim-hq/ashim/compare/v1.15.1...v1.15.2) (2026-04-16) +## [1.15.2](https://github.com/snapotter-hq/snapotter/compare/v1.15.1...v1.15.2) (2026-04-16) ### Bug Fixes -* use GHCR_TOKEN with write:packages scope for GHCR login ([e14414f](https://github.com/ashim-hq/ashim/commit/e14414f3061981b1454dc7d4504c64ec01db945e)) +* use GHCR_TOKEN with write:packages scope for GHCR login ([e14414f](https://github.com/snapotter-hq/snapotter/commit/e14414f3061981b1454dc7d4504c64ec01db945e)) -## [1.15.1](https://github.com/ashim-hq/ashim/compare/v1.15.0...v1.15.1) (2026-04-16) +## [1.15.1](https://github.com/snapotter-hq/snapotter/compare/v1.15.0...v1.15.1) (2026-04-16) ### Bug Fixes -* **docker:** create /opt/models unconditionally so chown works in CI ([93ce289](https://github.com/ashim-hq/ashim/commit/93ce2891cc26afc93f01168d008927d3d356c1a9)) -* **docker:** run frontend builder on BUILDPLATFORM to fix esbuild crash under QEMU ([6a3ad0d](https://github.com/ashim-hq/ashim/commit/6a3ad0d496e291b30a3f719ca079c43ce7aab705)) -* resolve runtime model path mismatch for non-root Docker user ([f28792a](https://github.com/ashim-hq/ashim/commit/f28792a5ed78221f38cf2f3c80cae9f24cd7f5e3)) +* **docker:** create /opt/models unconditionally so chown works in CI ([93ce289](https://github.com/snapotter-hq/snapotter/commit/93ce2891cc26afc93f01168d008927d3d356c1a9)) +* **docker:** run frontend builder on BUILDPLATFORM to fix esbuild crash under QEMU ([6a3ad0d](https://github.com/snapotter-hq/snapotter/commit/6a3ad0d496e291b30a3f719ca079c43ce7aab705)) +* resolve runtime model path mismatch for non-root Docker user ([f28792a](https://github.com/snapotter-hq/snapotter/commit/f28792a5ed78221f38cf2f3c80cae9f24cd7f5e3)) -# [1.14.0](https://github.com/ashim-hq/ashim/compare/v1.13.0...v1.14.0) (2026-04-10) +# [1.14.0](https://github.com/snapotter-hq/snapotter/compare/v1.13.0...v1.14.0) (2026-04-10) ### Bug Fixes -* add FILES_STORAGE_PATH to Dockerfile ENV to prevent data loss ([b575243](https://github.com/ashim-hq/ashim/commit/b575243e9a0cb2ac4567d785a74e57dea912e9e2)) -* add shutdown timeout and improve health endpoint ([986ad37](https://github.com/ashim-hq/ashim/commit/986ad37bb5e6644dd93521018a1bcd2d6243f502)) -* address code review findings before merge ([caf65bc](https://github.com/ashim-hq/ashim/commit/caf65bc4697ddfea27674b56fd2e8de847edc734)) -* correct PaddleOCR language codes for model download and OCR ([e1ee571](https://github.com/ashim-hq/ashim/commit/e1ee57103c201f104b737c2719d0014d4912d4b2)) -* force CPU mode in download_models.py for build-time compatibility ([b4b59a7](https://github.com/ashim-hq/ashim/commit/b4b59a7500375bc2e65cb0050e5308b07610d2cf)) -* handle paddlepaddle-gpu CUDA import at build time gracefully ([0083a74](https://github.com/ashim-hq/ashim/commit/0083a741a9a3924ccc37c4e622c2980a8a41f1a3)) -* install cuda-compat stubs for build-time PaddlePaddle import ([d31d665](https://github.com/ashim-hq/ashim/commit/d31d66556ef0aa7c20a73a94f5d95b54b99fbb8a)) -* load RealESRGAN pretrained weights for actual AI upscaling ([fa9569c](https://github.com/ashim-hq/ashim/commit/fa9569c920d6bdac094dcd661fc5cf3b4be3f17a)) -* revert to npx tsx in CMD for pnpm compatibility ([e55253d](https://github.com/ashim-hq/ashim/commit/e55253dee03f9e93187d50e0ffb66b423a1230c0)) -* simplify smoke test to CPU-only imports for build-time compat ([3481663](https://github.com/ashim-hq/ashim/commit/34816639609cbccab91a5cad5760fea769c4b565)) -* skip RealESRGAN import check on arm64 in smoke test ([1e2ef52](https://github.com/ashim-hq/ashim/commit/1e2ef5284686253ae33e05411a515369b7f41a3e)) -* split paddlepaddle-gpu and paddleocr installs, use --extra-index-url ([74183e8](https://github.com/ashim-hq/ashim/commit/74183e8dc1e3d8f90cff4484f5526c3c3dfba9a6)) -* suppress ML library stdout noise in ocr.py and upscale.py ([c0b419d](https://github.com/ashim-hq/ashim/commit/c0b419de21acb92b243ef78191dff6a2153c5961)) -* use PaddlePaddle GPU package index for CUDA wheels ([dd9528f](https://github.com/ashim-hq/ashim/commit/dd9528f53c9bcf148842ab94f14a4ebd5ae223ec)) -* use platform-specific mediapipe version for arm64 compatibility ([7face19](https://github.com/ashim-hq/ashim/commit/7face19238f54cfea02d453b697e34b50ccd9d21)) +* add FILES_STORAGE_PATH to Dockerfile ENV to prevent data loss ([b575243](https://github.com/snapotter-hq/snapotter/commit/b575243e9a0cb2ac4567d785a74e57dea912e9e2)) +* add shutdown timeout and improve health endpoint ([986ad37](https://github.com/snapotter-hq/snapotter/commit/986ad37bb5e6644dd93521018a1bcd2d6243f502)) +* address code review findings before merge ([caf65bc](https://github.com/snapotter-hq/snapotter/commit/caf65bc4697ddfea27674b56fd2e8de847edc734)) +* correct PaddleOCR language codes for model download and OCR ([e1ee571](https://github.com/snapotter-hq/snapotter/commit/e1ee57103c201f104b737c2719d0014d4912d4b2)) +* force CPU mode in download_models.py for build-time compatibility ([b4b59a7](https://github.com/snapotter-hq/snapotter/commit/b4b59a7500375bc2e65cb0050e5308b07610d2cf)) +* handle paddlepaddle-gpu CUDA import at build time gracefully ([0083a74](https://github.com/snapotter-hq/snapotter/commit/0083a741a9a3924ccc37c4e622c2980a8a41f1a3)) +* install cuda-compat stubs for build-time PaddlePaddle import ([d31d665](https://github.com/snapotter-hq/snapotter/commit/d31d66556ef0aa7c20a73a94f5d95b54b99fbb8a)) +* load RealESRGAN pretrained weights for actual AI upscaling ([fa9569c](https://github.com/snapotter-hq/snapotter/commit/fa9569c920d6bdac094dcd661fc5cf3b4be3f17a)) +* revert to npx tsx in CMD for pnpm compatibility ([e55253d](https://github.com/snapotter-hq/snapotter/commit/e55253dee03f9e93187d50e0ffb66b423a1230c0)) +* simplify smoke test to CPU-only imports for build-time compat ([3481663](https://github.com/snapotter-hq/snapotter/commit/34816639609cbccab91a5cad5760fea769c4b565)) +* skip RealESRGAN import check on arm64 in smoke test ([1e2ef52](https://github.com/snapotter-hq/snapotter/commit/1e2ef5284686253ae33e05411a515369b7f41a3e)) +* split paddlepaddle-gpu and paddleocr installs, use --extra-index-url ([74183e8](https://github.com/snapotter-hq/snapotter/commit/74183e8dc1e3d8f90cff4484f5526c3c3dfba9a6)) +* suppress ML library stdout noise in ocr.py and upscale.py ([c0b419d](https://github.com/snapotter-hq/snapotter/commit/c0b419de21acb92b243ef78191dff6a2153c5961)) +* use PaddlePaddle GPU package index for CUDA wheels ([dd9528f](https://github.com/snapotter-hq/snapotter/commit/dd9528f53c9bcf148842ab94f14a4ebd5ae223ec)) +* use platform-specific mediapipe version for arm64 compatibility ([7face19](https://github.com/snapotter-hq/snapotter/commit/7face19238f54cfea02d453b697e34b50ccd9d21)) ### Features -* expand model pre-download with verification and smoke test ([a9e3b96](https://github.com/ashim-hq/ashim/commit/a9e3b9688776a51efd2f42cae810de425cf1d9cf)) -* simplify CI to single unified Docker build ([b385a2e](https://github.com/ashim-hq/ashim/commit/b385a2eabb255f7a8fe2d3720a358ff5bf254310)) -* simplify compose to single file, add log rotation ([84f7057](https://github.com/ashim-hq/ashim/commit/84f7057a49850b7a47440099ec2caad8d3b87efe)) -* unified Docker image with GPU auto-detection ([6c3eb3b](https://github.com/ashim-hq/ashim/commit/6c3eb3b876cee0301d5fb3ed8324a3c8e92b1307)) +* expand model pre-download with verification and smoke test ([a9e3b96](https://github.com/snapotter-hq/snapotter/commit/a9e3b9688776a51efd2f42cae810de425cf1d9cf)) +* simplify CI to single unified Docker build ([b385a2e](https://github.com/snapotter-hq/snapotter/commit/b385a2eabb255f7a8fe2d3720a358ff5bf254310)) +* simplify compose to single file, add log rotation ([84f7057](https://github.com/snapotter-hq/snapotter/commit/84f7057a49850b7a47440099ec2caad8d3b87efe)) +* unified Docker image with GPU auto-detection ([6c3eb3b](https://github.com/snapotter-hq/snapotter/commit/6c3eb3b876cee0301d5fb3ed8324a3c8e92b1307)) -# [1.13.0](https://github.com/ashim-hq/ashim/compare/v1.12.0...v1.13.0) (2026-04-10) +# [1.13.0](https://github.com/snapotter-hq/snapotter/compare/v1.12.0...v1.13.0) (2026-04-10) ### Bug Fixes -* complete RBAC implementation lost during merge ([cc8a272](https://github.com/ashim-hq/ashim/commit/cc8a27239b02a63ca88abc3e363c8a46f89674e8)) +* complete RBAC implementation lost during merge ([cc8a272](https://github.com/snapotter-hq/snapotter/commit/cc8a27239b02a63ca88abc3e363c8a46f89674e8)) ### Features -* add backend permission map and requirePermission middleware ([1a99571](https://github.com/ashim-hq/ashim/commit/1a995711535a1525e709cdd7bff75361f457e942)) -* add permission checks and admin override to API key routes ([d776680](https://github.com/ashim-hq/ashim/commit/d776680f2d2342e35b84821792d6c24ae7e0ffbc)) -* add permission checks and admin override to pipeline routes ([59f40db](https://github.com/ashim-hq/ashim/commit/59f40dbfd4a97f8691b5fbbf6d338063c389987b)) -* add permission checks and ownership scoping to user-files routes ([86ba698](https://github.com/ashim-hq/ashim/commit/86ba69825a1dd87c9f868d79cd806b7d594cce1b)) -* add shared Permission and Role types ([2f594e9](https://github.com/ashim-hq/ashim/commit/2f594e96057c72bf107f3012426e87af5f97eb94)) -* add tools:use permission check to tool, batch, pipeline, and upload routes ([885ace5](https://github.com/ashim-hq/ashim/commit/885ace54f09b3301989f8aa404c15f60e19c054d)) -* extend useAuth hook with role and permissions from session ([e0ba8be](https://github.com/ashim-hq/ashim/commit/e0ba8be7b3211299c8cde90b2d22e7796eee2206)) -* filter settings tabs by user permissions, remove admin fallback ([bcbd24a](https://github.com/ashim-hq/ashim/commit/bcbd24a2395b93b64dbbf638ba0138f9ec9ba9da)) -* include permissions and teamName in login/session responses ([4943177](https://github.com/ashim-hq/ashim/commit/49431772ec6a02eae8aced48da92ef87a6c89afb)) -* replace requireAdmin with requirePermission on all routes ([af7f57d](https://github.com/ashim-hq/ashim/commit/af7f57d52f49c8f8412876639076084c96eba284)) +* add backend permission map and requirePermission middleware ([1a99571](https://github.com/snapotter-hq/snapotter/commit/1a995711535a1525e709cdd7bff75361f457e942)) +* add permission checks and admin override to API key routes ([d776680](https://github.com/snapotter-hq/snapotter/commit/d776680f2d2342e35b84821792d6c24ae7e0ffbc)) +* add permission checks and admin override to pipeline routes ([59f40db](https://github.com/snapotter-hq/snapotter/commit/59f40dbfd4a97f8691b5fbbf6d338063c389987b)) +* add permission checks and ownership scoping to user-files routes ([86ba698](https://github.com/snapotter-hq/snapotter/commit/86ba69825a1dd87c9f868d79cd806b7d594cce1b)) +* add shared Permission and Role types ([2f594e9](https://github.com/snapotter-hq/snapotter/commit/2f594e96057c72bf107f3012426e87af5f97eb94)) +* add tools:use permission check to tool, batch, pipeline, and upload routes ([885ace5](https://github.com/snapotter-hq/snapotter/commit/885ace54f09b3301989f8aa404c15f60e19c054d)) +* extend useAuth hook with role and permissions from session ([e0ba8be](https://github.com/snapotter-hq/snapotter/commit/e0ba8be7b3211299c8cde90b2d22e7796eee2206)) +* filter settings tabs by user permissions, remove admin fallback ([bcbd24a](https://github.com/snapotter-hq/snapotter/commit/bcbd24a2395b93b64dbbf638ba0138f9ec9ba9da)) +* include permissions and teamName in login/session responses ([4943177](https://github.com/snapotter-hq/snapotter/commit/49431772ec6a02eae8aced48da92ef87a6c89afb)) +* replace requireAdmin with requirePermission on all routes ([af7f57d](https://github.com/snapotter-hq/snapotter/commit/af7f57d52f49c8f8412876639076084c96eba284)) -# [1.12.0](https://github.com/ashim-hq/ashim/compare/v1.11.0...v1.12.0) (2026-04-10) +# [1.12.0](https://github.com/snapotter-hq/snapotter/compare/v1.11.0...v1.12.0) (2026-04-10) ### Bug Fixes -* **a11y:** add keyboard support to pdf-to-image upload dropzone ([1778f72](https://github.com/ashim-hq/ashim/commit/1778f7266b9837a07b20f167e82e1e9b163086b7)) -* use specific selector in pdf-to-image e2e test ([b2a2c89](https://github.com/ashim-hq/ashim/commit/b2a2c890a1d25f60e392e6a2df23e1600cc3ad8d)) +* **a11y:** add keyboard support to pdf-to-image upload dropzone ([1778f72](https://github.com/snapotter-hq/snapotter/commit/1778f7266b9837a07b20f167e82e1e9b163086b7)) +* use specific selector in pdf-to-image e2e test ([b2a2c89](https://github.com/snapotter-hq/snapotter/commit/b2a2c890a1d25f60e392e6a2df23e1600cc3ad8d)) ### Features -* add pdf-to-image backend route with info and processing endpoints ([30155c1](https://github.com/ashim-hq/ashim/commit/30155c1c7073c55290d4f662f7f93779cc4512b7)) -* add pdf-to-image frontend settings component ([44bbfba](https://github.com/ashim-hq/ashim/commit/44bbfba80dfb3eb069c563e5ca691a0f8dce1eea)) -* register pdf-to-image in frontend tool registry ([5fd294c](https://github.com/ashim-hq/ashim/commit/5fd294c994e7df076c4de0016f62d952a161345b)) -* register pdf-to-image tool in shared constants and i18n ([43324c1](https://github.com/ashim-hq/ashim/commit/43324c1f23e3f278c89fa301d5a0275b12f587e7)) -* unified Docker image with GPU auto-detection ([#37](https://github.com/ashim-hq/ashim/issues/37)) ([b0083e2](https://github.com/ashim-hq/ashim/commit/b0083e2b083d0bf52b6a576f7ef67fbff0cc8cbe)) +* add pdf-to-image backend route with info and processing endpoints ([30155c1](https://github.com/snapotter-hq/snapotter/commit/30155c1c7073c55290d4f662f7f93779cc4512b7)) +* add pdf-to-image frontend settings component ([44bbfba](https://github.com/snapotter-hq/snapotter/commit/44bbfba80dfb3eb069c563e5ca691a0f8dce1eea)) +* register pdf-to-image in frontend tool registry ([5fd294c](https://github.com/snapotter-hq/snapotter/commit/5fd294c994e7df076c4de0016f62d952a161345b)) +* register pdf-to-image tool in shared constants and i18n ([43324c1](https://github.com/snapotter-hq/snapotter/commit/43324c1f23e3f278c89fa301d5a0275b12f587e7)) +* unified Docker image with GPU auto-detection ([#37](https://github.com/snapotter-hq/snapotter/issues/37)) ([b0083e2](https://github.com/snapotter-hq/snapotter/commit/b0083e2b083d0bf52b6a576f7ef67fbff0cc8cbe)) -# [1.12.0](https://github.com/ashim-hq/ashim/compare/v1.11.0...v1.12.0) (2026-04-10) +# [1.12.0](https://github.com/snapotter-hq/snapotter/compare/v1.11.0...v1.12.0) (2026-04-10) ### Features -* unified Docker image with GPU auto-detection ([#37](https://github.com/ashim-hq/ashim/issues/37)) ([b0083e2](https://github.com/ashim-hq/ashim/commit/b0083e2b083d0bf52b6a576f7ef67fbff0cc8cbe)) +* unified Docker image with GPU auto-detection ([#37](https://github.com/snapotter-hq/snapotter/issues/37)) ([b0083e2](https://github.com/snapotter-hq/snapotter/commit/b0083e2b083d0bf52b6a576f7ef67fbff0cc8cbe)) -# [1.11.0](https://github.com/ashim-hq/ashim/compare/v1.10.0...v1.11.0) (2026-04-07) +# [1.11.0](https://github.com/snapotter-hq/snapotter/compare/v1.10.0...v1.11.0) (2026-04-07) ### Features -* **docs:** auto-generate llms.txt via vitepress-plugin-llms ([ee28ec6](https://github.com/ashim-hq/ashim/commit/ee28ec66ea137127bb1f4f1bf9e43be0b9f78cbf)) +* **docs:** auto-generate llms.txt via vitepress-plugin-llms ([ee28ec6](https://github.com/snapotter-hq/snapotter/commit/ee28ec66ea137127bb1f4f1bf9e43be0b9f78cbf)) -# [1.10.0](https://github.com/ashim-hq/ashim/compare/v1.9.0...v1.10.0) (2026-04-07) +# [1.10.0](https://github.com/snapotter-hq/snapotter/compare/v1.9.0...v1.10.0) (2026-04-07) ### Features -* add content-aware resize API route and registration ([aa3cc5c](https://github.com/ashim-hq/ashim/commit/aa3cc5c6d0d602bcc88dac23684620676c4b3a3f)) -* add content-aware resize toggle to resize settings UI ([4b4464f](https://github.com/ashim-hq/ashim/commit/4b4464f4a0b63ec312d961fecc22232b39e14872)) -* add seam carving AI bridge module ([3c0f5b6](https://github.com/ashim-hq/ashim/commit/3c0f5b6c45bf0ba8b37d67aa0fa25d3c3603e888)) -* add seam carving Python script with face protection ([fb833e4](https://github.com/ashim-hq/ashim/commit/fb833e4613ab8aa63b95facc2fe621eaa27e438a)) +* add content-aware resize API route and registration ([aa3cc5c](https://github.com/snapotter-hq/snapotter/commit/aa3cc5c6d0d602bcc88dac23684620676c4b3a3f)) +* add content-aware resize toggle to resize settings UI ([4b4464f](https://github.com/snapotter-hq/snapotter/commit/4b4464f4a0b63ec312d961fecc22232b39e14872)) +* add seam carving AI bridge module ([3c0f5b6](https://github.com/snapotter-hq/snapotter/commit/3c0f5b6c45bf0ba8b37d67aa0fa25d3c3603e888)) +* add seam carving Python script with face protection ([fb833e4](https://github.com/snapotter-hq/snapotter/commit/fb833e4613ab8aa63b95facc2fe621eaa27e438a)) -# [1.9.0](https://github.com/ashim-hq/ashim/compare/v1.8.1...v1.9.0) (2026-04-07) +# [1.9.0](https://github.com/snapotter-hq/snapotter/compare/v1.8.1...v1.9.0) (2026-04-07) ### Features -* add stitch API route handler ([63ea0ba](https://github.com/ashim-hq/ashim/commit/63ea0ba5ef23ba3b1b296ae21358ce150f8f2bf2)) -* add stitch settings UI component ([6abe893](https://github.com/ashim-hq/ashim/commit/6abe893c467b4b868383e15316132787d5831029)) -* register stitch component in web tool registry ([612f7d9](https://github.com/ashim-hq/ashim/commit/612f7d90124e92ba324a59b5a6642290dc216cff)) -* register stitch route in API tool registry ([a37d54f](https://github.com/ashim-hq/ashim/commit/a37d54f2c1e72b711901b87367b4d1c9ba2a5c5b)) -* register stitch tool in shared constants and i18n ([b881416](https://github.com/ashim-hq/ashim/commit/b881416a164cc482a050adc93164fa1c88937a2f)) +* add stitch API route handler ([63ea0ba](https://github.com/snapotter-hq/snapotter/commit/63ea0ba5ef23ba3b1b296ae21358ce150f8f2bf2)) +* add stitch settings UI component ([6abe893](https://github.com/snapotter-hq/snapotter/commit/6abe893c467b4b868383e15316132787d5831029)) +* register stitch component in web tool registry ([612f7d9](https://github.com/snapotter-hq/snapotter/commit/612f7d90124e92ba324a59b5a6642290dc216cff)) +* register stitch route in API tool registry ([a37d54f](https://github.com/snapotter-hq/snapotter/commit/a37d54f2c1e72b711901b87367b4d1c9ba2a5c5b)) +* register stitch tool in shared constants and i18n ([b881416](https://github.com/snapotter-hq/snapotter/commit/b881416a164cc482a050adc93164fa1c88937a2f)) -## [1.8.1](https://github.com/ashim-hq/ashim/compare/v1.8.0...v1.8.1) (2026-04-07) +## [1.8.1](https://github.com/snapotter-hq/snapotter/compare/v1.8.0...v1.8.1) (2026-04-07) ### Bug Fixes -* add variant diagnostics to health endpoint and lite mode banner ([2c6e499](https://github.com/ashim-hq/ashim/commit/2c6e4996d5d711d1d20fb6105f55da48d6f04c62)) +* add variant diagnostics to health endpoint and lite mode banner ([2c6e499](https://github.com/snapotter-hq/snapotter/commit/2c6e4996d5d711d1d20fb6105f55da48d6f04c62)) -# [1.8.0](https://github.com/ashim-hq/ashim/compare/v1.7.7...v1.8.0) (2026-04-06) +# [1.8.0](https://github.com/snapotter-hq/snapotter/compare/v1.7.7...v1.8.0) (2026-04-06) ### Bug Fixes -* filter unsafe round-trip keys server-side in editMetadata ([32bde85](https://github.com/ashim-hq/ashim/commit/32bde85956c4d99c7b8c255fc3166a79a72644ff)) +* filter unsafe round-trip keys server-side in editMetadata ([32bde85](https://github.com/snapotter-hq/snapotter/commit/32bde85956c4d99c7b8c255fc3166a79a72644ff)) ### Features -* add edit-metadata API route with inspect and edit endpoints ([ff07b83](https://github.com/ashim-hq/ashim/commit/ff07b8301ce3db875307296d62a17037fa960360)) -* add edit-metadata UI component with granular strip support ([dcd600d](https://github.com/ashim-hq/ashim/commit/dcd600d0f4a4ded2669d3471926d63288aaada84)) -* add EditMetadataOptions type and exif-reader dep to image-engine ([39bc5bc](https://github.com/ashim-hq/ashim/commit/39bc5bc9eb02f21774fed1c0a4fbdd3d09623483)) -* extract shared metadata parsing utilities into image-engine ([c075849](https://github.com/ashim-hq/ashim/commit/c07584993f99de2eaa455c9962e3ab3eaadd9613)) -* implement editMetadata operation in image-engine ([f3be1ef](https://github.com/ashim-hq/ashim/commit/f3be1efd8b03bef84e9237fc3dac8bc6f70ff234)) -* register edit-metadata in shared constants and i18n ([4a424d7](https://github.com/ashim-hq/ashim/commit/4a424d74b5a82aff26f09b67de3f3ab4c0f5555e)) +* add edit-metadata API route with inspect and edit endpoints ([ff07b83](https://github.com/snapotter-hq/snapotter/commit/ff07b8301ce3db875307296d62a17037fa960360)) +* add edit-metadata UI component with granular strip support ([dcd600d](https://github.com/snapotter-hq/snapotter/commit/dcd600d0f4a4ded2669d3471926d63288aaada84)) +* add EditMetadataOptions type and exif-reader dep to image-engine ([39bc5bc](https://github.com/snapotter-hq/snapotter/commit/39bc5bc9eb02f21774fed1c0a4fbdd3d09623483)) +* extract shared metadata parsing utilities into image-engine ([c075849](https://github.com/snapotter-hq/snapotter/commit/c07584993f99de2eaa455c9962e3ab3eaadd9613)) +* implement editMetadata operation in image-engine ([f3be1ef](https://github.com/snapotter-hq/snapotter/commit/f3be1efd8b03bef84e9237fc3dac8bc6f70ff234)) +* register edit-metadata in shared constants and i18n ([4a424d7](https://github.com/snapotter-hq/snapotter/commit/4a424d74b5a82aff26f09b67de3f3ab4c0f5555e)) -## [1.7.7](https://github.com/ashim-hq/ashim/compare/v1.7.6...v1.7.7) (2026-04-06) +## [1.7.7](https://github.com/snapotter-hq/snapotter/compare/v1.7.6...v1.7.7) (2026-04-06) ### Bug Fixes -* improve AI tool reliability for face detection and background removal ([#25](https://github.com/ashim-hq/ashim/issues/25)) ([1963a80](https://github.com/ashim-hq/ashim/commit/1963a8012c572fe86132e6847e313019165416da)) +* improve AI tool reliability for face detection and background removal ([#25](https://github.com/snapotter-hq/snapotter/issues/25)) ([1963a80](https://github.com/snapotter-hq/snapotter/commit/1963a8012c572fe86132e6847e313019165416da)) -## [1.7.6](https://github.com/ashim-hq/ashim/compare/v1.7.5...v1.7.6) (2026-04-06) +## [1.7.6](https://github.com/snapotter-hq/snapotter/compare/v1.7.5...v1.7.6) (2026-04-06) ### Bug Fixes -* batch SSE progress and non-AI processing UX ([#24](https://github.com/ashim-hq/ashim/issues/24)) ([0ce42d1](https://github.com/ashim-hq/ashim/commit/0ce42d1b2fa4f0b753a962a1f45a491e29ecee24)) +* batch SSE progress and non-AI processing UX ([#24](https://github.com/snapotter-hq/snapotter/issues/24)) ([0ce42d1](https://github.com/snapotter-hq/snapotter/commit/0ce42d1b2fa4f0b753a962a1f45a491e29ecee24)) -## [1.7.5](https://github.com/ashim-hq/ashim/compare/v1.7.4...v1.7.5) (2026-04-06) +## [1.7.5](https://github.com/snapotter-hq/snapotter/compare/v1.7.4...v1.7.5) (2026-04-06) ### Bug Fixes -* add server-side logging to AI tool routes ([#23](https://github.com/ashim-hq/ashim/issues/23)) ([3645de8](https://github.com/ashim-hq/ashim/commit/3645de89326644c5173cdfee58f6b762cb308609)) +* add server-side logging to AI tool routes ([#23](https://github.com/snapotter-hq/snapotter/issues/23)) ([3645de8](https://github.com/snapotter-hq/snapotter/commit/3645de89326644c5173cdfee58f6b762cb308609)) -## [1.7.4](https://github.com/ashim-hq/ashim/compare/v1.7.3...v1.7.4) (2026-04-06) +## [1.7.4](https://github.com/snapotter-hq/snapotter/compare/v1.7.3...v1.7.4) (2026-04-06) ### Bug Fixes -* batch file ordering and format preservation for image tools ([#20](https://github.com/ashim-hq/ashim/issues/20)) ([822a078](https://github.com/ashim-hq/ashim/commit/822a078882ba4ade851c68bc8fe115dc69cb2a81)), closes [#13](https://github.com/ashim-hq/ashim/issues/13) [#14](https://github.com/ashim-hq/ashim/issues/14) +* batch file ordering and format preservation for image tools ([#20](https://github.com/snapotter-hq/snapotter/issues/20)) ([822a078](https://github.com/snapotter-hq/snapotter/commit/822a078882ba4ade851c68bc8fe115dc69cb2a81)), closes [#13](https://github.com/snapotter-hq/snapotter/issues/13) [#14](https://github.com/snapotter-hq/snapotter/issues/14) -## [1.7.3](https://github.com/ashim-hq/ashim/compare/v1.7.2...v1.7.3) (2026-04-06) +## [1.7.3](https://github.com/snapotter-hq/snapotter/compare/v1.7.2...v1.7.3) (2026-04-06) ### Bug Fixes -* **docs:** correct broken llms.txt links on REST API page ([5e3a8b3](https://github.com/ashim-hq/ashim/commit/5e3a8b390c33812b7c4d0044b2a0ba3719d380ac)) +* **docs:** correct broken llms.txt links on REST API page ([5e3a8b3](https://github.com/snapotter-hq/snapotter/commit/5e3a8b390c33812b7c4d0044b2a0ba3719d380ac)) -## [1.7.2](https://github.com/ashim-hq/ashim/compare/v1.7.1...v1.7.2) (2026-04-05) +## [1.7.2](https://github.com/snapotter-hq/snapotter/compare/v1.7.1...v1.7.2) (2026-04-05) ### Bug Fixes -* use torch.cuda for GPU detection instead of onnxruntime providers ([7185bd5](https://github.com/ashim-hq/ashim/commit/7185bd5ce373a42cd94e750765ee11d328fb34bb)) +* use torch.cuda for GPU detection instead of onnxruntime providers ([7185bd5](https://github.com/snapotter-hq/snapotter/commit/7185bd5ce373a42cd94e750765ee11d328fb34bb)) -## [1.7.1](https://github.com/ashim-hq/ashim/compare/v1.7.0...v1.7.1) (2026-04-05) +## [1.7.1](https://github.com/snapotter-hq/snapotter/compare/v1.7.0...v1.7.1) (2026-04-05) ### Bug Fixes -* prevent false GPU detection when CUDA image runs without GPU ([1efb163](https://github.com/ashim-hq/ashim/commit/1efb163acd0271f956fb777955f8701460230def)) +* prevent false GPU detection when CUDA image runs without GPU ([1efb163](https://github.com/snapotter-hq/snapotter/commit/1efb163acd0271f956fb777955f8701460230def)) -# [1.7.0](https://github.com/ashim-hq/ashim/compare/v1.6.0...v1.7.0) (2026-04-05) +# [1.7.0](https://github.com/snapotter-hq/snapotter/compare/v1.6.0...v1.7.0) (2026-04-05) ### Bug Fixes -* **web:** skip empty Authorization header for forward-auth proxy compatibility ([636153f](https://github.com/ashim-hq/ashim/commit/636153f8f131e683b2553df2732e967772e07017)), closes [#6](https://github.com/ashim-hq/ashim/issues/6) +* **web:** skip empty Authorization header for forward-auth proxy compatibility ([636153f](https://github.com/snapotter-hq/snapotter/commit/636153f8f131e683b2553df2732e967772e07017)), closes [#6](https://github.com/snapotter-hq/snapotter/issues/6) ### Features -* add GPU/CUDA acceleration support (:cuda Docker tag) ([a5f62f0](https://github.com/ashim-hq/ashim/commit/a5f62f0d1426092b6b0164cf1ae1159a392ebf44)) +* add GPU/CUDA acceleration support (:cuda Docker tag) ([a5f62f0](https://github.com/snapotter-hq/snapotter/commit/a5f62f0d1426092b6b0164cf1ae1159a392ebf44)) -# [1.6.0](https://github.com/ashim-hq/ashim/compare/v1.5.3...v1.6.0) (2026-04-04) +# [1.6.0](https://github.com/snapotter-hq/snapotter/compare/v1.5.3...v1.6.0) (2026-04-04) ### Features -* lightweight Docker image without AI/ML tools (:lite tag) ([3a0b988](https://github.com/ashim-hq/ashim/commit/3a0b988b746a5fbe6df10fe8ee288e30e42d747f)), closes [#1](https://github.com/ashim-hq/ashim/issues/1) +* lightweight Docker image without AI/ML tools (:lite tag) ([3a0b988](https://github.com/snapotter-hq/snapotter/commit/3a0b988b746a5fbe6df10fe8ee288e30e42d747f)), closes [#1](https://github.com/snapotter-hq/snapotter/issues/1) -## [1.5.3](https://github.com/ashim-hq/ashim/compare/v1.5.2...v1.5.3) (2026-04-04) +## [1.5.3](https://github.com/snapotter-hq/snapotter/compare/v1.5.2...v1.5.3) (2026-04-04) ### Bug Fixes -* use heif-convert for HEIC decoding on Linux ([da15a1e](https://github.com/ashim-hq/ashim/commit/da15a1e833c15c3d93a9da734d354b725b99b0bf)) +* use heif-convert for HEIC decoding on Linux ([da15a1e](https://github.com/snapotter-hq/snapotter/commit/da15a1e833c15c3d93a9da734d354b725b99b0bf)) -## [1.5.2](https://github.com/ashim-hq/ashim/compare/v1.5.1...v1.5.2) (2026-04-04) +## [1.5.2](https://github.com/snapotter-hq/snapotter/compare/v1.5.1...v1.5.2) (2026-04-04) ### Bug Fixes -* install HEVC codec plugins for CI HEIC tests ([24e7591](https://github.com/ashim-hq/ashim/commit/24e7591b9af777b739e7cc0db80839b776074b6f)) +* install HEVC codec plugins for CI HEIC tests ([24e7591](https://github.com/snapotter-hq/snapotter/commit/24e7591b9af777b739e7cc0db80839b776074b6f)) -## [1.5.1](https://github.com/ashim-hq/ashim/compare/v1.5.0...v1.5.1) (2026-04-04) +## [1.5.1](https://github.com/snapotter-hq/snapotter/compare/v1.5.0...v1.5.1) (2026-04-04) ### Bug Fixes -* install libheif-examples in CI for HEIC tests ([d06092c](https://github.com/ashim-hq/ashim/commit/d06092cba9db8cd91154196a11796a6dfc37bebb)) +* install libheif-examples in CI for HEIC tests ([d06092c](https://github.com/snapotter-hq/snapotter/commit/d06092cba9db8cd91154196a11796a6dfc37bebb)) -# [1.5.0](https://github.com/ashim-hq/ashim/compare/v1.4.0...v1.5.0) (2026-04-04) +# [1.5.0](https://github.com/snapotter-hq/snapotter/compare/v1.4.0...v1.5.0) (2026-04-04) ### Features -* add HEIC/HEIF format support for input and output ([df1dc02](https://github.com/ashim-hq/ashim/commit/df1dc029857f0fa614f63c2bc835f9502be046fb)) +* add HEIC/HEIF format support for input and output ([df1dc02](https://github.com/snapotter-hq/snapotter/commit/df1dc029857f0fa614f63c2bc835f9502be046fb)) -# [1.4.0](https://github.com/ashim-hq/ashim/compare/v1.3.1...v1.4.0) (2026-04-04) +# [1.4.0](https://github.com/snapotter-hq/snapotter/compare/v1.3.1...v1.4.0) (2026-04-04) ### Features -* add "Crop to Content" mode to smart crop tool ([df479d3](https://github.com/ashim-hq/ashim/commit/df479d3410a8b0d89c93f14ab6471c9dda2b0744)), closes [#7](https://github.com/ashim-hq/ashim/issues/7) +* add "Crop to Content" mode to smart crop tool ([df479d3](https://github.com/snapotter-hq/snapotter/commit/df479d3410a8b0d89c93f14ab6471c9dda2b0744)), closes [#7](https://github.com/snapotter-hq/snapotter/issues/7) -## [1.3.1](https://github.com/ashim-hq/ashim/compare/v1.3.0...v1.3.1) (2026-04-04) +## [1.3.1](https://github.com/snapotter-hq/snapotter/compare/v1.3.0...v1.3.1) (2026-04-04) ### Bug Fixes -* default theme to light instead of following system preference ([018fcce](https://github.com/ashim-hq/ashim/commit/018fcce84cd2bf4c7b49f1eff9eda5bc078d19d3)) +* default theme to light instead of following system preference ([018fcce](https://github.com/snapotter-hq/snapotter/commit/018fcce84cd2bf4c7b49f1eff9eda5bc078d19d3)) -# [1.3.0](https://github.com/ashim-hq/ashim/compare/v1.2.1...v1.3.0) (2026-04-04) +# [1.3.0](https://github.com/snapotter-hq/snapotter/compare/v1.2.1...v1.3.0) (2026-04-04) ### Bug Fixes -* add XHR timeout to prevent UI spinning forever ([0abacb2](https://github.com/ashim-hq/ashim/commit/0abacb211cc60f3c1e8dabccc24bc6ca46ce782a)) -* disable worker pool to prevent Docker processing hang ([e36cd0c](https://github.com/ashim-hq/ashim/commit/e36cd0c24a34c5f716b5018e57f3d319fe5c5c44)) -* log volume permission errors instead of swallowing them ([a3e6927](https://github.com/ashim-hq/ashim/commit/a3e6927df0f4fdd06f6c2aafbf6dbd1c52019cb2)) -* replace crypto.randomUUID with generateId in AI tool settings ([ed91861](https://github.com/ashim-hq/ashim/commit/ed918615d2449bdda93d6ea12420454571edbf2d)) -* replace crypto.randomUUID with generateId in pipeline/automation ([bcbf86c](https://github.com/ashim-hq/ashim/commit/bcbf86c04b76ecdbc2bfae5a67d5ac929ba2ae8e)) -* replace crypto.randomUUID with generateId in use-tool-processor ([07cc2d0](https://github.com/ashim-hq/ashim/commit/07cc2d002e5964a1dee20d05021aa4b479c75f6e)) -* replace navigator.clipboard with copyToClipboard utility ([1857aeb](https://github.com/ashim-hq/ashim/commit/1857aeb89407ecb878ae967594e6408150d20d37)) -* resolve multiple API and e2e test bugs ([00deafb](https://github.com/ashim-hq/ashim/commit/00deafb2c8ad5cef14eb74207f3b2bd2bc3f13f2)) -* restore navigator.clipboard and execCommand mocks in tests ([57e71b7](https://github.com/ashim-hq/ashim/commit/57e71b7c9a2c3d77bf6318df35bed7fe8c1d7e69)) +* add XHR timeout to prevent UI spinning forever ([0abacb2](https://github.com/snapotter-hq/snapotter/commit/0abacb211cc60f3c1e8dabccc24bc6ca46ce782a)) +* disable worker pool to prevent Docker processing hang ([e36cd0c](https://github.com/snapotter-hq/snapotter/commit/e36cd0c24a34c5f716b5018e57f3d319fe5c5c44)) +* log volume permission errors instead of swallowing them ([a3e6927](https://github.com/snapotter-hq/snapotter/commit/a3e6927df0f4fdd06f6c2aafbf6dbd1c52019cb2)) +* replace crypto.randomUUID with generateId in AI tool settings ([ed91861](https://github.com/snapotter-hq/snapotter/commit/ed918615d2449bdda93d6ea12420454571edbf2d)) +* replace crypto.randomUUID with generateId in pipeline/automation ([bcbf86c](https://github.com/snapotter-hq/snapotter/commit/bcbf86c04b76ecdbc2bfae5a67d5ac929ba2ae8e)) +* replace crypto.randomUUID with generateId in use-tool-processor ([07cc2d0](https://github.com/snapotter-hq/snapotter/commit/07cc2d002e5964a1dee20d05021aa4b479c75f6e)) +* replace navigator.clipboard with copyToClipboard utility ([1857aeb](https://github.com/snapotter-hq/snapotter/commit/1857aeb89407ecb878ae967594e6408150d20d37)) +* resolve multiple API and e2e test bugs ([00deafb](https://github.com/snapotter-hq/snapotter/commit/00deafb2c8ad5cef14eb74207f3b2bd2bc3f13f2)) +* restore navigator.clipboard and execCommand mocks in tests ([57e71b7](https://github.com/snapotter-hq/snapotter/commit/57e71b7c9a2c3d77bf6318df35bed7fe8c1d7e69)) ### Features -* add copyToClipboard() utility with execCommand fallback ([8686131](https://github.com/ashim-hq/ashim/commit/868613188e010760e33c96df60d03930027535da)) -* add generateId() utility for non-secure context compatibility ([ee7741b](https://github.com/ashim-hq/ashim/commit/ee7741b26765e95cf145400f4a39bfa06b9dfe9a)) +* add copyToClipboard() utility with execCommand fallback ([8686131](https://github.com/snapotter-hq/snapotter/commit/868613188e010760e33c96df60d03930027535da)) +* add generateId() utility for non-secure context compatibility ([ee7741b](https://github.com/snapotter-hq/snapotter/commit/ee7741b26765e95cf145400f4a39bfa06b9dfe9a)) -## [1.2.1](https://github.com/ashim-hq/ashim/compare/v1.2.0...v1.2.1) (2026-04-03) +## [1.2.1](https://github.com/snapotter-hq/snapotter/compare/v1.2.0...v1.2.1) (2026-04-03) ### Bug Fixes -* handle volume permission issues for bind-mounted /data directory ([863a51c](https://github.com/ashim-hq/ashim/commit/863a51c37d481f5f01b965f58e56eae0f7cd6538)) +* handle volume permission issues for bind-mounted /data directory ([863a51c](https://github.com/snapotter-hq/snapotter/commit/863a51c37d481f5f01b965f58e56eae0f7cd6538)) -# [1.2.0](https://github.com/ashim-hq/ashim/compare/v1.1.0...v1.2.0) (2026-04-03) +# [1.2.0](https://github.com/snapotter-hq/snapotter/compare/v1.1.0...v1.2.0) (2026-04-03) ### Features -* move theme toggle and GitHub button to top-right navbar ([0ba9fa5](https://github.com/ashim-hq/ashim/commit/0ba9fa5db7efa2557ed569d638c15256f9453364)) +* move theme toggle and GitHub button to top-right navbar ([0ba9fa5](https://github.com/snapotter-hq/snapotter/commit/0ba9fa5db7efa2557ed569d638c15256f9453364)) -# [1.1.0](https://github.com/ashim-hq/ashim/compare/v1.0.1...v1.1.0) (2026-04-03) +# [1.1.0](https://github.com/snapotter-hq/snapotter/compare/v1.0.1...v1.1.0) (2026-04-03) ### Features -* add GitHub stars button to docs navbar and fix footer license ([90030fc](https://github.com/ashim-hq/ashim/commit/90030fccafed8ad247063ef71dca3cdedaff3916)) +* add GitHub stars button to docs navbar and fix footer license ([90030fc](https://github.com/snapotter-hq/snapotter/commit/90030fccafed8ad247063ef71dca3cdedaff3916)) -## [1.0.1](https://github.com/ashim-hq/ashim/compare/v1.0.0...v1.0.1) (2026-03-30) +## [1.0.1](https://github.com/snapotter-hq/snapotter/compare/v1.0.0...v1.0.1) (2026-03-30) ### Bug Fixes -* allow SVG files in the convert tool ([034281b](https://github.com/ashim-hq/ashim/commit/034281b1d4b19487ec0f900c3173465e0faf2510)) +* allow SVG files in the convert tool ([034281b](https://github.com/snapotter-hq/snapotter/commit/034281b1d4b19487ec0f900c3173465e0faf2510)) # 1.0.0 (2026-03-30) ### Bug Fixes -* **a11y:** add aria-hidden to decorative GemLogo SVG ([ae185ce](https://github.com/ashim-hq/ashim/commit/ae185ce767a480719d2f54d5675cbd7d64beb7b5)) -* add remove-background settings to pipeline step configurator ([ae5ac81](https://github.com/ashim-hq/ashim/commit/ae5ac8134689e211f17534f3064995597b6337c8)) -* add SSE progress endpoint to public paths ([18c3da0](https://github.com/ashim-hq/ashim/commit/18c3da0d41cba74c55fffd1a9f58c1a8ee5d5574)) -* **api:** allow Scalar docs through auth and CSP ([6023109](https://github.com/ashim-hq/ashim/commit/6023109df9c66c1e7b4d81f3e902f081809ed6ba)) -* **api:** resolve team name lookup and show server error messages ([609fc8b](https://github.com/ashim-hq/ashim/commit/609fc8b6cc2d2408226e2576c35d7715bdf1498c)) -* **api:** use content instead of spec.content for Scalar v1.49 API ([dfcb4d5](https://github.com/ashim-hq/ashim/commit/dfcb4d579f4b44013d23dff8617d9a9f6315b452)) -* apply continuous progress bar to erase-object and OCR ([196c553](https://github.com/ashim-hq/ashim/commit/196c553af57bb9efbd32282dd24fc080fb7228dd)) -* **blur-faces:** switch from MediaPipe to OpenCV and auto-orient images ([dc10f90](https://github.com/ashim-hq/ashim/commit/dc10f905c62c662f1a40701c81874e5854ea33e6)) -* bridge.ts ENOENT check for Python venv fallback ([92442cd](https://github.com/ashim-hq/ashim/commit/92442cd0fd354e9644d7957dd5035a9fc16d9b95)) -* clear search when adding a step from the tool picker ([ae2e63f](https://github.com/ashim-hq/ashim/commit/ae2e63f7fc4af3556539eee577b253c0616cbd0f)) -* continuous progress bar (no 100%→0% reset) ([b4abefe](https://github.com/ashim-hq/ashim/commit/b4abefe94776a1b9a9700f469e56de060c7626ca)) -* **crop:** use percentCrop from onChange to fix inflated pixel values ([f238820](https://github.com/ashim-hq/ashim/commit/f2388206324e4ddc6114b91421ca8bcb634fc340)) -* deduplicate react in Vite to prevent zustand hook errors in monorepo ([b3d6947](https://github.com/ashim-hq/ashim/commit/b3d6947d47f9b22b155e3a8c46667dd7671ac508)) -* **docker:** add build layer caching for faster Docker rebuilds ([03ba30d](https://github.com/ashim-hq/ashim/commit/03ba30d8f01c5c2500641d934b08a875589bcd68)) -* **docker:** skip husky prepare script in production install ([fdfb0a0](https://github.com/ashim-hq/ashim/commit/fdfb0a0e7412c86e3b85a70daf5093f44c34ee99)) -* **docs:** clean up footer llms.txt links ([e842cde](https://github.com/ashim-hq/ashim/commit/e842cde838ad3deb1437c4c43c8ccd796276248c)) -* **docs:** ignore localhost dead links in VitePress build ([78269d4](https://github.com/ashim-hq/ashim/commit/78269d499c914d5d68c4455475a1608f4af2a075)) -* **docs:** remove hero logo from home page ([64c0ec8](https://github.com/ashim-hq/ashim/commit/64c0ec895f82b09e50d5ecf2b85f759f0a481232)) -* handle migration race condition in concurrent test workers ([d576ab1](https://github.com/ashim-hq/ashim/commit/d576ab1dfb1e9d2aa739c681c1f83d6fef3f7d22)) -* make port 1349 the UI port in all modes ([20a2637](https://github.com/ashim-hq/ashim/commit/20a26372d8be1c2c4fc10a821b1e000c663efb0c)) -* move health diagnostics behind admin auth ([ee9a20f](https://github.com/ashim-hq/ashim/commit/ee9a20f6a35a0681b3688f0e206914fceed8fd8c)) -* **ocr:** update PaddleOCR for v3 API and add Tesseract fallback ([e260a93](https://github.com/ashim-hq/ashim/commit/e260a93cf65f1e7cd22b7b5d491c6125fee8c915)) -* pipeline only shows compatible tools and displays errors ([fe021c1](https://github.com/ashim-hq/ashim/commit/fe021c18b134c853262c8f0dac81c13f9ceeb435)) -* prevent pipeline step settings from resetting on collapse ([d899ef1](https://github.com/ashim-hq/ashim/commit/d899ef128004e46200da785a960da50894e93861)) -* prevent stale closure in pipeline step callbacks ([c67f002](https://github.com/ashim-hq/ashim/commit/c67f0027804f167e250bd497505399c07b539c4e)) -* prevent useAuth infinite loop causing rate limit storms ([9624dae](https://github.com/ashim-hq/ashim/commit/9624dae1569b6f2ad52ce990fc84eca809b849a8)) -* Python bridge fallback only on missing venv, not script errors ([79e4116](https://github.com/ashim-hq/ashim/commit/79e41160cb8bc1010ab87d1c396934e15e104086)) -* reject HTML tags in settings API to prevent stored XSS ([d5bd011](https://github.com/ashim-hq/ashim/commit/d5bd01189766ee0797fe35ff3651f38f59a65881)) -* remove explicit pnpm version from CI to avoid conflict with packageManager ([c0f5dad](https://github.com/ashim-hq/ashim/commit/c0f5dad93332bad09e5e771e1b52513186256b33)) -* remove Google Drive coming soon placeholder from files nav ([e487fe0](https://github.com/ashim-hq/ashim/commit/e487fe06bf4cad6512100bf9660498e06c1047ba)) -* resolve 3 critical UX bugs - home upload, auth, and form submit ([97267c7](https://github.com/ashim-hq/ashim/commit/97267c7b747e0d5861ca5272f553af4162e8cd9a)) -* resolve pipeline step race condition and infinite re-render loop ([e0177d4](https://github.com/ashim-hq/ashim/commit/e0177d405ef043a64f0b3a885e98169312be1fac)) -* resolve test failures from shared DB race conditions ([1a7116d](https://github.com/ashim-hq/ashim/commit/1a7116d79072d131b94d1c454abbc32b9e961c1b)) -* resolve tsx not found in AI docs updater workflow ([dfbef8d](https://github.com/ashim-hq/ashim/commit/dfbef8d723dcc2960187db36676107f708707e33)) -* resolve TypeScript Uint8Array type error with fflate ([c1b06b3](https://github.com/ashim-hq/ashim/commit/c1b06b37f2cf2aef6971f1b16b5691ce7d932b87)) -* restore APP_VERSION import used by health endpoint ([2a74b60](https://github.com/ashim-hq/ashim/commit/2a74b604466193994bcc87ba2ef589f4c15d9547)) -* setError(null) was overriding setProcessing(true) ([2be94b7](https://github.com/ashim-hq/ashim/commit/2be94b77b2b288086b55101e6854bf0407935b28)) -* show checkerboard behind transparent images in before/after slider ([73741e6](https://github.com/ashim-hq/ashim/commit/73741e6efbdee53396810a2bb11eaf9597e4aa32)) -* simplify public health to static response, add 403 test ([9c05da6](https://github.com/ashim-hq/ashim/commit/9c05da6f1372abd071e5249b102d86fa294e0d22)) -* streamline CI/CD — remove broken AI docs updater, fix Docker publish ([ad2c96d](https://github.com/ashim-hq/ashim/commit/ad2c96d7b86b55b602e973f5da30d517605ed5cd)) -* surface hidden errors and add batch rejection tests ([2f8e2ce](https://github.com/ashim-hq/ashim/commit/2f8e2ce7e2b96613ebda249890632bc54c11980b)) -* switch README Docker references from GHCR to Docker Hub ([9e15679](https://github.com/ashim-hq/ashim/commit/9e1567971d50d755ef3b51d31e80b5a31a28ed2d)) -* sync stepsRef during render, not useEffect ([0c86744](https://github.com/ashim-hq/ashim/commit/0c86744dda1073988c7e6bb55073f08e399c26f3)) -* **test:** add missing PNG fixture files to repo ([45c6b9d](https://github.com/ashim-hq/ashim/commit/45c6b9de08124fb357ac759e43c4fbf1eb5fbfb9)) -* **test:** exclude e2e tests from vitest and fix CI test suite ([9d28485](https://github.com/ashim-hq/ashim/commit/9d28485339e17b80586cea91bd18dafc989d7f24)) -* **tests:** remove temp DB cleanup that races with other test files ([498bfb3](https://github.com/ashim-hq/ashim/commit/498bfb3def2d6786fa5e387b3e30ede9768ef616)) -* trigger browser password save prompt on password change ([6b279ad](https://github.com/ashim-hq/ashim/commit/6b279ad09b9e74de34732b0e854f1180f25b34bd)) -* **ui:** clean up settings, automate page, fullscreen logo, and README ([b3c8ad4](https://github.com/ashim-hq/ashim/commit/b3c8ad4697000454a11aaace27d0baa37a9959d9)) -* unify project on port 1349, improve strip-metadata and UI components ([4912ee3](https://github.com/ashim-hq/ashim/commit/4912ee37e961b9ba9748d7ffa9164d7ca5ae0abb)) -* **upscale:** auto-orient images before upscaling and improve UI ([8a6e665](https://github.com/ashim-hq/ashim/commit/8a6e665a4484bda1e4b93b520c393bb707a624aa)) -* use BiRefNet-Lite as default model and fix JSON parsing ([c8159d3](https://github.com/ashim-hq/ashim/commit/c8159d3a9a0394f1bec3a66ffea6122a787a7ca7)) -* use two-pass validation in settings PUT to prevent partial writes ([2dc39d3](https://github.com/ashim-hq/ashim/commit/2dc39d353320b73d9abb96ee5ae1080c2ee2f9cb)) -* use U2-Net as default model (fast, 2s) with BiRefNet as opt-in ([7ebed9a](https://github.com/ashim-hq/ashim/commit/7ebed9a8d44f13d091fbc599be83b34a92049c5f)) -* white screen crash when uploading photos with null GPS EXIF data ([c913df9](https://github.com/ashim-hq/ashim/commit/c913df9c0eccb0a1d0ff305cc6dcb1c99ddf96f4)) +* **a11y:** add aria-hidden to decorative GemLogo SVG ([ae185ce](https://github.com/snapotter-hq/snapotter/commit/ae185ce767a480719d2f54d5675cbd7d64beb7b5)) +* add remove-background settings to pipeline step configurator ([ae5ac81](https://github.com/snapotter-hq/snapotter/commit/ae5ac8134689e211f17534f3064995597b6337c8)) +* add SSE progress endpoint to public paths ([18c3da0](https://github.com/snapotter-hq/snapotter/commit/18c3da0d41cba74c55fffd1a9f58c1a8ee5d5574)) +* **api:** allow Scalar docs through auth and CSP ([6023109](https://github.com/snapotter-hq/snapotter/commit/6023109df9c66c1e7b4d81f3e902f081809ed6ba)) +* **api:** resolve team name lookup and show server error messages ([609fc8b](https://github.com/snapotter-hq/snapotter/commit/609fc8b6cc2d2408226e2576c35d7715bdf1498c)) +* **api:** use content instead of spec.content for Scalar v1.49 API ([dfcb4d5](https://github.com/snapotter-hq/snapotter/commit/dfcb4d579f4b44013d23dff8617d9a9f6315b452)) +* apply continuous progress bar to erase-object and OCR ([196c553](https://github.com/snapotter-hq/snapotter/commit/196c553af57bb9efbd32282dd24fc080fb7228dd)) +* **blur-faces:** switch from MediaPipe to OpenCV and auto-orient images ([dc10f90](https://github.com/snapotter-hq/snapotter/commit/dc10f905c62c662f1a40701c81874e5854ea33e6)) +* bridge.ts ENOENT check for Python venv fallback ([92442cd](https://github.com/snapotter-hq/snapotter/commit/92442cd0fd354e9644d7957dd5035a9fc16d9b95)) +* clear search when adding a step from the tool picker ([ae2e63f](https://github.com/snapotter-hq/snapotter/commit/ae2e63f7fc4af3556539eee577b253c0616cbd0f)) +* continuous progress bar (no 100%→0% reset) ([b4abefe](https://github.com/snapotter-hq/snapotter/commit/b4abefe94776a1b9a9700f469e56de060c7626ca)) +* **crop:** use percentCrop from onChange to fix inflated pixel values ([f238820](https://github.com/snapotter-hq/snapotter/commit/f2388206324e4ddc6114b91421ca8bcb634fc340)) +* deduplicate react in Vite to prevent zustand hook errors in monorepo ([b3d6947](https://github.com/snapotter-hq/snapotter/commit/b3d6947d47f9b22b155e3a8c46667dd7671ac508)) +* **docker:** add build layer caching for faster Docker rebuilds ([03ba30d](https://github.com/snapotter-hq/snapotter/commit/03ba30d8f01c5c2500641d934b08a875589bcd68)) +* **docker:** skip husky prepare script in production install ([fdfb0a0](https://github.com/snapotter-hq/snapotter/commit/fdfb0a0e7412c86e3b85a70daf5093f44c34ee99)) +* **docs:** clean up footer llms.txt links ([e842cde](https://github.com/snapotter-hq/snapotter/commit/e842cde838ad3deb1437c4c43c8ccd796276248c)) +* **docs:** ignore localhost dead links in VitePress build ([78269d4](https://github.com/snapotter-hq/snapotter/commit/78269d499c914d5d68c4455475a1608f4af2a075)) +* **docs:** remove hero logo from home page ([64c0ec8](https://github.com/snapotter-hq/snapotter/commit/64c0ec895f82b09e50d5ecf2b85f759f0a481232)) +* handle migration race condition in concurrent test workers ([d576ab1](https://github.com/snapotter-hq/snapotter/commit/d576ab1dfb1e9d2aa739c681c1f83d6fef3f7d22)) +* make port 1349 the UI port in all modes ([20a2637](https://github.com/snapotter-hq/snapotter/commit/20a26372d8be1c2c4fc10a821b1e000c663efb0c)) +* move health diagnostics behind admin auth ([ee9a20f](https://github.com/snapotter-hq/snapotter/commit/ee9a20f6a35a0681b3688f0e206914fceed8fd8c)) +* **ocr:** update PaddleOCR for v3 API and add Tesseract fallback ([e260a93](https://github.com/snapotter-hq/snapotter/commit/e260a93cf65f1e7cd22b7b5d491c6125fee8c915)) +* pipeline only shows compatible tools and displays errors ([fe021c1](https://github.com/snapotter-hq/snapotter/commit/fe021c18b134c853262c8f0dac81c13f9ceeb435)) +* prevent pipeline step settings from resetting on collapse ([d899ef1](https://github.com/snapotter-hq/snapotter/commit/d899ef128004e46200da785a960da50894e93861)) +* prevent stale closure in pipeline step callbacks ([c67f002](https://github.com/snapotter-hq/snapotter/commit/c67f0027804f167e250bd497505399c07b539c4e)) +* prevent useAuth infinite loop causing rate limit storms ([9624dae](https://github.com/snapotter-hq/snapotter/commit/9624dae1569b6f2ad52ce990fc84eca809b849a8)) +* Python bridge fallback only on missing venv, not script errors ([79e4116](https://github.com/snapotter-hq/snapotter/commit/79e41160cb8bc1010ab87d1c396934e15e104086)) +* reject HTML tags in settings API to prevent stored XSS ([d5bd011](https://github.com/snapotter-hq/snapotter/commit/d5bd01189766ee0797fe35ff3651f38f59a65881)) +* remove explicit pnpm version from CI to avoid conflict with packageManager ([c0f5dad](https://github.com/snapotter-hq/snapotter/commit/c0f5dad93332bad09e5e771e1b52513186256b33)) +* remove Google Drive coming soon placeholder from files nav ([e487fe0](https://github.com/snapotter-hq/snapotter/commit/e487fe06bf4cad6512100bf9660498e06c1047ba)) +* resolve 3 critical UX bugs - home upload, auth, and form submit ([97267c7](https://github.com/snapotter-hq/snapotter/commit/97267c7b747e0d5861ca5272f553af4162e8cd9a)) +* resolve pipeline step race condition and infinite re-render loop ([e0177d4](https://github.com/snapotter-hq/snapotter/commit/e0177d405ef043a64f0b3a885e98169312be1fac)) +* resolve test failures from shared DB race conditions ([1a7116d](https://github.com/snapotter-hq/snapotter/commit/1a7116d79072d131b94d1c454abbc32b9e961c1b)) +* resolve tsx not found in AI docs updater workflow ([dfbef8d](https://github.com/snapotter-hq/snapotter/commit/dfbef8d723dcc2960187db36676107f708707e33)) +* resolve TypeScript Uint8Array type error with fflate ([c1b06b3](https://github.com/snapotter-hq/snapotter/commit/c1b06b37f2cf2aef6971f1b16b5691ce7d932b87)) +* restore APP_VERSION import used by health endpoint ([2a74b60](https://github.com/snapotter-hq/snapotter/commit/2a74b604466193994bcc87ba2ef589f4c15d9547)) +* setError(null) was overriding setProcessing(true) ([2be94b7](https://github.com/snapotter-hq/snapotter/commit/2be94b77b2b288086b55101e6854bf0407935b28)) +* show checkerboard behind transparent images in before/after slider ([73741e6](https://github.com/snapotter-hq/snapotter/commit/73741e6efbdee53396810a2bb11eaf9597e4aa32)) +* simplify public health to static response, add 403 test ([9c05da6](https://github.com/snapotter-hq/snapotter/commit/9c05da6f1372abd071e5249b102d86fa294e0d22)) +* streamline CI/CD — remove broken AI docs updater, fix Docker publish ([ad2c96d](https://github.com/snapotter-hq/snapotter/commit/ad2c96d7b86b55b602e973f5da30d517605ed5cd)) +* surface hidden errors and add batch rejection tests ([2f8e2ce](https://github.com/snapotter-hq/snapotter/commit/2f8e2ce7e2b96613ebda249890632bc54c11980b)) +* switch README Docker references from GHCR to Docker Hub ([9e15679](https://github.com/snapotter-hq/snapotter/commit/9e1567971d50d755ef3b51d31e80b5a31a28ed2d)) +* sync stepsRef during render, not useEffect ([0c86744](https://github.com/snapotter-hq/snapotter/commit/0c86744dda1073988c7e6bb55073f08e399c26f3)) +* **test:** add missing PNG fixture files to repo ([45c6b9d](https://github.com/snapotter-hq/snapotter/commit/45c6b9de08124fb357ac759e43c4fbf1eb5fbfb9)) +* **test:** exclude e2e tests from vitest and fix CI test suite ([9d28485](https://github.com/snapotter-hq/snapotter/commit/9d28485339e17b80586cea91bd18dafc989d7f24)) +* **tests:** remove temp DB cleanup that races with other test files ([498bfb3](https://github.com/snapotter-hq/snapotter/commit/498bfb3def2d6786fa5e387b3e30ede9768ef616)) +* trigger browser password save prompt on password change ([6b279ad](https://github.com/snapotter-hq/snapotter/commit/6b279ad09b9e74de34732b0e854f1180f25b34bd)) +* **ui:** clean up settings, automate page, fullscreen logo, and README ([b3c8ad4](https://github.com/snapotter-hq/snapotter/commit/b3c8ad4697000454a11aaace27d0baa37a9959d9)) +* unify project on port 1349, improve strip-metadata and UI components ([4912ee3](https://github.com/snapotter-hq/snapotter/commit/4912ee37e961b9ba9748d7ffa9164d7ca5ae0abb)) +* **upscale:** auto-orient images before upscaling and improve UI ([8a6e665](https://github.com/snapotter-hq/snapotter/commit/8a6e665a4484bda1e4b93b520c393bb707a624aa)) +* use BiRefNet-Lite as default model and fix JSON parsing ([c8159d3](https://github.com/snapotter-hq/snapotter/commit/c8159d3a9a0394f1bec3a66ffea6122a787a7ca7)) +* use two-pass validation in settings PUT to prevent partial writes ([2dc39d3](https://github.com/snapotter-hq/snapotter/commit/2dc39d353320b73d9abb96ee5ae1080c2ee2f9cb)) +* use U2-Net as default model (fast, 2s) with BiRefNet as opt-in ([7ebed9a](https://github.com/snapotter-hq/snapotter/commit/7ebed9a8d44f13d091fbc599be83b34a92049c5f)) +* white screen crash when uploading photos with null GPS EXIF data ([c913df9](https://github.com/snapotter-hq/snapotter/commit/c913df9c0eccb0a1d0ff305cc6dcb1c99ddf96f4)) ### Features -* accept clientJobId in batch endpoint for SSE progress correlation ([8ed57f4](https://github.com/ashim-hq/ashim/commit/8ed57f400fd083fbef7528f51231f59ecd3b1bee)) -* add authentication with default admin user ([2189628](https://github.com/ashim-hq/ashim/commit/2189628861b83ffd29b60841f2ee74458a76a7cc)) -* add automatic workspace file cleanup cron ([5af7437](https://github.com/ashim-hq/ashim/commit/5af7437d809a4e68376d68d201bf56700711836c)) -* add CSS transform props to ImageViewer for live rotate/flip preview ([de3340f](https://github.com/ashim-hq/ashim/commit/de3340fc5b201cc5c046cbb38a274e7dfa026b41)) -* add CSS transform props to ImageViewer for live rotate/flip preview ([7627853](https://github.com/ashim-hq/ashim/commit/762785394b2e66a25ee858da96868cd752942a7d)) -* add Fastify API server with health check and env config ([be73ce9](https://github.com/ashim-hq/ashim/commit/be73ce9a2bcbab3c6a72fa735a500c6b83f86a9c)) -* add forced password change page on first login ([e0900a8](https://github.com/ashim-hq/ashim/commit/e0900a877643c75266aeed5ac29501458ef0dcda)) -* add format tools (SVG-to-raster, vectorize, GIF) and optimization (rename, favicon, image-to-PDF) ([7b29b04](https://github.com/ashim-hq/ashim/commit/7b29b043d850de46c5cf4ef1829f8a97dc9a0143)) -* add generic tool page template with settings panel and dropzone ([0f32ba1](https://github.com/ashim-hq/ashim/commit/0f32ba10327f2fe96594544e0c7dc1b20ca479b0)) -* add image-engine and ai stub packages ([17ac7b8](https://github.com/ashim-hq/ashim/commit/17ac7b83658c29a3e7a7711536c0648b3b23420a)) -* add layout tools (collage, splitting, border/frame) ([e46dbf6](https://github.com/ashim-hq/ashim/commit/e46dbf6efb61e2812a7eb4c50a29b9391cd50654)) -* add live preview callback to RotateSettings, rename button to Apply ([17be50b](https://github.com/ashim-hq/ashim/commit/17be50b213e1ca6d1d6e8d949b65de70c68d108d)) -* add live preview callback to RotateSettings, rename button to Apply ([06844ec](https://github.com/ashim-hq/ashim/commit/06844ec1ada4d5685691f26655ecb8712b4d94d9)) -* add login page with split layout matching ashim style ([2b82f93](https://github.com/ashim-hq/ashim/commit/2b82f93b083c7a5bfcd37c25e85e5887c09c87ae)) -* add multi-stage Docker build with Python ML dependencies ([8d70123](https://github.com/ashim-hq/ashim/commit/8d7012398973fd561db7b868dd2d50c2e71d2ed7)) -* add MultiImageViewer with arrow navigation and filmstrip ([1fa8747](https://github.com/ashim-hq/ashim/commit/1fa874758ca58efb4b9f68d76a02648d6a84abfe)) -* add password generator and browser save prompt on change-password page ([d56c644](https://github.com/ashim-hq/ashim/commit/d56c6446fee8384ab61ba180160f5e020a1e412e)) -* add Phase 4 AI tools with Python bridge and 6 new tools ([21df50e](https://github.com/ashim-hq/ashim/commit/21df50e140248ca51bc82fbc7b16748cf0f9c909)) -* add privacy policy page and fix CSP blocking API docs ([3e314f0](https://github.com/ashim-hq/ashim/commit/3e314f032491c59196db3493d0b86f6aeec22c63)) -* add processAllFiles batch method to tool processor hook ([cd1e180](https://github.com/ashim-hq/ashim/commit/cd1e18026fb4b866c4bbde6c259412674a501f05)) -* add replace-color tool and update tool page routing ([d5d09e4](https://github.com/ashim-hq/ashim/commit/d5d09e4a0f23091fb251cd15e17a639cf72a407a)) -* add semantic-release for automated versioning and help dialog ([83a0272](https://github.com/ashim-hq/ashim/commit/83a0272af284f182fa32e7fd9baa77fe2bd74e39)) -* add shared package with types, tool definitions, and constants ([96ed415](https://github.com/ashim-hq/ashim/commit/96ed4159a57fd27f8bb3214ec01bd085a5b34a54)) -* add SideBySideComparison component for resize results ([d037305](https://github.com/ashim-hq/ashim/commit/d037305f29a32ead0addf6d79ace4823c9ba0e2b)) -* add SideBySideComparison component for resize results ([2d0ba5a](https://github.com/ashim-hq/ashim/commit/2d0ba5a65683b45a6382ca1aea9f7a75d1143702)) -* add SQLite database with Drizzle ORM schema and migrations ([88c41cf](https://github.com/ashim-hq/ashim/commit/88c41cf27c79004fc02df0afc67c4bbc4aa1cd2f)) -* add ashim-style layout with sidebar, tool panel, dropzone, and theme toggle ([90f10f4](https://github.com/ashim-hq/ashim/commit/90f10f41510136ec1fde90a00bf62f1940a10d6e)) -* add Swagger/OpenAPI documentation at /api/docs ([0ef1a5a](https://github.com/ashim-hq/ashim/commit/0ef1a5a021893049fece83b48b4e178db4675813)) -* add theme system with dark/light/system support and persistence ([e35d249](https://github.com/ashim-hq/ashim/commit/e35d249ac80616754b93d67da367d0e43df20064)) -* add ThumbnailStrip filmstrip component ([9caa613](https://github.com/ashim-hq/ashim/commit/9caa613883a7f0f0ccfbb268d3e88596e92ce094)) -* add utility tools (image info, compare, duplicates, color palette, QR, barcode) ([e17992e](https://github.com/ashim-hq/ashim/commit/e17992e6bdf4ee99980e851270c788e7a478a64f)) -* add Vite + React SPA with Tailwind CSS and routing ([9483ad7](https://github.com/ashim-hq/ashim/commit/9483ad740e46adc5f2fa6b5c4992f19d429dacaf)) -* add watermark, text overlay, and image composition tools ([b2543d9](https://github.com/ashim-hq/ashim/commit/b2543d9b5fc8e33a10d36c0cf32d7cb2de1e7901)) -* add worker threads, persistent Python sidecar, graceful shutdown, and architectural improvements ([1274cc1](https://github.com/ashim-hq/ashim/commit/1274cc103fa2f0f934e9e2322c6034533ab62ec4)) -* **adjustments:** add real-time live preview for all color tools ([b5c924e](https://github.com/ashim-hq/ashim/commit/b5c924e0fc7468c6364ef320958cea2e5ef18420)) -* **ai:** add emit_progress() calls to all Python AI scripts ([eb6f57d](https://github.com/ashim-hq/ashim/commit/eb6f57dfa35fa10ada4493e9fd73fe4d4788c03c)) -* **ai:** add onProgress callback to all AI wrapper functions ([021c9f1](https://github.com/ashim-hq/ashim/commit/021c9f12b5a1aca6c6c7cb8c9d9fad3d0406ab94)) -* **ai:** rewrite bridge.ts to stream stderr progress via spawn ([9d9c45a](https://github.com/ashim-hq/ashim/commit/9d9c45a04c2a85e99021a35a3da94e1e19cb9043)) -* **api,web:** add batch processing with ZIP download and SSE progress ([f8aa5f7](https://github.com/ashim-hq/ashim/commit/f8aa5f7bf2d81fc06e1118741d011023c2a4889b)) -* **api:** add all remaining endpoints to OpenAPI spec ([e7b38ba](https://github.com/ashim-hq/ashim/commit/e7b38ba68f8ae7fae5675bafc0f2dc2c4f22ecd2)) -* **api:** add all tool endpoints to OpenAPI spec ([753ba3e](https://github.com/ashim-hq/ashim/commit/753ba3e4689b1a3504960d15d1ebceaf2a08876e)) -* **api:** add generic tool route factory for all image tools ([43555c9](https://github.com/ashim-hq/ashim/commit/43555c90ecedcb9364de73d51003e657f649c126)) -* **api:** add llms.txt and llms-full.txt endpoints ([12ba52a](https://github.com/ashim-hq/ashim/commit/12ba52a6a0c1260f02a4d7787be8113383575d9e)) -* **api:** add logo upload/serve/delete routes with tests ([6063f4d](https://github.com/ashim-hq/ashim/commit/6063f4daa98acf3f03e004a588de562e377105c7)) -* **api:** add multipart file upload, workspace management, and download routes ([415de2a](https://github.com/ashim-hq/ashim/commit/415de2a5dff2c5344d38dd3b3d31513d5c2ed85b)) -* **api:** add OpenAPI 3.1 spec skeleton with common schemas ([b2189f5](https://github.com/ashim-hq/ashim/commit/b2189f556815ef8d5c781eee72b8263db09f6a1a)) -* **api:** add persistent file management helpers to frontend api module ([ecbfcce](https://github.com/ashim-hq/ashim/commit/ecbfcceec82010fa44244c6839928b9930d59b5a)) -* **api:** add pipeline execution, save, and list endpoints ([d4f1148](https://github.com/ashim-hq/ashim/commit/d4f1148860d7801f8d0fd276d6a2ec9efa1f68af)) -* **api:** add resize, crop, rotate, convert, compress, metadata, and color tool routes ([4874701](https://github.com/ashim-hq/ashim/commit/48747016ed71ad8300d463e8128b922177c23721)) -* **api:** add Scalar docs route and install dependency ([6f2c319](https://github.com/ashim-hq/ashim/commit/6f2c3190b8414d1c4c3b1a78cf7a86a96109c934)) -* **api:** add SingleFileProgress type and SSE update function ([12b85d4](https://github.com/ashim-hq/ashim/commit/12b85d4def1f29ca291d6f5e538181f2bcbcf774)) -* **api:** add teams CRUD routes and update auth team references ([ec22e53](https://github.com/ashim-hq/ashim/commit/ec22e53a3b15ae030743e76db0d57584000727b6)) -* **api:** add tool filtering and DB-backed cleanup settings ([07e7e8d](https://github.com/ashim-hq/ashim/commit/07e7e8d58d311d89f43cee1c7fa21dd0eb4c9dfb)) -* **api:** add user files CRUD routes at /api/v1/files/* ([6a07007](https://github.com/ashim-hq/ashim/commit/6a070071456611d2bf2acf4a474be8c43680e1b0)) -* **api:** register docs route in server and test helper ([bc6b389](https://github.com/ashim-hq/ashim/commit/bc6b38918ff11f1027efeb934ae0e56d6068b81f)) -* **api:** wire AI route handlers to SSE progress via clientJobId ([a3f85da](https://github.com/ashim-hq/ashim/commit/a3f85da20f73f02cd5ec141519aa73fcfeb2157b)) -* **branding:** add faceted gem SVG logo assets ([4bc9335](https://github.com/ashim-hq/ashim/commit/4bc93351541b039534197821d290d34cad12c9a7)) -* **branding:** add favicon and meta tags to index.html ([2508fd0](https://github.com/ashim-hq/ashim/commit/2508fd04871cdb776523ec9d602ad934283c6211)) -* **branding:** add OG social preview image ([c6c5b92](https://github.com/ashim-hq/ashim/commit/c6c5b926e271d457effea9aec07b70bbc7227ef5)) -* **branding:** add PWA manifest and PNG logo assets ([298567d](https://github.com/ashim-hq/ashim/commit/298567d090f298600b334184b09d35c178097362)) -* **branding:** show gem icon in app header as default logo ([dd857fb](https://github.com/ashim-hq/ashim/commit/dd857fbcc778a2425806f1d96d83f118dc92831a)) -* conditional result views — side-by-side for resize, live preview for rotate ([f0d18be](https://github.com/ashim-hq/ashim/commit/f0d18bee5ebc110e63bb3cf9fd829d80900759ce)) -* conditional result views — side-by-side for resize, live preview for rotate ([6682649](https://github.com/ashim-hq/ashim/commit/668264990c33667e586e4e24703f1957b18e1c0c)) -* **crop:** add CropCanvas component with visual overlay, grid, and keyboard controls ([018bbf4](https://github.com/ashim-hq/ashim/commit/018bbf44bfed4acf475de49ff9f3f5c20ee63295)) -* **crop:** add react-image-crop dependency ([b7ecd41](https://github.com/ashim-hq/ashim/commit/b7ecd41897de4f48e6f970dfbb1188848e9bcd2a)) -* **crop:** redesign CropSettings with aspect presets, pixel inputs, and grid toggle ([d75f458](https://github.com/ashim-hq/ashim/commit/d75f458dc0f13e69640bc012adea0ee29d02b82b)) -* **crop:** wire CropCanvas and CropSettings into tool-page with bidirectional state ([ea7fb46](https://github.com/ashim-hq/ashim/commit/ea7fb46f7ecad5639c007ba43d652fd72c75b39f)) -* **db:** add teams table and migration ([365783b](https://github.com/ashim-hq/ashim/commit/365783b6dc1f5cfa631bb4f6915fcf99d91f574d)) -* **db:** add userFiles table and migration ([a2fdbd5](https://github.com/ashim-hq/ashim/commit/a2fdbd5fef2cf02f90692166d6386c5ac21c2cef)) -* **docs:** add gem favicon to VitePress site ([0918f93](https://github.com/ashim-hq/ashim/commit/0918f933719ae0d8ff16cf7a8ac0e8936e90805a)) -* **docs:** add gem logo to GitHub Pages nav bar and home hero ([f0b8162](https://github.com/ashim-hq/ashim/commit/f0b8162955fa8f6b1891968163b4292b279f1ea1)) -* **docs:** add llms.txt and llms-full.txt to GitHub Pages ([5f6959a](https://github.com/ashim-hq/ashim/commit/5f6959a21e3b2708edb011a0a7ce48fbfbc64c87)) -* **docs:** add llms.txt links to GitHub Pages footer ([b874445](https://github.com/ashim-hq/ashim/commit/b874445dc6d31c54a095d7471390e664b233d491)) -* **env:** add FILES_STORAGE_PATH config variable ([3c737a6](https://github.com/ashim-hq/ashim/commit/3c737a6c724f4862d302bf22a75ebcd745f0df4c)) -* **erase-object:** replace mask upload with in-browser brush painting ([40e3081](https://github.com/ashim-hq/ashim/commit/40e30815915f18f9f7fc25c05a61c643f1dfdbe4)) -* extract auto-orient utility and expand test coverage ([8622c4a](https://github.com/ashim-hq/ashim/commit/8622c4a40245504372e75d3cd851535528639dea)) -* **files:** add Files page with nav, list, details, upload, and routing ([3f127a4](https://github.com/ashim-hq/ashim/commit/3f127a457e8a7a07d22fdf8776c3166092db562f)) -* **files:** add mobile layout for Files page ([e864d1e](https://github.com/ashim-hq/ashim/commit/e864d1e430bd516ccbe1732ec7451e1e7d670177)) -* **files:** wire serverFileId for version tracking ([8868d3e](https://github.com/ashim-hq/ashim/commit/8868d3e556beedcff35de268e72241e7f10998a3)) -* harden auth, security headers, SVG sanitization, and pipeline ownership ([beaad1d](https://github.com/ashim-hq/ashim/commit/beaad1d3044f6b2535aacb6a67541464f736778b)) -* **i18n:** add translation keys for settings phase 1 ([c5ff80a](https://github.com/ashim-hq/ashim/commit/c5ff80acfbe18b953cfd96a88498fc70b82b541e)) -* **image-engine:** add Sharp wrapper with 14 image operations ([3e7f71c](https://github.com/ashim-hq/ashim/commit/3e7f71ca830549ea28b47656b14b9375fa8c2c34)) -* **image-to-pdf:** add live PDF page preview with margin visualization ([cd666ea](https://github.com/ashim-hq/ashim/commit/cd666eaef0b13bcd9223439f0bbb5efd88b2f25e)) -* implement Files page with persistent storage and version tracking ([f6183d2](https://github.com/ashim-hq/ashim/commit/f6183d2c62e6ad04dec3fe0250468cbfd6cbc035)) -* initialize Turborepo monorepo with pnpm workspaces ([db31cf6](https://github.com/ashim-hq/ashim/commit/db31cf6f115c454eb59454fc227058a773944f93)) -* integrate MultiImageViewer and multi-file UX into tool page ([52aab1e](https://github.com/ashim-hq/ashim/commit/52aab1e2bf5f938a800a78b4e5c11f5ad9fbae27)) -* make AI tools pipeline-compatible and add search to tool picker ([2d46b09](https://github.com/ashim-hq/ashim/commit/2d46b096fa80e43f7a59e213ac884b5d1d30b586)) -* merge multi-image UX — batch processing, filmstrip navigation, resize/rotate redesign ([9bfdb75](https://github.com/ashim-hq/ashim/commit/9bfdb75f5c205906f2bd62d496e96d6b402e1dc1)) -* multi-arch Docker support, security hardening, and test improvements ([748d2b7](https://github.com/ashim-hq/ashim/commit/748d2b70460b3975a9c61edec0b121d788d0ee06)) -* multi-file metadata display with per-file caching ([42b59f3](https://github.com/ashim-hq/ashim/commit/42b59f3e2d84b3d9fd6724b9ed9fb272fb11201a)) -* **pipeline:** add inline settings configuration for automation steps ([827eae8](https://github.com/ashim-hq/ashim/commit/827eae824543ab9cea2a5d3a82acd388736fa424)) -* production Docker, Playwright tests, settings API, and bug fixes ([027c515](https://github.com/ashim-hq/ashim/commit/027c515f3582c5f030fb4c3cacae2ceee575e7c7)) -* replace model dropdown with intuitive subject/quality selector in remove-bg ([bc26d60](https://github.com/ashim-hq/ashim/commit/bc26d60d54a47a9fb6f58115131845d1ae5ee868)) -* rewrite file-store with FileEntry model for multi-image support ([abbb3e4](https://github.com/ashim-hq/ashim/commit/abbb3e4d6e8f21f35b385c51fb659010099556d1)) -* rewrite resize settings with tab-based UI (presets, custom, scale) ([b9f3ac0](https://github.com/ashim-hq/ashim/commit/b9f3ac0d222f3712d35becd6c831dc62f728a16a)) -* rewrite resize settings with tab-based UI (presets, custom, scale) ([3b39a8c](https://github.com/ashim-hq/ashim/commit/3b39a8cc5f11a5093f42bcdbe97989fce3841616)) -* **rotate:** add editable angle input and fine-tune +/- buttons ([e1f04c2](https://github.com/ashim-hq/ashim/commit/e1f04c28a6b03c0503266c0e78e7a9161011d939)) -* serve React SPA from Fastify in production mode ([d4ae4d5](https://github.com/ashim-hq/ashim/commit/d4ae4d586a60fe88f6834e5f32b89f7ef3d3bc7e)) -* **storage:** add file storage helpers module ([7c37213](https://github.com/ashim-hq/ashim/commit/7c372135c8eb9d65198c0720bc2d0c83ac145004)) -* **stores:** add Zustand store for Files page state management ([fb487be](https://github.com/ashim-hq/ashim/commit/fb487be051c6da6ca22a443323cf4788d4ca4e6b)) -* **tool-factory:** auto-save results to persistent file store when fileId provided ([27d8629](https://github.com/ashim-hq/ashim/commit/27d8629c704bc9cabed8c7dd87c34ea8e9433347)) -* **ui:** add teams, tools, feature flags, temp files, logo to settings dialog ([fbce0dd](https://github.com/ashim-hq/ashim/commit/fbce0dddd05c1e539bfbdb084c3b53d59f5dfd76)) -* upgrade to BiRefNet SOTA background removal model ([f53937b](https://github.com/ashim-hq/ashim/commit/f53937b07006c6de26096467a106b0a055a4c95e)) -* **web:** add before/after image comparison slider component ([64c8f90](https://github.com/ashim-hq/ashim/commit/64c8f908d7f188e079ff3bd5f469f5ab701cc25d)) -* **web:** add fullscreen tool grid view ([86b716b](https://github.com/ashim-hq/ashim/commit/86b716b76514494a3611798e0651f8dc3601ce8b)) -* **web:** add i18n architecture with English translations ([994cba7](https://github.com/ashim-hq/ashim/commit/994cba77164c6f1a1b092e76f9fa441077639079)) -* **web:** add keyboard shortcuts for tool navigation ([e06e44c](https://github.com/ashim-hq/ashim/commit/e06e44cf2763265acfe97b14e863f22bd60dd264)) -* **web:** add mobile responsive layout with bottom navigation ([ade6469](https://github.com/ashim-hq/ashim/commit/ade64699adbe54bbfed39f1a3cba924c3caeaef1)) -* **web:** add pipeline builder UI with saved automations and templates ([39a7bf2](https://github.com/ashim-hq/ashim/commit/39a7bf259b25bc31575376bdec036f4693c5e777)) -* **web:** add ProgressCard component ([ed69488](https://github.com/ashim-hq/ashim/commit/ed6948804b52ee5d8977732130a55c6c1efc358d)) -* **web:** add ProgressCard to non-AI tool settings (Group A) ([17035e9](https://github.com/ashim-hq/ashim/commit/17035e98abc84f7abd0de91b9c0b324403a31c71)) -* **web:** add settings dialog with general, security, API keys, and about sections ([bca8e81](https://github.com/ashim-hq/ashim/commit/bca8e81e3ad73a7f39451c8e3cc6d105f6665dcf)) -* **web:** add ashim-style file preview, review panel, and tool chaining UX ([e12fc57](https://github.com/ashim-hq/ashim/commit/e12fc57ce101f7d68b718a2fb5bf3ea4884f69f2)) -* **web:** add tool settings UI for all core image tools ([f9be6d6](https://github.com/ashim-hq/ashim/commit/f9be6d6eeff2ebe2d10fa69cc37993427f52ec76)) -* **web:** migrate AI tool settings to ProgressCard ([eed4fc2](https://github.com/ashim-hq/ashim/commit/eed4fc28db80967aa3bb513459bf05d9b417d65f)) -* **web:** redesign home page upload flow and add auth guard ([915a8cc](https://github.com/ashim-hq/ashim/commit/915a8cc2d5ecb8dc60b968cf85c5519a0c64cef6)) -* **web:** rewrite useToolProcessor with XHR upload progress and SSE ([305f50b](https://github.com/ashim-hq/ashim/commit/305f50b5f4bd87cc19a3a8fe0d0374bb78bad101)) -* wire up batch processing across tool settings components ([1d87091](https://github.com/ashim-hq/ashim/commit/1d87091bbc4bce9d8e78b0cddd474d21dd4dcd1c)) +* accept clientJobId in batch endpoint for SSE progress correlation ([8ed57f4](https://github.com/snapotter-hq/snapotter/commit/8ed57f400fd083fbef7528f51231f59ecd3b1bee)) +* add authentication with default admin user ([2189628](https://github.com/snapotter-hq/snapotter/commit/2189628861b83ffd29b60841f2ee74458a76a7cc)) +* add automatic workspace file cleanup cron ([5af7437](https://github.com/snapotter-hq/snapotter/commit/5af7437d809a4e68376d68d201bf56700711836c)) +* add CSS transform props to ImageViewer for live rotate/flip preview ([de3340f](https://github.com/snapotter-hq/snapotter/commit/de3340fc5b201cc5c046cbb38a274e7dfa026b41)) +* add CSS transform props to ImageViewer for live rotate/flip preview ([7627853](https://github.com/snapotter-hq/snapotter/commit/762785394b2e66a25ee858da96868cd752942a7d)) +* add Fastify API server with health check and env config ([be73ce9](https://github.com/snapotter-hq/snapotter/commit/be73ce9a2bcbab3c6a72fa735a500c6b83f86a9c)) +* add forced password change page on first login ([e0900a8](https://github.com/snapotter-hq/snapotter/commit/e0900a877643c75266aeed5ac29501458ef0dcda)) +* add format tools (SVG-to-raster, vectorize, GIF) and optimization (rename, favicon, image-to-PDF) ([7b29b04](https://github.com/snapotter-hq/snapotter/commit/7b29b043d850de46c5cf4ef1829f8a97dc9a0143)) +* add generic tool page template with settings panel and dropzone ([0f32ba1](https://github.com/snapotter-hq/snapotter/commit/0f32ba10327f2fe96594544e0c7dc1b20ca479b0)) +* add image-engine and ai stub packages ([17ac7b8](https://github.com/snapotter-hq/snapotter/commit/17ac7b83658c29a3e7a7711536c0648b3b23420a)) +* add layout tools (collage, splitting, border/frame) ([e46dbf6](https://github.com/snapotter-hq/snapotter/commit/e46dbf6efb61e2812a7eb4c50a29b9391cd50654)) +* add live preview callback to RotateSettings, rename button to Apply ([17be50b](https://github.com/snapotter-hq/snapotter/commit/17be50b213e1ca6d1d6e8d949b65de70c68d108d)) +* add live preview callback to RotateSettings, rename button to Apply ([06844ec](https://github.com/snapotter-hq/snapotter/commit/06844ec1ada4d5685691f26655ecb8712b4d94d9)) +* add login page with split layout matching SnapOtter style ([2b82f93](https://github.com/snapotter-hq/snapotter/commit/2b82f93b083c7a5bfcd37c25e85e5887c09c87ae)) +* add multi-stage Docker build with Python ML dependencies ([8d70123](https://github.com/snapotter-hq/snapotter/commit/8d7012398973fd561db7b868dd2d50c2e71d2ed7)) +* add MultiImageViewer with arrow navigation and filmstrip ([1fa8747](https://github.com/snapotter-hq/snapotter/commit/1fa874758ca58efb4b9f68d76a02648d6a84abfe)) +* add password generator and browser save prompt on change-password page ([d56c644](https://github.com/snapotter-hq/snapotter/commit/d56c6446fee8384ab61ba180160f5e020a1e412e)) +* add Phase 4 AI tools with Python bridge and 6 new tools ([21df50e](https://github.com/snapotter-hq/snapotter/commit/21df50e140248ca51bc82fbc7b16748cf0f9c909)) +* add privacy policy page and fix CSP blocking API docs ([3e314f0](https://github.com/snapotter-hq/snapotter/commit/3e314f032491c59196db3493d0b86f6aeec22c63)) +* add processAllFiles batch method to tool processor hook ([cd1e180](https://github.com/snapotter-hq/snapotter/commit/cd1e18026fb4b866c4bbde6c259412674a501f05)) +* add replace-color tool and update tool page routing ([d5d09e4](https://github.com/snapotter-hq/snapotter/commit/d5d09e4a0f23091fb251cd15e17a639cf72a407a)) +* add semantic-release for automated versioning and help dialog ([83a0272](https://github.com/snapotter-hq/snapotter/commit/83a0272af284f182fa32e7fd9baa77fe2bd74e39)) +* add shared package with types, tool definitions, and constants ([96ed415](https://github.com/snapotter-hq/snapotter/commit/96ed4159a57fd27f8bb3214ec01bd085a5b34a54)) +* add SideBySideComparison component for resize results ([d037305](https://github.com/snapotter-hq/snapotter/commit/d037305f29a32ead0addf6d79ace4823c9ba0e2b)) +* add SideBySideComparison component for resize results ([2d0ba5a](https://github.com/snapotter-hq/snapotter/commit/2d0ba5a65683b45a6382ca1aea9f7a75d1143702)) +* add SQLite database with Drizzle ORM schema and migrations ([88c41cf](https://github.com/snapotter-hq/snapotter/commit/88c41cf27c79004fc02df0afc67c4bbc4aa1cd2f)) +* add SnapOtter-style layout with sidebar, tool panel, dropzone, and theme toggle ([90f10f4](https://github.com/snapotter-hq/snapotter/commit/90f10f41510136ec1fde90a00bf62f1940a10d6e)) +* add Swagger/OpenAPI documentation at /api/docs ([0ef1a5a](https://github.com/snapotter-hq/snapotter/commit/0ef1a5a021893049fece83b48b4e178db4675813)) +* add theme system with dark/light/system support and persistence ([e35d249](https://github.com/snapotter-hq/snapotter/commit/e35d249ac80616754b93d67da367d0e43df20064)) +* add ThumbnailStrip filmstrip component ([9caa613](https://github.com/snapotter-hq/snapotter/commit/9caa613883a7f0f0ccfbb268d3e88596e92ce094)) +* add utility tools (image info, compare, duplicates, color palette, QR, barcode) ([e17992e](https://github.com/snapotter-hq/snapotter/commit/e17992e6bdf4ee99980e851270c788e7a478a64f)) +* add Vite + React SPA with Tailwind CSS and routing ([9483ad7](https://github.com/snapotter-hq/snapotter/commit/9483ad740e46adc5f2fa6b5c4992f19d429dacaf)) +* add watermark, text overlay, and image composition tools ([b2543d9](https://github.com/snapotter-hq/snapotter/commit/b2543d9b5fc8e33a10d36c0cf32d7cb2de1e7901)) +* add worker threads, persistent Python sidecar, graceful shutdown, and architectural improvements ([1274cc1](https://github.com/snapotter-hq/snapotter/commit/1274cc103fa2f0f934e9e2322c6034533ab62ec4)) +* **adjustments:** add real-time live preview for all color tools ([b5c924e](https://github.com/snapotter-hq/snapotter/commit/b5c924e0fc7468c6364ef320958cea2e5ef18420)) +* **ai:** add emit_progress() calls to all Python AI scripts ([eb6f57d](https://github.com/snapotter-hq/snapotter/commit/eb6f57dfa35fa10ada4493e9fd73fe4d4788c03c)) +* **ai:** add onProgress callback to all AI wrapper functions ([021c9f1](https://github.com/snapotter-hq/snapotter/commit/021c9f12b5a1aca6c6c7cb8c9d9fad3d0406ab94)) +* **ai:** rewrite bridge.ts to stream stderr progress via spawn ([9d9c45a](https://github.com/snapotter-hq/snapotter/commit/9d9c45a04c2a85e99021a35a3da94e1e19cb9043)) +* **api,web:** add batch processing with ZIP download and SSE progress ([f8aa5f7](https://github.com/snapotter-hq/snapotter/commit/f8aa5f7bf2d81fc06e1118741d011023c2a4889b)) +* **api:** add all remaining endpoints to OpenAPI spec ([e7b38ba](https://github.com/snapotter-hq/snapotter/commit/e7b38ba68f8ae7fae5675bafc0f2dc2c4f22ecd2)) +* **api:** add all tool endpoints to OpenAPI spec ([753ba3e](https://github.com/snapotter-hq/snapotter/commit/753ba3e4689b1a3504960d15d1ebceaf2a08876e)) +* **api:** add generic tool route factory for all image tools ([43555c9](https://github.com/snapotter-hq/snapotter/commit/43555c90ecedcb9364de73d51003e657f649c126)) +* **api:** add llms.txt and llms-full.txt endpoints ([12ba52a](https://github.com/snapotter-hq/snapotter/commit/12ba52a6a0c1260f02a4d7787be8113383575d9e)) +* **api:** add logo upload/serve/delete routes with tests ([6063f4d](https://github.com/snapotter-hq/snapotter/commit/6063f4daa98acf3f03e004a588de562e377105c7)) +* **api:** add multipart file upload, workspace management, and download routes ([415de2a](https://github.com/snapotter-hq/snapotter/commit/415de2a5dff2c5344d38dd3b3d31513d5c2ed85b)) +* **api:** add OpenAPI 3.1 spec skeleton with common schemas ([b2189f5](https://github.com/snapotter-hq/snapotter/commit/b2189f556815ef8d5c781eee72b8263db09f6a1a)) +* **api:** add persistent file management helpers to frontend api module ([ecbfcce](https://github.com/snapotter-hq/snapotter/commit/ecbfcceec82010fa44244c6839928b9930d59b5a)) +* **api:** add pipeline execution, save, and list endpoints ([d4f1148](https://github.com/snapotter-hq/snapotter/commit/d4f1148860d7801f8d0fd276d6a2ec9efa1f68af)) +* **api:** add resize, crop, rotate, convert, compress, metadata, and color tool routes ([4874701](https://github.com/snapotter-hq/snapotter/commit/48747016ed71ad8300d463e8128b922177c23721)) +* **api:** add Scalar docs route and install dependency ([6f2c319](https://github.com/snapotter-hq/snapotter/commit/6f2c3190b8414d1c4c3b1a78cf7a86a96109c934)) +* **api:** add SingleFileProgress type and SSE update function ([12b85d4](https://github.com/snapotter-hq/snapotter/commit/12b85d4def1f29ca291d6f5e538181f2bcbcf774)) +* **api:** add teams CRUD routes and update auth team references ([ec22e53](https://github.com/snapotter-hq/snapotter/commit/ec22e53a3b15ae030743e76db0d57584000727b6)) +* **api:** add tool filtering and DB-backed cleanup settings ([07e7e8d](https://github.com/snapotter-hq/snapotter/commit/07e7e8d58d311d89f43cee1c7fa21dd0eb4c9dfb)) +* **api:** add user files CRUD routes at /api/v1/files/* ([6a07007](https://github.com/snapotter-hq/snapotter/commit/6a070071456611d2bf2acf4a474be8c43680e1b0)) +* **api:** register docs route in server and test helper ([bc6b389](https://github.com/snapotter-hq/snapotter/commit/bc6b38918ff11f1027efeb934ae0e56d6068b81f)) +* **api:** wire AI route handlers to SSE progress via clientJobId ([a3f85da](https://github.com/snapotter-hq/snapotter/commit/a3f85da20f73f02cd5ec141519aa73fcfeb2157b)) +* **branding:** add faceted gem SVG logo assets ([4bc9335](https://github.com/snapotter-hq/snapotter/commit/4bc93351541b039534197821d290d34cad12c9a7)) +* **branding:** add favicon and meta tags to index.html ([2508fd0](https://github.com/snapotter-hq/snapotter/commit/2508fd04871cdb776523ec9d602ad934283c6211)) +* **branding:** add OG social preview image ([c6c5b92](https://github.com/snapotter-hq/snapotter/commit/c6c5b926e271d457effea9aec07b70bbc7227ef5)) +* **branding:** add PWA manifest and PNG logo assets ([298567d](https://github.com/snapotter-hq/snapotter/commit/298567d090f298600b334184b09d35c178097362)) +* **branding:** show gem icon in app header as default logo ([dd857fb](https://github.com/snapotter-hq/snapotter/commit/dd857fbcc778a2425806f1d96d83f118dc92831a)) +* conditional result views — side-by-side for resize, live preview for rotate ([f0d18be](https://github.com/snapotter-hq/snapotter/commit/f0d18bee5ebc110e63bb3cf9fd829d80900759ce)) +* conditional result views — side-by-side for resize, live preview for rotate ([6682649](https://github.com/snapotter-hq/snapotter/commit/668264990c33667e586e4e24703f1957b18e1c0c)) +* **crop:** add CropCanvas component with visual overlay, grid, and keyboard controls ([018bbf4](https://github.com/snapotter-hq/snapotter/commit/018bbf44bfed4acf475de49ff9f3f5c20ee63295)) +* **crop:** add react-image-crop dependency ([b7ecd41](https://github.com/snapotter-hq/snapotter/commit/b7ecd41897de4f48e6f970dfbb1188848e9bcd2a)) +* **crop:** redesign CropSettings with aspect presets, pixel inputs, and grid toggle ([d75f458](https://github.com/snapotter-hq/snapotter/commit/d75f458dc0f13e69640bc012adea0ee29d02b82b)) +* **crop:** wire CropCanvas and CropSettings into tool-page with bidirectional state ([ea7fb46](https://github.com/snapotter-hq/snapotter/commit/ea7fb46f7ecad5639c007ba43d652fd72c75b39f)) +* **db:** add teams table and migration ([365783b](https://github.com/snapotter-hq/snapotter/commit/365783b6dc1f5cfa631bb4f6915fcf99d91f574d)) +* **db:** add userFiles table and migration ([a2fdbd5](https://github.com/snapotter-hq/snapotter/commit/a2fdbd5fef2cf02f90692166d6386c5ac21c2cef)) +* **docs:** add gem favicon to VitePress site ([0918f93](https://github.com/snapotter-hq/snapotter/commit/0918f933719ae0d8ff16cf7a8ac0e8936e90805a)) +* **docs:** add gem logo to GitHub Pages nav bar and home hero ([f0b8162](https://github.com/snapotter-hq/snapotter/commit/f0b8162955fa8f6b1891968163b4292b279f1ea1)) +* **docs:** add llms.txt and llms-full.txt to GitHub Pages ([5f6959a](https://github.com/snapotter-hq/snapotter/commit/5f6959a21e3b2708edb011a0a7ce48fbfbc64c87)) +* **docs:** add llms.txt links to GitHub Pages footer ([b874445](https://github.com/snapotter-hq/snapotter/commit/b874445dc6d31c54a095d7471390e664b233d491)) +* **env:** add FILES_STORAGE_PATH config variable ([3c737a6](https://github.com/snapotter-hq/snapotter/commit/3c737a6c724f4862d302bf22a75ebcd745f0df4c)) +* **erase-object:** replace mask upload with in-browser brush painting ([40e3081](https://github.com/snapotter-hq/snapotter/commit/40e30815915f18f9f7fc25c05a61c643f1dfdbe4)) +* extract auto-orient utility and expand test coverage ([8622c4a](https://github.com/snapotter-hq/snapotter/commit/8622c4a40245504372e75d3cd851535528639dea)) +* **files:** add Files page with nav, list, details, upload, and routing ([3f127a4](https://github.com/snapotter-hq/snapotter/commit/3f127a457e8a7a07d22fdf8776c3166092db562f)) +* **files:** add mobile layout for Files page ([e864d1e](https://github.com/snapotter-hq/snapotter/commit/e864d1e430bd516ccbe1732ec7451e1e7d670177)) +* **files:** wire serverFileId for version tracking ([8868d3e](https://github.com/snapotter-hq/snapotter/commit/8868d3e556beedcff35de268e72241e7f10998a3)) +* harden auth, security headers, SVG sanitization, and pipeline ownership ([beaad1d](https://github.com/snapotter-hq/snapotter/commit/beaad1d3044f6b2535aacb6a67541464f736778b)) +* **i18n:** add translation keys for settings phase 1 ([c5ff80a](https://github.com/snapotter-hq/snapotter/commit/c5ff80acfbe18b953cfd96a88498fc70b82b541e)) +* **image-engine:** add Sharp wrapper with 14 image operations ([3e7f71c](https://github.com/snapotter-hq/snapotter/commit/3e7f71ca830549ea28b47656b14b9375fa8c2c34)) +* **image-to-pdf:** add live PDF page preview with margin visualization ([cd666ea](https://github.com/snapotter-hq/snapotter/commit/cd666eaef0b13bcd9223439f0bbb5efd88b2f25e)) +* implement Files page with persistent storage and version tracking ([f6183d2](https://github.com/snapotter-hq/snapotter/commit/f6183d2c62e6ad04dec3fe0250468cbfd6cbc035)) +* initialize Turborepo monorepo with pnpm workspaces ([db31cf6](https://github.com/snapotter-hq/snapotter/commit/db31cf6f115c454eb59454fc227058a773944f93)) +* integrate MultiImageViewer and multi-file UX into tool page ([52aab1e](https://github.com/snapotter-hq/snapotter/commit/52aab1e2bf5f938a800a78b4e5c11f5ad9fbae27)) +* make AI tools pipeline-compatible and add search to tool picker ([2d46b09](https://github.com/snapotter-hq/snapotter/commit/2d46b096fa80e43f7a59e213ac884b5d1d30b586)) +* merge multi-image UX — batch processing, filmstrip navigation, resize/rotate redesign ([9bfdb75](https://github.com/snapotter-hq/snapotter/commit/9bfdb75f5c205906f2bd62d496e96d6b402e1dc1)) +* multi-arch Docker support, security hardening, and test improvements ([748d2b7](https://github.com/snapotter-hq/snapotter/commit/748d2b70460b3975a9c61edec0b121d788d0ee06)) +* multi-file metadata display with per-file caching ([42b59f3](https://github.com/snapotter-hq/snapotter/commit/42b59f3e2d84b3d9fd6724b9ed9fb272fb11201a)) +* **pipeline:** add inline settings configuration for automation steps ([827eae8](https://github.com/snapotter-hq/snapotter/commit/827eae824543ab9cea2a5d3a82acd388736fa424)) +* production Docker, Playwright tests, settings API, and bug fixes ([027c515](https://github.com/snapotter-hq/snapotter/commit/027c515f3582c5f030fb4c3cacae2ceee575e7c7)) +* replace model dropdown with intuitive subject/quality selector in remove-bg ([bc26d60](https://github.com/snapotter-hq/snapotter/commit/bc26d60d54a47a9fb6f58115131845d1ae5ee868)) +* rewrite file-store with FileEntry model for multi-image support ([abbb3e4](https://github.com/snapotter-hq/snapotter/commit/abbb3e4d6e8f21f35b385c51fb659010099556d1)) +* rewrite resize settings with tab-based UI (presets, custom, scale) ([b9f3ac0](https://github.com/snapotter-hq/snapotter/commit/b9f3ac0d222f3712d35becd6c831dc62f728a16a)) +* rewrite resize settings with tab-based UI (presets, custom, scale) ([3b39a8c](https://github.com/snapotter-hq/snapotter/commit/3b39a8cc5f11a5093f42bcdbe97989fce3841616)) +* **rotate:** add editable angle input and fine-tune +/- buttons ([e1f04c2](https://github.com/snapotter-hq/snapotter/commit/e1f04c28a6b03c0503266c0e78e7a9161011d939)) +* serve React SPA from Fastify in production mode ([d4ae4d5](https://github.com/snapotter-hq/snapotter/commit/d4ae4d586a60fe88f6834e5f32b89f7ef3d3bc7e)) +* **storage:** add file storage helpers module ([7c37213](https://github.com/snapotter-hq/snapotter/commit/7c372135c8eb9d65198c0720bc2d0c83ac145004)) +* **stores:** add Zustand store for Files page state management ([fb487be](https://github.com/snapotter-hq/snapotter/commit/fb487be051c6da6ca22a443323cf4788d4ca4e6b)) +* **tool-factory:** auto-save results to persistent file store when fileId provided ([27d8629](https://github.com/snapotter-hq/snapotter/commit/27d8629c704bc9cabed8c7dd87c34ea8e9433347)) +* **ui:** add teams, tools, feature flags, temp files, logo to settings dialog ([fbce0dd](https://github.com/snapotter-hq/snapotter/commit/fbce0dddd05c1e539bfbdb084c3b53d59f5dfd76)) +* upgrade to BiRefNet SOTA background removal model ([f53937b](https://github.com/snapotter-hq/snapotter/commit/f53937b07006c6de26096467a106b0a055a4c95e)) +* **web:** add before/after image comparison slider component ([64c8f90](https://github.com/snapotter-hq/snapotter/commit/64c8f908d7f188e079ff3bd5f469f5ab701cc25d)) +* **web:** add fullscreen tool grid view ([86b716b](https://github.com/snapotter-hq/snapotter/commit/86b716b76514494a3611798e0651f8dc3601ce8b)) +* **web:** add i18n architecture with English translations ([994cba7](https://github.com/snapotter-hq/snapotter/commit/994cba77164c6f1a1b092e76f9fa441077639079)) +* **web:** add keyboard shortcuts for tool navigation ([e06e44c](https://github.com/snapotter-hq/snapotter/commit/e06e44cf2763265acfe97b14e863f22bd60dd264)) +* **web:** add mobile responsive layout with bottom navigation ([ade6469](https://github.com/snapotter-hq/snapotter/commit/ade64699adbe54bbfed39f1a3cba924c3caeaef1)) +* **web:** add pipeline builder UI with saved automations and templates ([39a7bf2](https://github.com/snapotter-hq/snapotter/commit/39a7bf259b25bc31575376bdec036f4693c5e777)) +* **web:** add ProgressCard component ([ed69488](https://github.com/snapotter-hq/snapotter/commit/ed6948804b52ee5d8977732130a55c6c1efc358d)) +* **web:** add ProgressCard to non-AI tool settings (Group A) ([17035e9](https://github.com/snapotter-hq/snapotter/commit/17035e98abc84f7abd0de91b9c0b324403a31c71)) +* **web:** add settings dialog with general, security, API keys, and about sections ([bca8e81](https://github.com/snapotter-hq/snapotter/commit/bca8e81e3ad73a7f39451c8e3cc6d105f6665dcf)) +* **web:** add SnapOtter-style file preview, review panel, and tool chaining UX ([e12fc57](https://github.com/snapotter-hq/snapotter/commit/e12fc57ce101f7d68b718a2fb5bf3ea4884f69f2)) +* **web:** add tool settings UI for all core image tools ([f9be6d6](https://github.com/snapotter-hq/snapotter/commit/f9be6d6eeff2ebe2d10fa69cc37993427f52ec76)) +* **web:** migrate AI tool settings to ProgressCard ([eed4fc2](https://github.com/snapotter-hq/snapotter/commit/eed4fc28db80967aa3bb513459bf05d9b417d65f)) +* **web:** redesign home page upload flow and add auth guard ([915a8cc](https://github.com/snapotter-hq/snapotter/commit/915a8cc2d5ecb8dc60b968cf85c5519a0c64cef6)) +* **web:** rewrite useToolProcessor with XHR upload progress and SSE ([305f50b](https://github.com/snapotter-hq/snapotter/commit/305f50b5f4bd87cc19a3a8fe0d0374bb78bad101)) +* wire up batch processing across tool settings components ([1d87091](https://github.com/snapotter-hq/snapotter/commit/1d87091bbc4bce9d8e78b0cddd474d21dd4dcd1c)) -# [0.19.0](https://github.com/ashim-hq/ashim/compare/v0.18.0...v0.19.0) (2026-03-29) +# [0.19.0](https://github.com/snapotter-hq/snapotter/compare/v0.18.0...v0.19.0) (2026-03-29) ### Features -* add privacy policy page and fix CSP blocking API docs ([3e314f0](https://github.com/ashim-hq/ashim/commit/3e314f032491c59196db3493d0b86f6aeec22c63)) +* add privacy policy page and fix CSP blocking API docs ([3e314f0](https://github.com/snapotter-hq/snapotter/commit/3e314f032491c59196db3493d0b86f6aeec22c63)) -# [0.18.0](https://github.com/ashim-hq/ashim/compare/v0.17.7...v0.18.0) (2026-03-29) +# [0.18.0](https://github.com/snapotter-hq/snapotter/compare/v0.17.7...v0.18.0) (2026-03-29) ### Features -* add worker threads, persistent Python sidecar, graceful shutdown, and architectural improvements ([1274cc1](https://github.com/ashim-hq/ashim/commit/1274cc103fa2f0f934e9e2322c6034533ab62ec4)) +* add worker threads, persistent Python sidecar, graceful shutdown, and architectural improvements ([1274cc1](https://github.com/snapotter-hq/snapotter/commit/1274cc103fa2f0f934e9e2322c6034533ab62ec4)) -## [0.17.7](https://github.com/ashim-hq/ashim/compare/v0.17.6...v0.17.7) (2026-03-28) +## [0.17.7](https://github.com/snapotter-hq/snapotter/compare/v0.17.6...v0.17.7) (2026-03-28) ### Bug Fixes -* move health diagnostics behind admin auth ([ee9a20f](https://github.com/ashim-hq/ashim/commit/ee9a20f6a35a0681b3688f0e206914fceed8fd8c)) -* reject HTML tags in settings API to prevent stored XSS ([d5bd011](https://github.com/ashim-hq/ashim/commit/d5bd01189766ee0797fe35ff3651f38f59a65881)) -* simplify public health to static response, add 403 test ([9c05da6](https://github.com/ashim-hq/ashim/commit/9c05da6f1372abd071e5249b102d86fa294e0d22)) -* switch README Docker references from GHCR to Docker Hub ([9e15679](https://github.com/ashim-hq/ashim/commit/9e1567971d50d755ef3b51d31e80b5a31a28ed2d)) -* use two-pass validation in settings PUT to prevent partial writes ([2dc39d3](https://github.com/ashim-hq/ashim/commit/2dc39d353320b73d9abb96ee5ae1080c2ee2f9cb)) +* move health diagnostics behind admin auth ([ee9a20f](https://github.com/snapotter-hq/snapotter/commit/ee9a20f6a35a0681b3688f0e206914fceed8fd8c)) +* reject HTML tags in settings API to prevent stored XSS ([d5bd011](https://github.com/snapotter-hq/snapotter/commit/d5bd01189766ee0797fe35ff3651f38f59a65881)) +* simplify public health to static response, add 403 test ([9c05da6](https://github.com/snapotter-hq/snapotter/commit/9c05da6f1372abd071e5249b102d86fa294e0d22)) +* switch README Docker references from GHCR to Docker Hub ([9e15679](https://github.com/snapotter-hq/snapotter/commit/9e1567971d50d755ef3b51d31e80b5a31a28ed2d)) +* use two-pass validation in settings PUT to prevent partial writes ([2dc39d3](https://github.com/snapotter-hq/snapotter/commit/2dc39d353320b73d9abb96ee5ae1080c2ee2f9cb)) -## [0.17.6](https://github.com/ashim-hq/ashim/compare/v0.17.5...v0.17.6) (2026-03-28) +## [0.17.6](https://github.com/snapotter-hq/snapotter/compare/v0.17.5...v0.17.6) (2026-03-28) ### Bug Fixes -* resolve pipeline step race condition and infinite re-render loop ([e0177d4](https://github.com/ashim-hq/ashim/commit/e0177d405ef043a64f0b3a885e98169312be1fac)) -* show checkerboard behind transparent images in before/after slider ([73741e6](https://github.com/ashim-hq/ashim/commit/73741e6efbdee53396810a2bb11eaf9597e4aa32)) +* resolve pipeline step race condition and infinite re-render loop ([e0177d4](https://github.com/snapotter-hq/snapotter/commit/e0177d405ef043a64f0b3a885e98169312be1fac)) +* show checkerboard behind transparent images in before/after slider ([73741e6](https://github.com/snapotter-hq/snapotter/commit/73741e6efbdee53396810a2bb11eaf9597e4aa32)) -## [0.17.5](https://github.com/ashim-hq/ashim/compare/v0.17.4...v0.17.5) (2026-03-28) +## [0.17.5](https://github.com/snapotter-hq/snapotter/compare/v0.17.4...v0.17.5) (2026-03-28) ### Bug Fixes -* sync stepsRef during render, not useEffect ([0c86744](https://github.com/ashim-hq/ashim/commit/0c86744dda1073988c7e6bb55073f08e399c26f3)) +* sync stepsRef during render, not useEffect ([0c86744](https://github.com/snapotter-hq/snapotter/commit/0c86744dda1073988c7e6bb55073f08e399c26f3)) -## [0.17.4](https://github.com/ashim-hq/ashim/compare/v0.17.3...v0.17.4) (2026-03-28) +## [0.17.4](https://github.com/snapotter-hq/snapotter/compare/v0.17.3...v0.17.4) (2026-03-28) ### Bug Fixes -* prevent stale closure in pipeline step callbacks ([c67f002](https://github.com/ashim-hq/ashim/commit/c67f0027804f167e250bd497505399c07b539c4e)) +* prevent stale closure in pipeline step callbacks ([c67f002](https://github.com/snapotter-hq/snapotter/commit/c67f0027804f167e250bd497505399c07b539c4e)) -## [0.17.3](https://github.com/ashim-hq/ashim/compare/v0.17.2...v0.17.3) (2026-03-28) +## [0.17.3](https://github.com/snapotter-hq/snapotter/compare/v0.17.2...v0.17.3) (2026-03-28) ### Bug Fixes -* clear search when adding a step from the tool picker ([ae2e63f](https://github.com/ashim-hq/ashim/commit/ae2e63f7fc4af3556539eee577b253c0616cbd0f)) +* clear search when adding a step from the tool picker ([ae2e63f](https://github.com/snapotter-hq/snapotter/commit/ae2e63f7fc4af3556539eee577b253c0616cbd0f)) -## [0.17.2](https://github.com/ashim-hq/ashim/compare/v0.17.1...v0.17.2) (2026-03-28) +## [0.17.2](https://github.com/snapotter-hq/snapotter/compare/v0.17.1...v0.17.2) (2026-03-28) ### Bug Fixes -* prevent pipeline step settings from resetting on collapse ([d899ef1](https://github.com/ashim-hq/ashim/commit/d899ef128004e46200da785a960da50894e93861)) +* prevent pipeline step settings from resetting on collapse ([d899ef1](https://github.com/snapotter-hq/snapotter/commit/d899ef128004e46200da785a960da50894e93861)) -## [0.17.1](https://github.com/ashim-hq/ashim/compare/v0.17.0...v0.17.1) (2026-03-28) +## [0.17.1](https://github.com/snapotter-hq/snapotter/compare/v0.17.0...v0.17.1) (2026-03-28) ### Bug Fixes -* add remove-background settings to pipeline step configurator ([ae5ac81](https://github.com/ashim-hq/ashim/commit/ae5ac8134689e211f17534f3064995597b6337c8)) +* add remove-background settings to pipeline step configurator ([ae5ac81](https://github.com/snapotter-hq/snapotter/commit/ae5ac8134689e211f17534f3064995597b6337c8)) -# [0.17.0](https://github.com/ashim-hq/ashim/compare/v0.16.4...v0.17.0) (2026-03-28) +# [0.17.0](https://github.com/snapotter-hq/snapotter/compare/v0.16.4...v0.17.0) (2026-03-28) ### Features -* make AI tools pipeline-compatible and add search to tool picker ([2d46b09](https://github.com/ashim-hq/ashim/commit/2d46b096fa80e43f7a59e213ac884b5d1d30b586)) +* make AI tools pipeline-compatible and add search to tool picker ([2d46b09](https://github.com/snapotter-hq/snapotter/commit/2d46b096fa80e43f7a59e213ac884b5d1d30b586)) -## [0.16.4](https://github.com/ashim-hq/ashim/compare/v0.16.3...v0.16.4) (2026-03-28) +## [0.16.4](https://github.com/snapotter-hq/snapotter/compare/v0.16.3...v0.16.4) (2026-03-28) ### Bug Fixes -* surface hidden errors and add batch rejection tests ([2f8e2ce](https://github.com/ashim-hq/ashim/commit/2f8e2ce7e2b96613ebda249890632bc54c11980b)) +* surface hidden errors and add batch rejection tests ([2f8e2ce](https://github.com/snapotter-hq/snapotter/commit/2f8e2ce7e2b96613ebda249890632bc54c11980b)) -## [0.16.3](https://github.com/ashim-hq/ashim/compare/v0.16.2...v0.16.3) (2026-03-28) +## [0.16.3](https://github.com/snapotter-hq/snapotter/compare/v0.16.2...v0.16.3) (2026-03-28) ### Bug Fixes -* remove Google Drive coming soon placeholder from files nav ([e487fe0](https://github.com/ashim-hq/ashim/commit/e487fe06bf4cad6512100bf9660498e06c1047ba)) +* remove Google Drive coming soon placeholder from files nav ([e487fe0](https://github.com/snapotter-hq/snapotter/commit/e487fe06bf4cad6512100bf9660498e06c1047ba)) -## [0.16.2](https://github.com/ashim-hq/ashim/compare/v0.16.1...v0.16.2) (2026-03-28) +## [0.16.2](https://github.com/snapotter-hq/snapotter/compare/v0.16.1...v0.16.2) (2026-03-28) ### Bug Fixes -* pipeline only shows compatible tools and displays errors ([fe021c1](https://github.com/ashim-hq/ashim/commit/fe021c18b134c853262c8f0dac81c13f9ceeb435)) +* pipeline only shows compatible tools and displays errors ([fe021c1](https://github.com/snapotter-hq/snapotter/commit/fe021c18b134c853262c8f0dac81c13f9ceeb435)) -## [0.16.1](https://github.com/ashim-hq/ashim/compare/v0.16.0...v0.16.1) (2026-03-28) +## [0.16.1](https://github.com/snapotter-hq/snapotter/compare/v0.16.0...v0.16.1) (2026-03-28) ### Bug Fixes -* trigger browser password save prompt on password change ([6b279ad](https://github.com/ashim-hq/ashim/commit/6b279ad09b9e74de34732b0e854f1180f25b34bd)) +* trigger browser password save prompt on password change ([6b279ad](https://github.com/snapotter-hq/snapotter/commit/6b279ad09b9e74de34732b0e854f1180f25b34bd)) -# [0.16.0](https://github.com/ashim-hq/ashim/compare/v0.15.0...v0.16.0) (2026-03-28) +# [0.16.0](https://github.com/snapotter-hq/snapotter/compare/v0.15.0...v0.16.0) (2026-03-28) ### Features -* add password generator and browser save prompt on change-password page ([d56c644](https://github.com/ashim-hq/ashim/commit/d56c6446fee8384ab61ba180160f5e020a1e412e)) +* add password generator and browser save prompt on change-password page ([d56c644](https://github.com/snapotter-hq/snapotter/commit/d56c6446fee8384ab61ba180160f5e020a1e412e)) -# [0.15.0](https://github.com/ashim-hq/ashim/compare/v0.14.2...v0.15.0) (2026-03-28) +# [0.15.0](https://github.com/snapotter-hq/snapotter/compare/v0.14.2...v0.15.0) (2026-03-28) ### Features -* add forced password change page on first login ([e0900a8](https://github.com/ashim-hq/ashim/commit/e0900a877643c75266aeed5ac29501458ef0dcda)) +* add forced password change page on first login ([e0900a8](https://github.com/snapotter-hq/snapotter/commit/e0900a877643c75266aeed5ac29501458ef0dcda)) -## [0.14.2](https://github.com/ashim-hq/ashim/compare/v0.14.1...v0.14.2) (2026-03-28) +## [0.14.2](https://github.com/snapotter-hq/snapotter/compare/v0.14.1...v0.14.2) (2026-03-28) ### Bug Fixes -* **tests:** remove temp DB cleanup that races with other test files ([498bfb3](https://github.com/ashim-hq/ashim/commit/498bfb3def2d6786fa5e387b3e30ede9768ef616)) +* **tests:** remove temp DB cleanup that races with other test files ([498bfb3](https://github.com/snapotter-hq/snapotter/commit/498bfb3def2d6786fa5e387b3e30ede9768ef616)) -## [0.14.1](https://github.com/ashim-hq/ashim/compare/v0.14.0...v0.14.1) (2026-03-28) +## [0.14.1](https://github.com/snapotter-hq/snapotter/compare/v0.14.0...v0.14.1) (2026-03-28) ### Bug Fixes -* handle migration race condition in concurrent test workers ([d576ab1](https://github.com/ashim-hq/ashim/commit/d576ab1dfb1e9d2aa739c681c1f83d6fef3f7d22)) +* handle migration race condition in concurrent test workers ([d576ab1](https://github.com/snapotter-hq/snapotter/commit/d576ab1dfb1e9d2aa739c681c1f83d6fef3f7d22)) -# [0.14.0](https://github.com/ashim-hq/ashim/compare/v0.13.1...v0.14.0) (2026-03-28) +# [0.14.0](https://github.com/snapotter-hq/snapotter/compare/v0.13.1...v0.14.0) (2026-03-28) ### Features -* multi-arch Docker support, security hardening, and test improvements ([748d2b7](https://github.com/ashim-hq/ashim/commit/748d2b70460b3975a9c61edec0b121d788d0ee06)) +* multi-arch Docker support, security hardening, and test improvements ([748d2b7](https://github.com/snapotter-hq/snapotter/commit/748d2b70460b3975a9c61edec0b121d788d0ee06)) -## [0.13.1](https://github.com/ashim-hq/ashim/compare/v0.13.0...v0.13.1) (2026-03-27) +## [0.13.1](https://github.com/snapotter-hq/snapotter/compare/v0.13.0...v0.13.1) (2026-03-27) ### Bug Fixes -* **docs:** remove hero logo from home page ([64c0ec8](https://github.com/ashim-hq/ashim/commit/64c0ec895f82b09e50d5ecf2b85f759f0a481232)) +* **docs:** remove hero logo from home page ([64c0ec8](https://github.com/snapotter-hq/snapotter/commit/64c0ec895f82b09e50d5ecf2b85f759f0a481232)) -# [0.13.0](https://github.com/ashim-hq/ashim/compare/v0.12.1...v0.13.0) (2026-03-27) +# [0.13.0](https://github.com/snapotter-hq/snapotter/compare/v0.12.1...v0.13.0) (2026-03-27) ### Features -* **docs:** add gem logo to GitHub Pages nav bar and home hero ([f0b8162](https://github.com/ashim-hq/ashim/commit/f0b8162955fa8f6b1891968163b4292b279f1ea1)) +* **docs:** add gem logo to GitHub Pages nav bar and home hero ([f0b8162](https://github.com/snapotter-hq/snapotter/commit/f0b8162955fa8f6b1891968163b4292b279f1ea1)) -## [0.12.1](https://github.com/ashim-hq/ashim/compare/v0.12.0...v0.12.1) (2026-03-27) +## [0.12.1](https://github.com/snapotter-hq/snapotter/compare/v0.12.0...v0.12.1) (2026-03-27) ### Bug Fixes -* **docs:** clean up footer llms.txt links ([e842cde](https://github.com/ashim-hq/ashim/commit/e842cde838ad3deb1437c4c43c8ccd796276248c)) +* **docs:** clean up footer llms.txt links ([e842cde](https://github.com/snapotter-hq/snapotter/commit/e842cde838ad3deb1437c4c43c8ccd796276248c)) -# [0.12.0](https://github.com/ashim-hq/ashim/compare/v0.11.1...v0.12.0) (2026-03-27) +# [0.12.0](https://github.com/snapotter-hq/snapotter/compare/v0.11.1...v0.12.0) (2026-03-27) ### Bug Fixes -* **api:** resolve team name lookup and show server error messages ([609fc8b](https://github.com/ashim-hq/ashim/commit/609fc8b6cc2d2408226e2576c35d7715bdf1498c)) +* **api:** resolve team name lookup and show server error messages ([609fc8b](https://github.com/snapotter-hq/snapotter/commit/609fc8b6cc2d2408226e2576c35d7715bdf1498c)) ### Features -* **docs:** add llms.txt links to GitHub Pages footer ([b874445](https://github.com/ashim-hq/ashim/commit/b874445dc6d31c54a095d7471390e664b233d491)) +* **docs:** add llms.txt links to GitHub Pages footer ([b874445](https://github.com/snapotter-hq/snapotter/commit/b874445dc6d31c54a095d7471390e664b233d491)) -## [0.11.1](https://github.com/ashim-hq/ashim/compare/v0.11.0...v0.11.1) (2026-03-27) +## [0.11.1](https://github.com/snapotter-hq/snapotter/compare/v0.11.0...v0.11.1) (2026-03-27) ### Bug Fixes -* **docs:** ignore localhost dead links in VitePress build ([78269d4](https://github.com/ashim-hq/ashim/commit/78269d499c914d5d68c4455475a1608f4af2a075)) +* **docs:** ignore localhost dead links in VitePress build ([78269d4](https://github.com/snapotter-hq/snapotter/commit/78269d499c914d5d68c4455475a1608f4af2a075)) -# [0.11.0](https://github.com/ashim-hq/ashim/compare/v0.10.0...v0.11.0) (2026-03-27) +# [0.11.0](https://github.com/snapotter-hq/snapotter/compare/v0.10.0...v0.11.0) (2026-03-27) ### Bug Fixes -* **a11y:** add aria-hidden to decorative GemLogo SVG ([ae185ce](https://github.com/ashim-hq/ashim/commit/ae185ce767a480719d2f54d5675cbd7d64beb7b5)) -* **api:** allow Scalar docs through auth and CSP ([6023109](https://github.com/ashim-hq/ashim/commit/6023109df9c66c1e7b4d81f3e902f081809ed6ba)) -* **api:** use content instead of spec.content for Scalar v1.49 API ([dfcb4d5](https://github.com/ashim-hq/ashim/commit/dfcb4d579f4b44013d23dff8617d9a9f6315b452)) -* **ui:** clean up settings, automate page, fullscreen logo, and README ([b3c8ad4](https://github.com/ashim-hq/ashim/commit/b3c8ad4697000454a11aaace27d0baa37a9959d9)) +* **a11y:** add aria-hidden to decorative GemLogo SVG ([ae185ce](https://github.com/snapotter-hq/snapotter/commit/ae185ce767a480719d2f54d5675cbd7d64beb7b5)) +* **api:** allow Scalar docs through auth and CSP ([6023109](https://github.com/snapotter-hq/snapotter/commit/6023109df9c66c1e7b4d81f3e902f081809ed6ba)) +* **api:** use content instead of spec.content for Scalar v1.49 API ([dfcb4d5](https://github.com/snapotter-hq/snapotter/commit/dfcb4d579f4b44013d23dff8617d9a9f6315b452)) +* **ui:** clean up settings, automate page, fullscreen logo, and README ([b3c8ad4](https://github.com/snapotter-hq/snapotter/commit/b3c8ad4697000454a11aaace27d0baa37a9959d9)) ### Features -* **api:** add all remaining endpoints to OpenAPI spec ([e7b38ba](https://github.com/ashim-hq/ashim/commit/e7b38ba68f8ae7fae5675bafc0f2dc2c4f22ecd2)) -* **api:** add all tool endpoints to OpenAPI spec ([753ba3e](https://github.com/ashim-hq/ashim/commit/753ba3e4689b1a3504960d15d1ebceaf2a08876e)) -* **api:** add llms.txt and llms-full.txt endpoints ([12ba52a](https://github.com/ashim-hq/ashim/commit/12ba52a6a0c1260f02a4d7787be8113383575d9e)) -* **api:** add OpenAPI 3.1 spec skeleton with common schemas ([b2189f5](https://github.com/ashim-hq/ashim/commit/b2189f556815ef8d5c781eee72b8263db09f6a1a)) -* **api:** add Scalar docs route and install dependency ([6f2c319](https://github.com/ashim-hq/ashim/commit/6f2c3190b8414d1c4c3b1a78cf7a86a96109c934)) -* **api:** register docs route in server and test helper ([bc6b389](https://github.com/ashim-hq/ashim/commit/bc6b38918ff11f1027efeb934ae0e56d6068b81f)) -* **branding:** add faceted gem SVG logo assets ([4bc9335](https://github.com/ashim-hq/ashim/commit/4bc93351541b039534197821d290d34cad12c9a7)) -* **branding:** add favicon and meta tags to index.html ([2508fd0](https://github.com/ashim-hq/ashim/commit/2508fd04871cdb776523ec9d602ad934283c6211)) -* **branding:** add OG social preview image ([c6c5b92](https://github.com/ashim-hq/ashim/commit/c6c5b926e271d457effea9aec07b70bbc7227ef5)) -* **branding:** add PWA manifest and PNG logo assets ([298567d](https://github.com/ashim-hq/ashim/commit/298567d090f298600b334184b09d35c178097362)) -* **branding:** show gem icon in app header as default logo ([dd857fb](https://github.com/ashim-hq/ashim/commit/dd857fbcc778a2425806f1d96d83f118dc92831a)) -* **docs:** add gem favicon to VitePress site ([0918f93](https://github.com/ashim-hq/ashim/commit/0918f933719ae0d8ff16cf7a8ac0e8936e90805a)) -* **docs:** add llms.txt and llms-full.txt to GitHub Pages ([5f6959a](https://github.com/ashim-hq/ashim/commit/5f6959a21e3b2708edb011a0a7ce48fbfbc64c87)) +* **api:** add all remaining endpoints to OpenAPI spec ([e7b38ba](https://github.com/snapotter-hq/snapotter/commit/e7b38ba68f8ae7fae5675bafc0f2dc2c4f22ecd2)) +* **api:** add all tool endpoints to OpenAPI spec ([753ba3e](https://github.com/snapotter-hq/snapotter/commit/753ba3e4689b1a3504960d15d1ebceaf2a08876e)) +* **api:** add llms.txt and llms-full.txt endpoints ([12ba52a](https://github.com/snapotter-hq/snapotter/commit/12ba52a6a0c1260f02a4d7787be8113383575d9e)) +* **api:** add OpenAPI 3.1 spec skeleton with common schemas ([b2189f5](https://github.com/snapotter-hq/snapotter/commit/b2189f556815ef8d5c781eee72b8263db09f6a1a)) +* **api:** add Scalar docs route and install dependency ([6f2c319](https://github.com/snapotter-hq/snapotter/commit/6f2c3190b8414d1c4c3b1a78cf7a86a96109c934)) +* **api:** register docs route in server and test helper ([bc6b389](https://github.com/snapotter-hq/snapotter/commit/bc6b38918ff11f1027efeb934ae0e56d6068b81f)) +* **branding:** add faceted gem SVG logo assets ([4bc9335](https://github.com/snapotter-hq/snapotter/commit/4bc93351541b039534197821d290d34cad12c9a7)) +* **branding:** add favicon and meta tags to index.html ([2508fd0](https://github.com/snapotter-hq/snapotter/commit/2508fd04871cdb776523ec9d602ad934283c6211)) +* **branding:** add OG social preview image ([c6c5b92](https://github.com/snapotter-hq/snapotter/commit/c6c5b926e271d457effea9aec07b70bbc7227ef5)) +* **branding:** add PWA manifest and PNG logo assets ([298567d](https://github.com/snapotter-hq/snapotter/commit/298567d090f298600b334184b09d35c178097362)) +* **branding:** show gem icon in app header as default logo ([dd857fb](https://github.com/snapotter-hq/snapotter/commit/dd857fbcc778a2425806f1d96d83f118dc92831a)) +* **docs:** add gem favicon to VitePress site ([0918f93](https://github.com/snapotter-hq/snapotter/commit/0918f933719ae0d8ff16cf7a8ac0e8936e90805a)) +* **docs:** add llms.txt and llms-full.txt to GitHub Pages ([5f6959a](https://github.com/snapotter-hq/snapotter/commit/5f6959a21e3b2708edb011a0a7ce48fbfbc64c87)) -# [0.10.0](https://github.com/ashim-hq/ashim/compare/v0.9.0...v0.10.0) (2026-03-26) +# [0.10.0](https://github.com/snapotter-hq/snapotter/compare/v0.9.0...v0.10.0) (2026-03-26) ### Bug Fixes -* **ocr:** update PaddleOCR for v3 API and add Tesseract fallback ([e260a93](https://github.com/ashim-hq/ashim/commit/e260a93cf65f1e7cd22b7b5d491c6125fee8c915)) +* **ocr:** update PaddleOCR for v3 API and add Tesseract fallback ([e260a93](https://github.com/snapotter-hq/snapotter/commit/e260a93cf65f1e7cd22b7b5d491c6125fee8c915)) ### Features -* **erase-object:** replace mask upload with in-browser brush painting ([40e3081](https://github.com/ashim-hq/ashim/commit/40e30815915f18f9f7fc25c05a61c643f1dfdbe4)) +* **erase-object:** replace mask upload with in-browser brush painting ([40e3081](https://github.com/snapotter-hq/snapotter/commit/40e30815915f18f9f7fc25c05a61c643f1dfdbe4)) -# [0.9.0](https://github.com/ashim-hq/ashim/compare/v0.8.2...v0.9.0) (2026-03-26) +# [0.9.0](https://github.com/snapotter-hq/snapotter/compare/v0.8.2...v0.9.0) (2026-03-26) ### Bug Fixes -* **blur-faces:** switch from MediaPipe to OpenCV and auto-orient images ([dc10f90](https://github.com/ashim-hq/ashim/commit/dc10f905c62c662f1a40701c81874e5854ea33e6)) -* **docker:** add build layer caching for faster Docker rebuilds ([03ba30d](https://github.com/ashim-hq/ashim/commit/03ba30d8f01c5c2500641d934b08a875589bcd68)) -* **upscale:** auto-orient images before upscaling and improve UI ([8a6e665](https://github.com/ashim-hq/ashim/commit/8a6e665a4484bda1e4b93b520c393bb707a624aa)) +* **blur-faces:** switch from MediaPipe to OpenCV and auto-orient images ([dc10f90](https://github.com/snapotter-hq/snapotter/commit/dc10f905c62c662f1a40701c81874e5854ea33e6)) +* **docker:** add build layer caching for faster Docker rebuilds ([03ba30d](https://github.com/snapotter-hq/snapotter/commit/03ba30d8f01c5c2500641d934b08a875589bcd68)) +* **upscale:** auto-orient images before upscaling and improve UI ([8a6e665](https://github.com/snapotter-hq/snapotter/commit/8a6e665a4484bda1e4b93b520c393bb707a624aa)) ### Features -* **adjustments:** add real-time live preview for all color tools ([b5c924e](https://github.com/ashim-hq/ashim/commit/b5c924e0fc7468c6364ef320958cea2e5ef18420)) -* **image-to-pdf:** add live PDF page preview with margin visualization ([cd666ea](https://github.com/ashim-hq/ashim/commit/cd666eaef0b13bcd9223439f0bbb5efd88b2f25e)) -* **rotate:** add editable angle input and fine-tune +/- buttons ([e1f04c2](https://github.com/ashim-hq/ashim/commit/e1f04c28a6b03c0503266c0e78e7a9161011d939)) +* **adjustments:** add real-time live preview for all color tools ([b5c924e](https://github.com/snapotter-hq/snapotter/commit/b5c924e0fc7468c6364ef320958cea2e5ef18420)) +* **image-to-pdf:** add live PDF page preview with margin visualization ([cd666ea](https://github.com/snapotter-hq/snapotter/commit/cd666eaef0b13bcd9223439f0bbb5efd88b2f25e)) +* **rotate:** add editable angle input and fine-tune +/- buttons ([e1f04c2](https://github.com/snapotter-hq/snapotter/commit/e1f04c28a6b03c0503266c0e78e7a9161011d939)) -## [0.8.2](https://github.com/ashim-hq/ashim/compare/v0.8.1...v0.8.2) (2026-03-25) +## [0.8.2](https://github.com/snapotter-hq/snapotter/compare/v0.8.1...v0.8.2) (2026-03-25) ### Bug Fixes -* **test:** add missing PNG fixture files to repo ([45c6b9d](https://github.com/ashim-hq/ashim/commit/45c6b9de08124fb357ac759e43c4fbf1eb5fbfb9)) -* **test:** exclude e2e tests from vitest and fix CI test suite ([9d28485](https://github.com/ashim-hq/ashim/commit/9d28485339e17b80586cea91bd18dafc989d7f24)) +* **test:** add missing PNG fixture files to repo ([45c6b9d](https://github.com/snapotter-hq/snapotter/commit/45c6b9de08124fb357ac759e43c4fbf1eb5fbfb9)) +* **test:** exclude e2e tests from vitest and fix CI test suite ([9d28485](https://github.com/snapotter-hq/snapotter/commit/9d28485339e17b80586cea91bd18dafc989d7f24)) -## [0.8.1](https://github.com/ashim-hq/ashim/compare/v0.8.0...v0.8.1) (2026-03-25) +## [0.8.1](https://github.com/snapotter-hq/snapotter/compare/v0.8.0...v0.8.1) (2026-03-25) ### Bug Fixes -* resolve test failures from shared DB race conditions ([1a7116d](https://github.com/ashim-hq/ashim/commit/1a7116d79072d131b94d1c454abbc32b9e961c1b)) +* resolve test failures from shared DB race conditions ([1a7116d](https://github.com/snapotter-hq/snapotter/commit/1a7116d79072d131b94d1c454abbc32b9e961c1b)) -# [0.8.0](https://github.com/ashim-hq/ashim/compare/v0.7.0...v0.8.0) (2026-03-25) +# [0.8.0](https://github.com/snapotter-hq/snapotter/compare/v0.7.0...v0.8.0) (2026-03-25) ### Bug Fixes -* **docker:** skip husky prepare script in production install ([fdfb0a0](https://github.com/ashim-hq/ashim/commit/fdfb0a0e7412c86e3b85a70daf5093f44c34ee99)) -* prevent useAuth infinite loop causing rate limit storms ([9624dae](https://github.com/ashim-hq/ashim/commit/9624dae1569b6f2ad52ce990fc84eca809b849a8)) +* **docker:** skip husky prepare script in production install ([fdfb0a0](https://github.com/snapotter-hq/snapotter/commit/fdfb0a0e7412c86e3b85a70daf5093f44c34ee99)) +* prevent useAuth infinite loop causing rate limit storms ([9624dae](https://github.com/snapotter-hq/snapotter/commit/9624dae1569b6f2ad52ce990fc84eca809b849a8)) ### Features -* **api:** add logo upload/serve/delete routes with tests ([6063f4d](https://github.com/ashim-hq/ashim/commit/6063f4daa98acf3f03e004a588de562e377105c7)) -* **api:** add persistent file management helpers to frontend api module ([ecbfcce](https://github.com/ashim-hq/ashim/commit/ecbfcceec82010fa44244c6839928b9930d59b5a)) -* **api:** add teams CRUD routes and update auth team references ([ec22e53](https://github.com/ashim-hq/ashim/commit/ec22e53a3b15ae030743e76db0d57584000727b6)) -* **api:** add tool filtering and DB-backed cleanup settings ([07e7e8d](https://github.com/ashim-hq/ashim/commit/07e7e8d58d311d89f43cee1c7fa21dd0eb4c9dfb)) -* **api:** add user files CRUD routes at /api/v1/files/* ([6a07007](https://github.com/ashim-hq/ashim/commit/6a070071456611d2bf2acf4a474be8c43680e1b0)) -* **db:** add teams table and migration ([365783b](https://github.com/ashim-hq/ashim/commit/365783b6dc1f5cfa631bb4f6915fcf99d91f574d)) -* **db:** add userFiles table and migration ([a2fdbd5](https://github.com/ashim-hq/ashim/commit/a2fdbd5fef2cf02f90692166d6386c5ac21c2cef)) -* **env:** add FILES_STORAGE_PATH config variable ([3c737a6](https://github.com/ashim-hq/ashim/commit/3c737a6c724f4862d302bf22a75ebcd745f0df4c)) -* **files:** add Files page with nav, list, details, upload, and routing ([3f127a4](https://github.com/ashim-hq/ashim/commit/3f127a457e8a7a07d22fdf8776c3166092db562f)) -* **files:** add mobile layout for Files page ([e864d1e](https://github.com/ashim-hq/ashim/commit/e864d1e430bd516ccbe1732ec7451e1e7d670177)) -* **files:** wire serverFileId for version tracking ([8868d3e](https://github.com/ashim-hq/ashim/commit/8868d3e556beedcff35de268e72241e7f10998a3)) -* **i18n:** add translation keys for settings phase 1 ([c5ff80a](https://github.com/ashim-hq/ashim/commit/c5ff80acfbe18b953cfd96a88498fc70b82b541e)) -* implement Files page with persistent storage and version tracking ([f6183d2](https://github.com/ashim-hq/ashim/commit/f6183d2c62e6ad04dec3fe0250468cbfd6cbc035)) -* **storage:** add file storage helpers module ([7c37213](https://github.com/ashim-hq/ashim/commit/7c372135c8eb9d65198c0720bc2d0c83ac145004)) -* **stores:** add Zustand store for Files page state management ([fb487be](https://github.com/ashim-hq/ashim/commit/fb487be051c6da6ca22a443323cf4788d4ca4e6b)) -* **tool-factory:** auto-save results to persistent file store when fileId provided ([27d8629](https://github.com/ashim-hq/ashim/commit/27d8629c704bc9cabed8c7dd87c34ea8e9433347)) -* **ui:** add teams, tools, feature flags, temp files, logo to settings dialog ([fbce0dd](https://github.com/ashim-hq/ashim/commit/fbce0dddd05c1e539bfbdb084c3b53d59f5dfd76)) +* **api:** add logo upload/serve/delete routes with tests ([6063f4d](https://github.com/snapotter-hq/snapotter/commit/6063f4daa98acf3f03e004a588de562e377105c7)) +* **api:** add persistent file management helpers to frontend api module ([ecbfcce](https://github.com/snapotter-hq/snapotter/commit/ecbfcceec82010fa44244c6839928b9930d59b5a)) +* **api:** add teams CRUD routes and update auth team references ([ec22e53](https://github.com/snapotter-hq/snapotter/commit/ec22e53a3b15ae030743e76db0d57584000727b6)) +* **api:** add tool filtering and DB-backed cleanup settings ([07e7e8d](https://github.com/snapotter-hq/snapotter/commit/07e7e8d58d311d89f43cee1c7fa21dd0eb4c9dfb)) +* **api:** add user files CRUD routes at /api/v1/files/* ([6a07007](https://github.com/snapotter-hq/snapotter/commit/6a070071456611d2bf2acf4a474be8c43680e1b0)) +* **db:** add teams table and migration ([365783b](https://github.com/snapotter-hq/snapotter/commit/365783b6dc1f5cfa631bb4f6915fcf99d91f574d)) +* **db:** add userFiles table and migration ([a2fdbd5](https://github.com/snapotter-hq/snapotter/commit/a2fdbd5fef2cf02f90692166d6386c5ac21c2cef)) +* **env:** add FILES_STORAGE_PATH config variable ([3c737a6](https://github.com/snapotter-hq/snapotter/commit/3c737a6c724f4862d302bf22a75ebcd745f0df4c)) +* **files:** add Files page with nav, list, details, upload, and routing ([3f127a4](https://github.com/snapotter-hq/snapotter/commit/3f127a457e8a7a07d22fdf8776c3166092db562f)) +* **files:** add mobile layout for Files page ([e864d1e](https://github.com/snapotter-hq/snapotter/commit/e864d1e430bd516ccbe1732ec7451e1e7d670177)) +* **files:** wire serverFileId for version tracking ([8868d3e](https://github.com/snapotter-hq/snapotter/commit/8868d3e556beedcff35de268e72241e7f10998a3)) +* **i18n:** add translation keys for settings phase 1 ([c5ff80a](https://github.com/snapotter-hq/snapotter/commit/c5ff80acfbe18b953cfd96a88498fc70b82b541e)) +* implement Files page with persistent storage and version tracking ([f6183d2](https://github.com/snapotter-hq/snapotter/commit/f6183d2c62e6ad04dec3fe0250468cbfd6cbc035)) +* **storage:** add file storage helpers module ([7c37213](https://github.com/snapotter-hq/snapotter/commit/7c372135c8eb9d65198c0720bc2d0c83ac145004)) +* **stores:** add Zustand store for Files page state management ([fb487be](https://github.com/snapotter-hq/snapotter/commit/fb487be051c6da6ca22a443323cf4788d4ca4e6b)) +* **tool-factory:** auto-save results to persistent file store when fileId provided ([27d8629](https://github.com/snapotter-hq/snapotter/commit/27d8629c704bc9cabed8c7dd87c34ea8e9433347)) +* **ui:** add teams, tools, feature flags, temp files, logo to settings dialog ([fbce0dd](https://github.com/snapotter-hq/snapotter/commit/fbce0dddd05c1e539bfbdb084c3b53d59f5dfd76)) # Changelog @@ -972,14 +972,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Home upload flow, auth redirect, and form submit handling bugs - Background removal defaults to U2-Net (fast, ~2s) instead of slow BiRefNet -[Unreleased]: https://github.com/ashim-hq/ashim/compare/v0.7.0...HEAD -[0.7.0]: https://github.com/ashim-hq/ashim/compare/v0.6.0...v0.7.0 -[0.6.0]: https://github.com/ashim-hq/ashim/compare/v0.5.2...v0.6.0 -[0.5.2]: https://github.com/ashim-hq/ashim/compare/v0.5.1...v0.5.2 -[0.5.1]: https://github.com/ashim-hq/ashim/compare/v0.5.0...v0.5.1 -[0.5.0]: https://github.com/ashim-hq/ashim/compare/v0.4.1...v0.5.0 -[0.4.1]: https://github.com/ashim-hq/ashim/compare/v0.4.0...v0.4.1 -[0.4.0]: https://github.com/ashim-hq/ashim/compare/v0.3.1...v0.4.0 -[0.3.1]: https://github.com/ashim-hq/ashim/compare/v0.3.0...v0.3.1 -[0.3.0]: https://github.com/ashim-hq/ashim/compare/v0.2.1...v0.3.0 -[0.2.1]: https://github.com/ashim-hq/ashim/releases/tag/v0.2.1 +[Unreleased]: https://github.com/snapotter-hq/snapotter/compare/v0.7.0...HEAD +[0.7.0]: https://github.com/snapotter-hq/snapotter/compare/v0.6.0...v0.7.0 +[0.6.0]: https://github.com/snapotter-hq/snapotter/compare/v0.5.2...v0.6.0 +[0.5.2]: https://github.com/snapotter-hq/snapotter/compare/v0.5.1...v0.5.2 +[0.5.1]: https://github.com/snapotter-hq/snapotter/compare/v0.5.0...v0.5.1 +[0.5.0]: https://github.com/snapotter-hq/snapotter/compare/v0.4.1...v0.5.0 +[0.4.1]: https://github.com/snapotter-hq/snapotter/compare/v0.4.0...v0.4.1 +[0.4.0]: https://github.com/snapotter-hq/snapotter/compare/v0.3.1...v0.4.0 +[0.3.1]: https://github.com/snapotter-hq/snapotter/compare/v0.3.0...v0.3.1 +[0.3.0]: https://github.com/snapotter-hq/snapotter/compare/v0.2.1...v0.3.0 +[0.2.1]: https://github.com/snapotter-hq/snapotter/releases/tag/v0.2.1 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 97821637..44007909 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -3,7 +3,7 @@ ## Our Pledge We as members, contributors, and maintainers pledge to make participation in -the ashim community a harassment-free experience for everyone, regardless of +the SnapOtter community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or @@ -36,12 +36,12 @@ Examples of unacceptable behavior: ## Scope This Code of Conduct applies within all community spaces, including GitHub -Issues, Discussions, and any other channels managed by the ashim project. +Issues, Discussions, and any other channels managed by the SnapOtter project. ## Reporting Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to **ashim.hq@gmail.com**. All complaints will be reviewed promptly +reported to **snapotter.hq@gmail.com**. All complaints will be reviewed promptly and fairly. The maintainer is obligated to respect the privacy and security of the reporter of any incident. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 26fb2b07..db3d7828 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,10 @@ -# Contributing to ashim +# Contributing to SnapOtter -Thanks for your interest in the project. Community feedback helps shape ashim, and there are several ways to get involved. +Thanks for your interest in the project. Community feedback helps shape SnapOtter, and there are several ways to get involved. ## How to contribute -The best way to contribute is through [GitHub Issues](https://github.com/ashim-hq/ashim/issues): +The best way to contribute is through [GitHub Issues](https://github.com/snapotter-hq/snapotter/issues): - **Bug reports** - Found something broken? Open a bug report with steps to reproduce, your Docker setup, and what you expected to happen. - **Feature requests** - Have an idea for a new tool or improvement? Describe the problem you want solved and why it matters to you. @@ -18,8 +18,8 @@ If you've found a bug, please open an issue describing it rather than submitting ## Forking -You're welcome to fork the project for your own use under the terms of the [AGPLv3 license](LICENSE). The [Developer Guide](https://ashim-hq.github.io/ashim/guide/developer) covers setup, architecture, and how to add new tools. +You're welcome to fork the project for your own use under the terms of the [AGPLv3 license](LICENSE). The [Developer Guide](https://docs.snapotter.com/guide/developer) covers setup, architecture, and how to add new tools. ## Security -If you discover a security vulnerability, please report it privately through [GitHub Security Advisories](https://github.com/ashim-hq/ashim/security/advisories/new) rather than opening a public issue. +If you discover a security vulnerability, please report it privately through [GitHub Security Advisories](https://github.com/snapotter-hq/snapotter/security/advisories/new) rather than opening a public issue. diff --git a/LICENSE b/LICENSE index 5846d9ff..a64cf7d0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -ashim +SnapOtter Copyright (C) 2025-present Siddharth Kumar Sah This software is dual-licensed: diff --git a/README.md b/README.md index 51946a85..c3a369f1 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@

- ashim — A Self Hosted Image Manipulator + SnapOtter — A Self Hosted Image Manipulator

- Docker Hub - GHCR - CI - License - Stars + Docker Hub + GHCR + CI + License + Stars

-![ashim - Dashboard](images/dashboard.png) +![SnapOtter - Dashboard](images/dashboard.png) ## Key Features @@ -20,12 +20,12 @@ - **REST API** - Every tool available via API with API key auth. Interactive docs at `/api/docs` - **Single container** - One `docker run`, no Redis, no Postgres, no external services - **Multi-arch** - Runs on AMD64 and ARM64 (Intel, Apple Silicon, Raspberry Pi) -- **Privacy first** - Your images never leave your machine. ashim asks once whether you'd like to share anonymous product analytics (which tools are used, errors encountered — never file data). Change anytime in Settings, or set `ANALYTICS_ENABLED=false` to disable completely +- **Privacy first** - Your images never leave your machine. SnapOtter asks once whether you'd like to share anonymous product analytics (which tools are used, errors encountered — never file data). Change anytime in Settings, or set `ANALYTICS_ENABLED=false` to disable completely ## Quick Start ```bash -docker run -d --name ashim -p 1349:1349 -v ashim-data:/data ghcr.io/ashim-hq/ashim:latest +docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data ghcr.io/snapotter-hq/snapotter:latest ``` Open http://localhost:1349 in your browser. @@ -36,10 +36,10 @@ Open http://localhost:1349 in your browser. Add `--gpus all` for GPU-accelerated background removal, upscaling, and OCR: ```bash -docker run -d --name ashim -p 1349:1349 --gpus all -v ashim-data:/data ghcr.io/ashim-hq/ashim:latest +docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data ghcr.io/snapotter-hq/snapotter:latest ``` -> Requires an NVIDIA GPU and [Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Falls back to CPU if no GPU is found. See [Docker Tags](https://ashim-hq.github.io/ashim/guide/docker-tags) for benchmarks and Docker Compose examples. +> Requires an NVIDIA GPU and [Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Falls back to CPU if no GPU is found. See [Docker Tags](https://docs.snapotter.com/guide/docker-tags) for benchmarks and Docker Compose examples. @@ -52,30 +52,30 @@ docker run -d --name ashim -p 1349:1349 --gpus all -v ashim-data:/data ghcr.io/a You will be asked to change your password on first login. -For Docker Compose, persistent storage, and other setup options, see the [Getting Started Guide](https://ashim-hq.github.io/ashim/guide/getting-started). For GPU acceleration and tag details, see [Docker Tags](https://ashim-hq.github.io/ashim/guide/docker-tags). +For Docker Compose, persistent storage, and other setup options, see the [Getting Started Guide](https://docs.snapotter.com/guide/getting-started). For GPU acceleration and tag details, see [Docker Tags](https://docs.snapotter.com/guide/docker-tags). ## Documentation -- [Getting Started](https://ashim-hq.github.io/ashim/guide/getting-started) -- [Configuration](https://ashim-hq.github.io/ashim/guide/configuration) -- [Deployment](https://ashim-hq.github.io/ashim/guide/deployment) -- [Docker Tags](https://ashim-hq.github.io/ashim/guide/docker-tags) -- [REST API](https://ashim-hq.github.io/ashim/api/rest) -- [AI Engine](https://ashim-hq.github.io/ashim/api/ai) -- [Image Engine](https://ashim-hq.github.io/ashim/api/image-engine) -- [Architecture](https://ashim-hq.github.io/ashim/guide/architecture) -- [Database](https://ashim-hq.github.io/ashim/guide/database) -- [Developer Guide](https://ashim-hq.github.io/ashim/guide/developer) -- [Contributing](https://ashim-hq.github.io/ashim/guide/contributing) -- [Translation Guide](https://ashim-hq.github.io/ashim/guide/translations) +- [Getting Started](https://docs.snapotter.com/guide/getting-started) +- [Configuration](https://docs.snapotter.com/guide/configuration) +- [Deployment](https://docs.snapotter.com/guide/deployment) +- [Docker Tags](https://docs.snapotter.com/guide/docker-tags) +- [REST API](https://docs.snapotter.com/api/rest) +- [AI Engine](https://docs.snapotter.com/api/ai) +- [Image Engine](https://docs.snapotter.com/api/image-engine) +- [Architecture](https://docs.snapotter.com/guide/architecture) +- [Database](https://docs.snapotter.com/guide/database) +- [Developer Guide](https://docs.snapotter.com/guide/developer) +- [Contributing](https://docs.snapotter.com/guide/contributing) +- [Translation Guide](https://docs.snapotter.com/guide/translations) ## Feedback -Found a bug or have a feature idea? Open a [GitHub Issue](https://github.com/ashim-hq/ashim/issues). We don't accept pull requests, but your feedback directly shapes the project. See [CONTRIBUTING.md](CONTRIBUTING.md) for details. +Found a bug or have a feature idea? Open a [GitHub Issue](https://github.com/snapotter-hq/snapotter/issues). We don't accept pull requests, but your feedback directly shapes the project. See [CONTRIBUTING.md](CONTRIBUTING.md) for details. ## License This project is dual-licensed under the [AGPLv3](LICENSE) and a commercial license. - **AGPLv3 (free):** You may use, modify, and distribute this software under the AGPLv3. If you run a modified version as a network service, you must make your source code available under the AGPLv3. This applies to personal use, open-source projects, and any use that complies with AGPLv3 terms. -- **Commercial license (paid):** For use in proprietary software or SaaS products where AGPLv3 source-disclosure is not suitable, a commercial license is available. [Contact us](mailto:ashim.hq@gmail.com) for pricing and terms. +- **Commercial license (paid):** For use in proprietary software or SaaS products where AGPLv3 source-disclosure is not suitable, a commercial license is available. [Contact us](mailto:snapotter.hq@gmail.com) for pricing and terms. diff --git a/SECURITY.md b/SECURITY.md index c89dc45f..0cbe02b0 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,20 +2,20 @@ ## Supported Versions -Only the latest release of ashim receives security updates. We recommend always running the most recent version. +Only the latest release of SnapOtter receives security updates. We recommend always running the most recent version. | Version | Supported | |---------|-----------| | Latest release | Yes | | Previous releases | No | -Self-hosted deployments should subscribe to [GitHub release notifications](https://github.com/ashim-hq/ashim/releases) and upgrade promptly when security patches are published. +Self-hosted deployments should subscribe to [GitHub release notifications](https://github.com/snapotter-hq/snapotter/releases) and upgrade promptly when security patches are published. ## Reporting a Vulnerability **Do not open a public GitHub issue for security vulnerabilities.** -To report a vulnerability, email **security@ashim.local** with: +To report a vulnerability, email **security@snapotter.local** with: - A description of the vulnerability and its potential impact - Steps to reproduce or a proof-of-concept @@ -83,7 +83,7 @@ The following headers are set on all responses: ### Container Security -- **Non-root execution**: Dedicated `ashim` user and group created at build time. The entrypoint starts as root only to fix volume permissions, then drops privileges via `gosu` +- **Non-root execution**: Dedicated `snapotter` user and group created at build time. The entrypoint starts as root only to fix volume permissions, then drops privileges via `gosu` - **Root prevention**: PUID/PGID of 0 are explicitly rejected with a warning - **PID 1**: `tini` handles zombie reaping and signal forwarding - **Multi-stage build**: Production image contains only runtime dependencies @@ -105,11 +105,11 @@ Security-relevant events are dual-written to structured stdout (for log aggregat ## Shared Responsibility Model -ashim is a self-hosted application. Security is a shared responsibility between the ashim maintainers and the deployer. +SnapOtter is a self-hosted application. Security is a shared responsibility between the SnapOtter maintainers and the deployer. -| Area | ashim maintainers | Deployer | +| Area | SnapOtter maintainers | Deployer | |------|-------------------|----------| -| Application code | Patch vulnerabilities, follow secure coding practices | Keep ashim updated to the latest release | +| Application code | Patch vulnerabilities, follow secure coding practices | Keep SnapOtter updated to the latest release | | Docker image | Publish hardened images with non-root user, minimal attack surface | Pull updates regularly, scan images with your own tooling | | Dependencies | Monitor and update npm/pip dependencies | N/A | | Authentication | Provide secure auth implementation (scrypt, RBAC, brute-force protection) | Change default credentials before production use, enforce strong passwords | @@ -127,7 +127,7 @@ The following configurations are recommended for production deployments: ### Required - [ ] Change the default admin password immediately after first login (enforced by `mustChangePassword` unless `SKIP_MUST_CHANGE_PASSWORD=true`) -- [ ] Place ashim behind a TLS-terminating reverse proxy (nginx, Caddy, Traefik) +- [ ] Place SnapOtter behind a TLS-terminating reverse proxy (nginx, Caddy, Traefik) - [ ] Set `CORS_ORIGIN` to your specific domain(s) if cross-origin access is needed (default in production is same-origin only) ### Strongly Recommended diff --git a/apps/api/drizzle.config.ts b/apps/api/drizzle.config.ts index 1851a36a..7e895224 100644 --- a/apps/api/drizzle.config.ts +++ b/apps/api/drizzle.config.ts @@ -5,6 +5,6 @@ export default defineConfig({ out: "./drizzle", dialect: "sqlite", dbCredentials: { - url: process.env.DB_PATH || "./data/ashim.db", + url: process.env.DB_PATH || "./data/snapotter.db", }, }); diff --git a/apps/api/package.json b/apps/api/package.json index 36375b39..624cee26 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -1,5 +1,5 @@ { - "name": "@ashim/api", + "name": "@snapotter/api", "version": "1.15.9", "private": true, "type": "module", @@ -12,9 +12,9 @@ "clean": "rm -rf dist" }, "dependencies": { - "@ashim/ai": "workspace:*", - "@ashim/image-engine": "workspace:*", - "@ashim/shared": "workspace:*", + "@snapotter/ai": "workspace:*", + "@snapotter/image-engine": "workspace:*", + "@snapotter/shared": "workspace:*", "@fastify/cors": "^11.0.0", "@fastify/multipart": "^9.0.0", "@fastify/rate-limit": "^10.2.0", diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 7c2608f2..98ab097f 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; -import { isGpuAvailable } from "@ashim/ai"; -import { APP_VERSION } from "@ashim/shared"; import cors from "@fastify/cors"; import rateLimit from "@fastify/rate-limit"; +import { isGpuAvailable } from "@snapotter/ai"; +import { APP_VERSION } from "@snapotter/shared"; import { eq } from "drizzle-orm"; import Fastify from "fastify"; import { env } from "./config.js"; @@ -230,7 +230,7 @@ try { const gpu = isGpuAvailable(); console.log( [ - `ashim v${APP_VERSION} running on port ${env.PORT}`, + `SnapOtter v${APP_VERSION} running on port ${env.PORT}`, gpu ? "[INFO] GPU detected — AI tools will use CUDA acceleration" : "[WARN] No GPU detected — AI tools will use CPU (slower)", @@ -275,7 +275,7 @@ async function shutdown(signal: string) { } try { - const { shutdownDispatcher } = await import("@ashim/ai"); + const { shutdownDispatcher } = await import("@snapotter/ai"); shutdownDispatcher(); console.log("Python dispatcher shut down"); } catch { diff --git a/apps/api/src/lib/env.ts b/apps/api/src/lib/env.ts index 67eba88f..349c6a2d 100644 --- a/apps/api/src/lib/env.ts +++ b/apps/api/src/lib/env.ts @@ -21,12 +21,12 @@ const envSchema = z.object({ CONCURRENT_JOBS: z.coerce.number().default(0), MAX_MEGAPIXELS: z.coerce.number().default(0), RATE_LIMIT_PER_MIN: z.coerce.number().default(0), - DB_PATH: z.string().default("./data/ashim.db"), + DB_PATH: z.string().default("./data/snapotter.db"), FILES_STORAGE_PATH: z.string().default("./data/files"), WORKSPACE_PATH: z.string().default("./tmp/workspace"), DEFAULT_THEME: z.enum(["light", "dark"]).default("light"), DEFAULT_LOCALE: z.string().default("en"), - APP_NAME: z.string().default("ashim"), + APP_NAME: z.string().default("snapotter"), CORS_ORIGIN: z.string().default(""), MAX_USERS: z.coerce.number().default(0), LOG_LEVEL: z.enum(["fatal", "error", "warn", "info", "debug", "trace"]).default("info"), diff --git a/apps/api/src/lib/feature-status.ts b/apps/api/src/lib/feature-status.ts index 78929142..462ca472 100644 --- a/apps/api/src/lib/feature-status.ts +++ b/apps/api/src/lib/feature-status.ts @@ -10,8 +10,8 @@ import { writeFileSync, } from "node:fs"; import { join } from "node:path"; -import type { FeatureBundleState, FeatureStatus } from "@ashim/shared"; -import { FEATURE_BUNDLES, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import type { FeatureBundleState, FeatureStatus } from "@snapotter/shared"; +import { FEATURE_BUNDLES, TOOL_BUNDLE_MAP } from "@snapotter/shared"; // ── Paths ─────────────────────────────────────────────────────────────── diff --git a/apps/api/src/openapi.yaml b/apps/api/src/openapi.yaml index 9b2a1f45..7fb2ba09 100644 --- a/apps/api/src/openapi.yaml +++ b/apps/api/src/openapi.yaml @@ -1,9 +1,9 @@ openapi: 3.1.0 info: - title: ashim API + title: SnapOtter API version: 1.15.9 description: | - REST API for ashim, a self-hosted image processing platform with 30+ tools. + REST API for SnapOtter, a self-hosted image processing platform with 30+ tools. ## Authentication @@ -16,7 +16,7 @@ info: Endpoints marked with a lock icon require authentication. Admin-only endpoints are noted in their description. license: name: AGPL-3.0 - url: https://github.com/ashim-hq/ashim/blob/main/LICENSE + url: https://github.com/snapotter-hq/snapotter/blob/main/LICENSE servers: - url: / diff --git a/apps/api/src/permissions.ts b/apps/api/src/permissions.ts index eabd8a15..e566d76a 100644 --- a/apps/api/src/permissions.ts +++ b/apps/api/src/permissions.ts @@ -1,4 +1,4 @@ -import type { Permission, Role } from "@ashim/shared"; +import type { Permission, Role } from "@snapotter/shared"; import { eq } from "drizzle-orm"; import type { FastifyReply, FastifyRequest } from "fastify"; import { db, schema } from "./db/index.js"; diff --git a/apps/api/src/routes/batch.ts b/apps/api/src/routes/batch.ts index c47d76f3..96943bc4 100644 --- a/apps/api/src/routes/batch.ts +++ b/apps/api/src/routes/batch.ts @@ -9,7 +9,7 @@ */ import { randomUUID } from "node:crypto"; import { extname } from "node:path"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import archiver from "archiver"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import PQueue from "p-queue"; diff --git a/apps/api/src/routes/features.ts b/apps/api/src/routes/features.ts index 1dcedf2a..4abfe22f 100644 --- a/apps/api/src/routes/features.ts +++ b/apps/api/src/routes/features.ts @@ -11,8 +11,8 @@ import { spawn } from "node:child_process"; import crypto from "node:crypto"; import { existsSync, readdirSync, readFileSync, statSync, unlinkSync } from "node:fs"; import { join } from "node:path"; -import { shutdownDispatcher } from "@ashim/ai"; -import { ANALYTICS_EVENTS, FEATURE_BUNDLES } from "@ashim/shared"; +import { shutdownDispatcher } from "@snapotter/ai"; +import { ANALYTICS_EVENTS, FEATURE_BUNDLES } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { trackEvent } from "../lib/analytics.js"; import { diff --git a/apps/api/src/routes/pipeline.ts b/apps/api/src/routes/pipeline.ts index 036385dc..7a42f3b0 100644 --- a/apps/api/src/routes/pipeline.ts +++ b/apps/api/src/routes/pipeline.ts @@ -9,7 +9,7 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { join } from "node:path"; -import { ANALYTICS_EVENTS, getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { ANALYTICS_EVENTS, getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import archiver from "archiver"; import { eq } from "drizzle-orm"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; diff --git a/apps/api/src/routes/roles.ts b/apps/api/src/routes/roles.ts index eb7f62a5..c69e7615 100644 --- a/apps/api/src/routes/roles.ts +++ b/apps/api/src/routes/roles.ts @@ -1,5 +1,5 @@ import { randomUUID } from "node:crypto"; -import type { Permission } from "@ashim/shared"; +import type { Permission } from "@snapotter/shared"; import { eq, sql } from "drizzle-orm"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { z } from "zod"; diff --git a/apps/api/src/routes/tool-factory.ts b/apps/api/src/routes/tool-factory.ts index 78830bd8..a9ce24a2 100644 --- a/apps/api/src/routes/tool-factory.ts +++ b/apps/api/src/routes/tool-factory.ts @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { extname, join } from "node:path"; -import { ANALYTICS_EVENTS, getBundleForTool, TOOL_BUNDLE_MAP, TOOLS } from "@ashim/shared"; +import { ANALYTICS_EVENTS, getBundleForTool, TOOL_BUNDLE_MAP, TOOLS } from "@snapotter/shared"; import { eq } from "drizzle-orm"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; diff --git a/apps/api/src/routes/tools/blur-faces.ts b/apps/api/src/routes/tools/blur-faces.ts index 4757b187..f987412b 100644 --- a/apps/api/src/routes/tools/blur-faces.ts +++ b/apps/api/src/routes/tools/blur-faces.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { blurFaces } from "@ashim/ai"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { blurFaces } from "@snapotter/ai"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { z } from "zod"; import { autoOrient } from "../../lib/auto-orient.js"; diff --git a/apps/api/src/routes/tools/color-adjustments.ts b/apps/api/src/routes/tools/color-adjustments.ts index 49d66c1b..848c74c1 100644 --- a/apps/api/src/routes/tools/color-adjustments.ts +++ b/apps/api/src/routes/tools/color-adjustments.ts @@ -6,7 +6,7 @@ import { grayscale, invert, sepia, -} from "@ashim/image-engine"; +} from "@snapotter/image-engine"; import type { FastifyInstance } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/colorize.ts b/apps/api/src/routes/tools/colorize.ts index be988c70..aae1a9f7 100644 --- a/apps/api/src/routes/tools/colorize.ts +++ b/apps/api/src/routes/tools/colorize.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { colorize } from "@ashim/ai"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { colorize } from "@snapotter/ai"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/compress.ts b/apps/api/src/routes/tools/compress.ts index 50046bf7..2fdf84f0 100644 --- a/apps/api/src/routes/tools/compress.ts +++ b/apps/api/src/routes/tools/compress.ts @@ -1,4 +1,4 @@ -import { compress } from "@ashim/image-engine"; +import { compress } from "@snapotter/image-engine"; import type { FastifyInstance } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/content-aware-resize.ts b/apps/api/src/routes/tools/content-aware-resize.ts index d0ab861a..3c549444 100644 --- a/apps/api/src/routes/tools/content-aware-resize.ts +++ b/apps/api/src/routes/tools/content-aware-resize.ts @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { seamCarve } from "@ashim/ai"; +import { seamCarve } from "@snapotter/ai"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { z } from "zod"; import { autoOrient } from "../../lib/auto-orient.js"; diff --git a/apps/api/src/routes/tools/convert.ts b/apps/api/src/routes/tools/convert.ts index fa988607..d0dd7925 100644 --- a/apps/api/src/routes/tools/convert.ts +++ b/apps/api/src/routes/tools/convert.ts @@ -1,5 +1,5 @@ import { extname } from "node:path"; -import { convert } from "@ashim/image-engine"; +import { convert } from "@snapotter/image-engine"; import type { FastifyInstance } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/crop.ts b/apps/api/src/routes/tools/crop.ts index 027a58fd..18e915f2 100644 --- a/apps/api/src/routes/tools/crop.ts +++ b/apps/api/src/routes/tools/crop.ts @@ -1,4 +1,4 @@ -import { crop } from "@ashim/image-engine"; +import { crop } from "@snapotter/image-engine"; import type { FastifyInstance } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/enhance-faces.ts b/apps/api/src/routes/tools/enhance-faces.ts index 7e4862c4..f9b362b0 100644 --- a/apps/api/src/routes/tools/enhance-faces.ts +++ b/apps/api/src/routes/tools/enhance-faces.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { enhanceFaces } from "@ashim/ai"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { enhanceFaces } from "@snapotter/ai"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/erase-object.ts b/apps/api/src/routes/tools/erase-object.ts index 992caf97..9dfa0997 100644 --- a/apps/api/src/routes/tools/erase-object.ts +++ b/apps/api/src/routes/tools/erase-object.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { inpaint } from "@ashim/ai"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { inpaint } from "@snapotter/ai"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/image-enhancement.ts b/apps/api/src/routes/tools/image-enhancement.ts index d96bd37e..54cdd8b0 100644 --- a/apps/api/src/routes/tools/image-enhancement.ts +++ b/apps/api/src/routes/tools/image-enhancement.ts @@ -1,4 +1,4 @@ -import { analyzeImage, applyCorrections } from "@ashim/image-engine"; +import { analyzeImage, applyCorrections } from "@snapotter/image-engine"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/index.ts b/apps/api/src/routes/tools/index.ts index 800c2a11..2cac9c5d 100644 --- a/apps/api/src/routes/tools/index.ts +++ b/apps/api/src/routes/tools/index.ts @@ -1,4 +1,4 @@ -import { TOOLS } from "@ashim/shared"; +import { TOOLS } from "@snapotter/shared"; import { eq } from "drizzle-orm"; import type { FastifyInstance } from "fastify"; import { db, schema } from "../../db/index.js"; diff --git a/apps/api/src/routes/tools/noise-removal.ts b/apps/api/src/routes/tools/noise-removal.ts index acda7f12..6063d52d 100644 --- a/apps/api/src/routes/tools/noise-removal.ts +++ b/apps/api/src/routes/tools/noise-removal.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { join } from "node:path"; -import { noiseRemoval } from "@ashim/ai"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { noiseRemoval } from "@snapotter/ai"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { z } from "zod"; import { autoOrient } from "../../lib/auto-orient.js"; diff --git a/apps/api/src/routes/tools/ocr.ts b/apps/api/src/routes/tools/ocr.ts index a2304b38..4e6dfd85 100644 --- a/apps/api/src/routes/tools/ocr.ts +++ b/apps/api/src/routes/tools/ocr.ts @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; import { basename } from "node:path"; -import { extractText } from "@ashim/ai"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { extractText } from "@snapotter/ai"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { z } from "zod"; import { formatZodErrors } from "../../lib/errors.js"; diff --git a/apps/api/src/routes/tools/optimize-for-web.ts b/apps/api/src/routes/tools/optimize-for-web.ts index c7c7346a..72e28318 100644 --- a/apps/api/src/routes/tools/optimize-for-web.ts +++ b/apps/api/src/routes/tools/optimize-for-web.ts @@ -1,5 +1,5 @@ import { extname } from "node:path"; -import { optimizeForWeb } from "@ashim/image-engine"; +import { optimizeForWeb } from "@snapotter/image-engine"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/passport-photo.ts b/apps/api/src/routes/tools/passport-photo.ts index 4681af84..57ffdc84 100644 --- a/apps/api/src/routes/tools/passport-photo.ts +++ b/apps/api/src/routes/tools/passport-photo.ts @@ -1,8 +1,13 @@ import { randomUUID } from "node:crypto"; import { readFile, writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { detectFaceLandmarks, removeBackground } from "@ashim/ai"; -import { getBundleForTool, PASSPORT_SPECS, PRINT_LAYOUTS, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { detectFaceLandmarks, removeBackground } from "@snapotter/ai"; +import { + getBundleForTool, + PASSPORT_SPECS, + PRINT_LAYOUTS, + TOOL_BUNDLE_MAP, +} from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/red-eye-removal.ts b/apps/api/src/routes/tools/red-eye-removal.ts index bf425e36..c29d9aa9 100644 --- a/apps/api/src/routes/tools/red-eye-removal.ts +++ b/apps/api/src/routes/tools/red-eye-removal.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { removeRedEye } from "@ashim/ai"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { removeRedEye } from "@snapotter/ai"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { z } from "zod"; import { autoOrient } from "../../lib/auto-orient.js"; diff --git a/apps/api/src/routes/tools/remove-background.ts b/apps/api/src/routes/tools/remove-background.ts index 87fbe949..9ece7a67 100644 --- a/apps/api/src/routes/tools/remove-background.ts +++ b/apps/api/src/routes/tools/remove-background.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; import { readFile, writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { removeBackground } from "@ashim/ai"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { removeBackground } from "@snapotter/ai"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { z } from "zod"; import { autoOrient } from "../../lib/auto-orient.js"; diff --git a/apps/api/src/routes/tools/resize.ts b/apps/api/src/routes/tools/resize.ts index 49f1baee..fe9be6ab 100644 --- a/apps/api/src/routes/tools/resize.ts +++ b/apps/api/src/routes/tools/resize.ts @@ -1,4 +1,4 @@ -import { resize } from "@ashim/image-engine"; +import { resize } from "@snapotter/image-engine"; import type { FastifyInstance } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/restore-photo.ts b/apps/api/src/routes/tools/restore-photo.ts index d8461e56..a26460c7 100644 --- a/apps/api/src/routes/tools/restore-photo.ts +++ b/apps/api/src/routes/tools/restore-photo.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { restorePhoto } from "@ashim/ai"; -import { getBundleForTool } from "@ashim/shared"; +import { restorePhoto } from "@snapotter/ai"; +import { getBundleForTool } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/rotate.ts b/apps/api/src/routes/tools/rotate.ts index ef193e90..da4369cc 100644 --- a/apps/api/src/routes/tools/rotate.ts +++ b/apps/api/src/routes/tools/rotate.ts @@ -1,4 +1,4 @@ -import { flip, rotate } from "@ashim/image-engine"; +import { flip, rotate } from "@snapotter/image-engine"; import type { FastifyInstance } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/sharpening.ts b/apps/api/src/routes/tools/sharpening.ts index ff044f06..e598ef95 100644 --- a/apps/api/src/routes/tools/sharpening.ts +++ b/apps/api/src/routes/tools/sharpening.ts @@ -1,4 +1,4 @@ -import { sharpenAdvanced } from "@ashim/image-engine"; +import { sharpenAdvanced } from "@snapotter/image-engine"; import type { FastifyInstance } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/smart-crop.ts b/apps/api/src/routes/tools/smart-crop.ts index a6dfcf98..13fc671c 100644 --- a/apps/api/src/routes/tools/smart-crop.ts +++ b/apps/api/src/routes/tools/smart-crop.ts @@ -1,5 +1,5 @@ -import { detectFaces } from "@ashim/ai"; -import { SMART_CROP_FACE_PRESETS } from "@ashim/shared"; +import { detectFaces } from "@snapotter/ai"; +import { SMART_CROP_FACE_PRESETS } from "@snapotter/shared"; import type { FastifyInstance } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/strip-metadata.ts b/apps/api/src/routes/tools/strip-metadata.ts index 51a6db9d..c62f1124 100644 --- a/apps/api/src/routes/tools/strip-metadata.ts +++ b/apps/api/src/routes/tools/strip-metadata.ts @@ -1,5 +1,5 @@ import { basename } from "node:path"; -import { parseExif, parseGps, parseXmp, stripMetadata } from "@ashim/image-engine"; +import { parseExif, parseGps, parseXmp, stripMetadata } from "@snapotter/image-engine"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/api/src/routes/tools/upscale.ts b/apps/api/src/routes/tools/upscale.ts index 3f460b01..91186da7 100644 --- a/apps/api/src/routes/tools/upscale.ts +++ b/apps/api/src/routes/tools/upscale.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { basename, join } from "node:path"; -import { upscale } from "@ashim/ai"; -import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared"; +import { upscale } from "@snapotter/ai"; +import { getBundleForTool, TOOL_BUNDLE_MAP } from "@snapotter/shared"; import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import sharp from "sharp"; import { z } from "zod"; diff --git a/apps/docs/.vitepress/config.mts b/apps/docs/.vitepress/config.mts index 03c0964a..dcbfcb38 100644 --- a/apps/docs/.vitepress/config.mts +++ b/apps/docs/.vitepress/config.mts @@ -6,6 +6,7 @@ export default defineConfig({ description: "Documentation for SnapOtter - A Self Hosted Image Manipulator. 45+ tools, local AI, pipelines, REST API.", base: "/", + appearance: { initialValue: "light" }, srcDir: ".", outDir: "./.vitepress/dist", ignoreDeadLinks: [/localhost/], @@ -13,13 +14,13 @@ export default defineConfig({ head: [ ["meta", { name: "theme-color", content: "#3b82f6" }], ["link", { rel: "icon", type: "image/png", href: "/favicon.png" }], - ["link", { rel: "llms-txt", href: "/ashim/llms.txt" }], + ["link", { rel: "llms-txt", href: "/llms.txt" }], ], vite: { plugins: [ llmstxt({ - domain: "https://ashim-hq.github.io", + domain: "https://docs.snapotter.com", customLLMsTxtTemplate: `# {title} {description} @@ -42,7 +43,7 @@ export default defineConfig({ ## Source -- [GitHub](https://github.com/ashim-hq/ashim) +- [GitHub](https://github.com/snapotter-hq/snapotter) - License: AGPLv3 (commercial license also available) `, customTemplateVariables: { @@ -96,13 +97,13 @@ export default defineConfig({ footer: { message: - 'Released under the AGPLv3 License.', + 'Released under the AGPLv3 License.', copyright: - 'AI-friendly docs available at /llms.txt · /llms-full.txt', + 'AI-friendly docs available at /llms.txt · /llms-full.txt', }, editLink: { - pattern: "https://github.com/ashim-hq/ashim/edit/main/apps/docs/:path", + pattern: "https://github.com/snapotter-hq/snapotter/edit/main/apps/docs/:path", text: "Edit this page on GitHub", }, }, diff --git a/apps/docs/.vitepress/theme/GitHubStars.vue b/apps/docs/.vitepress/theme/GitHubStars.vue index 549c64a2..7fe7c714 100644 --- a/apps/docs/.vitepress/theme/GitHubStars.vue +++ b/apps/docs/.vitepress/theme/GitHubStars.vue @@ -2,11 +2,11 @@ import { onMounted, ref } from "vue"; const stars = ref(null); -const repo = "https://github.com/ashim-hq/ashim"; +const repo = "https://github.com/snapotter-hq/snapotter"; onMounted(async () => { try { - const res = await fetch("https://api.github.com/repos/ashim-hq/ashim"); + const res = await fetch("https://api.github.com/repos/snapotter-hq/snapotter"); if (!res.ok) return; const data = await res.json(); const count = data.stargazers_count; diff --git a/apps/docs/.vitepress/theme/github-stars.css b/apps/docs/.vitepress/theme/github-stars.css index fe0fd1b1..69e962b7 100644 --- a/apps/docs/.vitepress/theme/github-stars.css +++ b/apps/docs/.vitepress/theme/github-stars.css @@ -1,6 +1,6 @@ /* Quick start command banner on homepage */ .quick-start-banner { - max-width: 640px; + max-width: 960px; margin: -16px auto 48px; padding: 0 24px; text-align: center; diff --git a/apps/docs/api/ai.md b/apps/docs/api/ai.md index 13600640..f47eead1 100644 --- a/apps/docs/api/ai.md +++ b/apps/docs/api/ai.md @@ -1,6 +1,6 @@ # AI Engine Reference -The `@ashim/ai` package bridges Node.js to a **persistent Python sidecar** for all ML operations. The dispatcher process stays alive between requests for fast warm-start performance. GPU is auto-detected at startup and used when available. +The `@snapotter/ai` package bridges Node.js to a **persistent Python sidecar** for all ML operations. The dispatcher process stays alive between requests for fast warm-start performance. GPU is auto-detected at startup and used when available. 14 AI tool routes. All models run locally - no internet required after initial model download. @@ -10,7 +10,7 @@ The `@ashim/ai` package bridges Node.js to a **persistent Python sidecar** for a Node.js Tool Route │ ▼ - @ashim/ai bridge.ts + @snapotter/ai bridge.ts │ (stdin/stdout JSON + stderr progress events) ▼ Python dispatcher (persistent process) diff --git a/apps/docs/api/image-engine.md b/apps/docs/api/image-engine.md index c222fe78..352d558b 100644 --- a/apps/docs/api/image-engine.md +++ b/apps/docs/api/image-engine.md @@ -1,6 +1,6 @@ # Image engine -The `@ashim/image-engine` package handles all non-AI image operations. It wraps [Sharp](https://sharp.pixelplumbing.com/) and runs entirely in-process with no external dependencies. +The `@snapotter/image-engine` package handles all non-AI image operations. It wraps [Sharp](https://sharp.pixelplumbing.com/) and runs entirely in-process with no external dependencies. ## Operations diff --git a/apps/docs/guide/architecture.md b/apps/docs/guide/architecture.md index b7663c5f..33525772 100644 --- a/apps/docs/guide/architecture.md +++ b/apps/docs/guide/architecture.md @@ -1,11 +1,11 @@ # Architecture -ashim is a monorepo managed with pnpm workspaces and Turborepo. Everything ships as a single Docker container. +SnapOtter is a monorepo managed with pnpm workspaces and Turborepo. Everything ships as a single Docker container. ## Project structure ``` -ashim/ +snapotter/ ├── apps/ │ ├── api/ # Fastify backend │ ├── web/ # React + Vite frontend @@ -19,13 +19,13 @@ ashim/ ## Packages -### `@ashim/image-engine` +### `@snapotter/image-engine` The core image processing library built on [Sharp](https://sharp.pixelplumbing.com/). It handles all non-AI operations: resize, crop, rotate, flip, convert, compress, strip metadata, and color adjustments (brightness, contrast, saturation, grayscale, sepia, invert, color channels). This package has no network dependencies and runs entirely in-process. -### `@ashim/ai` +### `@snapotter/ai` A bridge layer that calls Python scripts for ML operations. On first use, the bridge starts a persistent Python dispatcher process that pre-imports heavy libraries (PIL, NumPy, MediaPipe, rembg) so subsequent AI calls skip the import overhead. If the dispatcher is not yet ready, the bridge falls back to spawning a fresh Python subprocess per request. @@ -35,7 +35,7 @@ Supported operations: background removal (rembg/BiRefNet), upscaling (RealESRGAN Python scripts live in `packages/ai/python/`. The Docker image pre-downloads all model weights during the build so the container works fully offline. -### `@ashim/shared` +### `@snapotter/shared` Shared TypeScript types, constants (like `APP_VERSION` and tool definitions), and i18n translation strings used by both the frontend and backend. @@ -88,7 +88,7 @@ For batch processing, the API uses p-queue with a configurable concurrency limit ## Resource footprint -ashim is designed for low idle memory use. Nothing is preloaded or kept warm at startup. +SnapOtter is designed for low idle memory use. Nothing is preloaded or kept warm at startup. ### At idle diff --git a/apps/docs/guide/configuration.md b/apps/docs/guide/configuration.md index 7de9d67a..01cfa950 100644 --- a/apps/docs/guide/configuration.md +++ b/apps/docs/guide/configuration.md @@ -1,6 +1,6 @@ # Configuration -All configuration is done through environment variables. Every variable has a sensible default, so ashim works out of the box without setting any of them. +All configuration is done through environment variables. Every variable has a sensible default, so SnapOtter works out of the box without setting any of them. ## Environment variables @@ -30,7 +30,7 @@ All configuration is done through environment variables. Every variable has a se | Variable | Default | Description | |---|---|---| | `STORAGE_MODE` | `local` | `local` or `s3`. Only local storage is currently implemented. | -| `DB_PATH` | `./data/ashim.db` | Path to the SQLite database file. | +| `DB_PATH` | `./data/snapotter.db` | Path to the SQLite database file. | | `WORKSPACE_PATH` | `./tmp/workspace` | Directory for temporary files during processing. Cleaned up automatically. | | `FILES_STORAGE_PATH` | `./data/files` | Directory for persistent user files (uploaded images, saved results). | @@ -62,7 +62,7 @@ All configuration is done through environment variables. Every variable has a se | Variable | Default | Description | |---|---|---| -| `APP_NAME` | `ashim` | Display name shown in the UI. | +| `APP_NAME` | `SnapOtter` | Display name shown in the UI. | | `DEFAULT_THEME` | `light` | Default theme for new sessions. `light` or `dark`. | | `DEFAULT_LOCALE` | `en` | Default interface language. | @@ -77,13 +77,13 @@ All configuration is done through environment variables. Every variable has a se ```yaml services: - ashim: - image: ashimhq/ashim:latest + SnapOtter: + image: snapotterhq/snapotter:latest ports: - "1349:1349" volumes: - - ashim-data:/data - - ashim-workspace:/tmp/workspace + - SnapOtter-data:/data + - SnapOtter-workspace:/tmp/workspace environment: - AUTH_ENABLED=true - DEFAULT_USERNAME=admin diff --git a/apps/docs/guide/contributing.md b/apps/docs/guide/contributing.md index f559b0f5..6b1b2a79 100644 --- a/apps/docs/guide/contributing.md +++ b/apps/docs/guide/contributing.md @@ -1,10 +1,10 @@ # Contributing -Thanks for your interest in ashim. Community feedback helps shape the project, and there are several ways to get involved. +Thanks for your interest in SnapOtter. Community feedback helps shape the project, and there are several ways to get involved. ## How to contribute -The best way to contribute is through [GitHub Issues](https://github.com/ashim-hq/ashim/issues): +The best way to contribute is through [GitHub Issues](https://github.com/snapotter-hq/snapotter/issues): - **Bug reports** - Found something broken? Open a bug report with steps to reproduce, your Docker setup, and what you expected to happen. - **Feature requests** - Have an idea for a new tool or improvement? Describe the problem you want solved and why it matters to you. @@ -18,8 +18,8 @@ If you have found a bug, open an issue describing it rather than submitting a fi ## Forking -You are welcome to fork the project for your own use under the terms of the [AGPLv3 license](https://github.com/ashim-hq/ashim/blob/main/LICENSE). The [Developer Guide](/guide/developer) covers setup, architecture, and how to add new tools. +You are welcome to fork the project for your own use under the terms of the [AGPLv3 license](https://github.com/snapotter-hq/snapotter/blob/main/LICENSE). The [Developer Guide](/guide/developer) covers setup, architecture, and how to add new tools. ## Security -If you discover a security vulnerability, please report it privately through [GitHub Security Advisories](https://github.com/ashim-hq/ashim/security/advisories/new) rather than opening a public issue. +If you discover a security vulnerability, please report it privately through [GitHub Security Advisories](https://github.com/snapotter-hq/snapotter/security/advisories/new) rather than opening a public issue. diff --git a/apps/docs/guide/database.md b/apps/docs/guide/database.md index 3fd09e62..1c8fcbea 100644 --- a/apps/docs/guide/database.md +++ b/apps/docs/guide/database.md @@ -1,8 +1,8 @@ # Database -ashim uses SQLite with [Drizzle ORM](https://orm.drizzle.team/) for data persistence. The schema is defined in `apps/api/src/db/schema.ts`. +SnapOtter uses SQLite with [Drizzle ORM](https://orm.drizzle.team/) for data persistence. The schema is defined in `apps/api/src/db/schema.ts`. -The database file lives at the path set by `DB_PATH` (defaults to `./data/ashim.db`). In Docker, mount the `/data` volume to persist it across container restarts. +The database file lives at the path set by `DB_PATH` (defaults to `./data/snapotter.db`). In Docker, mount the `/data` volume to persist it across container restarts. ## Tables @@ -119,7 +119,7 @@ Key-value store for server-wide settings that admins can change from the UI. Drizzle handles schema migrations. The config is in `apps/api/drizzle.config.ts`. During development, run: ```bash -pnpm --filter @ashim/api drizzle-kit push +pnpm --filter @snapotter/api drizzle-kit push ``` In production, the schema is applied automatically on startup. diff --git a/apps/docs/guide/deployment.md b/apps/docs/guide/deployment.md index cd3bd44a..0d595263 100644 --- a/apps/docs/guide/deployment.md +++ b/apps/docs/guide/deployment.md @@ -1,6 +1,6 @@ # Deployment -ashim ships as a single Docker container. The image supports **linux/amd64** (with NVIDIA CUDA) and **linux/arm64** (CPU), so it runs natively on Intel/AMD servers, Apple Silicon Macs, and ARM devices like the Raspberry Pi 4/5. +SnapOtter ships as a single Docker container. The image supports **linux/amd64** (with NVIDIA CUDA) and **linux/arm64** (CPU), so it runs natively on Intel/AMD servers, Apple Silicon Macs, and ARM devices like the Raspberry Pi 4/5. See [Docker Image](./docker-tags) for GPU setup, Docker Compose examples, and version pinning. @@ -9,14 +9,14 @@ See [Docker Image](./docker-tags) for GPU setup, Docker Compose examples, and ve ```yaml # docker-compose.yml — Copy this file and run: docker compose up -d services: - ashim: - image: ashimhq/ashim:latest # or ghcr.io/ashim-hq/ashim:latest - container_name: ashim + SnapOtter: + image: snapotterhq/snapotter:latest # or ghcr.io/snapotter-hq/snapotter:latest + container_name: SnapOtter ports: - "1349:1349" # Web UI + API volumes: - - ashim-data:/data # Database, AI models, user files (PERSISTENT) - - ashim-workspace:/tmp/workspace # Temp processing files (can be tmpfs) + - SnapOtter-data:/data # Database, AI models, user files (PERSISTENT) + - SnapOtter-workspace:/tmp/workspace # Temp processing files (can be tmpfs) environment: # --- Authentication --- - AUTH_ENABLED=true # Set to false to disable login entirely @@ -50,8 +50,8 @@ services: max-file: "3" volumes: - ashim-data: # Named volume — Docker manages permissions automatically - ashim-workspace: + SnapOtter-data: # Named volume — Docker manages permissions automatically + SnapOtter-workspace: ``` ```bash @@ -60,7 +60,7 @@ docker compose up -d The app is then available at `http://localhost:1349`. -> **Docker Hub rate limits?** Replace `ashimhq/ashim:latest` with `ghcr.io/ashim-hq/ashim:latest` to pull from GitHub Container Registry instead. Both registries receive the same image on every release. +> **Docker Hub rate limits?** Replace `snapotterhq/snapotter:latest` with `ghcr.io/snapotter-hq/snapotter:latest` to pull from GitHub Container Registry instead. Both registries receive the same image on every release. ## Quick Start (GPU) @@ -70,14 +70,14 @@ For NVIDIA GPU acceleration on AI tools (background removal, upscaling, face enh # docker-compose-gpu.yml — Requires: NVIDIA GPU + nvidia-container-toolkit # Install toolkit: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html services: - ashim: - image: ashimhq/ashim:latest - container_name: ashim + SnapOtter: + image: snapotterhq/snapotter:latest + container_name: SnapOtter ports: - "1349:1349" volumes: - - ashim-data:/data - - ashim-workspace:/tmp/workspace + - SnapOtter-data:/data + - SnapOtter-workspace:/tmp/workspace environment: - AUTH_ENABLED=true - DEFAULT_USERNAME=admin @@ -104,8 +104,8 @@ services: max-file: "3" volumes: - ashim-data: - ashim-workspace: + SnapOtter-data: + SnapOtter-workspace: ``` ```bash @@ -115,7 +115,7 @@ docker compose -f docker-compose-gpu.yml up -d Check GPU detection in the logs: ```bash -docker logs ashim 2>&1 | head -20 +docker logs SnapOtter 2>&1 | head -20 # Look for: [INFO] GPU detected — AI tools will use CUDA acceleration ``` @@ -281,13 +281,13 @@ Not supported: BMP (V4/V5 headers), JPEG XL (JXL), EXR (missing decode delegate **Named volumes** (recommended) — Docker manages permissions automatically: ```yaml volumes: - - ashim-data:/data + - SnapOtter-data:/data ``` **Bind mounts** — You manage permissions. Set `PUID`/`PGID` to match your host user: ```yaml volumes: - - ./ashim-data:/data + - ./SnapOtter-data:/data environment: - PUID=1000 # Your host UID (run: id -u) - PGID=1000 # Your host GID (run: id -g) @@ -318,7 +318,7 @@ The container includes a built-in health check: ```bash # Check container health status -docker inspect --format='{{.State.Health.Status}}' ashim +docker inspect --format='{{.State.Health.Status}}' SnapOtter # Manual health check curl http://localhost:1349/api/v1/health @@ -327,7 +327,7 @@ curl http://localhost:1349/api/v1/health ## Reverse Proxy -ashim sets `TRUST_PROXY=true` by default so rate limiting and logging use the real client IP from `X-Forwarded-For` headers. +SnapOtter sets `TRUST_PROXY=true` by default so rate limiting and logging use the real client IP from `X-Forwarded-For` headers. ### Nginx @@ -360,23 +360,23 @@ server { 1. Add a new Proxy Host 2. Set Domain Name to your domain -3. Set Scheme to `http`, Forward Hostname to `ashim` (or your container IP), Forward Port to `1349` +3. Set Scheme to `http`, Forward Hostname to `SnapOtter` (or your container IP), Forward Port to `1349` 4. Enable WebSocket support 5. Under Advanced, add: `client_max_body_size 500M;` and `proxy_buffering off;` ### Traefik ```yaml -# Add these labels to the ashim service in docker-compose.yml +# Add these labels to the SnapOtter service in docker-compose.yml labels: - "traefik.enable=true" - - "traefik.http.routers.ashim.rule=Host(`images.example.com`)" - - "traefik.http.routers.ashim.entrypoints=websecure" - - "traefik.http.routers.ashim.tls.certresolver=letsencrypt" - - "traefik.http.services.ashim.loadbalancer.server.port=1349" + - "traefik.http.routers.snapotter.rule=Host(`images.example.com`)" + - "traefik.http.routers.snapotter.entrypoints=websecure" + - "traefik.http.routers.snapotter.tls.certresolver=letsencrypt" + - "traefik.http.services.snapotter.loadbalancer.server.port=1349" # Increase upload limit (default 2MB is too low) - - "traefik.http.middlewares.ashim-body.buffering.maxRequestBodyBytes=524288000" - - "traefik.http.routers.ashim.middlewares=ashim-body" + - "traefik.http.middlewares.snapotter-body.buffering.maxRequestBodyBytes=524288000" + - "traefik.http.routers.snapotter.middlewares=snapotter-body" ``` ### Cloudflare Tunnels @@ -392,7 +392,7 @@ Note: Cloudflare has a 100 MB upload limit on free plans. Set `MAX_UPLOAD_SIZE_M The GitHub repository has three workflows: - **ci.yml** -- Runs automatically on every push and PR. Lints, typechecks, tests, builds, and validates the Docker image (without pushing). -- **release.yml** -- Triggered manually via `workflow_dispatch`. Runs semantic-release to create a version tag and GitHub release, then builds a multi-arch Docker image (amd64 + arm64) and pushes to Docker Hub (`ashimhq/ashim`) and GitHub Container Registry (`ghcr.io/ashim-hq/ashim`). +- **release.yml** -- Triggered manually via `workflow_dispatch`. Runs semantic-release to create a version tag and GitHub release, then builds a multi-arch Docker image (amd64 + arm64) and pushes to Docker Hub (`snapotterhq/snapotter`) and GitHub Container Registry (`ghcr.io/snapotter-hq/snapotter`). - **deploy-docs.yml** -- Builds this documentation site and deploys it to GitHub Pages on push to `main`. To create a release, go to **Actions > Release > Run workflow** in the GitHub UI, or run: diff --git a/apps/docs/guide/developer.md b/apps/docs/guide/developer.md index 96d16feb..c9a70718 100644 --- a/apps/docs/guide/developer.md +++ b/apps/docs/guide/developer.md @@ -1,6 +1,6 @@ # Developer guide -How to set up a local development environment and contribute code to ashim. +How to set up a local development environment and contribute code to SnapOtter. ## Prerequisites @@ -14,8 +14,8 @@ Python 3.10+ is only needed if you are working on the AI/ML sidecar (background ## Setup ```bash -git clone https://github.com/ashim-hq/ashim.git -cd ashim +git clone https://github.com/snapotter-hq/snapotter.git +cd snapotter pnpm install pnpm dev ``` @@ -72,7 +72,7 @@ pnpm test:coverage # tests with coverage report ## Database -SQLite via Drizzle ORM. The database file lives at `./data/ashim.db` by default. +SQLite via Drizzle ORM. The database file lives at `./data/snapotter.db` by default. ```bash cd apps/api @@ -195,13 +195,13 @@ Add a `data-testid` attribute to your action button (as shown above) so e2e test Build the full production image locally: ```bash -docker build -f docker/Dockerfile -t ashim:latest . +docker build -f docker/Dockerfile -t snapotter:latest . ``` Use BuildKit cache mounts for faster rebuilds: ```bash -DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t ashim:latest . +DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t snapotter:latest . ``` ## Environment variables diff --git a/apps/docs/guide/docker-tags.md b/apps/docs/guide/docker-tags.md index a4a14d57..6fa11caf 100644 --- a/apps/docs/guide/docker-tags.md +++ b/apps/docs/guide/docker-tags.md @@ -1,11 +1,11 @@ # Docker Image -ashim ships as a single Docker image that works on all platforms. +SnapOtter ships as a single Docker image that works on all platforms. ## Quick start ```bash -docker run -d --name ashim -p 1349:1349 -v ashim-data:/data ashimhq/ashim:latest +docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotterhq/snapotter:latest ``` The app is available at `http://localhost:1349`. @@ -15,7 +15,7 @@ The app is available at `http://localhost:1349`. The image includes CUDA support on amd64. If you have an NVIDIA GPU with the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) installed, add `--gpus all`: ```bash -docker run -d --name ashim --gpus all -p 1349:1349 -v ashim-data:/data ashimhq/ashim:latest +docker run -d --name SnapOtter --gpus all -p 1349:1349 -v SnapOtter-data:/data snapotterhq/snapotter:latest ``` The image auto-detects your GPU at runtime. Without `--gpus all`, it runs on CPU. Same image either way. @@ -56,13 +56,13 @@ GET /api/v1/admin/health ```yaml services: - ashim: - image: ashimhq/ashim:latest + SnapOtter: + image: snapotterhq/snapotter:latest ports: - "1349:1349" volumes: - - ashim-data:/data - - ashim-workspace:/tmp/workspace + - SnapOtter-data:/data + - SnapOtter-workspace:/tmp/workspace restart: unless-stopped logging: driver: json-file @@ -71,21 +71,21 @@ services: max-file: "3" volumes: - ashim-data: - ashim-workspace: + SnapOtter-data: + SnapOtter-workspace: ``` For GPU acceleration via Docker Compose, add the deploy section: ```yaml services: - ashim: - image: ashimhq/ashim:latest + SnapOtter: + image: snapotterhq/snapotter:latest ports: - "1349:1349" volumes: - - ashim-data:/data - - ashim-workspace:/tmp/workspace + - SnapOtter-data:/data + - SnapOtter-workspace:/tmp/workspace deploy: resources: reservations: @@ -96,8 +96,8 @@ services: restart: unless-stopped volumes: - ashim-data: - ashim-workspace: + SnapOtter-data: + SnapOtter-workspace: ``` ## Version pinning diff --git a/apps/docs/guide/getting-started.md b/apps/docs/guide/getting-started.md index 45d8e028..ad05c5c4 100644 --- a/apps/docs/guide/getting-started.md +++ b/apps/docs/guide/getting-started.md @@ -3,14 +3,14 @@ ## Quick Start ```bash -docker run -d --name ashim -p 1349:1349 -v ashim-data:/data ghcr.io/ashim-hq/ashim:latest +docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data ghcr.io/snapotter-hq/snapotter:latest ``` Open [http://localhost:1349](http://localhost:1349) in your browser. ::: tip Also on Docker Hub ```bash -docker run -d --name ashim -p 1349:1349 -v ashim-data:/data ashimhq/ashim:latest +docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotterhq/snapotter:latest ``` Both registries publish the same image on every release. @@ -29,7 +29,7 @@ You will be asked to change your password on first login. Add `--gpus all` for GPU-accelerated background removal, upscaling, OCR, face enhancement, and restoration: ```bash -docker run -d --name ashim -p 1349:1349 --gpus all -v ashim-data:/data ashimhq/ashim:latest +docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotterhq/snapotter:latest ``` Requires the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Falls back to CPU automatically. See [Docker Tags](/guide/docker-tags) for benchmarks. @@ -39,12 +39,12 @@ Requires the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud ```yaml services: - ashim: - image: ghcr.io/ashim-hq/ashim:latest # or ashimhq/ashim:latest + SnapOtter: + image: ghcr.io/snapotter-hq/snapotter:latest # or snapotterhq/snapotter:latest ports: - "1349:1349" volumes: - - ashim-data:/data + - SnapOtter-data:/data environment: - AUTH_ENABLED=true - DEFAULT_USERNAME=admin @@ -52,7 +52,7 @@ services: restart: unless-stopped volumes: - ashim-data: + SnapOtter-data: ``` See [Configuration](/guide/configuration) for all environment variables. @@ -62,8 +62,8 @@ See [Configuration](/guide/configuration) for all environment variables. **Prerequisites:** Node.js 22+, pnpm 9+, Python 3.10+ (for AI features), Git. ```bash -git clone https://github.com/ashim-hq/ashim.git -cd ashim +git clone https://github.com/snapotter-hq/snapotter.git +cd snapotter pnpm install pnpm dev ``` @@ -99,7 +99,7 @@ Pipelines have unlimited steps by default. ### File Library -Every file you process can be saved to your **Files** library. ashim tracks the full version history so you can trace every processing step from the original upload to the final output. +Every file you process can be saved to your **Files** library. SnapOtter tracks the full version history so you can trace every processing step from the original upload to the final output. ### REST API & API Keys diff --git a/apps/docs/guide/translations.md b/apps/docs/guide/translations.md index e5cffc27..3765ecde 100644 --- a/apps/docs/guide/translations.md +++ b/apps/docs/guide/translations.md @@ -1,6 +1,6 @@ # Translation guide -ashim ships with English by default. The i18n system is designed so adding a new language is straightforward. +SnapOtter ships with English by default. The i18n system is designed so adding a new language is straightforward. ## How translations work @@ -10,7 +10,7 @@ The `TranslationKeys` type is derived from the English file, so TypeScript will ## Requesting a translation -To request a new language or report a mistranslation, open a [GitHub Issue](https://github.com/ashim-hq/ashim/issues) with: +To request a new language or report a mistranslation, open a [GitHub Issue](https://github.com/snapotter-hq/snapotter/issues) with: - The language name and locale code (e.g., German / `de`) - Any specific strings or sections you want translated diff --git a/apps/docs/index.md b/apps/docs/index.md index 5c2d3316..8c84d952 100644 --- a/apps/docs/index.md +++ b/apps/docs/index.md @@ -31,7 +31,7 @@ features:
```bash -docker run -d --name ashim -p 1349:1349 -v ashim-data:/data ghcr.io/ashim-hq/ashim:latest +docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data ghcr.io/snapotter-hq/snapotter:latest ```
diff --git a/apps/docs/package.json b/apps/docs/package.json index df6421c4..c148f6fb 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -1,5 +1,5 @@ { - "name": "@ashim/docs", + "name": "@snapotter/docs", "version": "1.15.9", "private": true, "scripts": { diff --git a/apps/docs/public/logo.png b/apps/docs/public/logo.png index 3c499ec2..af0ba9cb 100644 Binary files a/apps/docs/public/logo.png and b/apps/docs/public/logo.png differ diff --git a/apps/landing/package.json b/apps/landing/package.json index 9ad9163b..cb517c60 100644 --- a/apps/landing/package.json +++ b/apps/landing/package.json @@ -1,5 +1,5 @@ { - "name": "@ashim/landing", + "name": "@snapotter/landing", "version": "1.15.9", "private": true, "type": "module", diff --git a/apps/landing/public/logo.png b/apps/landing/public/logo.png index 3c499ec2..f2a103b7 100644 Binary files a/apps/landing/public/logo.png and b/apps/landing/public/logo.png differ diff --git a/apps/landing/src/components/footer.tsx b/apps/landing/src/components/footer.tsx index 6c6c051d..61ea1670 100644 --- a/apps/landing/src/components/footer.tsx +++ b/apps/landing/src/components/footer.tsx @@ -23,14 +23,14 @@ const columns = [ { title: "Community", links: [ - { label: "GitHub", href: "https://github.com/ashim-hq/ashim" }, + { label: "GitHub", href: "https://github.com/snapotter-hq/snapotter" }, { label: "Contributing", - href: "https://github.com/ashim-hq/ashim/blob/main/CONTRIBUTING.md", + href: "https://github.com/snapotter-hq/snapotter/blob/main/CONTRIBUTING.md", }, { label: "Discussions", - href: "https://github.com/ashim-hq/ashim/discussions", + href: "https://github.com/snapotter-hq/snapotter/discussions", }, ], }, @@ -88,7 +88,7 @@ export function Footer() {

© {new Date().getFullYear()} SnapOtter

("Star"); useEffect(() => { - fetch("https://api.github.com/repos/ashim-hq/ashim") + fetch("https://api.github.com/repos/snapotter-hq/snapotter") .then((res) => res.json()) .then((data) => { if (typeof data.stargazers_count === "number") { @@ -65,7 +65,7 @@ export function Navbar() {
{ setUser({ id: 0, - username: localStorage.getItem("ashim-username") || "", + username: localStorage.getItem("snapotter-username") || "", role: "unknown", }); }), @@ -232,7 +232,7 @@ function GeneralSection() { const handleLogout = () => { clearToken(); - localStorage.removeItem("ashim-username"); + localStorage.removeItem("snapotter-username"); window.location.href = "/login"; }; @@ -2530,7 +2530,7 @@ function AboutSection() {

Links

0) parts.push("url(#ashim-sharpen-filter)"); + if (hasTempTint) parts.push("url(#snapotter-temp-tint-filter)"); + if (hasChannelChanges) parts.push("url(#snapotter-channel-filter)"); + if (sharpness > 0) parts.push("url(#snapotter-sharpen-filter)"); if (effect === "grayscale") parts.push("grayscale(1)"); if (effect === "sepia") parts.push("sepia(1)"); if (effect === "invert") parts.push("invert(1)"); @@ -149,7 +149,7 @@ export function ColorControls({ {hasTempTint && ( Temperature and tint color filter - + Color channel filter - + 0 && ( Sharpen filter - + 2) { - parts.push("url(#ashim-enhance-temp-filter)"); + parts.push("url(#snapotter-enhance-temp-filter)"); } if (toggles.sharpness && c.sharpness > 2) { - parts.push("url(#ashim-enhance-sharpen-filter)"); + parts.push("url(#snapotter-enhance-sharpen-filter)"); } onPreviewFilter(parts.join(" ")); @@ -246,7 +246,7 @@ export function ImageEnhancementControls({ {toggles.whiteBalance && Math.abs(tempAdj) > 0.02 && ( White balance temperature filter - + 0.02 && ( Sharpen filter - + (path: string): Promise { } export function setToken(token: string) { - localStorage.setItem("ashim-token", token); + localStorage.setItem("snapotter-token", token); } export function clearToken() { - localStorage.removeItem("ashim-token"); + localStorage.removeItem("snapotter-token"); } // ── File Upload / Download ────────────────────────────────────── diff --git a/apps/web/src/lib/icon-map.ts b/apps/web/src/lib/icon-map.ts index 314f73a8..384ea582 100644 --- a/apps/web/src/lib/icon-map.ts +++ b/apps/web/src/lib/icon-map.ts @@ -49,7 +49,7 @@ import { ZoomIn, } from "lucide-react"; -// Only the icons actually used by tool definitions in @ashim/shared constants. +// Only the icons actually used by tool definitions in @snapotter/shared constants. // Avoids `import * as icons from "lucide-react"` which pulls the entire 1000+ icon library. export const ICON_MAP: Record = { CheckCircle2, diff --git a/apps/web/src/pages/analytics-consent-page.tsx b/apps/web/src/pages/analytics-consent-page.tsx index 79dfc38a..e974fde6 100644 --- a/apps/web/src/pages/analytics-consent-page.tsx +++ b/apps/web/src/pages/analytics-consent-page.tsx @@ -1,4 +1,4 @@ -import { en } from "@ashim/shared"; +import { en } from "@snapotter/shared"; import { Shield } from "lucide-react"; import { useEffect } from "react"; import { useNavigate } from "react-router-dom"; diff --git a/apps/web/src/pages/change-password-page.tsx b/apps/web/src/pages/change-password-page.tsx index 639bf9fb..401629ee 100644 --- a/apps/web/src/pages/change-password-page.tsx +++ b/apps/web/src/pages/change-password-page.tsx @@ -99,7 +99,7 @@ export function ChangePasswordPage() { } // Trigger browser password save prompt via real form submission + navigation - const username = localStorage.getItem("ashim-username") || "admin"; + const username = localStorage.getItem("snapotter-username") || "admin"; triggerBrowserPasswordSave(username, newPassword); return; // navigation happens inside triggerBrowserPasswordSave } catch { @@ -133,7 +133,7 @@ export function ChangePasswordPage() { type="text" name="username" autoComplete="username" - value={localStorage.getItem("ashim-username") || "admin"} + value={localStorage.getItem("snapotter-username") || "admin"} readOnly className="w-full px-4 py-3 rounded-lg border border-border bg-muted text-muted-foreground cursor-not-allowed" /> diff --git a/apps/web/src/pages/fullscreen-grid-page.tsx b/apps/web/src/pages/fullscreen-grid-page.tsx index d3b42a4c..98066809 100644 --- a/apps/web/src/pages/fullscreen-grid-page.tsx +++ b/apps/web/src/pages/fullscreen-grid-page.tsx @@ -1,5 +1,5 @@ -import type { CategoryInfo, Tool } from "@ashim/shared"; -import { ANALYTICS_EVENTS, CATEGORIES, TOOLS } from "@ashim/shared"; +import type { CategoryInfo, Tool } from "@snapotter/shared"; +import { ANALYTICS_EVENTS, CATEGORIES, TOOLS } from "@snapotter/shared"; import { Eye, EyeOff, FileImage, LayoutGrid, List, Search } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import { Link, useNavigate } from "react-router-dom"; diff --git a/apps/web/src/pages/home-page.tsx b/apps/web/src/pages/home-page.tsx index 313b5cec..2086cc8c 100644 --- a/apps/web/src/pages/home-page.tsx +++ b/apps/web/src/pages/home-page.tsx @@ -1,4 +1,4 @@ -import { CATEGORIES, PYTHON_SIDECAR_TOOLS, TOOLS } from "@ashim/shared"; +import { CATEGORIES, PYTHON_SIDECAR_TOOLS, TOOLS } from "@snapotter/shared"; import { Download, Loader2 } from "lucide-react"; import { useCallback, useEffect } from "react"; import { useNavigate } from "react-router-dom"; diff --git a/apps/web/src/pages/login-page.tsx b/apps/web/src/pages/login-page.tsx index 9b1ad1f1..67f763e1 100644 --- a/apps/web/src/pages/login-page.tsx +++ b/apps/web/src/pages/login-page.tsx @@ -25,7 +25,7 @@ export function LoginPage() { const data = await res.json(); setToken(data.token); // Store username for settings display - localStorage.setItem("ashim-username", data.user?.username || username); + localStorage.setItem("snapotter-username", data.user?.username || username); // Redirect to password change if required, otherwise go home if (data.user?.mustChangePassword) { window.location.href = "/change-password"; diff --git a/apps/web/src/pages/tool-page.tsx b/apps/web/src/pages/tool-page.tsx index 37b011ae..bb596943 100644 --- a/apps/web/src/pages/tool-page.tsx +++ b/apps/web/src/pages/tool-page.tsx @@ -1,4 +1,4 @@ -import { PYTHON_SIDECAR_TOOLS, TOOL_BUNDLE_MAP, TOOLS } from "@ashim/shared"; +import { PYTHON_SIDECAR_TOOLS, TOOL_BUNDLE_MAP, TOOLS } from "@snapotter/shared"; import { CheckCircle2, ChevronLeft, diff --git a/apps/web/src/stores/analytics-store.ts b/apps/web/src/stores/analytics-store.ts index 7aaf65f2..37db8f1f 100644 --- a/apps/web/src/stores/analytics-store.ts +++ b/apps/web/src/stores/analytics-store.ts @@ -1,4 +1,4 @@ -import type { AnalyticsConfig, ConsentState } from "@ashim/shared"; +import type { AnalyticsConfig, ConsentState } from "@snapotter/shared"; import { create } from "zustand"; import { setAnalyticsConsent } from "@/lib/analytics"; import { apiPut } from "@/lib/api"; @@ -44,7 +44,7 @@ export const useAnalyticsStore = create((set, get) => ({ try { await apiPut("/v1/user/analytics", { enabled: true }); } catch { - localStorage.setItem("ashim-analytics-consent", "true"); + localStorage.setItem("snapotter-analytics-consent", "true"); } const now = Date.now(); const consent: ConsentState = { @@ -60,7 +60,7 @@ export const useAnalyticsStore = create((set, get) => ({ try { await apiPut("/v1/user/analytics", { enabled: false }); } catch { - localStorage.setItem("ashim-analytics-consent", "false"); + localStorage.setItem("snapotter-analytics-consent", "false"); } const now = Date.now(); const consent: ConsentState = { @@ -76,7 +76,7 @@ export const useAnalyticsStore = create((set, get) => ({ try { await apiPut("/v1/user/analytics", { remindLater: true }); } catch { - localStorage.setItem("ashim-analytics-consent", "remind"); + localStorage.setItem("snapotter-analytics-consent", "remind"); } const now = Date.now(); const consent: ConsentState = { @@ -92,7 +92,7 @@ export const useAnalyticsStore = create((set, get) => ({ try { await apiPut("/v1/user/analytics", { enabled }); } catch { - localStorage.setItem("ashim-analytics-consent", enabled ? "true" : "false"); + localStorage.setItem("snapotter-analytics-consent", enabled ? "true" : "false"); } set((state) => ({ consent: { ...state.consent, analyticsEnabled: enabled }, diff --git a/apps/web/src/stores/features-store.ts b/apps/web/src/stores/features-store.ts index bff31bd2..6cad7106 100644 --- a/apps/web/src/stores/features-store.ts +++ b/apps/web/src/stores/features-store.ts @@ -1,5 +1,5 @@ -import type { FeatureBundleState } from "@ashim/shared"; -import { TOOL_BUNDLE_MAP } from "@ashim/shared"; +import type { FeatureBundleState } from "@snapotter/shared"; +import { TOOL_BUNDLE_MAP } from "@snapotter/shared"; import { create } from "zustand"; import { apiGet, apiPost } from "@/lib/api"; diff --git a/apps/web/src/stores/theme-store.ts b/apps/web/src/stores/theme-store.ts index 4185a408..6ae7bbaf 100644 --- a/apps/web/src/stores/theme-store.ts +++ b/apps/web/src/stores/theme-store.ts @@ -25,6 +25,6 @@ export const useThemeStore = create()( set({ theme, resolvedTheme: resolved }); }, }), - { name: "ashim-theme" }, + { name: "snapotter-theme" }, ), ); diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index 3b5263db..4ce74429 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -12,7 +12,8 @@ export default defineConfig({ dedupe: ["react", "react-dom"], }, server: { - port: Number(process.env.PORT) || 1349, + host: true, + port: Number(process.env.PORT) || 1351, proxy: { "/api": process.env.VITE_API_URL || "http://localhost:13490", }, diff --git a/docker/Dockerfile b/docker/Dockerfile index d2e1b4eb..3540e99f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 # ============================================ -# ashim - Unified Production Dockerfile +# SnapOtter - Unified Production Dockerfile # Single image: GPU auto-detected on amd64, CPU on arm64 # ============================================ @@ -38,7 +38,7 @@ COPY apps/web/public ./apps/web/public # Build only the web frontend (API runs from TS source via tsx) RUN --mount=type=cache,id=turbo-cache,target=/app/.turbo \ - pnpm --filter @ashim/web build + pnpm --filter @snapotter/web build # ============================================ # Stage 2: Build caire (content-aware resize) @@ -223,7 +223,7 @@ RUN mkdir -p /data /data/files /data/ai/models /data/ai/pip-cache /tmp/workspace ENV PORT=1349 \ NODE_ENV=production \ STORAGE_MODE=local \ - DB_PATH=/data/ashim.db \ + DB_PATH=/data/snapotter.db \ WORKSPACE_PATH=/tmp/workspace \ FILES_STORAGE_PATH=/data/files \ PYTHON_VENV_PATH=/data/ai/venv \ @@ -232,7 +232,7 @@ ENV PORT=1349 \ U2NET_HOME=/data/ai/models/rembg \ DEFAULT_THEME=light \ DEFAULT_LOCALE=en \ - APP_NAME="ashim" \ + APP_NAME="snapotter" \ FILE_MAX_AGE_HOURS=72 \ CLEANUP_INTERVAL_MINUTES=60 \ MAX_UPLOAD_SIZE_MB=0 \ @@ -264,10 +264,10 @@ ENV PYTHONWARNINGS=default \ PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK=True # Create non-root user for runtime -RUN groupadd -r ashim && useradd -r -g ashim -d /app -s /sbin/nologin ashim -RUN chown -R ashim:ashim /app /data /tmp/workspace /opt/venv +RUN groupadd -r snapotter && useradd -r -g snapotter -d /app -s /sbin/nologin snapotter +RUN chown -R snapotter:snapotter /app /data /tmp/workspace /opt/venv -# Entrypoint fixes volume permissions then drops to ashim via gosu +# Entrypoint fixes volume permissions then drops to snapotter via gosu COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh @@ -278,4 +278,4 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \ # tini as PID 1 for zombie reaping + signal forwarding ENTRYPOINT ["tini", "--", "entrypoint.sh"] -CMD ["pnpm", "--filter", "@ashim/api", "run", "start"] +CMD ["pnpm", "--filter", "@snapotter/api", "run", "start"] diff --git a/docker/Dockerfile.test b/docker/Dockerfile.test index 83c63ab4..20ecb4f7 100644 --- a/docker/Dockerfile.test +++ b/docker/Dockerfile.test @@ -1,5 +1,5 @@ # ============================================ -# ashim - Test Dockerfile +# SnapOtter - Test Dockerfile # Runs the full test suite (unit + integration) # ============================================ @@ -40,7 +40,7 @@ ENV NODE_ENV=test \ AUTH_ENABLED=true \ DEFAULT_USERNAME=admin \ DEFAULT_PASSWORD=admin \ - DB_PATH=/tmp/test-ashim.db \ + DB_PATH=/tmp/test-snapotter.db \ WORKSPACE_PATH=/tmp/test-workspace \ MAX_MEGAPIXELS=100 \ MAX_UPLOAD_SIZE_MB=100 \ diff --git a/docker/docker-compose-gpu.yml b/docker/docker-compose-gpu.yml index 57cf5eec..d3f179e9 100644 --- a/docker/docker-compose-gpu.yml +++ b/docker/docker-compose-gpu.yml @@ -1,22 +1,22 @@ -name: ashim +name: SnapOtter # NVIDIA GPU deployment — requires nvidia-container-toolkit. # Install: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html # Usage: docker compose -f docker-compose-gpu.yml up -d -# Verify: docker logs ashim 2>&1 | grep GPU +# Verify: docker logs SnapOtter 2>&1 | grep GPU services: - ashim: + SnapOtter: build: context: .. dockerfile: docker/Dockerfile - image: ashim:latest - container_name: ashim + image: snapotter:latest + container_name: SnapOtter ports: - "1349:1349" volumes: - - ashim-data:/data # Database, AI models, user files - - ashim-workspace:/tmp/workspace # Temp processing (auto-cleaned) + - SnapOtter-data:/data # Database, AI models, user files + - SnapOtter-workspace:/tmp/workspace # Temp processing (auto-cleaned) environment: - AUTH_ENABLED=true - DEFAULT_USERNAME=admin @@ -55,5 +55,5 @@ services: max-file: "5" volumes: - ashim-data: - ashim-workspace: + SnapOtter-data: + SnapOtter-workspace: diff --git a/docker/docker-compose.test.yml b/docker/docker-compose.test.yml index 8daac45e..b008dee2 100644 --- a/docker/docker-compose.test.yml +++ b/docker/docker-compose.test.yml @@ -8,14 +8,14 @@ services: build: context: .. dockerfile: docker/Dockerfile.test - container_name: ashim-test-unit + container_name: SnapOtter-test-unit command: ["pnpm", "test:ci"] environment: - NODE_ENV=test - AUTH_ENABLED=true - DEFAULT_USERNAME=admin - DEFAULT_PASSWORD=admin - - DB_PATH=/tmp/test-ashim.db + - DB_PATH=/tmp/test-snapotter.db - WORKSPACE_PATH=/tmp/test-workspace - MAX_MEGAPIXELS=100 - RATE_LIMIT_PER_MIN=1000 @@ -28,14 +28,14 @@ services: build: context: .. dockerfile: docker/Dockerfile.test - container_name: ashim-test-e2e + container_name: SnapOtter-test-e2e command: ["sh", "-c", "npx playwright install --with-deps chromium && pnpm test:e2e"] environment: - NODE_ENV=test - AUTH_ENABLED=true - DEFAULT_USERNAME=admin - DEFAULT_PASSWORD=admin - - DB_PATH=/tmp/test-ashim.db + - DB_PATH=/tmp/test-snapotter.db - WORKSPACE_PATH=/tmp/test-workspace - MAX_MEGAPIXELS=100 - RATE_LIMIT_PER_MIN=1000 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 3d7afed2..8e8ce2da 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,21 +1,21 @@ -name: ashim +name: SnapOtter # CPU deployment — no GPU required. # Usage: docker compose up -d # GPU: docker compose -f docker-compose-gpu.yml up -d services: - ashim: + SnapOtter: build: context: .. dockerfile: docker/Dockerfile - image: ashim:latest - container_name: ashim + image: snapotter:latest + container_name: SnapOtter ports: - "1349:1349" volumes: - - ashim-data:/data # Database, AI models, user files - - ashim-workspace:/tmp/workspace # Temp processing (auto-cleaned) + - SnapOtter-data:/data # Database, AI models, user files + - SnapOtter-workspace:/tmp/workspace # Temp processing (auto-cleaned) environment: - AUTH_ENABLED=true - DEFAULT_USERNAME=admin @@ -47,5 +47,5 @@ services: max-file: "5" volumes: - ashim-data: - ashim-workspace: + SnapOtter-data: + SnapOtter-workspace: diff --git a/docker/download_models.py b/docker/download_models.py index e534eb67..ef69a3a3 100644 --- a/docker/download_models.py +++ b/docker/download_models.py @@ -11,7 +11,7 @@ import urllib.request # Some servers (e.g. Berkeley) block the default Python-urllib User-Agent. _opener = urllib.request.build_opener() -_opener.addheaders = [("User-Agent", "ashim/1.0")] +_opener.addheaders = [("User-Agent", "snapotter/1.0")] urllib.request.install_opener(_opener) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 05118d8b..8e1b0a3f 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -25,51 +25,51 @@ if [ ! -d "$AI_VENV" ] && [ -d "/opt/venv" ]; then echo "AI venv ready at $AI_VENV" fi -# Fix ownership of mounted volumes so the non-root ashim user can write. -# This runs as root, fixes permissions, then drops to ashim via gosu. +# Fix ownership of mounted volumes so the non-root snapotter user can write. +# This runs as root, fixes permissions, then drops to snapotter via gosu. if [ "$(id -u)" = "0" ]; then - # PUID/PGID support: remap the ashim user/group to match host UID/GID. + # PUID/PGID support: remap the snapotter user/group to match host UID/GID. # This prevents permission conflicts when using bind mounts. - PUID="${PUID:-$(id -u ashim)}" - PGID="${PGID:-$(id -g ashim)}" + PUID="${PUID:-$(id -u snapotter)}" + PGID="${PGID:-$(id -g snapotter)}" if [ "$PUID" = "0" ] || [ "$PGID" = "0" ]; then - echo "WARNING: PUID=0 or PGID=0 would run the app as root. Ignoring — using default ashim UID/GID." >&2 - PUID=$(id -u ashim) - PGID=$(id -g ashim) + echo "WARNING: PUID=0 or PGID=0 would run the app as root. Ignoring — using default snapotter UID/GID." >&2 + PUID=$(id -u snapotter) + PGID=$(id -g snapotter) fi - CUR_UID=$(id -u ashim) - CUR_GID=$(id -g ashim) + CUR_UID=$(id -u snapotter) + CUR_GID=$(id -g snapotter) if [ "$CUR_UID" != "$PUID" ] || [ "$CUR_GID" != "$PGID" ]; then # Evict any conflicting user/group that holds the target UID/GID. # Delete user first (may cascade-delete its primary group). if [ "$CUR_UID" != "$PUID" ]; then EXISTING_USER=$(getent passwd "$PUID" 2>/dev/null | cut -d: -f1 || true) - if [ -n "$EXISTING_USER" ] && [ "$EXISTING_USER" != "ashim" ]; then + if [ -n "$EXISTING_USER" ] && [ "$EXISTING_USER" != "snapotter" ]; then deluser "$EXISTING_USER" 2>/dev/null || userdel "$EXISTING_USER" 2>/dev/null || true fi fi if [ "$CUR_GID" != "$PGID" ]; then EXISTING_GROUP=$(getent group "$PGID" 2>/dev/null | cut -d: -f1 || true) - if [ -n "$EXISTING_GROUP" ] && [ "$EXISTING_GROUP" != "ashim" ]; then + if [ -n "$EXISTING_GROUP" ] && [ "$EXISTING_GROUP" != "snapotter" ]; then delgroup "$EXISTING_GROUP" 2>/dev/null || groupdel "$EXISTING_GROUP" 2>/dev/null || true fi - groupmod -g "$PGID" ashim 2>/dev/null || true + groupmod -g "$PGID" snapotter 2>/dev/null || true fi if [ "$CUR_UID" != "$PUID" ]; then - usermod -u "$PUID" ashim 2>/dev/null || true + usermod -u "$PUID" snapotter 2>/dev/null || true fi fi # Chown writable directories (/data is the persistent volume, /tmp/workspace is ephemeral). # /app and /opt/venv are read-only at runtime — no chown needed. - chown -R ashim:ashim /data /tmp/workspace 2>&1 || \ + chown -R snapotter:snapotter /data /tmp/workspace 2>&1 || \ echo "WARNING: Could not fix volume permissions. Use named volumes (not Windows bind mounts) to avoid this. See docs for details." >&2 - exec gosu ashim "$@" + exec gosu snapotter "$@" fi -# Already running as ashim (e.g. Kubernetes runAsUser) +# Already running as snapotter (e.g. Kubernetes runAsUser) exec "$@" diff --git a/docs/COMMUNITY_GUIDE.md b/docs/COMMUNITY_GUIDE.md index 78069683..12e3bae9 100644 --- a/docs/COMMUNITY_GUIDE.md +++ b/docs/COMMUNITY_GUIDE.md @@ -1,7 +1,7 @@ # Community Guide — GitHub Discussions Setup This document contains the category structure, pinned Welcome post, and seed -post ideas for the ashim GitHub Discussions. +post ideas for the SnapOtter GitHub Discussions. --- @@ -11,16 +11,16 @@ Create these 5 categories in **Settings → Discussions → Categories** on GitH | Category | Format | Description | |----------|--------|-------------| -| **General** | Open | Announcements, project updates, and casual conversation about ashim. Pinned Welcome post lives here. | +| **General** | Open | Announcements, project updates, and casual conversation about SnapOtter. Pinned Welcome post lives here. | | **Q&A** | Question / Answer | Ask for help with image processing, tool behavior, or unexpected results. Mark accepted answers so others can find solutions quickly. | | **Ideas** | Open | Suggest new tools, improvements to existing features, or workflow changes. Upvote ideas you want to see prioritized. | -| **Show & Tell** | Open | Share your ashim setup — screenshots of pipelines, Docker Compose configs, automation scripts using the REST API, before/after results. | -| **Self-Hosting Help** | Question / Answer | Docker, reverse proxy, storage, networking, multi-arch, and environment configuration. If your question is about getting ashim running rather than using its tools, post here. | +| **Show & Tell** | Open | Share your SnapOtter setup — screenshots of pipelines, Docker Compose configs, automation scripts using the REST API, before/after results. | +| **Self-Hosting Help** | Question / Answer | Docker, reverse proxy, storage, networking, multi-arch, and environment configuration. If your question is about getting SnapOtter running rather than using its tools, post here. | ### Why these categories - **Q&A vs Self-Hosting Help** — Separating "how do I use the resize tool" from - "how do I get ashim behind Caddy" keeps both channels useful. Self-hosters + "how do I get SnapOtter behind Caddy" keeps both channels useful. Self-hosters and image-tool users are often different people with different expertise. - **Show & Tell** — Pipeline sharing/export isn't built into the app yet, so this category is the place to describe your workflows with screenshots and @@ -33,14 +33,14 @@ Create these 5 categories in **Settings → Discussions → Categories** on GitH ## Pinned Welcome Post -> **Title:** Welcome to ashim Discussions +> **Title:** Welcome to SnapOtter Discussions > > **Category:** General > > --- > -> Thanks for joining the ashim community. This is the place to ask questions, -> suggest features, and share what you're building with ashim. +> Thanks for joining the SnapOtter community. This is the place to ask questions, +> suggest features, and share what you're building with SnapOtter. > > **Where to post:** > @@ -50,8 +50,8 @@ Create these 5 categories in **Settings → Discussions → Categories** on GitH > | Get help with Docker, reverse proxies, or deployment | [Self-Hosting Help] | > | Suggest a new feature or improvement | [Ideas] | > | Show off my setup, pipeline, or results | [Show & Tell] | -> | Report a bug | [GitHub Issues](https://github.com/ashim-hq/ashim/issues/new/choose) | -> | Report a security vulnerability | [Security Advisories](https://github.com/ashim-hq/ashim/security/advisories/new) | +> | Report a bug | [GitHub Issues](https://github.com/snapotter-hq/snapotter/issues/new/choose) | +> | Report a security vulnerability | [Security Advisories](https://github.com/snapotter-hq/snapotter/security/advisories/new) | > > **A few ground rules:** > @@ -59,10 +59,10 @@ Create these 5 categories in **Settings → Discussions → Categories** on GitH > - In Q&A and Self-Hosting Help, mark the reply that solved your problem so > others can find it. > - Keep it constructive. We follow the -> [Code of Conduct](https://github.com/ashim-hq/ashim/blob/main/CODE_OF_CONDUCT.md). +> [Code of Conduct](https://github.com/snapotter-hq/snapotter/blob/main/CODE_OF_CONDUCT.md). > -> If you're new to ashim, the -> [documentation](https://github.com/ashim-hq/ashim#readme) is the best +> If you're new to SnapOtter, the +> [documentation](https://github.com/snapotter-hq/snapotter#readme) is the best > starting point. --- @@ -73,11 +73,11 @@ Two posts you can publish yourself to get early activity in the community. ### Seed Post 1 — Self-Hosting Help -> **Title:** What's your ashim deployment setup? +> **Title:** What's your SnapOtter deployment setup? > > **Category:** Self-Hosting Help > -> I'm curious how everyone is running ashim. A few things I'd love to hear +> I'm curious how everyone is running SnapOtter. A few things I'd love to hear > about: > > - Are you running it on a NAS, a VPS, or a home server? @@ -85,7 +85,7 @@ Two posts you can publish yourself to get early activity in the community. > - Have you enabled the AI features, and if so, how much RAM/VRAM does your > setup have? > -> I'll go first — I run ashim on [describe your own setup here] with +> I'll go first — I run SnapOtter on [describe your own setup here] with > [reverse proxy] in front. The AI sidecar uses about [X] GB of RAM on my > machine. diff --git a/package.json b/package.json index 9011fa34..ae648364 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { - "name": "ashim", + "name": "snapotter", "version": "1.15.9", "private": true, "packageManager": "pnpm@9.15.4", "scripts": { "dev": "turbo dev", - "docs:dev": "pnpm --filter @ashim/docs docs:dev", + "docs:dev": "pnpm --filter @snapotter/docs docs:dev", "build": "turbo build", "lint": "turbo lint", "lint:fix": "biome check --write .", diff --git a/packages/ai/package.json b/packages/ai/package.json index de1579c5..562ae372 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,5 +1,5 @@ { - "name": "@ashim/ai", + "name": "@snapotter/ai", "version": "1.15.9", "private": true, "type": "module", @@ -10,7 +10,7 @@ "clean": "rm -rf dist" }, "dependencies": { - "@ashim/shared": "workspace:*", + "@snapotter/shared": "workspace:*", "sharp": "^0.33.0" }, "devDependencies": { diff --git a/packages/ai/python/gpu.py b/packages/ai/python/gpu.py index 97a96a25..8f915e0e 100644 --- a/packages/ai/python/gpu.py +++ b/packages/ai/python/gpu.py @@ -15,7 +15,7 @@ def emit_info(msg): def gpu_available(): """Return True if a usable CUDA GPU is present at runtime.""" # Allow explicit disable via env var (set to "false" or "0") - override = os.environ.get("ASHIM_GPU") + override = os.environ.get("SNAPOTTER_GPU") if override is not None and override.lower() in ("0", "false", "no"): return False diff --git a/packages/ai/python/inpaint.py b/packages/ai/python/inpaint.py index e6fd3aa4..1ea8821a 100644 --- a/packages/ai/python/inpaint.py +++ b/packages/ai/python/inpaint.py @@ -15,7 +15,7 @@ def emit_progress(percent, stage): _MODELS_BASE = os.environ.get("MODELS_PATH", "/opt/models") LAMA_MODEL_DIR = os.environ.get("LAMA_MODEL_DIR", os.path.join(_MODELS_BASE, "lama")) LAMA_MODEL_PATH = os.path.join(LAMA_MODEL_DIR, "lama_fp32.onnx") -LAMA_LOCAL_CACHE = os.path.join(os.path.expanduser("~"), ".cache", "ashim", "lama") +LAMA_LOCAL_CACHE = os.path.join(os.path.expanduser("~"), ".cache", "snapotter", "lama") LAMA_LOCAL_PATH = os.path.join(LAMA_LOCAL_CACHE, "lama_fp32.onnx") LAMA_HF_URL = "https://huggingface.co/Carve/LaMa-ONNX/resolve/main/lama_fp32.onnx" diff --git a/packages/ai/python/install_feature.py b/packages/ai/python/install_feature.py index 1b0c0471..b0a5cb5c 100644 --- a/packages/ai/python/install_feature.py +++ b/packages/ai/python/install_feature.py @@ -228,7 +228,7 @@ def urlretrieve_with_retry(url: str, dest: str, max_retries: int = 3) -> None: for attempt in range(max_retries): try: req = urllib.request.Request( - url, headers={"User-Agent": "ashim-installer/1.0"} + url, headers={"User-Agent": "snapotter-installer/1.0"} ) with urllib.request.urlopen(req, timeout=300) as resp, open(dest, "wb") as f: shutil.copyfileobj(resp, f) diff --git a/packages/ai/python/noise_removal.py b/packages/ai/python/noise_removal.py index fef4423c..d2b1df81 100644 --- a/packages/ai/python/noise_removal.py +++ b/packages/ai/python/noise_removal.py @@ -23,7 +23,7 @@ NAFNET_MODEL_PATH = os.environ.get( ) # Local cache for dev installs -_CACHE_DIR = os.path.join(os.path.expanduser("~"), ".cache", "ashim", "models") +_CACHE_DIR = os.path.join(os.path.expanduser("~"), ".cache", "snapotter", "models") # GitHub release URLs for auto-download SCUNET_URL = "https://github.com/cszn/KAIR/releases/download/v1.0/scunet_color_real_psnr.pth" diff --git a/packages/ai/python/restore.py b/packages/ai/python/restore.py index 50ee31a2..5b661ad9 100644 --- a/packages/ai/python/restore.py +++ b/packages/ai/python/restore.py @@ -31,13 +31,13 @@ _MODELS_BASE = os.environ.get("MODELS_PATH", "/opt/models") LAMA_MODEL_DIR = os.environ.get("LAMA_MODEL_DIR", os.path.join(_MODELS_BASE, "lama")) LAMA_MODEL_PATH = os.path.join(LAMA_MODEL_DIR, "lama_fp32.onnx") -LAMA_LOCAL_CACHE = os.path.join(os.path.expanduser("~"), ".cache", "ashim", "lama") +LAMA_LOCAL_CACHE = os.path.join(os.path.expanduser("~"), ".cache", "snapotter", "lama") LAMA_LOCAL_PATH = os.path.join(LAMA_LOCAL_CACHE, "lama_fp32.onnx") CODEFORMER_MODEL_DIR = os.environ.get("CODEFORMER_MODEL_DIR", os.path.join(_MODELS_BASE, "codeformer")) CODEFORMER_MODEL_PATH = os.path.join(CODEFORMER_MODEL_DIR, "codeformer.onnx") CODEFORMER_LOCAL_CACHE = os.path.join( - os.path.expanduser("~"), ".cache", "ashim", "codeformer" + os.path.expanduser("~"), ".cache", "snapotter", "codeformer" ) CODEFORMER_LOCAL_PATH = os.path.join(CODEFORMER_LOCAL_CACHE, "codeformer.onnx") diff --git a/packages/image-engine/package.json b/packages/image-engine/package.json index 4a75e9f5..39f889c9 100644 --- a/packages/image-engine/package.json +++ b/packages/image-engine/package.json @@ -1,5 +1,5 @@ { - "name": "@ashim/image-engine", + "name": "@snapotter/image-engine", "version": "1.15.9", "private": true, "type": "module", @@ -12,7 +12,7 @@ "clean": "rm -rf dist" }, "dependencies": { - "@ashim/shared": "workspace:*", + "@snapotter/shared": "workspace:*", "exif-reader": "^2.0.3", "sharp": "^0.33.0" }, diff --git a/packages/shared/package.json b/packages/shared/package.json index 28314757..9a0221f2 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,5 +1,5 @@ { - "name": "@ashim/shared", + "name": "@snapotter/shared", "version": "1.15.9", "private": true, "type": "module", diff --git a/packages/shared/src/i18n/en.ts b/packages/shared/src/i18n/en.ts index 974928d3..d6be25e4 100644 --- a/packages/shared/src/i18n/en.ts +++ b/packages/shared/src/i18n/en.ts @@ -193,7 +193,7 @@ export const en = { regenerateKey: "Regenerate", copyKey: "Copy Key", aboutDescription: - "ashim is a self-hosted, privacy-first image processing suite with 30+ tools.", + "SnapOtter is a self-hosted, privacy-first image processing suite with 30+ tools.", aboutLinks: "Links", github: "GitHub", documentation: "Documentation", @@ -302,14 +302,14 @@ export const en = { settings: "Settings", }, analytics: { - consentTitle: "Help improve ashim", + consentTitle: "Help improve SnapOtter", consentDescription: "Anonymous usage stats help us fix bugs and build the tools you actually need. Your images and files stay on your machine.", consentChangeable: "You can turn this off anytime in Settings.", acceptButton: "Sure, sounds good", declineButton: "Not right now", settingsTitle: "Product Analytics", - settingsDescription: "Share anonymous usage data to help improve ashim.", + settingsDescription: "Share anonymous usage data to help improve SnapOtter.", settingsPrivacy: "Your images never leave your machine.", settingsDisabledByAdmin: "Product analytics has been disabled by the server administrator.", learnMore: "Learn more", diff --git a/playwright.config.ts b/playwright.config.ts index cb9fba06..cee69e01 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -2,7 +2,7 @@ import path from "node:path"; import { defineConfig, devices } from "@playwright/test"; const authFile = path.join(__dirname, "test-results", ".auth", "user.json"); -const testDbPath = path.join(__dirname, "test-results", ".e2e-db", "ashim.db"); +const testDbPath = path.join(__dirname, "test-results", ".e2e-db", "snapotter.db"); const TEST_WEB_PORT = 2349; @@ -43,7 +43,7 @@ export default defineConfig({ ], webServer: [ { - command: `rm -f "${testDbPath}" "${testDbPath}-shm" "${testDbPath}-wal" && mkdir -p "${path.dirname(testDbPath)}" && pnpm --filter @ashim/api dev`, + command: `rm -f "${testDbPath}" "${testDbPath}-shm" "${testDbPath}-wal" && mkdir -p "${path.dirname(testDbPath)}" && pnpm --filter @snapotter/api dev`, port: 13490, reuseExistingServer: !process.env.CI, env: { @@ -58,7 +58,7 @@ export default defineConfig({ timeout: 30_000, }, { - command: "pnpm --filter @ashim/web dev", + command: "pnpm --filter @snapotter/web dev", port: TEST_WEB_PORT, reuseExistingServer: !process.env.CI, env: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d1ccc15..f6e03bf5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,15 +87,6 @@ importers: apps/api: dependencies: - '@ashim/ai': - specifier: workspace:* - version: link:../../packages/ai - '@ashim/image-engine': - specifier: workspace:* - version: link:../../packages/image-engine - '@ashim/shared': - specifier: workspace:* - version: link:../../packages/shared '@fastify/cors': specifier: ^11.0.0 version: 11.2.0 @@ -117,6 +108,15 @@ importers: '@sentry/node': specifier: ^10.49.0 version: 10.49.0 + '@snapotter/ai': + specifier: workspace:* + version: link:../../packages/ai + '@snapotter/image-engine': + specifier: workspace:* + version: link:../../packages/image-engine + '@snapotter/shared': + specifier: workspace:* + version: link:../../packages/shared archiver: specifier: ^7.0.1 version: 7.0.1 @@ -251,9 +251,6 @@ importers: apps/web: dependencies: - '@ashim/shared': - specifier: workspace:* - version: link:../../packages/shared '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -266,6 +263,9 @@ importers: '@sentry/react': specifier: ^10.49.0 version: 10.49.0(react@19.2.4) + '@snapotter/shared': + specifier: workspace:* + version: link:../../packages/shared '@use-gesture/react': specifier: ^10.3.1 version: 10.3.1(react@19.2.4) @@ -339,7 +339,7 @@ importers: packages/ai: dependencies: - '@ashim/shared': + '@snapotter/shared': specifier: workspace:* version: link:../shared sharp: @@ -355,7 +355,7 @@ importers: packages/image-engine: dependencies: - '@ashim/shared': + '@snapotter/shared': specifier: workspace:* version: link:../shared exif-reader: diff --git a/scripts/test-docker-fixes.sh b/scripts/test-docker-fixes.sh index 20a59c87..35e336c8 100755 --- a/scripts/test-docker-fixes.sh +++ b/scripts/test-docker-fixes.sh @@ -2,12 +2,12 @@ set -e echo "=== Step 1: Stop existing container ===" -docker stop ashim 2>/dev/null || true -docker rm ashim 2>/dev/null || true +docker stop SnapOtter 2>/dev/null || true +docker rm SnapOtter 2>/dev/null || true echo "=== Step 2: Start test container ===" docker run -d \ - --name ashim-test \ + --name SnapOtter-test \ -p 1349:1349 \ -e AUTH_ENABLED=true \ -e DEFAULT_USERNAME=admin \ @@ -15,19 +15,19 @@ docker run -d \ -e LOG_LEVEL=debug \ -e RATE_LIMIT_PER_MIN=50000 \ -e SKIP_MUST_CHANGE_PASSWORD=true \ - ashim:test-fixes + snapotter:test-fixes echo "=== Step 3: Wait for container to be healthy ===" echo "Waiting for health check..." for i in $(seq 1 60); do - STATUS=$(docker inspect --format='{{.State.Health.Status}}' ashim-test 2>/dev/null || echo "starting") + STATUS=$(docker inspect --format='{{.State.Health.Status}}' SnapOtter-test 2>/dev/null || echo "starting") if [ "$STATUS" = "healthy" ]; then echo "Container is healthy after ${i}0 seconds" break fi if [ "$STATUS" = "unhealthy" ]; then echo "Container is unhealthy!" - docker logs ashim-test --tail 50 + docker logs SnapOtter-test --tail 50 exit 1 fi echo " Status: $STATUS (${i}0s elapsed)" @@ -41,14 +41,14 @@ TEST_EXIT=$? echo "=== Step 5: Check Docker logs for errors ===" echo "--- Container logs (last 50 lines) ---" -docker logs ashim-test --tail 50 +docker logs SnapOtter-test --tail 50 echo "=== Step 6: Cleanup ===" -docker stop ashim-test -docker rm ashim-test +docker stop SnapOtter-test +docker rm SnapOtter-test # Restart original container -echo "=== Restarting original ashim container ===" -docker start ashim 2>/dev/null || true +echo "=== Restarting original SnapOtter container ===" +docker start SnapOtter 2>/dev/null || true exit $TEST_EXIT diff --git a/social-preview.png b/social-preview.png index 29872b2e..4f9b1915 100644 Binary files a/social-preview.png and b/social-preview.png differ diff --git a/tests/benchmark/bench-ai.sh b/tests/benchmark/bench-ai.sh index 58dfb71e..d9dc801e 100755 --- a/tests/benchmark/bench-ai.sh +++ b/tests/benchmark/bench-ai.sh @@ -8,7 +8,7 @@ GPU_MODE="${4:-gpu}" BASE_URL="http://localhost:${PORT}" RESULTS_FILE="bench-ai-results-${SYSTEM}-${GPU_MODE}.jsonl" -CONTAINER_NAME="ashim" +CONTAINER_NAME="SnapOtter" log() { echo "[$(date +%H:%M:%S)] $*" >&2; } diff --git a/tests/benchmark/bench-limits.sh b/tests/benchmark/bench-limits.sh index 9646677a..6bc5a4f9 100755 --- a/tests/benchmark/bench-limits.sh +++ b/tests/benchmark/bench-limits.sh @@ -3,11 +3,11 @@ set -euo pipefail SYSTEM="${1:?Usage: bench-limits.sh }" FIXTURE_DIR="${2:?}" -DOCKER_IMAGE="${3:-ashim:latest}" +DOCKER_IMAGE="${3:-snapotter:latest}" PORT=13491 BASE_URL="http://localhost:${PORT}" RESULTS_FILE="bench-limits-results-${SYSTEM}.jsonl" -CONTAINER_NAME="ashim-bench-limits" +CONTAINER_NAME="SnapOtter-bench-limits" log() { echo "[$(date +%H:%M:%S)] $*" >&2; } diff --git a/tests/benchmark/bench.sh b/tests/benchmark/bench.sh index f21ec96a..f76b5bd5 100755 --- a/tests/benchmark/bench.sh +++ b/tests/benchmark/bench.sh @@ -7,7 +7,7 @@ PORT="${3:-1349}" BASE_URL="http://localhost:${PORT}" RESULTS_FILE="bench-results-${SYSTEM}.jsonl" -CONTAINER_NAME="ashim" +CONTAINER_NAME="SnapOtter" log() { echo "[$(date +%H:%M:%S)] $*" >&2; } diff --git a/tests/e2e-docker/analytics-consent.spec.ts b/tests/e2e-docker/analytics-consent.spec.ts index 9ce76ca0..c886c50f 100644 --- a/tests/e2e-docker/analytics-consent.spec.ts +++ b/tests/e2e-docker/analytics-consent.spec.ts @@ -46,7 +46,7 @@ test.describe("Analytics consent page", () => { // Verify session has analyticsEnabled=true via API (using the in-browser token) const sessionData = await page.evaluate(async () => { - const token = localStorage.getItem("ashim-token") ?? ""; + const token = localStorage.getItem("snapotter-token") ?? ""; const res = await fetch("/api/auth/session", { headers: { Authorization: `Bearer ${token}` }, }); diff --git a/tests/e2e-docker/analytics-no-data-leak.spec.ts b/tests/e2e-docker/analytics-no-data-leak.spec.ts index 90d1004a..593ca9d6 100644 --- a/tests/e2e-docker/analytics-no-data-leak.spec.ts +++ b/tests/e2e-docker/analytics-no-data-leak.spec.ts @@ -53,7 +53,7 @@ async function loginFresh(page: import("@playwright/test").Page) { */ async function disableAnalytics(page: import("@playwright/test").Page): Promise { const ok = await page.evaluate(async () => { - const token = localStorage.getItem("ashim-token") ?? ""; + const token = localStorage.getItem("snapotter-token") ?? ""; const res = await fetch("/api/v1/user/analytics", { method: "PUT", headers: { @@ -76,7 +76,7 @@ async function disableAnalytics(page: import("@playwright/test").Page): Promise< async function enableAnalytics(page: import("@playwright/test").Page): Promise { try { await page.evaluate(async () => { - const token = localStorage.getItem("ashim-token") ?? ""; + const token = localStorage.getItem("snapotter-token") ?? ""; await fetch("/api/v1/user/analytics", { method: "PUT", headers: { diff --git a/tests/e2e-docker/full-tool-audit.mjs b/tests/e2e-docker/full-tool-audit.mjs index 6147b289..3be26a17 100644 --- a/tests/e2e-docker/full-tool-audit.mjs +++ b/tests/e2e-docker/full-tool-audit.mjs @@ -1,5 +1,5 @@ /** - * FULL TOOL AUDIT — Tests every tool in ashim on Windows/amd64. + * FULL TOOL AUDIT — Tests every tool in SnapOtter on Windows/amd64. * Verifies: (1) tool works, (2) GPU tools use GPU not CPU fallback, * (3) no unexpected model/method downgrades. */ @@ -79,7 +79,7 @@ async function test(name, path, settings, checks = {}) { async function main() { console.log("============================================================="); - console.log(" ASHIM FULL TOOL AUDIT — Windows amd64 + RTX 4070"); + console.log(" SNAPOTTER FULL TOOL AUDIT — Windows amd64 + RTX 4070"); console.log("=============================================================\n"); // Login @@ -278,7 +278,7 @@ async function main() { // ════════════════════════════════════════════════════════════════ console.log("\n--- SPECIAL TOOLS (may need specific inputs) ---\n"); - await test("QR Generate", "qr-generate", { text: "https://ashim.app", size: 512, format: "png" }); + await test("QR Generate", "qr-generate", { text: "https://snapotter.app", size: 512, format: "png" }); await test("Text Overlay", "text-overlay", { text: "TEST", fontSize: 48, @@ -314,7 +314,7 @@ async function main() { // Check GPU usage in docker logs console.log("\n--- GPU USAGE CHECK ---\n"); const { execSync } = await import("child_process"); - const logs = execSync("docker logs ashim 2>&1", { encoding: "utf-8", maxBuffer: 1024 * 1024 }); + const logs = execSync("docker logs SnapOtter 2>&1", { encoding: "utf-8", maxBuffer: 1024 * 1024 }); const gpuLines = logs .split("\n") .filter( diff --git a/tests/e2e-docker/pipeline-tools.spec.ts b/tests/e2e-docker/pipeline-tools.spec.ts index 42c8fcf4..38005d06 100644 --- a/tests/e2e-docker/pipeline-tools.spec.ts +++ b/tests/e2e-docker/pipeline-tools.spec.ts @@ -469,7 +469,7 @@ test.describe("Pipeline edge cases", () => { { toolId: "watermark-text", settings: { - text: "ashim", + text: "snapotter", fontSize: 20, color: "#808080", opacity: 20, diff --git a/tests/e2e-docker/playwright-gpu-test.mjs b/tests/e2e-docker/playwright-gpu-test.mjs index 4949d519..917cb307 100644 --- a/tests/e2e-docker/playwright-gpu-test.mjs +++ b/tests/e2e-docker/playwright-gpu-test.mjs @@ -18,7 +18,7 @@ function log(tool, status, detail = "") { } async function main() { - console.log("=== Ashim GPU Tools E2E Test ===\n"); + console.log("=== SnapOtter GPU Tools E2E Test ===\n"); // Login via API const loginRes = await fetch(`${BASE}/api/auth/login`, { diff --git a/tests/e2e-docker/utility-tools.spec.ts b/tests/e2e-docker/utility-tools.spec.ts index e7fcefb4..48318c78 100644 --- a/tests/e2e-docker/utility-tools.spec.ts +++ b/tests/e2e-docker/utility-tools.spec.ts @@ -405,7 +405,7 @@ test.describe("QR Generate", () => { const res = await request.post("/api/v1/tools/qr-generate", { headers: { Authorization: `Bearer ${token}` }, data: { - text: "https://ashim.app", + text: "https://snapotter.app", size: 512, }, }); @@ -434,7 +434,7 @@ test.describe("QR Generate", () => { const res = await request.post("/api/v1/tools/qr-generate", { headers: { Authorization: `Bearer ${token}` }, data: { - text: "https://github.com/ashim-hq/ashim", + text: "https://github.com/snapotter/snapotter", size: 300, errorCorrection: "H", }, diff --git a/tests/e2e/auth.setup.ts b/tests/e2e/auth.setup.ts index f5265b87..04fa9242 100644 --- a/tests/e2e/auth.setup.ts +++ b/tests/e2e/auth.setup.ts @@ -15,7 +15,7 @@ setup("authenticate", async ({ page }) => { await page.getByRole("button", { name: /login/i }).click(); // Wait for login to complete and grab the token in one step - const handle = await page.waitForFunction(() => localStorage.getItem("ashim-token"), null, { + const handle = await page.waitForFunction(() => localStorage.getItem("snapotter-token"), null, { timeout: 15_000, }); const token = await handle.jsonValue(); diff --git a/tests/e2e/home-page.spec.ts b/tests/e2e/home-page.spec.ts index fad11baf..c4ccedf1 100644 --- a/tests/e2e/home-page.spec.ts +++ b/tests/e2e/home-page.spec.ts @@ -1,8 +1,8 @@ import { expect, test, uploadTestImage } from "./helpers"; test.describe("Home Page", () => { - test("shows ashim branding in dropzone", async ({ loggedInPage: page }) => { - await expect(page.getByText("ashim").first()).toBeVisible(); + test("shows SnapOtter branding in dropzone", async ({ loggedInPage: page }) => { + await expect(page.getByText("SnapOtter").first()).toBeVisible(); }); test("dropzone shows upload button", async ({ loggedInPage: page }) => { diff --git a/tests/e2e/rbac-full.spec.ts b/tests/e2e/rbac-full.spec.ts index e5db85e2..06e235e7 100644 --- a/tests/e2e/rbac-full.spec.ts +++ b/tests/e2e/rbac-full.spec.ts @@ -317,7 +317,7 @@ base.describe("RBAC Full — Custom Role User", () => { await login(page, CUSTOM_USER, CUSTOM_PASSWORD); // Extract token from localStorage - const token = await page.evaluate(() => localStorage.getItem("ashim-token")); + const token = await page.evaluate(() => localStorage.getItem("snapotter-token")); expect(token).toBeTruthy(); const bearerToken = token as string; diff --git a/tests/e2e/rbac.spec.ts b/tests/e2e/rbac.spec.ts index 90b0c29d..df41e251 100644 --- a/tests/e2e/rbac.spec.ts +++ b/tests/e2e/rbac.spec.ts @@ -160,7 +160,7 @@ base.describe("RBAC - User sees restricted tabs", () => { await login(page, TEST_USER, TEST_PASSWORD); // Extract token from localStorage - const token = await page.evaluate(() => localStorage.getItem("ashim-token")); + const token = await page.evaluate(() => localStorage.getItem("snapotter-token")); expect(token).toBeTruthy(); const bearerToken = token as string; @@ -269,7 +269,7 @@ base.describe("RBAC - Editor sees collaborative tabs", () => { base.test("editor gets 403 on admin API endpoints", async ({ page }) => { await login(page, "editortest", "EditorTest1"); - const token = await page.evaluate(() => localStorage.getItem("ashim-token")); + const token = await page.evaluate(() => localStorage.getItem("snapotter-token")); expect(token).toBeTruthy(); const usersRes = await fetch(`${API}/api/auth/users`, { diff --git a/tests/e2e/settings.spec.ts b/tests/e2e/settings.spec.ts index 9fddbbee..42cf77b6 100644 --- a/tests/e2e/settings.spec.ts +++ b/tests/e2e/settings.spec.ts @@ -76,7 +76,7 @@ test.describe("Settings Dialog", () => { await page.getByText("About").click(); // Should show app description - await expect(page.getByText(/ashim|privacy|self-hosted/i).first()).toBeVisible(); + await expect(page.getByText(/snapotter|privacy|self-hosted/i).first()).toBeVisible(); }); test("System Settings section has configuration", async ({ loggedInPage: page }) => { diff --git a/tests/integration/adversarial.test.ts b/tests/integration/adversarial.test.ts index 8e5ba8d1..77046216 100644 --- a/tests/integration/adversarial.test.ts +++ b/tests/integration/adversarial.test.ts @@ -1,5 +1,5 @@ /** - * Adversarial integration tests for the ashim image API. + * Adversarial integration tests for the SnapOtter image API. * * Tests malicious and stress inputs: corrupted images, truncated data, * oversized images, invalid dimensions, injection attacks, and malformed diff --git a/tests/integration/api.test.ts b/tests/integration/api.test.ts index b310e545..4f12341a 100644 --- a/tests/integration/api.test.ts +++ b/tests/integration/api.test.ts @@ -1,5 +1,5 @@ /** - * Integration tests for the ashim API. + * Integration tests for the SnapOtter API. * * These tests build a real Fastify server backed by an in-memory SQLite DB * and exercise every endpoint with real HTTP-like requests via `app.inject()`. diff --git a/tests/integration/concurrent.test.ts b/tests/integration/concurrent.test.ts index 549f7561..43e30922 100644 --- a/tests/integration/concurrent.test.ts +++ b/tests/integration/concurrent.test.ts @@ -1,5 +1,5 @@ /** - * Concurrent request integration tests for the ashim image API. + * Concurrent request integration tests for the SnapOtter image API. * * Tests that the server handles parallel and rapid sequential requests * correctly without data corruption, crashes, or race conditions. diff --git a/tests/integration/docs.test.ts b/tests/integration/docs.test.ts index 67880438..b9a17d87 100644 --- a/tests/integration/docs.test.ts +++ b/tests/integration/docs.test.ts @@ -20,7 +20,7 @@ describe("API docs", () => { expect(res.statusCode).toBe(200); expect(res.headers["content-type"]).toContain("text/yaml"); expect(res.body).toContain("openapi: 3.1.0"); - expect(res.body).toContain("ashim API"); + expect(res.body).toContain("SnapOtter API"); }); it("serves the Scalar docs page without auth", async () => { diff --git a/tests/integration/edge-cases.test.ts b/tests/integration/edge-cases.test.ts index 7dcdffbf..f0cb279a 100644 --- a/tests/integration/edge-cases.test.ts +++ b/tests/integration/edge-cases.test.ts @@ -1,5 +1,5 @@ /** - * Edge-case integration tests for the ashim image API. + * Edge-case integration tests for the SnapOtter image API. * * Tests unusual but valid inputs: empty files, tiny images, wrong extensions, * extreme filenames, missing/empty settings, and unknown fields. diff --git a/tests/integration/pipeline-edge-cases.test.ts b/tests/integration/pipeline-edge-cases.test.ts index ed7c9f95..27b598e8 100644 --- a/tests/integration/pipeline-edge-cases.test.ts +++ b/tests/integration/pipeline-edge-cases.test.ts @@ -1,5 +1,5 @@ /** - * Pipeline edge-case integration tests for the ashim image API. + * Pipeline edge-case integration tests for the SnapOtter image API. * * Tests the pipeline execution system with unusual inputs: empty pipelines, * single steps, invalid tools, conflicting steps, and multi-step chains. diff --git a/tests/integration/test-server.ts b/tests/integration/test-server.ts index 82285b52..bbaa18a4 100644 --- a/tests/integration/test-server.ts +++ b/tests/integration/test-server.ts @@ -19,8 +19,8 @@ import { dirname } from "node:path"; mkdirSync(dirname(process.env.DB_PATH!), { recursive: true }); mkdirSync(process.env.WORKSPACE_PATH!, { recursive: true }); -import { APP_VERSION } from "@ashim/shared"; import cors from "@fastify/cors"; +import { APP_VERSION } from "@snapotter/shared"; import { eq } from "drizzle-orm"; // --------------------------------------------------------------------------- // 2. Import app modules. config.ts already captured our env vars. diff --git a/tests/unit/analytics-consent-extended.test.ts b/tests/unit/analytics-consent-extended.test.ts index aed1fca8..53f91145 100644 --- a/tests/unit/analytics-consent-extended.test.ts +++ b/tests/unit/analytics-consent-extended.test.ts @@ -1,5 +1,5 @@ -import type { ConsentState } from "@ashim/shared"; -import { isConsentEnabled, shouldShowConsent } from "@ashim/shared"; +import type { ConsentState } from "@snapotter/shared"; +import { isConsentEnabled, shouldShowConsent } from "@snapotter/shared"; import { describe, expect, it } from "vitest"; const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000; diff --git a/tests/unit/analytics-consent.test.ts b/tests/unit/analytics-consent.test.ts index 4a18c146..03f5d651 100644 --- a/tests/unit/analytics-consent.test.ts +++ b/tests/unit/analytics-consent.test.ts @@ -1,4 +1,4 @@ -import { isConsentEnabled, shouldShowConsent } from "@ashim/shared"; +import { isConsentEnabled, shouldShowConsent } from "@snapotter/shared"; import { describe, expect, it } from "vitest"; describe("shouldShowConsent", () => { diff --git a/tests/unit/analytics-events.test.ts b/tests/unit/analytics-events.test.ts index f8835013..2ff66d0d 100644 --- a/tests/unit/analytics-events.test.ts +++ b/tests/unit/analytics-events.test.ts @@ -1,4 +1,4 @@ -import { ANALYTICS_EVENTS } from "@ashim/shared"; +import { ANALYTICS_EVENTS } from "@snapotter/shared"; import { describe, expect, it } from "vitest"; describe("ANALYTICS_EVENTS", () => { diff --git a/tests/unit/analytics-types.test.ts b/tests/unit/analytics-types.test.ts index 659dcd04..72e15f02 100644 --- a/tests/unit/analytics-types.test.ts +++ b/tests/unit/analytics-types.test.ts @@ -1,4 +1,4 @@ -import type { AnalyticsConfig, ConsentState } from "@ashim/shared"; +import type { AnalyticsConfig, ConsentState } from "@snapotter/shared"; import { describe, expect, it } from "vitest"; describe("AnalyticsConfig type", () => { diff --git a/tests/unit/api/effective-permissions.test.ts b/tests/unit/api/effective-permissions.test.ts index 7aca0393..0fb95ba2 100644 --- a/tests/unit/api/effective-permissions.test.ts +++ b/tests/unit/api/effective-permissions.test.ts @@ -5,7 +5,7 @@ * getPermissions edge cases, and hasPermission edge cases. */ -import type { Permission, Role } from "@ashim/shared"; +import type { Permission, Role } from "@snapotter/shared"; import { describe, expect, it, vi } from "vitest"; // Mock the auth plugin to avoid transitively opening a SQLite connection diff --git a/tests/unit/api/permissions.test.ts b/tests/unit/api/permissions.test.ts index dba3a21e..b4cf775a 100644 --- a/tests/unit/api/permissions.test.ts +++ b/tests/unit/api/permissions.test.ts @@ -5,7 +5,7 @@ * and that the hasPermission check works as expected. */ -import type { Role } from "@ashim/shared"; +import type { Role } from "@snapotter/shared"; import { describe, expect, it, vi } from "vitest"; // Mock the auth plugin to avoid transitively opening a SQLite connection diff --git a/tests/unit/api/utilities.test.ts b/tests/unit/api/utilities.test.ts index 9a805975..27df2d75 100644 --- a/tests/unit/api/utilities.test.ts +++ b/tests/unit/api/utilities.test.ts @@ -636,7 +636,7 @@ describe("workspace", () => { let TEST_WORKSPACE: string; beforeEach(async () => { - TEST_WORKSPACE = join(tmpdir(), `ashim-test-workspace-${randomUUID()}`); + TEST_WORKSPACE = join(tmpdir(), `SnapOtter-test-workspace-${randomUUID()}`); await mkdir(TEST_WORKSPACE, { recursive: true }); // Point the env mock's WORKSPACE_PATH at our temp dir diff --git a/tests/unit/auto-enhance.test.ts b/tests/unit/auto-enhance.test.ts index 64f145b1..817b85e4 100644 --- a/tests/unit/auto-enhance.test.ts +++ b/tests/unit/auto-enhance.test.ts @@ -1,6 +1,6 @@ import { readFileSync } from "node:fs"; import { join } from "node:path"; -import { analyzeImage, applyCorrections, scaleCorrections } from "@ashim/image-engine"; +import { analyzeImage, applyCorrections, scaleCorrections } from "@snapotter/image-engine"; import sharp from "sharp"; import { describe, expect, it } from "vitest"; diff --git a/tests/unit/features.test.ts b/tests/unit/features.test.ts index 4c12e372..753ac01b 100644 --- a/tests/unit/features.test.ts +++ b/tests/unit/features.test.ts @@ -4,7 +4,7 @@ import { getToolsForBundle, PYTHON_SIDECAR_TOOLS, TOOL_BUNDLE_MAP, -} from "@ashim/shared"; +} from "@snapotter/shared"; import { describe, expect, it } from "vitest"; describe("Feature bundles", () => { diff --git a/tests/unit/image-engine/detect.test.ts b/tests/unit/image-engine/detect.test.ts index 2fad437a..3e014e8b 100644 --- a/tests/unit/image-engine/detect.test.ts +++ b/tests/unit/image-engine/detect.test.ts @@ -1,6 +1,6 @@ import { readFileSync } from "node:fs"; import path from "node:path"; -import { detectFormat } from "@ashim/image-engine"; +import { detectFormat } from "@snapotter/image-engine"; import { describe, expect, it } from "vitest"; const FORMATS_DIR = path.resolve(__dirname, "../../fixtures/formats"); diff --git a/tests/unit/image-engine/engine.test.ts b/tests/unit/image-engine/engine.test.ts index 80df5c2e..665dbbd1 100644 --- a/tests/unit/image-engine/engine.test.ts +++ b/tests/unit/image-engine/engine.test.ts @@ -17,7 +17,7 @@ const require = createRequire( ); const sharp = require("sharp") as typeof import("sharp").default; -import { processImage } from "@ashim/image-engine"; +import { processImage } from "@snapotter/image-engine"; const FIXTURES_DIR = path.resolve(__dirname, "../../fixtures"); const FORMATS_DIR = path.resolve(__dirname, "../../fixtures/formats"); diff --git a/tests/unit/image-engine/metadata.test.ts b/tests/unit/image-engine/metadata.test.ts index 01e4ce22..aa9dc30a 100644 --- a/tests/unit/image-engine/metadata.test.ts +++ b/tests/unit/image-engine/metadata.test.ts @@ -9,7 +9,13 @@ const require = createRequire( ); const sharp = require("sharp") as typeof import("sharp").default; -import { getImageInfo, parseExif, parseGps, parseXmp, sanitizeValue } from "@ashim/image-engine"; +import { + getImageInfo, + parseExif, + parseGps, + parseXmp, + sanitizeValue, +} from "@snapotter/image-engine"; const FIXTURES_DIR = path.resolve(__dirname, "../../fixtures"); diff --git a/tests/unit/image-engine/mime.test.ts b/tests/unit/image-engine/mime.test.ts index 135c3914..ecdf372f 100644 --- a/tests/unit/image-engine/mime.test.ts +++ b/tests/unit/image-engine/mime.test.ts @@ -1,4 +1,4 @@ -import { extToMime, formatToExt, formatToMime, mimeToExt } from "@ashim/image-engine"; +import { extToMime, formatToExt, formatToMime, mimeToExt } from "@snapotter/image-engine"; import { describe, expect, it } from "vitest"; // --------------------------------------------------------------------------- diff --git a/tests/unit/image-engine/operations.test.ts b/tests/unit/image-engine/operations.test.ts index 2c94be12..884c9298 100644 --- a/tests/unit/image-engine/operations.test.ts +++ b/tests/unit/image-engine/operations.test.ts @@ -34,7 +34,7 @@ import { saturation, sepia, stripMetadata, -} from "@ashim/image-engine"; +} from "@snapotter/image-engine"; const FIXTURES_DIR = path.resolve(__dirname, "../../fixtures"); @@ -1395,7 +1395,7 @@ describe("parseExif", () => { const result = parseExif(metadata.exif!); expect(result.image.Artist).toBe("Test Artist"); expect(result.image.Copyright).toBe("2026 Test Copyright"); - expect(result.image.Software).toBe("ashim Test"); + expect(result.image.Software).toBe("SnapOtter Test"); expect(result.image.ImageDescription).toBe("Test Description"); }); @@ -1489,7 +1489,7 @@ describe("editMetadata", () => { expect(parsed.Image?.Artist).toBe("New Artist"); expect(parsed.Image?.Copyright).toBe("New Copyright"); // Original fields should be preserved via withExifMerge - expect(parsed.Image?.Software).toBe("ashim Test"); + expect(parsed.Image?.Software).toBe("SnapOtter Test"); }); it("clears GPS while preserving other EXIF", async () => { diff --git a/tests/unit/landing/components.test.tsx b/tests/unit/landing/components.test.tsx index 0aab5bb8..cabde36c 100644 --- a/tests/unit/landing/components.test.tsx +++ b/tests/unit/landing/components.test.tsx @@ -50,7 +50,7 @@ describe("Hero", () => { render(); const cta = screen.getByText("Get it for free"); const link = cta.closest("a"); - expect(link?.getAttribute("href")).toBe("https://github.com/ashim-hq/ashim"); + expect(link?.getAttribute("href")).toBe("https://github.com/snapotter-hq/snapotter"); expect(link?.getAttribute("target")).toBe("_blank"); }); @@ -175,7 +175,9 @@ describe("Pricing", () => { it("links free plan CTA to GitHub", () => { render(); const freeButton = screen.getByText(/Get Started Free/); - expect(freeButton.closest("a")?.getAttribute("href")).toBe("https://github.com/ashim-hq/ashim"); + expect(freeButton.closest("a")?.getAttribute("href")).toBe( + "https://github.com/snapotter-hq/snapotter", + ); }); it("links enterprise CTA to contact page", () => { @@ -201,7 +203,7 @@ describe("OpenSource", () => { it("links to GitHub", () => { render(); const link = screen.getByText("Star on GitHub").closest("a"); - expect(link?.getAttribute("href")).toBe("https://github.com/ashim-hq/ashim"); + expect(link?.getAttribute("href")).toBe("https://github.com/snapotter-hq/snapotter"); }); }); @@ -230,7 +232,9 @@ describe("Footer", () => { it("renders community links to GitHub", () => { render(
); const ghLink = screen.getByText("GitHub"); - expect(ghLink.closest("a")?.getAttribute("href")).toBe("https://github.com/ashim-hq/ashim"); + expect(ghLink.closest("a")?.getAttribute("href")).toBe( + "https://github.com/snapotter-hq/snapotter", + ); }); it("renders legal links", () => { diff --git a/tests/unit/landing/how-it-works.test.tsx b/tests/unit/landing/how-it-works.test.tsx index bec84c30..5c0e98cd 100644 --- a/tests/unit/landing/how-it-works.test.tsx +++ b/tests/unit/landing/how-it-works.test.tsx @@ -27,7 +27,7 @@ beforeEach(() => { afterEach(cleanup); const DOCKER_COMMAND = - "docker run -d --name ashim -p 1349:1349 -v ashim-data:/data ghcr.io/ashim-hq/ashim:latest"; + "docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data ghcr.io/snapotter-hq/snapotter:latest"; describe("HowItWorks", () => { it("renders the section heading", () => { diff --git a/tests/unit/landing/navbar.test.tsx b/tests/unit/landing/navbar.test.tsx index 84811381..63a0ee7e 100644 --- a/tests/unit/landing/navbar.test.tsx +++ b/tests/unit/landing/navbar.test.tsx @@ -50,7 +50,7 @@ describe("Navbar", () => { it("fetches GitHub star count on mount", async () => { render(); await waitFor(() => { - expect(fetchMock).toHaveBeenCalledWith("https://api.github.com/repos/ashim-hq/ashim"); + expect(fetchMock).toHaveBeenCalledWith("https://api.github.com/repos/snapotter-hq/snapotter"); }); }); @@ -121,7 +121,7 @@ describe("Navbar", () => { render(); const githubLinks = screen.getAllByText("Star on GitHub"); const link = githubLinks[0].closest("a"); - expect(link?.getAttribute("href")).toBe("https://github.com/ashim-hq/ashim"); + expect(link?.getAttribute("href")).toBe("https://github.com/snapotter-hq/snapotter"); expect(link?.getAttribute("target")).toBe("_blank"); }); }); diff --git a/tests/unit/web/stores.test.ts b/tests/unit/web/stores.test.ts index 7d51e6d1..c1dd63df 100644 --- a/tests/unit/web/stores.test.ts +++ b/tests/unit/web/stores.test.ts @@ -498,17 +498,17 @@ describe("API lib", () => { // -- Token management ---------------------------------------------------- describe("token management", () => { - it("setToken stores in localStorage under 'ashim-token'", () => { + it("setToken stores in localStorage under 'snapotter-token'", () => { setToken("my-secret"); - expect(localStorageMock.setItem).toHaveBeenCalledWith("ashim-token", "my-secret"); - expect(storageMap.get("ashim-token")).toBe("my-secret"); + expect(localStorageMock.setItem).toHaveBeenCalledWith("snapotter-token", "my-secret"); + expect(storageMap.get("snapotter-token")).toBe("my-secret"); }); - it("clearToken removes 'ashim-token' from localStorage", () => { + it("clearToken removes 'snapotter-token' from localStorage", () => { setToken("to-remove"); clearToken(); - expect(localStorageMock.removeItem).toHaveBeenCalledWith("ashim-token"); - expect(storageMap.has("ashim-token")).toBe(false); + expect(localStorageMock.removeItem).toHaveBeenCalledWith("snapotter-token"); + expect(storageMap.has("snapotter-token")).toBe(false); }); it("clearToken is idempotent (no throw when key missing)", () => { diff --git a/tests/unit/web/zustand-stores.test.ts b/tests/unit/web/zustand-stores.test.ts index a1e8e3f1..2719c53c 100644 --- a/tests/unit/web/zustand-stores.test.ts +++ b/tests/unit/web/zustand-stores.test.ts @@ -1447,7 +1447,7 @@ describe("useSettingsStore", () => { // FeaturesStore // ========================================================================== -vi.mock("@ashim/shared", async (importOriginal) => { +vi.mock("@snapotter/shared", async (importOriginal) => { const actual: Record = await importOriginal(); return { ...actual, @@ -1753,7 +1753,7 @@ describe("useAnalyticsStore", () => { await useAnalyticsStore.getState().acceptAnalytics(); - expect(localStorage.setItem).toHaveBeenCalledWith("ashim-analytics-consent", "true"); + expect(localStorage.setItem).toHaveBeenCalledWith("snapotter-analytics-consent", "true"); expect(useAnalyticsStore.getState().consent.analyticsEnabled).toBe(true); }); @@ -1773,7 +1773,7 @@ describe("useAnalyticsStore", () => { await useAnalyticsStore.getState().declineAnalytics(); - expect(localStorage.setItem).toHaveBeenCalledWith("ashim-analytics-consent", "false"); + expect(localStorage.setItem).toHaveBeenCalledWith("snapotter-analytics-consent", "false"); }); it("remindLater calls API and sets remind-at 7 days in the future", async () => { @@ -1798,7 +1798,7 @@ describe("useAnalyticsStore", () => { await useAnalyticsStore.getState().remindLater(); - expect(localStorage.setItem).toHaveBeenCalledWith("ashim-analytics-consent", "remind"); + expect(localStorage.setItem).toHaveBeenCalledWith("snapotter-analytics-consent", "remind"); }); it("toggleAnalytics enables analytics", async () => { @@ -1824,7 +1824,7 @@ describe("useAnalyticsStore", () => { await useAnalyticsStore.getState().toggleAnalytics(true); - expect(localStorage.setItem).toHaveBeenCalledWith("ashim-analytics-consent", "true"); + expect(localStorage.setItem).toHaveBeenCalledWith("snapotter-analytics-consent", "true"); expect(useAnalyticsStore.getState().consent.analyticsEnabled).toBe(true); }); }); diff --git a/vitest.config.ts b/vitest.config.ts index 1d2e2f93..844723bf 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -13,7 +13,7 @@ const webNodeModules = path.resolve(__dirname, "apps/web/node_modules"); const landingNodeModules = path.resolve(__dirname, "apps/landing/node_modules"); // Temp dir for integration test DB + workspace (set BEFORE any app code loads) -const testDir = path.join(os.tmpdir(), `ashim-test-${crypto.randomUUID().slice(0, 8)}`); +const testDir = path.join(os.tmpdir(), `SnapOtter-test-${crypto.randomUUID().slice(0, 8)}`); export default defineConfig({ esbuild: { @@ -84,8 +84,8 @@ export default defineConfig({ "@/components/navbar": path.resolve(__dirname, "apps/landing/src/components/navbar"), "@": path.resolve(__dirname, "apps/web/src"), "framer-motion": path.join(landingNodeModules, "framer-motion"), - "@ashim/image-engine": path.resolve(__dirname, "packages/image-engine/src/index.ts"), - "@ashim/shared": path.resolve(__dirname, "packages/shared/src/index.ts"), + "@snapotter/image-engine": path.resolve(__dirname, "packages/image-engine/src/index.ts"), + "@snapotter/shared": path.resolve(__dirname, "packages/shared/src/index.ts"), fastify: path.join(apiNodeModules, "fastify"), "@fastify/cors": path.join(apiNodeModules, "@fastify/cors"), "@fastify/multipart": path.join(apiNodeModules, "@fastify/multipart"),