Releases: outsharked/find-anything
Release list
v0.8.4
Fixed
- Markdown/RTF content rendered with forced line breaks at storage line-wrap points — the server intentionally wraps long lines at a length cap for the plain/code viewer, but the markdown renderer treated every one of those wrap points as a literal
<br>, turning long sentences into jagged short forced lines. Now renders with CommonMark's default soft-break behavior instead. (#80) - Opening a large file in the viewer could take minutes or appear to hang — the paged file endpoint (
GET /api/v1/file) fetched each line of a page with its own content-store call instead of one query for the whole range. A 2000-line page issued 2000 separate round trips; fixed by batching into a single ranged fetch. Verified against a 100K-line file: the same request dropped from 10+ minutes to ~20ms. (#81)
Full Changelog: v0.8.3...v0.8.4
v0.8.3
Fixed
- Links inside rendered markdown/RTF content did nothing on click — SvelteKit's client-side router intercepted same-origin
<a>clicks and performed a "soft" navigation viapushStatethat never firedpopstateor a load function, so clicking a link inside a markdown doc (e.g. the demo's "About" page) changed the URL but left the view frozen. (#76)
Internal
- CI: pinned
cargo-watch/cargo-llvm-covto fixed versions and scoped the web job'smise installto skip them, fixing intermittent crates.io index-lookup timeouts. (#77) - CI: fixed the Windows release build, which was downloading an HTML landing page instead of the Inno Setup installer after an upstream change to jrsoftware.org's download flow. (#79)
Full Changelog: v0.8.2...v0.8.3
v0.8.2
What's Changed
- perf: batch phase1 SQLite commits instead of one per file by @jamietre in #60
- fix: root_dev unused-variable warning on non-Unix builds by @jamietre in #61
- feat: Ctrl+G go-to-line dialog, fix #L hash edits not working by @jamietre in #62
- perf: virtualized scrolling in the file viewer (plan 092) by @jamietre in #63
- fix: throttle tree row refresh on live index events by @jamietre in #65
- perf: coalesce inbox requests into shared SQLite transactions (plan 093) by @jamietre in #66
- Release 0.8.0 by @jamietre in #68
- fix: include find-extract-dicom and find-extract-pe in release binaries by @jamietre in #70
- fix: rescan directory when .index/.noindex control files change by @jamietre in #67
- Release 0.8.1 by @jamietre in #71
- docs: no Co-Authored-By Claude trailer on commits in this repo by @jamietre in #74
- fix: image viewer Fit to viewport ignored small images by @jamietre in #72
- fix: include find-preview-dicom in release binaries by @jamietre in #73
Full Changelog: v0.7.7...v0.8.2
v0.8.1
What's Changed
- perf: batch phase1 SQLite commits instead of one per file by @jamietre in #60
- fix: root_dev unused-variable warning on non-Unix builds by @jamietre in #61
- feat: Ctrl+G go-to-line dialog, fix #L hash edits not working by @jamietre in #62
- perf: virtualized scrolling in the file viewer (plan 092) by @jamietre in #63
- fix: throttle tree row refresh on live index events by @jamietre in #65
- perf: coalesce inbox requests into shared SQLite transactions (plan 093) by @jamietre in #66
- Release 0.8.0 by @jamietre in #68
- fix: include find-extract-dicom and find-extract-pe in release binaries by @jamietre in #70
Full Changelog: v0.7.7...v0.8.1
v0.8.0
What's Changed
- perf: batch phase1 SQLite commits instead of one per file by @jamietre in #60
- fix: root_dev unused-variable warning on non-Unix builds by @jamietre in #61
- feat: Ctrl+G go-to-line dialog, fix #L hash edits not working by @jamietre in #62
- perf: virtualized scrolling in the file viewer (plan 092) by @jamietre in #63
- fix: throttle tree row refresh on live index events by @jamietre in #65
- perf: coalesce inbox requests into shared SQLite transactions (plan 093) by @jamietre in #66
Full Changelog: v0.7.7...v0.8.0
v0.7.7
Fixed
cross-based ARM/Windows builds: sccache wasn't actually being used —Cross.toml'svolumeskey was under the top-level[build]section, butcrossonly readsvolumes/passthroughfrom[build.env], so the sccache binary and cache dir mounts were silently dropped (cross even warned "found unused key(s)"). Even moved to the right place,crossdoesn't support Docker'shost:containerremap — it always mounts a volume at the same absolute path inside the container as on the host — soRUSTC_WRAPPER=sccache(a bare name) could never resolve via aPATHlookup the container doesn't have. Fixed by resolvingRUSTC_WRAPPERto sccache's absolute path viawhich sccachein.mise.toml'sbuild-arm/build-wintask env blocks (no hardcoded paths — portable across machines), and mounting/passing it through by that same env var name inCross.toml.
Changed
-
Silenced 5 recurring
state_referenced_locallybuild warnings —MetaDrawer,FileViewer,SearchBox, andTopBar(×2) each intentionally seed local$statefrom a prop once (or track a prop's previous value) and were already documented as such in surrounding comments, but Svelte's compiler can't distinguish that from a forgotten sync and warns on every build regardless. Added// svelte-ignore state_referenced_locallyat each site now that the intent is confirmed correct, rather than leaving the noise to reappear on everypnpm run check/dev server start. -
File viewer: targeted redraws for paged scrolling, plus a pagination bug the fix surfaced —
CodeViewer's line list was unkeyed ({#each codeLines as line, i}), soFileViewer's "load earlier lines" (prepending a page while scrolling up) shifted every existing row's index and forced Svelte to repatch the text content of every already-rendered row instead of just inserting the new ones; keyed the block by line number to fix it. Separately,FileViewer's paged mode (files overfileViewPageSize, default 2000 lines) re-ranhighlight.jsover the entire accumulated buffer on everyloadForward/loadBackwardcall, making a long scroll session O(n²) in total highlighting work and blocking the main thread on each page load. Replaced withappendCodeState/prependCodeState, which highlight only the newly-loaded page and concatenate the HTML — O(page size) per call. Addedhighlight.test.tsassertinghighlightFilealways emits one output line per input line (including across a multi-line token like a block comment), since the concatenation approach depends on that invariant to keepcodeLinesin sync withlineOffsets.- The line-number key change immediately surfaced a real, pre-existing bug:
forwardOffset += data.lines.lengthassumed the server's response always covers exactlydata.lines.lengthraw lines, butget_file_lines_paged(crates/server/src/db/mod.rs) silently skips any raw line whose stored chunk lookup misses — e.g. blank lines betweenCargo.lock[[package]]entries never got their own content chunk — so a page can return fewer lines than the raw range it actually covered. The under-counted offset made the next page re-fetch part of an already-rendered range, producing duplicate line-number keys and a hardeach_key_duplicatecrash that blanked the whole viewer. Fixed by advancing the offset withnextForwardOffset()(newpagination.tshelper, alongsidemergePage), which mirrors the server's ownmin(pageSize, totalLines - offset)clamp instead of trusting the response length.loadBackwardwas already unaffected — its offset math derives from the requested range, not the response length.
- The line-number key change immediately surfaced a real, pre-existing bug:
-
Rust dependency:
rand0.9 → 0.10 infind-content-store— only used inbench.rs(the load-testing tool behindfind-test, exercised by its own tests).Rng::random()/random_range()moved out of the coreRngtrait into a newRngExttrait that must be imported separately; addeduse rand::RngExt;and dropped the now-unuseduse rand::Rng;. -
Rust dependency:
zip2 → 8 infind-client's dev-dependencies — used only to build synthetic ZIP fixtures in tests (tests/scan.rs,tests/iwork.rs);find-server/find-extract-archivealready depend onzip = "8"for real archive extraction, so this just aligns the test-only pin with the runtime one. TheZipWriter/SimpleFileOptionsAPI used by those tests was unchanged across the jump — no code changes needed. -
Rust dependency:
quick-xml0.37 → 0.41 infind-extract-epubandfind-extract-office— 0.41 splits&entity;/&#nn;references out of text nodes into a newEvent::GeneralRefevent instead of leaving them inlined inEvent::Text, and removedBytesText::unescape()in favor of a two-stepdecode()(charset) +escape::unescape()(entities) call. Ported both the field-metadata parsers (OPFdc:*tags, DOCXdocProps/core.xml) and the paragraph walkers (XHTML, DOCX body, PPTX body) to accumulate text acrossText/GeneralReffragments and resolveGeneralRefvia a smallresolve_ref()helper (numeric refs viaresolve_char_ref(), named entities viaescape::resolve_predefined_entity()). Added regression tests for entity-escaped title/author metadata and body text in both crates — the initial fix silently truncated any field containing an entity (e.g.Q&Abecame justQ) since the code didn't yet know aboutGeneralRef. -
Rust dependency:
scraper0.21 → 0.27 infind-extract-html— no code changes needed; theHtml/Selector/ElementRefAPI used here is unchanged across the jump. Added a regression test asserting HTML entities (&,<,A, etc.) still decode correctly in extracted text — handled internally by html5ever at parse time, so unlike thequick-xmlbump there's no separate entity-event API to worry about. -
Rust dependency:
calamine0.26 → 0.35 infind-extract-office— no code changes needed. The existing xlsx test fixture only covered inline-string cells (t="inlineStr"), which real spreadsheet tools rarely produce — most.xlsxtext goes through the shared-strings table instead. Added a second fixture (make_realistic_xlsx()) covering shared strings, plain numeric/float cells, and a cell styled with a built-in date number format (numFmtId="14"), and pinned the pre-existing behavior that date-styled cells currently come through as raw XLSX serial numbers (e.g.45292) rather than formatted dates, since calamine'sdatesfeature isn't enabled — unrelated to this bump, but worth knowing if that's ever revisited. -
Rust dependency:
nom-exif2.8 → 3.6 infind-extract-media— before bumping, discovered that every existing video test only covered the magic-byte fallback path (AVI/FLV/MPEG/OGG/WMV); none exercisedextract_video_nom_exif, the code that actually calls intonom-exiffor MP4/MOV/MKV/WebM. Added a real MP4 fixture (testdata/tiny.mp4, generated withffmpeg) and a test asserting resolution/duration extraction, verified against 2.8 first as a baseline. The 3.x API changes:MediaSource::file_path()→MediaSource::open();MediaParser::parse()→MediaParser::parse_track()for video/audio track info;TrackInfoTag::ImageWidth/ImageHeight→Width/Height; andMediaSource::has_track()was removed sinceparse_track()now returnsError::TrackNotFounddirectly for track-less sources (handled by the existing error fallback, no behavior change). -
Rust dependency:
kamadak-exif0.5 → 0.6 infind-extract-media— no code changes needed. Same blind spot found again before bumping:extract_image()trieskamadak-exiffirst and only falls back to a hand-rolled JPEG/PNG header parser if that fails, but every existing image test used a synthetic fixture (make_jpeg_sof0()) with no real EXIF segment — so all of them were silently exercising the fallback parser, neverkamadak-exifitself. Generated a real JPEG with actual EXIF tags (Make/Model/Orientation/DateTime) via Pillow (testdata/exif_sample.jpg) and added a test, verified against 0.5 as a baseline before bumping. -
Rust dependency:
gray_matter0.2 → 0.3 infind-extract-text— unlike the last three bumps, existing frontmatter tests already exercised the real parser (including nested objects), so no new fixtures were needed.Matter::parse()became fallible (Result<ParsedEntity, Error>instead of a best-effortParsedEntity);extract_markdown_with_frontmatternow falls back to indexing the whole file as plain content with no metadata line on a parse error, matching the old best-effort behavior for malformed frontmatter. -
Svelte runes migration (incremental, 6/6 — final) —
FileViewer,+page.svelte,+layout.svelte,settings/+page.svelte,v/[code]/+page.svelteconverted from legacy syntax to runes, completing the migration started after the Svelte 5/Vite 8/TypeScript 6 toolchain bump. Highlights:FileViewer(1514 lines, the largest/highest-risk file): all ~30$:reactive statements split into$derived/$derived.by(pure) or$effect(side-effecting, e.g. the RTF-fetch-on-demand and live-update-banner blocks);dispatch('open'|'navigate'|'navigateDir'|'lineselect', ...)becameonOpen/onNavigate/onNavigateDir/onLineSelectcallback props, withFileView.svelte's<FileViewer>usage updated to match.afterUpdate(not available in runes mode) was replaced with an$effectthat reads the reactive values driving visible content changes (codeLines,wordWrap,showFormatted, etc.) as a stand-in for "rerun after every update," backed by the existingResizeObserverfor layout-only changes.selectionwas a locally-mutated one-way prop (Svelte 4 controlled-prop pattern); like earlier groups, this became compute-and-callback only, relying on the round-trip throughFileView/+page.svelteto reflect the new value back down.+page.svelte: found and fixed a real bug surfaced by thefileView/selectedSourcesstate con...
v0.7.6
What's Changed
- fix: spurious mass reindex on Windows + memory/logging improvements by @jamietre in #25
- feat: no_wrap_extensions — exempt file types from word-wrap by @jamietre in #26
- Release 0.7.4 by @jamietre in #27
- chore: update Cargo dependencies by @jamietre in #28
- feat: HTML viewer by @jamietre in #29
- Release 0.7.5 by @jamietre in #30
- feat: default to formatted view for direct file opens by @jamietre in #32
Full Changelog: v0.7.3...v0.7.6
v0.7.5
What's Changed
- fix: spurious mass reindex on Windows + memory/logging improvements by @jamietre in #25
- feat: no_wrap_extensions — exempt file types from word-wrap by @jamietre in #26
- Release 0.7.4 by @jamietre in #27
- chore: update Cargo dependencies by @jamietre in #28
- feat: HTML viewer by @jamietre in #29
Full Changelog: v0.7.3...v0.7.5
v0.7.4
What's Changed
- fix: spurious mass reindex on Windows + memory/logging improvements by @jamietre in #25
- feat: no_wrap_extensions — exempt file types from word-wrap by @jamietre in #26
Full Changelog: v0.7.3...v0.7.4
v0.7.3
Added
- Inbox circuit breaker — the inbox worker now tracks consecutive request processing timeouts; after
inbox_timeout_circuit_breaker(default 5) consecutive timeouts it automatically pauses the inbox and optionally sends an alert email via SMTP ([alerts]config block withsmtp_host,smtp_port,smtp_encryption,smtp_username,smtp_password,smtp_from,admin_email). The counter resets on any successful request or manual/api/v1/admin/inbox/resume. - SMTP alert emails — new
[alerts]config section supports sending a notification email when the inbox circuit breaker trips; useslettrewith STARTTLS (default), TLS, or plaintext; no fallback to sendmail. cross_filesystemsconfig option —[scan] cross_filesystems = false(default) prevents the walker from descending into directories on a different device than the walk root, avoiding accidental traversal of mounted backup volumes, borg archives, network shares, and bind mounts. Set totrueto restore the previous behaviour of crossing filesystem boundaries.- No-auth server support — the web UI now attempts to connect without a token first;
initialLoad()shows the token dialog only on anAuthError, so servers with no authentication configured load immediately without prompting. - Windows service starts immediately after install —
install_servicenow callsservice.start()after creating the service so no reboot or manualsc startis needed; output message updated accordingly - Windows installer task checkboxes — "Start file watcher service" and "Run full scan now" are now proper Inno Setup
[Tasks]checkboxes rather than a fixed[Run]entry, so they run in the same elevated context as the rest of the install - Configurable formatter timeouts —
batch_formatter_timeout_secs(default 60) andper_file_formatter_timeout_secs(default 10) added to[normalization]inserver.toml; previously hardcoded constants with#[cfg(test)]overrides
Fixed
- Inbox worker SQLite deadlock —
store.get_lines()(a read fromblobs.db) was called inside an open write transaction on the source DB, unnecessarily widening the write lock window; moved before the transaction opens so the two databases are never locked simultaneously - Timed-out inbox tasks held SQLite write locks indefinitely — a timed-out
spawn_blockingPhase 1 task continued holding its connection and any write lock until it finished; fixed by passing arusqlite::InterruptHandlevia oneshot channel sointerrupt()is called on timeout, causingSQLITE_INTERRUPTand immediate unblock - Default inbox request timeout reduced from 1800 s to 120 s — Phase 1 is pure SQLite writes; 1800 s allowed a single stuck request to block the inbox for 30 minutes before the circuit breaker could trip
- Document mode shows all matching lines —
doc:search now returns one result per matching line for each qualifying file, rather than a single representative; lines capped at 20 per file with a+badge indicating truncation - Server crash (OOM) on large archive batches — Phase 1 now streams the normalised
BulkRequestdirectly into theGzEncoderinstead of buffering a fullVec<u8>, halving peak memory for large 7z batches - Batch formatter could hang indefinitely —
apply_batch_formatternow has a 60-second timeout; a hung prettier/biome run no longer blocks the inbox worker forever - Search result line numbers off-by-one near chunk boundaries — empty lines at chunk boundaries no longer shift subsequent line numbers by -1
- Potential write-lock contention on startup — idempotent index creation moved from
open()tocheck_all_sources()so it runs once at startup under no concurrency - Context lines carried server-internal line numbers — each
ContextLinenow carries its ownline_number; sparse files (e.g. PDFs) no longer show wrong line positions - Directory renames not watched after rename —
find-watchnow callsregister_dirfor the new directory path so subsequent changes inside it are detected - No loading cursor while expanding tree directories — the row, arrow, and name now show
cursor: waitduring an in-flight expand request
What's Changed
- fix: prevent nlp-bar pills from being squished when results overflow by @jamietre in #5
- fix: loading spinner and error state for inline image viewer by @jamietre in #6
- feat: native iWork extraction, image viewer UX, structured IWA parsing by @jamietre in #8
- Release 0.7.2 by @jamietre in #10
- fix: dim stale results while typing in Ctrl+P palette by @jamietre in #11
- feat: make batch formatter timeouts configurable by @jamietre in #12
- fix: context lines carry their own line_number, fix chunk boundary bug by @jamietre in #13
- fix: move idempotent index creation from open() to check_all_sources() by @jamietre in #14
- fix: register inotify watch on new directory after rename by @jamietre in #15
- feat: start Windows service immediately after install by @jamietre in #16
- chore: move DICOM plan to completed, update code-quality command by @jamietre in #18
- fix: show wait cursor while tree directory is expanding by @jamietre in #17
- feat: cross_filesystems option + doc mode all-lines search by @jamietre in #20
- feat: inbox circuit breaker, SMTP alerts, and SQLite deadlock fixes by @jamietre in #21
- fix: run integration tests sequentially to prevent CI timeout by @jamietre in #22
- fix: skip token check on startup, show dialog only on auth error by @jamietre in #23
- Release 0.7.3 by @jamietre in #24
New Contributors
Full Changelog: v0.7.1...v0.7.3