diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index f62c22b9..c45724e8 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -29,6 +29,9 @@ jobs: - name: Install dependencies run: npm ci + - name: Run tests + run: npm run test:run + - name: Build distribution run: npm run build diff --git a/.github/workflows/docker-downloads-badge.yml b/.github/workflows/docker-downloads-badge.yml new file mode 100644 index 00000000..fcf6b559 --- /dev/null +++ b/.github/workflows/docker-downloads-badge.yml @@ -0,0 +1,59 @@ +name: Update Docker Downloads Badge + +on: + schedule: + - cron: '17 4 * * 1' + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: docker-downloads-badge + cancel-in-progress: false + +jobs: + update: + if: github.repository == 'alam00000/bentopdf' + runs-on: ubuntu-latest + steps: + - name: Sum GHCR download counts + id: counts + run: | + set -euo pipefail + total=0 + for pkg in bentopdf bentopdf-simple; do + raw=$(curl -sf --retry 3 --retry-delay 5 --max-time 30 \ + "https://ghcr-badge.elias.eu.org/api/alam00000/bentopdf/$pkg" \ + | jq -e -r '.downloadCountRaw') + case "$raw" in ''|*[!0-9]*) echo "::error::invalid count for $pkg: $raw"; exit 1 ;; esac + echo "$pkg: $raw" + total=$((total + raw)) + done + if [ "$total" -le 0 ]; then echo "::error::total is zero"; exit 1; fi + message=$(awk -v n="$total" 'BEGIN{ + if (n >= 1000000) printf "%.1fM", n/1000000; + else if (n >= 1000) printf "%.1fk", n/1000; + else printf "%d", n + }') + echo "total=$total" >> "$GITHUB_OUTPUT" + echo "message=$message" >> "$GITHUB_OUTPUT" + echo "combined: $total -> $message" + + - name: Publish badge JSON to badges branch + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MESSAGE: ${{ steps.counts.outputs.message }} + run: | + set -euo pipefail + mkdir badges && cd badges + jq -n --arg message "$MESSAGE" \ + '{schemaVersion: 1, label: "Docker Downloads", message: $message, color: "blue", namedLogo: "docker"}' \ + > docker-downloads.json + cat docker-downloads.json + git init -q -b badges + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add docker-downloads.json + git commit -qm "chore: update docker downloads badge ($MESSAGE)" + git push -qf "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" badges diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..0acc8b6f --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,36 @@ +name: Tests + +on: + push: + branches: + - 'main' + pull_request: + workflow_dispatch: + +concurrency: + group: tests-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + env: + HUSKY: 0 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Typecheck + run: npx tsc --noEmit + + - name: Run tests + run: npm run test:run diff --git a/.github/workflows/update-bentopdf-viewer.yml b/.github/workflows/update-bentopdf-viewer.yml new file mode 100644 index 00000000..7f0136ca --- /dev/null +++ b/.github/workflows/update-bentopdf-viewer.yml @@ -0,0 +1,198 @@ +name: Update PDF Engine and Viewer + +on: + workflow_dispatch: + schedule: + - cron: '17 4 * * *' + +permissions: + contents: write + pull-requests: write + +concurrency: + group: update-engine + cancel-in-progress: false + +env: + FORK_URL: https://github.com/alam00000/bentopdf-pdfium-viewer + HUSKY: 0 + +jobs: + update: + runs-on: ubuntu-latest + if: github.repository == 'alam00000/bentopdf' + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Read current upstream marker + id: current + run: | + if [ -f vendor/bentopdf-viewer/.upstream-version ]; then + echo "version=$(cat vendor/bentopdf-viewer/.upstream-version)" >> "$GITHUB_OUTPUT" + else + echo "version=" >> "$GITHUB_OUTPUT" + fi + + - name: Read fork HEAD + id: upstream + run: echo "version=$(git ls-remote "$FORK_URL" refs/heads/main | cut -c1-12)" >> "$GITHUB_OUTPUT" + + - name: Should update? + id: gate + run: | + if [ "${{ steps.upstream.outputs.version }}" = "${{ steps.current.outputs.version }}" ]; then + echo "run=false" >> "$GITHUB_OUTPUT" + echo "Already on ${{ steps.current.outputs.version }}." + else + echo "run=true" >> "$GITHUB_OUTPUT" + echo "Updating ${{ steps.current.outputs.version }} -> ${{ steps.upstream.outputs.version }}" + fi + + - name: Setup Node + if: steps.gate.outputs.run == 'true' + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - name: Enable corepack (pnpm) + if: steps.gate.outputs.run == 'true' + run: corepack enable + + - name: Clone the viewer fork + if: steps.gate.outputs.run == 'true' + run: git clone --depth 1 --branch main "$FORK_URL" ./_fork + + - name: Require a published engine + if: steps.gate.outputs.run == 'true' + run: | + test -s ./_fork/packages/pdfium/src/vendor/pdfium.wasm + test -s ./_fork/packages/pdfium/src/vendor/pdfium.js + + - name: Pack the engine + if: steps.gate.outputs.run == 'true' + id: engine + run: | + set -euo pipefail + SHA=${{ steps.upstream.outputs.version }} + VENDOR=./_fork/packages/pdfium/src/vendor + STAGE=$(mktemp -d)/package + mkdir -p "$STAGE" + cp "$VENDOR/pdfium.js" "$STAGE/editcore.js" + cp "$VENDOR/pdfium.wasm" "$STAGE/editcore.wasm" + cat > "$STAGE/package.json" <> "$GITHUB_OUTPUT" + + - name: Build the viewer + if: steps.gate.outputs.run == 'true' + working-directory: ./_fork + run: | + pnpm install --no-frozen-lockfile + pnpm run build:snippet + + - name: Pack the viewer without a second engine + if: steps.gate.outputs.run == 'true' + id: viewer + run: | + set -euo pipefail + SHA=${{ steps.upstream.outputs.version }} + WORK=$(mktemp -d) + (cd ./_fork && npm pack ./viewers/snippet --pack-destination "$WORK" >/dev/null) + TMP=$(mktemp -d) + tar -xzf "$WORK"/*.tgz -C "$TMP" + rm -f "$TMP/package/dist/pdfium.wasm" + PKG="$TMP/package/package.json" node - <<'NODE' + const fs = require('fs'); + const p = process.env.PKG; + const pkg = JSON.parse(fs.readFileSync(p, 'utf8')); + pkg.name = 'bentopdf-viewer'; + pkg.dependencies = pkg.dependencies || {}; + // The rollup bundle inlines every @embedpdf/* package, so these + // declared deps would only pull unused copies from upstream npm. + for (const k of Object.keys(pkg.dependencies)) { + if (k.startsWith('@embedpdf/')) delete pkg.dependencies[k]; + if (k === 'preact') pkg.dependencies[k] = '^10.17.0'; + } + fs.writeFileSync(p, JSON.stringify(pkg, null, 2) + '\n'); + NODE + mkdir -p vendor/bentopdf-viewer + OUT="vendor/bentopdf-viewer/bentopdf-viewer-$SHA.tgz" + tar -czf "$OUT" -C "$TMP" package + find vendor/bentopdf-viewer -maxdepth 1 -name 'bentopdf-viewer-*.tgz' ! -name "$(basename "$OUT")" -delete + echo "tarball=$OUT" >> "$GITHUB_OUTPUT" + + - name: Point dependencies at the new tarballs + if: steps.gate.outputs.run == 'true' + run: | + node -e " + const fs = require('fs'); + const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); + pkg.dependencies['bentopdf-pdfium'] = 'file:' + process.argv[1]; + pkg.dependencies['bentopdf-viewer'] = 'file:' + process.argv[2]; + fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); + " "${{ steps.engine.outputs.tarball }}" "${{ steps.viewer.outputs.tarball }}" + + - name: Cleanup upstream clone + if: steps.gate.outputs.run == 'true' + run: rm -rf ./_fork + + - name: Install and verify one shared engine + if: steps.gate.outputs.run == 'true' + run: | + set -euo pipefail + npm install + test -s node_modules/bentopdf-pdfium/editcore.wasm + if find node_modules/bentopdf-viewer -name '*.wasm' | grep -q .; then + echo "::error::viewer package still ships a wasm; the engine would be duplicated" + exit 1 + fi + if ! grep -q "bentopdf-pdfium/editcore.wasm" src/js/logic/edit-pdf-page.ts; then + echo "::error::the PDF editor no longer points at the shared engine" + exit 1 + fi + echo "engine sha256: $(sha256sum node_modules/bentopdf-pdfium/editcore.wasm | cut -c1-16)" + + - name: Typecheck and test + if: steps.gate.outputs.run == 'true' + run: | + npx tsc --noEmit + npm run test:run + + - name: Write upstream marker + if: steps.gate.outputs.run == 'true' + run: | + echo "${{ steps.upstream.outputs.version }}" > vendor/bentopdf-viewer/.upstream-version + echo "${{ steps.upstream.outputs.version }}" > vendor/bentopdf-pdfium/.upstream-version + + - name: Create Pull Request + if: steps.gate.outputs.run == 'true' + uses: peter-evans/create-pull-request@v6 + with: + commit-message: 'build(deps): bump PDF engine and viewer to ${{ steps.upstream.outputs.version }}' + title: 'build(deps): bump PDF engine and viewer to ${{ steps.upstream.outputs.version }}' + body: | + Both vendored packages built from one clone of the viewer fork at + `${{ steps.upstream.outputs.version }}`, so the text editor and the + PDF editor run the same engine. + + - `bentopdf-pdfium` — the engine wasm, packed from the fork's published `src/vendor` + - `bentopdf-viewer` — the snippet bundle, packed **without** `dist/pdfium.wasm` + + The viewer loads the shared engine through `EmbedPDF.init({ wasmUrl })`. + CI verified a single wasm on disk, typecheck, and the test suite. + branch: chore/update-pdf-engine + delete-branch: true diff --git a/.github/workflows/update-embedpdf-snippet.yml b/.github/workflows/update-embedpdf-snippet.yml deleted file mode 100644 index 9e91d4bb..00000000 --- a/.github/workflows/update-embedpdf-snippet.yml +++ /dev/null @@ -1,141 +0,0 @@ -name: Update EmbedPDF Snippet - -on: - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - update-snippet: - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Read current upstream version marker - id: current-version - run: | - if [ -f vendor/embedpdf/.upstream-version ]; then - CUR=$(cat vendor/embedpdf/.upstream-version) - else - CUR="" - fi - echo "version=$CUR" >> "$GITHUB_OUTPUT" - - - name: Read latest upstream version (@embedpdf/core) - id: upstream-version - run: | - LATEST=$(npm view @embedpdf/core version) - echo "version=$LATEST" >> "$GITHUB_OUTPUT" - - - name: Should update? - id: gate - run: | - if [ "${{ steps.upstream-version.outputs.version }}" = "${{ steps.current-version.outputs.version }}" ]; then - echo "run=false" >> "$GITHUB_OUTPUT" - echo "No upstream version change detected." - else - echo "run=true" >> "$GITHUB_OUTPUT" - echo "Updating from '${{ steps.current-version.outputs.version }}' to '${{ steps.upstream-version.outputs.version }}'" - fi - - - name: Enable corepack (pnpm) - if: steps.gate.outputs.run == 'true' - run: corepack enable - - - name: Prepare workspace - if: steps.gate.outputs.run == 'true' - run: | - mkdir -p vendor/embedpdf - npm config set cache ./\.npm-cache - - - name: Clone upstream embed-pdf-viewer - if: steps.gate.outputs.run == 'true' - run: git clone --depth 1 --branch main https://github.com/embedpdf/embed-pdf-viewer ./_upstream/embed-pdf-viewer - - - name: Setup Node - if: steps.gate.outputs.run == 'true' - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: npm - - - name: Install upstream deps - if: steps.gate.outputs.run == 'true' - working-directory: ./_upstream/embed-pdf-viewer - run: pnpm install --no-frozen-lockfile - - - name: Build snippet - if: steps.gate.outputs.run == 'true' - working-directory: ./_upstream/embed-pdf-viewer - run: pnpm run build:snippet - - - name: Pack snippet tarball - if: steps.gate.outputs.run == 'true' - working-directory: ./_upstream/embed-pdf-viewer - run: | - npm pack ./viewers/snippet --pack-destination ../../vendor/embedpdf - ls -l ../../vendor/embedpdf - - - name: Sanitize tarball (rename pkg and pin deps) - if: steps.gate.outputs.run == 'true' - env: - UPSTREAM_VERSION: ${{ steps.upstream-version.outputs.version }} - run: | - TARBALL=$(ls vendor/embedpdf/*.tgz | sort | tail -n1) - TMP=$(mktemp -d) - tar -xzf "$TARBALL" -C "$TMP" - PKG="$TMP/package/package.json" - PKG="$PKG" node - <<'NODE' - const fs = require("fs"); - const path = process.env.PKG; - const ver = process.env.UPSTREAM_VERSION || "1.4.1"; - const pkg = JSON.parse(fs.readFileSync(path, "utf8")); - pkg.name = "embedpdf-snippet"; - pkg.dependencies = pkg.dependencies || {}; - for (const k of Object.keys(pkg.dependencies)) { - if (k.startsWith("@embedpdf/")) pkg.dependencies[k] = `^${ver}`; - if (k === "preact") pkg.dependencies[k] = "^10.17.0"; - } - fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + "\n"); - NODE - NEW=vendor/embedpdf/embedpdf-snippet-${UPSTREAM_VERSION}.tgz - tar -czf "$NEW" -C "$TMP" package - # Remove any older snippet tarballs, keep only the new one - find vendor/embedpdf -maxdepth 1 -name 'embedpdf-snippet-*.tgz' ! -name "$(basename "$NEW")" -delete - rm -rf "$TMP" - ls -l vendor/embedpdf - - - name: Update package.json dependency path - if: steps.gate.outputs.run == 'true' - run: | - TARBALL=$(ls vendor/embedpdf/embedpdf-snippet-*.tgz | sort | tail -n1) - node -e "const fs=require('fs');const pkg=require('./package.json');const tar=process.argv[1];pkg.dependencies['embedpdf-snippet']='file:'+tar;fs.writeFileSync('package.json',JSON.stringify(pkg,null,2)+'\n');" "$TARBALL" - - - name: Refresh lockfile - if: steps.gate.outputs.run == 'true' - run: npm install --package-lock-only --ignore-scripts - - - name: Write upstream version marker - if: steps.gate.outputs.run == 'true' - run: | - echo "${{ steps.upstream-version.outputs.version }}" > vendor/embedpdf/.upstream-version - - - name: Cleanup upstream clone - if: steps.gate.outputs.run == 'true' - run: rm -rf ./_upstream - - - name: Create Pull Request - if: steps.gate.outputs.run == 'true' - uses: peter-evans/create-pull-request@v6 - with: - commit-message: "build(deps): bump embedpdf-snippet from ${{ steps.current-version.outputs.version }} to ${{ steps.upstream-version.outputs.version }}" - title: "build(deps): bump embedpdf-snippet from ${{ steps.current-version.outputs.version }} to ${{ steps.upstream-version.outputs.version }}" - body: | - - Build snippet from upstream embed-pdf-viewer via `npm run build:snippet` - - Pack tarball into `vendor/embedpdf/` and point dependency to it - - Refresh package-lock.json - branch: chore/update-embedpdf-snippet - delete-branch: true diff --git a/.gitignore b/.gitignore index 60fe8a18..d48b56e0 100644 --- a/.gitignore +++ b/.gitignore @@ -46,8 +46,11 @@ codeql-results.csv libreoffice-wasm-package # helm chart -bentopdf-*.tgz +/bentopdf-*.tgz # test dist-test -test \ No newline at end of file +test +# Sibling checkouts of the engine/viewer forks +bentopdf-pdfium-viewer/ +bentopdf-pymupdf-wasm/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c5ffb7bc..bb1e70eb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -81,7 +81,7 @@ When submitting code contributions, please use our [pull request template](.gith ```bash git clone https://github.com/alam00000/bentopdf.git - cd bento-pdf + cd bentopdf npm install ``` diff --git a/Dockerfile b/Dockerfile index a6eefff6..245e52a6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,8 @@ COPY . . # Pass SIMPLE_MODE environment variable if provided ARG SIMPLE_MODE=false ENV SIMPLE_MODE=$SIMPLE_MODE +ARG DISABLE_GITHUB_STARS=false +ENV DISABLE_GITHUB_STARS=$DISABLE_GITHUB_STARS ARG COMPRESSION_MODE=all ENV COMPRESSION_MODE=$COMPRESSION_MODE diff --git a/Dockerfile.nonroot b/Dockerfile.nonroot index 38f2bb82..aa16f550 100644 --- a/Dockerfile.nonroot +++ b/Dockerfile.nonroot @@ -19,6 +19,8 @@ COPY . . ARG SIMPLE_MODE=false ENV SIMPLE_MODE=$SIMPLE_MODE +ARG DISABLE_GITHUB_STARS=false +ENV DISABLE_GITHUB_STARS=$DISABLE_GITHUB_STARS ARG COMPRESSION_MODE=all ENV COMPRESSION_MODE=$COMPRESSION_MODE diff --git a/README.md b/README.md index 0c81ee36..d24cf108 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@

