feat: Museum PDF Tool - 100% client-side WebAssembly version#3
feat: Museum PDF Tool - 100% client-side WebAssembly version#3devonurefe wants to merge 1 commit into
Conversation
- Replaced Flask/Python backend with browser-based JS (pdf-lib, pdf.js, JSZip) - Added PWA service worker for full offline support - Added PWA manifest + app icons for Install as App - Created English user guide (guide.html) - Zero server processing, zero AV issues, zero Render.com timeouts
|
This PR was not deployed automatically as @devonurefe does not have access to the Railway project. In order to get automatic PR deploys, please add @devonurefe to your workspace on Railway. |
❌ Deploy Preview for charming-selkie-fc32c4 failed.
|
❌ Deploy Preview for museumprojct failed.
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
Bugbot Free Tier Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| e.preventDefault(); | ||
| if (!globalPdfBytes) return alert("Please select a PDF file first"); | ||
|
|
||
| btnText.textContent = "Processing... (Do not close tab)"; |
There was a problem hiding this comment.
Button SVG icon destroyed on every submission
Medium Severity
The #btn-text span contains an SVG icon as a child element alongside the "Process PDF" text. Assigning to .textContent replaces all child nodes — including the SVG — with a plain text node. After the first form submission, the play icon is permanently removed from the button and is never restored, because the finally block also resets via .textContent rather than targeting just the text node.
Additional Locations (1)
| let allPages = []; | ||
| const indicesSet = new Set(validIndices.map(i => i - 1)); | ||
| validIndices.forEach(i => allPages.push(...ranges[i - 1])); | ||
| allPages.sort((a, b) => a - b); |
There was a problem hiding this comment.
Duplicate block index causes doubled PDF pages
Low Severity
In mergeArticles, the filter(n => n) step removes zeros and NaNs but does not deduplicate valid indices. If a user enters the same block number twice (e.g., "1,1"), validIndices is [1, 1], and the forEach on line 83 pushes ranges[0] into allPages twice. The resulting merged article PDF contains every page from that block duplicated.
| if (start > end || start < 1 || end > maxPages) throw new Error(`Invalid page range: ${part}`); | ||
| const r = []; | ||
| for (let i = start; i <= end; i++) r.push(i); | ||
| ranges.push(r); |
There was a problem hiding this comment.
NaN input silently drops articles in range parser
Medium Severity
In parseRanges, when a range like "1-abc" is entered, Number("abc") produces NaN. All comparisons involving NaN (NaN < 1, NaN > maxPages, start > end) return false, so the validation guard never throws. The for loop condition i <= NaN is immediately false, so r stays []. The empty range is pushed into ranges, and later the article loop hits pagesToCopy.length === 0 and silently continues — the article is dropped from the output ZIP with no error or warning to the user.
| fullText += pageText + "\n\n"; | ||
| } | ||
| return fullText; | ||
| } |
There was a problem hiding this comment.
PDF.js documents never destroyed, leaking worker memory
Medium Severity
Both extractTextFromPdf and renderScaledImages call pdfjsLib.getDocument() and await the resulting pdf object but never call pdf.destroy(). The pdf.js worker holds internal references to each loaded document until explicitly destroyed. With two document loads per article, processing a magazine with many articles accumulates all decoded PDF data in the worker thread simultaneously, which can cause significant memory pressure or an out-of-memory crash in the browser tab.


Note
Medium Risk
Adds a new browser-only processing pipeline (PDF splitting/merging, page exclusion, image rendering, text extraction, ZIP packaging) plus a service worker that caches both local assets and third-party CDN resources, which could introduce runtime/performance issues or caching/update pitfalls.
Overview
Introduces a new
wasm_diststandalone web build of Museum PDF Tool that runs 100% client-side: users select a PDF, define page ranges/merges/exclusions, and the app generates per-article PDFs, thumbnails, extracted text, and a downloadable ZIP viawasm_engine.js.Adds PWA/offline support with
manifest.jsonandservice-worker.js(pre-caching app assets and key CDN libraries), plus a newguide.htmluser guide and updated styling for the new UI.Written by Cursor Bugbot for commit 2d79500. This will update automatically on new commits. Configure here.