-**BentoPDF** is a powerful, privacy-first, client-side PDF toolkit that is self hostable and allows you to manipulate, edit, merge, and process PDF files directly in your browser. No server-side processing is required, ensuring your files remain secure and private. +**BentoPDF** is a powerful, privacy-first, client-side PDF toolkit that is self-hostable and allows you to manipulate, edit, merge, and process PDF files directly in your browser. No server-side processing is required, ensuring your files remain secure and private. -[![Docker Downloads](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fghcr-badge.elias.eu.org%2Fapi%2Falam00000%2Fbentopdf%2Fbentopdf&query=%24.downloadCount&logo=docker&label=Docker%20Downloads&color=blue)](https://github.com/alam00000/bentopdf/pkgs/container/bentopdf) [![Ko-fi](https://img.shields.io/badge/Buy%20me%20a%20Coffee-yellow?logo=kofi&style=flat-square)](https://ko-fi.com/alio01) ![GitHub Stars](https://img.shields.io/github/stars/alam00000/bentopdf?style=social) +[![Docker Downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Falam00000%2Fbentopdf%2Fbadges%2Fdocker-downloads.json&cacheSeconds=3600)](https://github.com/alam00000/bentopdf/pkgs/container/bentopdf-simple) [![Ko-fi](https://img.shields.io/badge/Buy%20me%20a%20Coffee-yellow?logo=kofi&style=flat-square)](https://ko-fi.com/alio01) ![GitHub Stars](https://img.shields.io/github/stars/alam00000/bentopdf?style=social) [![Sponsor me on GitHub](https://img.shields.io/badge/Sponsor-%E2%9D%A4-ff69b4)](https://github.com/sponsors/alam00000) ![BentoPDF Tools](public/images/bentopdf-tools.png) @@ -41,6 +41,7 @@ - [Commercial Build](#-commercial-build) - [Custom Branding](#-custom-branding) - [Disabling Specific Tools](#-disabling-specific-tools) + - [Disabling the GitHub Star Counter](#-disabling-the-github-star-counter) - [WASM Configuration](#wasm-configuration) - [Air-Gapped / Offline Deployment](#air-gapped--offline-deployment) - [Security Features](#-security-features) @@ -112,7 +113,7 @@ BentoPDF does **not** bundle AGPL-licensed processing libraries in its source co ## ⭐ Stargazers over time -[![Star History Chart](https://api.star-history.com/svg?repos=alam00000/bentopdf&type=Date)](https://star-history.com/#alam00000/bentopdf&Date) +[![Star History Chart](https://star-history.dera.page/svg?repos=alam00000/bentopdf&type=Date)](https://github.com/alam00000/bentopdf/stargazers) --- @@ -131,7 +132,7 @@ We're incredibly grateful to all our sponsors and supporters who help keep Bento ## ✨ Why BentoPDF? - **Privacy First**: All processing happens in your browser. Your files are never uploaded to a server, guaranteeing 100% privacy. -- **No Limits**: Manipulate as many files as you want, as often you want. There are no restrictions or upload limits. +- **No Limits**: Manipulate as many files as you want, as often as you want. There are no restrictions or upload limits. - **High Performance**: Built with modern web technologies, BentoPDF is fast and efficient, handling even large PDF files with ease. - **Completely Free**: BentoPDF is a free and open-source tool for everyone. @@ -143,31 +144,31 @@ BentoPDF offers a comprehensive suite of tools to handle all your PDF needs. ### Organize & Manage PDFs -| Tool Name | Description | -| :--------------------------- | :------------------------------------------------------------------------------------------------------ | -| **Merge PDFs** | Combine multiple PDF files into one. Preserves Bookmarks. | -| **Split PDFs** | Extract specific pages or divide a document into smaller files. | -| **Organize Pages** | Reorder, duplicate, or delete pages with a simple drag-and-drop interface. | -| **Extract Pages** | Save a specific range of pages as a new PDF. | -| **Delete Pages** | Remove unwanted pages from your document. | -| **Rotate PDF** | Rotate individual or all pages in a document. | -| **Rotate by Custom Degrees** | Rotate pages by any custom angle. | -| **N-Up PDF** | Combine multiple pages onto a single page. | -| **View PDF** | A powerful, integrated PDF viewer. | -| **Alternate & Mix Pages** | Merge pages by alternating pages from each PDF. Preserves Bookmarks. | -| **Posterize PDF** | Split a PDF into multiple smaller pages for print. | -| **PDF Multi Tool** | Merge, Split, Organize, Delete, Rotate, Add Blank Pages, Extract and Duplicate in an unified interface. | -| **PDF Booklet** | Rearrange pages for double-sided booklet printing. Fold and staple to create a booklet. | -| **Add Attachments** | Embed one or more files into your PDF. | -| **Extract Attachments** | Extract all embedded files from PDF(s) as a ZIP. | -| **Edit Attachments** | View or remove attachments in your PDF. | -| **Divide Pages** | Divide pages horizontally or vertically. | -| **Combine to Single Page** | Stitch all pages into one continuous scroll. | -| **Add Blank Page** | Insert an empty page anywhere in your PDF. | -| **Reverse Pages** | Flip the order of all pages in your document. | -| **View Metadata** | Inspect the hidden properties of your PDF. | -| **PDFs to ZIP** | Package multiple PDF files into a ZIP archive. | -| **Compare PDFs** | Compare two PDFs side by side. | +| Tool Name | Description | +| :--------------------------- | :----------------------------------------------------------------------------------------------------- | +| **Merge PDFs** | Combine multiple PDF files into one. Preserves Bookmarks. | +| **Split PDFs** | Extract specific pages or divide a document into smaller files. | +| **Organize Pages** | Reorder, duplicate, or delete pages with a simple drag-and-drop interface. | +| **Extract Pages** | Save a specific range of pages as a new PDF. | +| **Delete Pages** | Remove unwanted pages from your document. | +| **Rotate PDF** | Rotate individual or all pages in a document. | +| **Rotate by Custom Degrees** | Rotate pages by any custom angle. | +| **N-Up PDF** | Combine multiple pages onto a single page. | +| **View PDF** | A powerful, integrated PDF viewer. | +| **Alternate & Mix Pages** | Merge pages by alternating pages from each PDF. Preserves Bookmarks. | +| **Posterize PDF** | Split a PDF into multiple smaller pages for print. | +| **PDF Multi Tool** | Merge, Split, Organize, Delete, Rotate, Add Blank Pages, Extract and Duplicate in a unified interface. | +| **PDF Booklet** | Rearrange pages for double-sided booklet printing. Fold and staple to create a booklet. | +| **Add Attachments** | Embed one or more files into your PDF. | +| **Extract Attachments** | Extract all embedded files from PDF(s) as a ZIP. | +| **Edit Attachments** | View or remove attachments in your PDF. | +| **Divide Pages** | Divide pages horizontally or vertically. | +| **Combine to Single Page** | Stitch all pages into one continuous scroll. | +| **Add Blank Page** | Insert an empty page anywhere in your PDF. | +| **Reverse Pages** | Flip the order of all pages in your document. | +| **View Metadata** | Inspect the hidden properties of your PDF. | +| **PDFs to ZIP** | Package multiple PDF files into a ZIP archive. | +| **Compare PDFs** | Compare two PDFs side by side. | ### Edit & Modify PDFs @@ -332,7 +333,7 @@ Open your browser at: http://localhost:3000 > - **Self-Hosted build** — `ghcr.io/alam00000/bentopdf-simple:latest`. Every PDF tool the public site has, **without** the BentoPDF marketing (no hero, FAQ, testimonials, footer). Use this for internal/team/organization deployments. It is **not** a feature-reduced lite version. > - **Commercial build** — `ghcr.io/alam00000/bentopdf:latest`. The full marketing site, used by bentopdf.com itself and by commercial license holders running public-facing deployments. Includes hero, FAQ, testimonials, and footer. > -> If in doubt: pull the Self Hosted build. +> If in doubt: pull the Self-Hosted build.
Alternative: Using Docker Hub or Podman @@ -684,7 +685,7 @@ BentoPDF can also be hosted from a subdirectory (e.g., `example.com/tools/bentop ```bash # Example: -# 1. Build the app with the specific BASE_URL. BASE_URL must have a trailing and leading slash. The BASE_URL can be any url of your choice. Here we are using /tools/bentopdf/ as an example. +# 1. Build the app with the specific BASE_URL. BASE_URL must have a trailing and leading slash. The BASE_URL can be any URL of your choice. Here we are using /tools/bentopdf/ as an example. BASE_URL=/tools/bentopdf/ npm run build @@ -806,7 +807,7 @@ For detailed Quadlet configuration, see [Self-Hosting Docker Guide](https://bent ### 🏢 Self-Hosted build (Simple Mode) -The Self-Hosted build (the `bentopdf-simple` image, also called Simple Mode) is **functionally identical** to the Commercial build. Every PDF tool is present and behaves the same. It just hides the marketing that only makes sense on bentopdf.com itself or on a commercial public-facing deployment. **It is not a feature reduced or "lite" version.** +The Self-Hosted build (the `bentopdf-simple` image, also called Simple Mode) is **functionally identical** to the Commercial build. Every PDF tool is present and behaves the same. It just hides the marketing that only makes sense on bentopdf.com itself or on a commercial public-facing deployment. **It is not a feature-reduced or "lite" version.** **What the Self-Hosted build hides** (cosmetic only, no PDF features are removed): @@ -818,7 +819,7 @@ The Self-Hosted build (the `bentopdf-simple` image, also called Simple Mode) is - All PDF tools (merge, split, edit, sign, OCR, Office conversion, every other tool) - Custom branding support, all build-time and runtime config -The Commercial build (`ghcr.io/alam00000/bentopdf:latest`) is what powers bentopdf.com itself and is used by commercial license holders running public facing deployments. It adds the hero, FAQ, testimonials, and footer that wouldn't make sense on an internal tool. +The Commercial build (`ghcr.io/alam00000/bentopdf:latest`) is what powers bentopdf.com itself and is used by commercial license holders running public-facing deployments. It adds the hero, FAQ, testimonials, and footer that wouldn't make sense on an internal tool. If you're self-hosting BentoPDF for your team, organization, or as an internal tool, pull `ghcr.io/alam00000/bentopdf-simple:latest`. For more details, see [SIMPLE_MODE.md](SIMPLE_MODE.md). @@ -934,6 +935,24 @@ You can also disable specific features inside the PDF Editor (e.g., redaction, f For the full list of editor categories, see the [self-hosting docs](https://bentopdf.com/docs/self-hosting/docker#disabling-editor-features). +### 🔕 Disabling the GitHub Star Counter + +The navbar shows a live GitHub star count, fetched from `api.github.com` on page load. The only external request that isn't serving a PDF feature. Self-hosters who want zero non-essential network calls can disable it at build time. This removes the fetch code from the bundle entirely and drops `api.github.com` from the Content-Security-Policy. + +Simple Mode builds (`bentopdf-simple`) always skip the star counter — this flag is only needed on the Commercial build or custom full builds. + +**Docker:** + +```bash +docker build --build-arg DISABLE_GITHUB_STARS=true -t bentopdf . +``` + +**Building from source:** + +```bash +DISABLE_GITHUB_STARS=true npm run build +``` + ### 🔒 Security Features BentoPDF runs as a non-root user using nginx-unprivileged for enhanced security: diff --git a/STATIC-HOSTING.md b/STATIC-HOSTING.md index c00dbe5b..434039db 100644 --- a/STATIC-HOSTING.md +++ b/STATIC-HOSTING.md @@ -1,18 +1,18 @@ # Hosting BentoPDF as a static website -As an alternative to runnning BenotPDF locally or in a Docker container, you can very easily host it as a set of static web pages. Here are a few examples: +As an alternative to running BentoPDF locally or in a Docker container, you can easily host it as a set of static web pages. Here are a few examples: ## Netlify ### Netlify - static deployment -One of simplest ways to host BentoPDF is to create a project at [Netlify](https://www.netlify.com/) and create a static deployment. You can accomplish this by first downloading the pre-built distribution file from our [GitHub releases](https://github.com/alam00000/bentopdf/releases). Each release includes a `dist-{version}.zip` file that contains all necessary files for self-hosting. +One of the simplest ways to host BentoPDF is to create a project at [Netlify](https://www.netlify.com/) and create a static deployment. You can accomplish this by first downloading the pre-built distribution file from our [GitHub releases](https://github.com/alam00000/bentopdf/releases). Each release includes a `dist-{version}.zip` file that contains all necessary files for self-hosting. 1. Go to [BentoPDF Releases](https://github.com/alam00000/bentopdf/releases) 2. Download the latest `dist-{version}.zip` file 3. Next, if you have not already done so, create a Netlify account and log in. 4. From your Netlify projects page, add a new project and select "Deploy manually". -5. Drag and drop to upload the Bentopdf zip file you downloaded in step 3. +5. Drag and drop to upload the BentoPDF zip file you downloaded in step 2. 6. Your BentoPDF deployment should now be working! Optionally, you can go into Project Configuration and change the project name. When a new BentoPDF release becomes available, you will need to repeat steps 1-3, then go into "Deploys" and upload the new release. @@ -21,7 +21,7 @@ When a new BentoPDF release becomes available, you will need to repeat steps 1-3 Alternatively, you can configure a Netlify project to automatically deploy whenever your BentoPDF is updated. -1. If you have not done so already, create a fork of BentoPDF into your own Github account. +1. If you have not done so already, create a fork of BentoPDF into your own GitHub account. 2. If you have not already done so, create a Netlify account and log in. 3. From your Netlify projects page, add a new project and select 'Import an existing project'. 4. Select the GitHub button, authorize Netlify, then choose where to install the integration. You can choose 'All repositories' or 'Only select repositories' and choose your BentoPDF fork. @@ -36,7 +36,7 @@ If you want to use BentoPDF's simple mode, go into Deploy Settings, then Environ Vercel provides similar services to Netlify dynamic hosting. -1. If you have not done so already, create a fork of BentoPDF into your own Github account. +1. If you have not done so already, create a fork of BentoPDF into your own GitHub account. 2. If you have not already done so, create a Vercel account and log in. 3. From your Vercel Overview page, select 'Add new project' 4. Under 'Import Git Repository' and then choose 'Add GitHub Account'. Follow the prompts to authorize Vercel integration. You can choose 'All repositories' or 'Only select repositories' and choose your BentoPDF fork. @@ -44,15 +44,15 @@ Vercel provides similar services to Netlify dynamic hosting. 6. Under 'Framework Preset', select 'Vite' and save the settings. 7. The Vercel build & deploy process will kick off. Once it finishes, you can click on the provided link to view your deployment of BentoPDF. -Whenever the BentoPDF source code is updated, you can sync the changes into your repo. This will kick off a new build and deploy within BentoPDF. +Whenever the BentoPDF source code is updated, you can sync the changes into your repo. This will kick off a new build and deploy within Vercel. If you want to use BentoPDF's simple mode, go into Project Settings, then Environment Variables, and Create a new variable. Add `SIMPLE_MODE` and set it to `true`. You will need to redeploy to get this to take effect. ## GitHub Pages -You can also host your own instance of BentoPDF using GitHub pages. An advantage of this over the other options is you are able to do everything in GitHub without any third party service. +You can also host your own instance of BentoPDF using GitHub Pages. An advantage of this over the other options is you are able to do everything in GitHub without any third-party service. -1. If you have not done so already, create a fork of BentoPDF into your own Github account. +1. If you have not done so already, create a fork of BentoPDF into your own GitHub account. 2. From your fork, go to `Settings->Pages`, and change the 'Source' to 'GitHub Actions' 3. Go to `Settings->Secrets and Variables > Actions`, then select 'Variables', and add the repository variable `BASE_URL`. Set the value to `/bentopdf`. _If you've renamed the repo to something other than bentopdf, put that here_. 4. Go to `Actions` in the top menu, and select 'I understand' to enable Actions diff --git a/TRANSLATION.md b/TRANSLATION.md index 94ba8f8e..579a5ea2 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -400,7 +400,7 @@ Some strings contain HTML or special characters: ```json { - "faq.analytics.answer": "We care about your privacy. BentoPDF does not track personal information. We use Simple Analytics solely to see anonymous visit counts." + "faq.analytics.answer": "No. BentoPDF does not track you at all. We do not use cookies, analytics, or any tracking scripts, not even on the live website at bentopdf.com. We never know who you are or what you do with the tools." } ``` @@ -408,7 +408,7 @@ When translating, **keep the HTML tags intact**: ```json { - "faq.analytics.answer": "Wir schätzen Ihre Privatsphäre. BentoPDF verfolgt keine persönlichen Informationen. Wir verwenden Simple Analytics ausschließlich, um anonyme Besucherzahlen zu sehen." + "faq.analytics.answer": "Nein. BentoPDF verfolgt Sie in keiner Weise. Wir verwenden keine Cookies, keine Analysetools und keine Tracking-Skripte – auch nicht auf der Live-Website bentopdf.com. Wir wissen nie, wer Sie sind oder was Sie mit den Tools tun." } ``` diff --git a/about.html b/about.html index 2574cc78..cb1c1063 100644 --- a/about.html +++ b/about.html @@ -145,7 +145,7 @@ data-i18n="about.philosophy.description" > In an era where data is a commodity, we take a different approach. - All processing for Bentopdf tools happens locally in your browser. + All processing for BentoPDF tools happens locally in your browser. This means your files never touch our servers, we never see your documents, and we don't track what you do. Your documents remain completely and unequivocally private. It's not just a feature; @@ -172,7 +172,7 @@

Why - Bentopdf? + BentoPDF?

@@ -280,7 +280,7 @@ class="text-lg text-gray-400 mb-8 max-w-2xl mx-auto" data-i18n="about.cta.description" > - Join thousands of users who trust Bentopdf for their daily document + Join thousands of users who trust BentoPDF for their daily document needs. Experience the difference that privacy and performance can make.

diff --git a/bentopdf-airgap-bundle/bentopdf-gs-wasm-0.1.1.tgz b/bentopdf-airgap-bundle/bentopdf-gs-wasm-0.1.1.tgz new file mode 100644 index 00000000..d131181e Binary files /dev/null and b/bentopdf-airgap-bundle/bentopdf-gs-wasm-0.1.1.tgz differ diff --git a/bentopdf-airgap-bundle/bentopdf-pymupdf-wasm-0.11.16.tgz b/bentopdf-airgap-bundle/bentopdf-pymupdf-wasm-0.11.16.tgz new file mode 100644 index 00000000..d51067a5 Binary files /dev/null and b/bentopdf-airgap-bundle/bentopdf-pymupdf-wasm-0.11.16.tgz differ diff --git a/chart/Chart.yaml b/chart/Chart.yaml index bb624b8e..5f9f397f 100644 --- a/chart/Chart.yaml +++ b/chart/Chart.yaml @@ -7,10 +7,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.0.6 +version: 1.0.7 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: '2.8.7' +appVersion: '2.8.8' diff --git a/chart/README.md b/chart/README.md index 18b63672..bc682c25 100644 --- a/chart/README.md +++ b/chart/README.md @@ -91,7 +91,7 @@ helm package . helm push bentopdf-*.tgz oci://ghcr.io/$GHCR_USERNAME/charts ``` -This could be automated as part of a Github workflow. +This could be automated as part of a GitHub workflow. ### Deploy diff --git a/cloudflare/wrangler.toml b/cloudflare/wrangler.toml index 491b4ae2..1a4b1594 100644 --- a/cloudflare/wrangler.toml +++ b/cloudflare/wrangler.toml @@ -3,7 +3,7 @@ main = "cors-proxy-worker.js" compatibility_date = "2024-01-01" # Deploy to Cloudflare's global network -# If you are self hosting change the name to your worker name +# If you are self-hosting, change the name to your worker name # Run: npx wrangler deploy # ============================================================================= diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index d6e327eb..f7ec0fa6 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -132,6 +132,7 @@ export default defineConfig({ { text: 'OCR PDF', link: '/tools/ocr-pdf' }, { text: 'Merge PDF', link: '/tools/merge-pdf' }, { text: 'Alternate & Mix Pages', link: '/tools/alternate-merge' }, + { text: 'Duplex Collate', link: '/tools/duplex-collate' }, { text: 'Organize & Duplicate', link: '/tools/organize-pdf' }, { text: 'Add Attachments', link: '/tools/add-attachments' }, { text: 'Extract Attachments', link: '/tools/extract-attachments' }, diff --git a/docs/self-hosting/docker.md b/docs/self-hosting/docker.md index 2baff7f0..54f7297b 100644 --- a/docs/self-hosting/docker.md +++ b/docs/self-hosting/docker.md @@ -115,6 +115,7 @@ docker run -d -p 3000:8080 bentopdf:custom | `VITE_BRAND_LOGO` | Logo path relative to `public/` | `images/favicon-no-bg.svg` | | `VITE_FOOTER_TEXT` | Custom footer/copyright text | `© 2026 BentoPDF. All rights reserved.` | | `DISABLE_TOOLS` | Comma-separated tool IDs to hide | _(empty; all tools enabled)_ | +| `DISABLE_GITHUB_STARS` | Skip the GitHub star-count fetch on page load and drop `api.github.com` from the CSP. Simple Mode builds always skip it. | `false` | WASM module URLs are pre-configured with CDN defaults — all advanced features work out of the box. Override these for air-gapped or self-hosted deployments. @@ -263,6 +264,16 @@ You can also disable specific features inside the PDF Editor (e.g., redaction, a Categories are hierarchical — disabling a parent (e.g., `annotation`) disables all its children. +### Disabling the GitHub Star Counter + +The navbar shows a live GitHub star count, fetched from `api.github.com` on page load. The only external request that isn't serving a PDF feature. Disable it at build time to remove the fetch code from the bundle and drop `api.github.com` from the Content-Security-Policy: + +```bash +docker build --build-arg DISABLE_GITHUB_STARS=true -t bentopdf . +``` + +Simple Mode builds (`bentopdf-simple`) always skip the star counter — this flag is only needed on the Commercial build or custom full builds. + ### Custom WASM URLs (Air-Gapped / Self-Hosted) > [!IMPORTANT] diff --git a/docs/tools/add-watermark.md b/docs/tools/add-watermark.md index ac0fe85c..faf44b3f 100644 --- a/docs/tools/add-watermark.md +++ b/docs/tools/add-watermark.md @@ -33,6 +33,13 @@ Add text or image watermarks to your PDF pages using a visual editor. You can po - **Opacity** -- Control image transparency. - **Scale** -- Resize the image watermark. +**Layout settings:** + +- **Single** -- One watermark per page, positioned by dragging or with the position presets. +- **Tiled** -- Repeats the watermark across the whole page in a diagonal grid that follows the rotation angle, so the mark covers the document from edge to edge. +- **Horizontal gap** -- Spacing between tiles along the text direction, as a percentage of the watermark width (tiled mode only). +- **Vertical gap** -- Spacing between tile rows, as a percentage of the watermark height (tiled mode only). + **General settings:** - **Apply to all pages** -- When checked, the same watermark applies to every page. Uncheck to set individual watermarks per page. @@ -43,6 +50,7 @@ Add text or image watermarks to your PDF pages using a visual editor. You can po - Visual drag-and-drop positioning on a live PDF preview - Resizable watermark with corner handles - Text and image watermark modes +- Single or full-page tiled (repeating) layout with adjustable spacing - Per-page or global watermark application - Page-by-page navigation in the preview - Opacity and rotation controls @@ -59,6 +67,7 @@ Add text or image watermarks to your PDF pages using a visual editor. You can po ## Tips - For diagonal watermarks across the page, set a rotation around 45 degrees and increase the font size. +- Tiled mode makes a document much harder to reuse after cropping, since removing one mark still leaves dozens behind. Lower the opacity when tiling so the underlying text stays readable. - Image watermarks with transparent backgrounds (PNG format) blend more naturally with the document content. - If you need different watermark text on different pages, uncheck "Apply to all pages" and navigate page by page. diff --git a/docs/tools/duplex-collate.md b/docs/tools/duplex-collate.md new file mode 100644 index 00000000..fbeea003 --- /dev/null +++ b/docs/tools/duplex-collate.md @@ -0,0 +1,55 @@ +--- +title: Duplex Collate +description: Reorder duplex scan PDFs that contain front pages and back pages in separate blocks into proper front/back page order. +--- + +# Duplex Collate + +Duplex Collate is designed for ADF scan workflows where one PDF contains two blocks of pages: + +- all front sides first +- all back sides second + +Instead of manually splitting and reassembling, this tool interleaves the two blocks into natural reading order: front1, back1, front2, back2, and so on. + +## How It Works + +1. Upload a single PDF created from duplex stack scanning. +2. Set the split point where the front block ends. +3. Choose back block handling: + - **Reverse back block** (common when the stack is flipped before scanning backs) + - **Keep back block as-is** +4. Click **Collate PDF** to download the reordered result. + +## Options + +- **Auto-detect split (half)**: sets the split point to `ceil(totalPages / 2)`. +- **Odd page warning**: warns when total pages are odd (often a scan mismatch). +- **Uneven block confirmation**: asks for confirmation when front/back block sizes differ. +- **Grouped export**: split the collated output into separate PDFs based on original document page count and download as ZIP. + +## Output Behavior + +- **Default**: one output PDF (single input PDF in, single output PDF out). +- **Grouped mode**: output is chunked by your pages-per-document value; if multiple chunks are produced, they are downloaded as one ZIP, otherwise a single PDF is downloaded. + +If block sizes are uneven, paired pages are collated first, and remaining unpaired pages are appended at the end. + +## Common Use Cases + +- Restoring order after scanning a pile of double-sided forms in two passes. +- Rebuilding front/back packets from office scanners that output all fronts then all backs. +- Post-processing archive scans before splitting into per-document files. + +## Tips + +- Most duplex batches should have an even total page count. +- If output looks inverted on backs, switch between **Reverse back block** and **Keep back block as-is**. +- For 2-page originals (front+back), use grouped export with `2` pages per document. + +## Related Tools + +- [Alternate & Mix Pages](./alternate-merge) +- [Split PDF](./split-pdf) +- [Merge PDF](./merge-pdf) +- [Organize & Duplicate](./organize-pdf) diff --git a/docs/tools/index.md b/docs/tools/index.md index 2b507dd7..08b4053a 100644 --- a/docs/tools/index.md +++ b/docs/tools/index.md @@ -117,6 +117,7 @@ Rearrange, combine, split, and manage your PDF pages and files. - [**OCR PDF**](./ocr-pdf) — Make a PDF searchable and copyable. - [**Merge PDF**](./merge-pdf) — Combine multiple PDFs into one file. - [**Alternate & Mix Pages**](./alternate-merge) — Merge PDFs by alternating pages from each PDF. +- [**Duplex Collate**](./duplex-collate) — Reorder front/back scan blocks into proper page sequence. - [**Organize & Duplicate**](./organize-pdf) — Duplicate, reorder, and delete pages. - [**Add Attachments**](./add-attachments) — Embed one or more files into your PDF. - [**Extract Attachments**](./extract-attachments) — Extract all embedded files from PDF(s) as a ZIP. diff --git a/eslint.config.mjs b/eslint.config.mjs index 0c303c25..8fdab9f1 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -26,6 +26,7 @@ export default [ ], }, { languageOptions: { globals: { ...globals.browser, ...globals.node } } }, + pluginJs.configs.recommended, ...tseslint.configs.recommended, eslintConfigPrettier, @@ -89,4 +90,14 @@ export default [ 'no-misleading-character-class': 'warn', }, }, + { + files: ['src/js/editcore/**/*.js'], + rules: { + 'no-useless-assignment': 'off', + 'security/detect-unsafe-regex': 'off', + 'security/detect-object-injection': 'off', + 'no-unsanitized/property': 'off', + 'no-empty': 'off', + }, + }, ]; diff --git a/faq.html b/faq.html index daee6bf1..9b68744f 100644 --- a/faq.html +++ b/faq.html @@ -226,19 +226,10 @@

- We care about your privacy. BentoPDF does not track personal - information. We use - Simple Analytics - solely to see anonymous visit counts. This means we can know how - many users visit our site, but - we never know who you are. Simple Analytics is - fully GDPR-compliant and respects your privacy. + No. BentoPDF does not track you at all. We do not use cookies, + analytics, or any tracking scripts, not even on the live website + at bentopdf.com. We never know who you are or what you do with the + tools.

@@ -342,7 +333,7 @@ "name": "Do you track my activity on BentoPDF?", "acceptedAnswer": { "@type": "Answer", - "text": "We care about your privacy. BentoPDF does not track personal information. We use Simple Analytics solely to see anonymous visit counts. This means we can know how many users visit our site, but we never know who you are. Simple Analytics is fully GDPR-compliant and respects your privacy." + "text": "No. BentoPDF does not track you at all. We do not use cookies, analytics, or any tracking scripts, not even on the live website at bentopdf.com. We never know who you are or what you do with the tools." } }, { diff --git a/index.html b/index.html index 78ac6396..52177c01 100644 --- a/index.html +++ b/index.html @@ -780,7 +780,7 @@ - +
@@ -1010,19 +1010,10 @@ class="faq-answer max-h-0 overflow-hidden transition-all duration-300 ease-in-out" >

- We care about your privacy. BentoPDF does not track personal - information. We use - Simple Analytics - solely to see anonymous visit counts. This means we can know how - many users visit our site, but - we never know who you are. Simple Analytics is - fully GDPR-compliant and respects your privacy. + No. BentoPDF does not track you at all. We do not use cookies, + analytics, or any tracking scripts, not even on the live website + at bentopdf.com. We never know who you are or what you do with the + tools.

diff --git a/licensing.html b/licensing.html index c0efbb65..9027743f 100644 --- a/licensing.html +++ b/licensing.html @@ -306,6 +306,25 @@ > without sharing your source code, you must purchase a commercial license. + The commercial license covers BentoPDF only and grants no + rights to + Kura + or + Hyper Compress.

@@ -912,6 +931,47 @@

+ +
+ +
+

+ No. The BentoPDF commercial license covers BentoPDF + only. + It grants no rights to + Kura + or + Hyper Compress. Those are separate projects with their own licenses, and any + commercial use of them must be licensed separately. +

+
+
diff --git a/nginx.conf b/nginx.conf index a6f82b2b..fccb0cc3 100644 --- a/nginx.conf +++ b/nginx.conf @@ -119,7 +119,7 @@ http { } location ~* \.json$ { - expires 1w; + expires epoch; } location ~* \.pdf$ { diff --git a/package-lock.json b/package-lock.json index bf04e701..39c210d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bento-pdf", - "version": "2.8.6", + "version": "2.8.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "bento-pdf", - "version": "2.8.6", + "version": "2.8.7", "license": "AGPL-3.0-only", "dependencies": { "@fontsource/cedarville-cursive": "^5.2.7", @@ -27,12 +27,13 @@ "@types/node-forge": "^1.3.14", "@types/papaparse": "^5.5.2", "archiver": "^7.0.1", + "bentopdf-pdfium": "file:vendor/bentopdf-pdfium/bentopdf-pdfium-8ff5002c6cd5.tgz", + "bentopdf-viewer": "file:vendor/bentopdf-viewer/bentopdf-viewer-8ff5002c6cd5.tgz", "blob-stream": "^0.1.3", "bwip-js": "^4.8.0", "cropperjs": "^1.6.2", "diff": "^8.0.3", "dompurify": "^3.4.12", - "embedpdf-snippet": "file:vendor/embedpdf/embedpdf-snippet-2.9.1.tgz", "fast-xml-parser": "^5.7.1", "heic2any": "^0.0.4", "highlight.js": "^11.11.1", @@ -57,7 +58,7 @@ "markdown-it-sup": "^2.0.0", "markdown-it-task-lists": "^2.1.1", "markdown-it-toc-done-right": "^4.2.0", - "mermaid": "^11.16.0", + "mermaid": "^11.16.1", "microdiff": "^1.5.0", "node-forge": "^1.4.0", "papaparse": "^5.5.3", @@ -448,6 +449,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -457,6 +459,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -466,6 +469,7 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -490,6 +494,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -725,564 +730,6 @@ } } }, - "node_modules/@embedpdf/core": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-2.9.1.tgz", - "integrity": "sha512-DlFV2o+tv9S+j4TeBVkRaIjjE9o3Tq3+hvJNoIOFtl87cR77UVQqEIRqOf61yk85Y+T2LfmnVPWjNcMuiKUh8w==", - "license": "MIT", - "dependencies": { - "@embedpdf/engines": "2.9.1", - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/engines": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/engines/-/engines-2.9.1.tgz", - "integrity": "sha512-zyUdKgM2BZVzkqkbIMiTPAKIdH4M3bRV91P1nXUJUU94AmL9DrDrMkf2Nv6+S0bxGt19OpqDlclGSRZ8txhbGw==", - "license": "MIT", - "dependencies": { - "@embedpdf/fonts-arabic": "1.0.0", - "@embedpdf/fonts-hebrew": "1.0.0", - "@embedpdf/fonts-jp": "1.0.0", - "@embedpdf/fonts-kr": "1.0.0", - "@embedpdf/fonts-latin": "1.0.0", - "@embedpdf/fonts-sc": "1.0.0", - "@embedpdf/fonts-tc": "1.0.0", - "@embedpdf/models": "2.9.1", - "@embedpdf/pdfium": "2.9.1" - }, - "peerDependencies": { - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/fonts-arabic": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@embedpdf/fonts-arabic/-/fonts-arabic-1.0.0.tgz", - "integrity": "sha512-SnGvQb+LwPZQO2WjjvlmXrJZolJUfLYbLZQSaYUw1vrQyMyJKT4LewvJGG+hZ+Yz2fz7OMIQ+4Gc98mGODZtOg==", - "license": "OFL-1.1" - }, - "node_modules/@embedpdf/fonts-hebrew": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@embedpdf/fonts-hebrew/-/fonts-hebrew-1.0.0.tgz", - "integrity": "sha512-5HVAKGL7VqPeTxxADDrSqAFBxfmAXdP8fIqrPwJIKkqdK2643bOer8CqnnpO3/nPoFhkzxhttWMB9BGiqSW62w==", - "license": "OFL-1.1" - }, - "node_modules/@embedpdf/fonts-jp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@embedpdf/fonts-jp/-/fonts-jp-1.0.0.tgz", - "integrity": "sha512-BY2tv/mcICUUKf+M/bizf3RU65PMqKClJ/e5o9mgMibxyML0OQvEDwYMRPODQkKgJKXCO3ScHmVvcmXp6kt+fA==", - "license": "OFL-1.1" - }, - "node_modules/@embedpdf/fonts-kr": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@embedpdf/fonts-kr/-/fonts-kr-1.0.0.tgz", - "integrity": "sha512-bh88HXSvOBS581kgmihWY7Ijp9hBsvlmXogFG5LSNx9UBAobRcakZiFMGieRBc06hUSkpo7WhjaFM/z/SfQ8dQ==", - "license": "OFL-1.1" - }, - "node_modules/@embedpdf/fonts-latin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@embedpdf/fonts-latin/-/fonts-latin-1.0.0.tgz", - "integrity": "sha512-LLYysdr8O6sRNzhmW3PbF3AeA8xnqvOi4XLFfIfNlW5uEZ+qsJdcfd78Q78sFJMhlaOAYFMziMMsnOzmx463rA==", - "license": "OFL-1.1" - }, - "node_modules/@embedpdf/fonts-sc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@embedpdf/fonts-sc/-/fonts-sc-1.0.0.tgz", - "integrity": "sha512-ETXl7XCwaQLSSvMO3EUDwMNqtL64kX2LlFxarTRi/NsIGGOIxUurGfKtrkmtnKHrWy1jAJSt6oxK2uJhvdvQIw==", - "license": "OFL-1.1" - }, - "node_modules/@embedpdf/fonts-tc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@embedpdf/fonts-tc/-/fonts-tc-1.0.0.tgz", - "integrity": "sha512-rGZJbVD6DYS5BbXdpEMnWkpVF0Knar+bsiyb2o3+YRx7O8eyFubEBQUSUInirQk69HA6fc3GhYCg7TyC/oD76Q==", - "license": "OFL-1.1" - }, - "node_modules/@embedpdf/models": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/models/-/models-2.9.1.tgz", - "integrity": "sha512-hUKj30D+a9dDOQlbqbrpjaECDPIcw/526Vo/s+eqJBY8zDNUkZ6meX+aVUrKg8+ApBm2dcEdVo3ff7KgNRhUGw==", - "license": "MIT" - }, - "node_modules/@embedpdf/pdfium": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/pdfium/-/pdfium-2.9.1.tgz", - "integrity": "sha512-GUu1rDF3XP8X7UpQNnOCvc/jAX/Tw0NoUpOF0aEksVZ6CoujBxtu84P3kWAxcJl6cicyIJq1GAp9szHBSYrTrQ==", - "license": "MIT" - }, - "node_modules/@embedpdf/plugin-annotation": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-annotation/-/plugin-annotation-2.9.1.tgz", - "integrity": "sha512-aNtXjI3NUwz7kdmWsQIWzuS1QdZmuHXGCc+Kwl9u5O0PAgoj74OLsgoNEcFzz9m1rljyq3WPVnLczO6ByiifpQ==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1", - "@embedpdf/utils": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-history": "2.9.1", - "@embedpdf/plugin-interaction-manager": "2.9.1", - "@embedpdf/plugin-selection": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-attachment": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-attachment/-/plugin-attachment-2.9.1.tgz", - "integrity": "sha512-7fPPHLWHZE9SXZRPnibo6o/AkuiknJQckdNgO16g9EdbPbO6IDNg/8e8pyjK4Knc+ckyyF4gnJ1lemWswSELUw==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-bookmark": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-bookmark/-/plugin-bookmark-2.9.1.tgz", - "integrity": "sha512-5qgz4yBFEi6h1cogvn9q9CBObGdNLVfkX809kVNPHuRIYsghEieqYkdoh1BNwdP/bm9+D7a6pcXZrVvbXs5e5w==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-capture": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-capture/-/plugin-capture-2.9.1.tgz", - "integrity": "sha512-bIix6Z69ADBzJ7ZJ3MkU2I+rZkR/f6Sk0NwjLvYzF+C0aWTptBuU442/gydBGJpSjExhENeVrzMpgUhuijQ6sA==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-interaction-manager": "2.9.1", - "@embedpdf/plugin-render": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-commands": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-commands/-/plugin-commands-2.9.1.tgz", - "integrity": "sha512-sj74w52U05l5xO/5XZTyrALMBZbp5noWOdFK9d6p25onRq2Vc6Etw1PBtjWuI5I9VH5ICVivt0c0OB/0zb8Ipg==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-document-manager": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-document-manager/-/plugin-document-manager-2.9.1.tgz", - "integrity": "sha512-TrqkZvPIQxcWikL9Fmm8/qAJvI+uG7ahPXuyGyyF0JxkrrHCkUMCL8SPJN/fntcPnLJRIi3/K/xR5Qnt/L0aAg==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-export": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-export/-/plugin-export-2.9.1.tgz", - "integrity": "sha512-oYl8H0km1m75SYz17mVwxm9ljZvW0yBV8sTcyCa7YhnqE7yxtczu7jw3BrU3KW4Sua9mr9izhs3AixvWkTASQg==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-fullscreen": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-fullscreen/-/plugin-fullscreen-2.9.1.tgz", - "integrity": "sha512-1afbocRTpvzdXdh7X2hhKvGTKWIfvHz/waf5wKDUPlOM4Bpi6a4/x+MWPq2SwtTo/74iRDULprcc2dTVf4IK0Q==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-history": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-history/-/plugin-history-2.9.1.tgz", - "integrity": "sha512-3AcvSTT7fmqe1ve/FvR3lJ5q7t5JYmnnAg8LKc9ATsDjS9J5b0WE03Omz9a8/sL19iKq8xeR1+W28phgvlcKNw==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-i18n": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-i18n/-/plugin-i18n-2.9.1.tgz", - "integrity": "sha512-0B2dEamhKQRv1n36skMQAf/1qicf/0tVQD8A++6o9/af2xUFdqqC8yCCW0EJCe2GJRbITWQr6vIAU7VilisBuQ==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-interaction-manager": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-2.9.1.tgz", - "integrity": "sha512-/wpdStr1NeyMCvAEMVSCPC0a3zaMd+TSK4u8INsIo3b1RoFfb9iTlBB+qW/aaxvZJ/C7MChQ7cLX6VSKXK/6JQ==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-pan": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-pan/-/plugin-pan-2.9.1.tgz", - "integrity": "sha512-LH5fp/2xKWuEYb5cc5jNWdXkhgOL+8TEf4oLcgao6hK33aV1xry+HAg5ATy+OPpIJItCwjU/Lk7Mc7uibYcFlA==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-interaction-manager": "2.9.1", - "@embedpdf/plugin-viewport": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-print": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-print/-/plugin-print-2.9.1.tgz", - "integrity": "sha512-brTn0R8AVyAfpm0SYxz/8bg0e373n4KaeIgw5E51DSrczVr3zIgqYGSvXFbfbv57ZUp63Hb93sVorP1et2AeUw==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=18.0.0", - "react-dom": ">=18.0.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-redaction": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-redaction/-/plugin-redaction-2.9.1.tgz", - "integrity": "sha512-2R81U4ex/JU4IAJ0+G3eIMOwpq80HnAIZ2sI5yMhkDbz+ZZE/sdAP4JKTOFIbhTkwk7DmC222yW34dQJoX4tRQ==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1", - "@embedpdf/utils": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-annotation": "2.9.1", - "@embedpdf/plugin-history": "2.9.1", - "@embedpdf/plugin-interaction-manager": "2.9.1", - "@embedpdf/plugin-selection": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-render": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-2.9.1.tgz", - "integrity": "sha512-mtfu6uDxlz3+j0xPXfKyvuu8iCFjapPkbnx8vGQ0z2PBNAMm+05hsNIzxJSGMP2VCFo09SOz2zCs7ch9J6NeNg==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-rotate": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-rotate/-/plugin-rotate-2.9.1.tgz", - "integrity": "sha512-OgfMI2IsSPHKs4A0DGpmHpxuhoBcZjvw+tz+CXGBi6ILL6oS7z5wXhoMZfRgCgkvjII8RnmjBvmLeahoSaepAA==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-scroll": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-2.9.1.tgz", - "integrity": "sha512-+U3PSIUuNlIOTXzRhnPBP+Rx20sFOd3OPiowyI2EP/Kx/j5R/amgL/t2rjrpw9gjXEMEGsli9Fn4UqnVgMrPaQ==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-viewport": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-search": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-search/-/plugin-search-2.9.1.tgz", - "integrity": "sha512-NefZgXPfj1MW8i5bYEfuphpXXAODutJTtwCHpLff1YwPw6liuBug9G1lDKSpNddvp+7aSkTcXV5LYNhcPxb1vg==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-selection": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-2.9.1.tgz", - "integrity": "sha512-dVLjiLGnZDo0xO7lZulLGl3cJ/mO7BcA3PGO2uMdhqSWK4tAF/DrakvwXdD581VBwXD/C25EJhxiNa2L7mU4wg==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1", - "@embedpdf/utils": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-interaction-manager": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-spread": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-spread/-/plugin-spread-2.9.1.tgz", - "integrity": "sha512-s9J4tvoucNac8pUAHVhv3PWDWMZJyK0ikaG78VdGwh4G2iMo5HW1LKDJkJ29l1TjAuxhIoKihpfQbLgUgi7JHA==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-thumbnail": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-thumbnail/-/plugin-thumbnail-2.9.1.tgz", - "integrity": "sha512-TAEUkVxvvB5kh2VVGf9RMuJFq++CQgWpKJ62ed2GhB9WvVKP5gBYj7G5ff90TLCrAV8iXZL9ENKcHgGKxrZrYw==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-render": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-tiling": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-tiling/-/plugin-tiling-2.9.1.tgz", - "integrity": "sha512-UQ/gr/Rdzj7sMsgvtuClw6Jq25fMr+OEdW4tQmg2bV/MqpKptpOEUZ5Aiay4M03X3cgoxhS8UvobRMnjlpYljA==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-render": "2.9.1", - "@embedpdf/plugin-scroll": "2.9.1", - "@embedpdf/plugin-viewport": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-ui": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-ui/-/plugin-ui-2.9.1.tgz", - "integrity": "sha512-nub5aaf0Ntxq9U5yRUMA496etUkI/AbADba6xE7oJ7u4gyTcEndY19pnIwm/eRYcHCU09d7QWcn3bjtIX3PP2g==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-render": "2.9.1", - "@embedpdf/plugin-scroll": "2.9.1", - "@embedpdf/plugin-viewport": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-viewport": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-2.9.1.tgz", - "integrity": "sha512-bVhBuZHTppKV+OB5lBLqXQv+5oW1A7kAIc5UzsImBwl6NpwH+2PdVkelfrF37yEqnEF/mdxobriWSP0aOVl93w==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/plugin-zoom": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/plugin-zoom/-/plugin-zoom-2.9.1.tgz", - "integrity": "sha512-FVOYj+AKTc2aCPrZHOrgbiYNTfBmiwVpFCedmqeGLYOIYTIeGzwJlyIHLU0PmIC/nuHcu1ZFwh0tH23fWAfVCQ==", - "license": "MIT", - "dependencies": { - "@embedpdf/models": "2.9.1" - }, - "peerDependencies": { - "@embedpdf/core": "2.9.1", - "@embedpdf/plugin-scroll": "2.9.1", - "@embedpdf/plugin-viewport": "2.9.1", - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, - "node_modules/@embedpdf/utils": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@embedpdf/utils/-/utils-2.9.1.tgz", - "integrity": "sha512-IKe/k5DruzpuyGJBIoLEL9AKJ9rEBDLgi1eSCWQPyYkuLWTJg4rBzyGh57eS4S4K4dzQrlJ3Z9zGAW1mgbY2Jw==", - "license": "MIT", - "peerDependencies": { - "preact": "^10.26.4", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "svelte": ">=5 <6", - "vue": ">=3.2.0" - } - }, "node_modules/@emnapi/core": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", @@ -2871,16 +2318,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@sveltejs/acorn-typescript": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz", - "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "acorn": "^8.9.0" - } - }, "node_modules/@swc/helpers": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.19.tgz", @@ -3547,6 +2984,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, "license": "MIT" }, "node_modules/@types/geojson": { @@ -3852,6 +3290,7 @@ "version": "8.57.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.1.tgz", "integrity": "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==", + "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4131,6 +3570,7 @@ "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -4144,6 +3584,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -4156,12 +3597,14 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, "license": "MIT" }, "node_modules/@vue/compiler-dom": { "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "dev": true, "license": "MIT", "dependencies": { "@vue/compiler-core": "3.5.30", @@ -4172,6 +3615,7 @@ "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -4189,12 +3633,14 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, "license": "MIT" }, "node_modules/@vue/compiler-ssr": { "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "dev": true, "license": "MIT", "dependencies": { "@vue/compiler-dom": "3.5.30", @@ -4241,6 +3687,7 @@ "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "dev": true, "license": "MIT", "dependencies": { "@vue/shared": "3.5.30" @@ -4250,6 +3697,7 @@ "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "dev": true, "license": "MIT", "dependencies": { "@vue/reactivity": "3.5.30", @@ -4260,6 +3708,7 @@ "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "dev": true, "license": "MIT", "dependencies": { "@vue/reactivity": "3.5.30", @@ -4272,6 +3721,7 @@ "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "dev": true, "license": "MIT", "dependencies": { "@vue/compiler-ssr": "3.5.30", @@ -4285,6 +3735,7 @@ "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "dev": true, "license": "MIT" }, "node_modules/@vueuse/core": { @@ -4679,16 +4130,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/b4a": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", @@ -4829,6 +4270,22 @@ ], "license": "MIT" }, + "node_modules/bentopdf-pdfium": { + "version": "0.0.0-8ff5002c6cd5", + "resolved": "file:vendor/bentopdf-pdfium/bentopdf-pdfium-8ff5002c6cd5.tgz", + "integrity": "sha512-bVDsJNwtan8snh2cibjvRNIjuM1UBvfKNd6OEn9RNYTZddH0JF4ekQBVSMbY9aVBNbNGCIwKPeaAFbrF8Jzvhw==", + "license": "AGPL-3.0" + }, + "node_modules/bentopdf-viewer": { + "version": "2.9.1", + "resolved": "file:vendor/bentopdf-viewer/bentopdf-viewer-8ff5002c6cd5.tgz", + "integrity": "sha512-ucbsz9WeAf2Y8VIsR32dNl/NSgidMi85UFUKgWvUE4i93c4ds0P3u4imfg/T641iWAahbK75agNDfhuuzp2AFQ==", + "license": "MIT", + "dependencies": { + "preact": "^10.17.0", + "tailwind-merge": "^3.4.0" + } + }, "node_modules/bidi-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", @@ -4889,16 +4346,16 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/braces": { @@ -5390,16 +4847,6 @@ "node": ">=0.8" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -5715,6 +5162,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, "license": "MIT" }, "node_modules/cytoscape": { @@ -6352,13 +5800,6 @@ "node": ">=8" } }, - "node_modules/devalue": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz", - "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==", - "license": "MIT", - "peer": true - }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", @@ -6480,45 +5921,6 @@ "dev": true, "license": "MIT" }, - "node_modules/embedpdf-snippet": { - "version": "2.9.1", - "resolved": "file:vendor/embedpdf/embedpdf-snippet-2.9.1.tgz", - "integrity": "sha512-DDKkXVTHmrxbbp3FN19xu7SZCOo8clcZnlwiTb6ovHq2s3nO8SKtE74xIPfYTHXPl/eKpNCQygCc44FnYqyNpQ==", - "license": "MIT", - "dependencies": { - "@embedpdf/core": "^2.9.1", - "@embedpdf/engines": "^2.9.1", - "@embedpdf/models": "^2.9.1", - "@embedpdf/pdfium": "^2.9.1", - "@embedpdf/plugin-annotation": "^2.9.1", - "@embedpdf/plugin-attachment": "^2.9.1", - "@embedpdf/plugin-bookmark": "^2.9.1", - "@embedpdf/plugin-capture": "^2.9.1", - "@embedpdf/plugin-commands": "^2.9.1", - "@embedpdf/plugin-document-manager": "^2.9.1", - "@embedpdf/plugin-export": "^2.9.1", - "@embedpdf/plugin-fullscreen": "^2.9.1", - "@embedpdf/plugin-history": "^2.9.1", - "@embedpdf/plugin-i18n": "^2.9.1", - "@embedpdf/plugin-interaction-manager": "^2.9.1", - "@embedpdf/plugin-pan": "^2.9.1", - "@embedpdf/plugin-print": "^2.9.1", - "@embedpdf/plugin-redaction": "^2.9.1", - "@embedpdf/plugin-render": "^2.9.1", - "@embedpdf/plugin-rotate": "^2.9.1", - "@embedpdf/plugin-scroll": "^2.9.1", - "@embedpdf/plugin-search": "^2.9.1", - "@embedpdf/plugin-selection": "^2.9.1", - "@embedpdf/plugin-spread": "^2.9.1", - "@embedpdf/plugin-thumbnail": "^2.9.1", - "@embedpdf/plugin-tiling": "^2.9.1", - "@embedpdf/plugin-ui": "^2.9.1", - "@embedpdf/plugin-viewport": "^2.9.1", - "@embedpdf/plugin-zoom": "^2.9.1", - "preact": "^10.17.0", - "tailwind-merge": "^3.4.0" - } - }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -6763,13 +6165,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/esm-env": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", - "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", - "license": "MIT", - "peer": true - }, "node_modules/espree": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", @@ -6801,17 +6196,6 @@ "node": ">=0.10" } }, - "node_modules/esrap": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.4.tgz", - "integrity": "sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15", - "@typescript-eslint/types": "^8.2.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -7297,9 +6681,9 @@ "license": "MIT" }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -7919,16 +7303,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-reference": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", - "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "^1.0.6" - } - }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -8092,6 +7466,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, "license": "MIT" }, "node_modules/jsdom": { @@ -8776,13 +8151,6 @@ "@types/trusted-types": "^2.0.2" } }, - "node_modules/locate-character": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", - "license": "MIT", - "peer": true - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -8904,19 +8272,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, "node_modules/lru-cache": { "version": "11.2.7", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", @@ -9154,9 +8509,9 @@ "license": "MIT" }, "node_modules/mermaid": { - "version": "11.16.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.16.0.tgz", - "integrity": "sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==", + "version": "11.16.1", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.16.1.tgz", + "integrity": "sha512-TQsq6u22fAn3rek5VOubrhKPo1g5hwC3FXUN9hiyupTckcYiGuuKGkNQrKYwGJkXUxZdojwRG46gsSCFZMDp4g==", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.2", @@ -9409,9 +8764,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "funding": [ { "type": "github", @@ -10100,9 +9455,9 @@ "license": "MIT-0" }, "node_modules/postcss": { - "version": "8.5.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", - "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "funding": [ { "type": "opencollective", @@ -10119,7 +9474,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -10301,33 +9656,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -10367,9 +9695,9 @@ "license": "MIT" }, "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -10831,16 +10159,6 @@ "node": ">=v12.22.7" } }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "node_modules/search-insights": { "version": "2.17.3", "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", @@ -11419,44 +10737,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/svelte": { - "version": "5.55.7", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.55.7.tgz", - "integrity": "sha512-ymI5ykLPwIHW839E053FQbI1G+jnRFJEw3Kv5Y4njixVWywQBx+NUFpkkKyk5LIb36Fg9DVXSYpqiGekLD0hyw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/remapping": "^2.3.4", - "@jridgewell/sourcemap-codec": "^1.5.0", - "@sveltejs/acorn-typescript": "^1.0.5", - "@types/estree": "^1.0.5", - "@types/trusted-types": "^2.0.7", - "acorn": "^8.12.1", - "aria-query": "5.3.1", - "axobject-query": "^4.1.0", - "clsx": "^2.1.1", - "devalue": "^5.8.1", - "esm-env": "^1.2.1", - "esrap": "^2.2.4", - "is-reference": "^3.0.3", - "locate-character": "^3.0.0", - "magic-string": "^0.30.11", - "zimmerframe": "^1.1.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/svelte/node_modules/aria-query": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", - "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/svg-pathdata": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", @@ -13511,6 +12791,7 @@ "version": "3.5.30", "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "dev": true, "license": "MIT", "dependencies": { "@vue/compiler-dom": "3.5.30", @@ -13860,13 +13141,6 @@ "pdf-lib": "1.17.1" } }, - "node_modules/zimmerframe": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", - "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", - "license": "MIT", - "peer": true - }, "node_modules/zip-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", diff --git a/package.json b/package.json index af7a7966..61ac703d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "bento-pdf", "private": true, - "version": "2.8.7", + "version": "2.8.8", "license": "AGPL-3.0-only", "type": "module", "scripts": { @@ -90,12 +90,13 @@ "@types/node-forge": "^1.3.14", "@types/papaparse": "^5.5.2", "archiver": "^7.0.1", + "bentopdf-pdfium": "file:vendor/bentopdf-pdfium/bentopdf-pdfium-8ff5002c6cd5.tgz", + "bentopdf-viewer": "file:vendor/bentopdf-viewer/bentopdf-viewer-8ff5002c6cd5.tgz", "blob-stream": "^0.1.3", "bwip-js": "^4.8.0", "cropperjs": "^1.6.2", "diff": "^8.0.3", "dompurify": "^3.4.12", - "embedpdf-snippet": "file:vendor/embedpdf/embedpdf-snippet-2.9.1.tgz", "fast-xml-parser": "^5.7.1", "heic2any": "^0.0.4", "highlight.js": "^11.11.1", @@ -120,7 +121,7 @@ "markdown-it-sup": "^2.0.0", "markdown-it-task-lists": "^2.1.1", "markdown-it-toc-done-right": "^4.2.0", - "mermaid": "^11.16.0", + "mermaid": "^11.16.1", "microdiff": "^1.5.0", "node-forge": "^1.4.0", "papaparse": "^5.5.3", diff --git a/pdf-editor.html b/pdf-editor.html index d926a7f7..da9ba6d4 100644 --- a/pdf-editor.html +++ b/pdf-editor.html @@ -116,6 +116,11 @@

Edit PDF

Comprehensive editing

+ + +

Edit PDF Text

+

Rewrite text in place

+

Compress PDF

diff --git a/pdf-merge-split.html b/pdf-merge-split.html index ec312b63..7832d020 100644 --- a/pdf-merge-split.html +++ b/pdf-merge-split.html @@ -14,7 +14,7 @@ /> @@ -164,6 +164,11 @@

Alternate Merge

Interleave PDFs

+ + +

Duplex Collate

+

Front/back sort

+
- Are these pdf security tools really free? + Are these PDF security tools really free?

- Yes! All BentoPDF pdf security tools are 100% free with no hidden + Yes! All BentoPDF PDF security tools are 100% free with no hidden fees, no premium tiers, and no subscription required. Use unlimited tools, unlimited times.

@@ -250,8 +250,8 @@

Absolutely! All processing happens entirely in your browser. Your - files never leave your device, are never uploaded to servers. - Complete privacy guaranteed. + files never leave your device and are never uploaded to servers. + Complete privacy is guaranteed.

diff --git a/privacy.html b/privacy.html index b7dbb7ac..00ca641d 100644 --- a/privacy.html +++ b/privacy.html @@ -83,9 +83,7 @@

Privacy Policy

-

- Last Updated: September 14, 2025 -

+

Last Updated: August 29, 2026