Conversation
…/3ad6e372f/f69e5d6a7)
- i18n: bind reportUrl in emptyChapterMessage (fixes broken link in non-en locales) - dialog: catch async onSubmit rejections (no unhandled rejection / stuck dialog) - skeleton: consolidate on @utils/useLoadingColors, drop stale duplicate - db: guard empty novelIds in updateNovelCategories; wrap chunked bulk ops in one transaction - novel: try/catch + toast on select-all; fix range-select guard after select-all - plugins: catch floating refreshPlugins in upsertRepository; document getLastUsedPluginId - epub: skip bare-# fragment references in findImageReference - migrations: dedupe registry comment; rename stale describe title
- usePlugins.refreshPlugins wiring: conditional INSTALLED_PLUGINS write, lastUsedPlugin re-stamp, clearUnavailableUpdates semantics - useLibrary: refetch-after-success keeps loading hidden; stale request-id result is discarded - ConfirmationDialog: dismiss deferred until onSubmit resolves; rejection keeps dialog open and interactive - update db mocks to route transaction statements to shared execAsync/runAsync
Resolve audit findings from the upstream synchronization batch while preserving fork-specific behavior. - Harden repository lifecycle handling, backup restoration, HTTPS validation, localization, and plugin update reconciliation. - Serialize plugin filesystem and MMKV mutations to prevent concurrent install, update, and refresh races. - Make chapter queries, migrations, history, library, and update flows resilient to stale async state, invalid ranges, nullable values, and failed writes. - Add namespace-tolerant EPUB parsing, collision-safe image/CSS asset mapping, and awaited metadata downloads. - Preserve falsy legacy backup settings and normalize repository enabled values across database and backup boundaries. - Expand regression coverage for migrations, selections, ranges, plugin refreshes, and backup schemas. Validation: type-check, lint, format, targeted Jest suites, native debug compilation, and diff checks passed.
All other refreshPlugins call sites attach a .catch (AvailableTab, SettingsRepositoryScreen); Main fired it unguarded during the app-boot effect, so a synchronous DB failure or corrupt MMKV JSON at cold start produced an unhandled rejection. Repository refresh is non-fatal — it re-runs on the next visit.
- Extract withPluginMutationLock into a dependency-free mutationQueue module (pluginManager pulls cheerio/htmlparser2/native deps, so the queue was untestable in isolation) and add serialization tests: FIFO exclusivity, release-on-reject, mid-chain rejection, sync ops. - Add insertChapters upsert tests for the changes===0 UPDATE branch (null-safe IS NOT comparisons + null bindings) and the changes>0 insert-only path; the branch was previously untested (mocks always returned changes:1). - Export the import.ts asset helpers (decodePath/normalizePath/basename/ createAssetNameMap/rewriteAssetReferences) and cover collision suffixing, percent-decoding, data:/absolute/fragment preservation, query/fragment suffix retention, and unquoted url() rewriting.
…ixtures - Correct stale suite counts in the 2026-08-15 audit record: 1496 -> 1501 tests, refreshPlugins wiring 5 -> 6, backup suites 27 -> 35. - Persist the 4-POV follow-up audit reports (concurrency / db-integrity / epub-native / tests-validation) under audit-followup/. - Add 4 EPUB device smoke-test fixtures (namespace-prefixed, css-relative-images, percent-encoded, duplicate-basenames) + generator script + procedure checklist at audit/epub-device-smoke-test.md — pending a device run, which cannot be done in-repo.
Living tracking list for the 2026-08-15 follow-up audit. Items 1-11 are deliberately NOT fixed in the sync branch: all are pre-existing, low- impact, or high-blast-radius (migration 004 needs its own PR per Batch D convention). EPUB device smoke test (item 11) is blocked on a device run.
Resolve audit findings from the upstream synchronization batch while preserving fork-specific behavior. - Harden update synchronization, plugin mutation serialization, installation timeouts, and library-state propagation. - Correct Indonesian localization and remove formatting defects from synchronization audit documentation. - Expand regression coverage for stale requests, write queues, plugin installation, and chapter queries. - Document the required Conventional Commits format and validation expectations in AGENTS.md. Validation: type-check, lint, format, targeted Jest suites, and diff checks passed.
- Prevent ZIP path traversal and bounded extraction bypasses. - Sanitize stitched chapters and validate restore/plugin URLs. - Remove forced process termination from DoH restart handling. - Validate with type-check, lint, focused Jest tests, and format.
- Apply persisted DoH to React Native OkHttp clients before startup networking. - Stage ZIP extraction atomically with bounded cleanup and rollback. - Correct stale update tests and restore Android unit-test dependencies. - Defer documented RED Android placeholder tests with explicit ignores. - Validate with full Jest, Gradle unit tests, type-check, lint, and format.
- Replace remote backup HttpURLConnection calls with the configured OkHttp client. - Preserve streaming ZIP extraction, limits, headers, timeouts, and atomic staging. - Leave Chromium WebView DNS outside the OkHttp-controlled scope. - Validate with TypeScript, Jest, Kotlin compilation, and Android unit tests.
- Build update fixtures from the current package patch version. - Keep update tests reactive to package version bumps.
- Write the ZIP central directory before completing remote backup uploads. - Preserve OkHttp sink ownership while producing valid archives. - Validate with Android Kotlin compilation.
- Exercise MediaSession lifecycle, playback state, AudioFocus, and media actions. - Throttle notification updates while preserving priority state changes. - Validate self-host backup folder names at backup and restore boundaries. - Validate with Android unit tests, focused Jest, type-check, lint, and format.
- Keep the reading flag active while refreshing the paused notification - Preserve the currently spoken paragraph display without changing resume state - Validate focused TTS utility and media control tests (42 passed)
- Add non-destructive WebView search highlighting and navigation - Preserve TTS paragraph traversal and wire React Native search controls - Update the root roadmap with implementation progress - Validate with type-check and focused WebView tests
- Apply locale-driven RTL layout to native and WebView readers. - Fix lint:fix so ESLint receives --fix as an option. - Validate with formatting, type-checking, linting, and diff checks.
- Add ReadingSession migration and aggregate statistics queries. - Track foreground manual reading with inactivity and TTS pause handling. - Record WebView touch and scroll activity without changing TTS indexing. - Add migration and query coverage and document commit newline handling. - Validate with type-checking, linting, formatting, tests, and diff checks.
- Add Overview, Time, and Plugins statistics tabs. - Add raw-SQL reading-time metrics, velocity, and top novels. - Add genre taxonomy exploration and SVG donut charts. - Add chart, query, and utility test coverage. - Validate with type-checking, linting, formatting, tests, and TTS checks.
- Persist supported automatic update intervals with safe normalization. - Dispatch due updates through ServiceManager on app foreground. - Add settings UI, focused tests, and scheduler documentation. - Validate with type-check, formatting, and focused tests.
- Record completion of 5 upstream roadmap features across phases 1-3. - Update test suite baseline count to 1628 passing tests. - Archive TTS Text Cleanup Pipeline into previous completed tasks. - Validate with type-check, lint, formatting, and test suite.
- Fix TabBarIndicator double translation offset and width scaling in TopTabBar. - Prevent duplicate status bar insets by excluding top padding on SafeAreaView. - Default Appbar to small mode for compact single-row header across all screens. - Validate with type-checking, linting, formatting, tests, and release build.
- map textAlign left to start for rtl auto-alignment and use logical css properties - self-heal scheduler on clock skew by treating future timestamps as due - remove yoga conflict in toptabbar and adopt safe area insets for appbar - harden donut chart sweep against zero division with finite guard - update tests and verify type-check, lint, unit tests and release build
- add ReaderSearchbar rendering, counter and min-length warning tests - add search.js non-destructive wrap/reset and tts paragraph preservation tests - add rtl locale dir detection and html attrs tests for 6ddfe3d
- add __resetQueueForTests to mutationQueue and writeQueue for isolation - replace timing-dependent tick(20) with deferred promise gate and beforeEach reset - verify 5/5 runs green, no interleaving, rejects still release queue
- extract splitCsvField helper to deduplicate genre/status parsing in 3 sites - filter empty entries consistently via filter(Boolean) in db queries and ui - update AGENTS.md summary limit from 50 to 72 chars (ideal 50, hard 90)
- export UI_SCALE_MIN/MAX/STEP from scaling.ts for single source of truth - clamp button steps to safe range and correct boundary markers to 80%/130% - sync localUiScale to persisted uiScale via useEffect on change - refactor Slider to single root View with direct PanResponder touch ownership - support real-time dragging progression and lock parent scrollview interference - add comprehensive unit test suite covering drag, tap, and disabled scenarios
- WebView (core.js): add flushPendingProgressSave() that clears 150ms debounce and calls saveProgress() synchronously - Wire visibilitychange (hidden) and pagehide to flush pending scroll save immediately, guarded by TTS reading check - WebViewReader.tsx: add AppState background/inactive listener that injects flushPendingProgressSave (fallback to saveProgress) for non-TTS reading - Prevents progress revert to 0% when user scrolls then backgrounds before debounce fires; MMKV sync write now guaranteed before suspension - Validation: type-check pass, 1657 tests pass (112 suites), format pass
- core.js: guard flush during initial suppressSaveOnScroll to avoid saving stale 0% before layout stabilizes - WebViewReader: stabilize AppState listener deps via isTTSReadingRef to prevent per-render resubscribe thrash - Audit hardening for 653a9e9; validation: type-check pass, 1657 tests pass
- cover AppState background/inactive injection of flushPendingProgressSave - verify injected JS is TTS-guarded and listener cleanup on unmount - verify core.js flush guards: debounce clear, tts.reading skip, suppressSaveOnScroll skip - validation: type-check pass, 1663 tests pass (113 suites)
…#4-5 - isValidPluginId: reject '.' and leading/trailing dots, require alphanum endpoints (C4) - NovelQueries: gate insertNovelAndChapters and _restoreNovelAndChapters with isValidPluginId (H1) - pluginManager: check response.ok before evaluating plugin code (H8) - DoHManagerModule: whitelist provider IDs before persisting (M5) - backup/utils + SettingsRepositoryScreen: replace greedy regex with URL parsing + pathname check (M6) - HistoryCard: use novelName instead of chapter name for novel navigation (M9) - Slider: wire shouldClaimPanResponder, onStart never claims, add Number.isFinite guard (H7) - ChapterQueries: chunk and wrap deleteDownloads/deleteReadChaptersFromDb in withExclusiveTransactionAsync (H9) - useUpdates: remove unconditional setIsLoading false in focus effect, add timer cleanup (M10) - UpdateNovelCard: add mountedRef + sequence guard to avoid stale setState (M11) - Main: log cold-start plugin refresh failures via rateLimitedLogger (M14) - ReaderSearchbar: 150ms debounce to avoid bridge flood (LOW-1) - DistributionBar: aggregate <0.5% slices into Other bucket (LOW-6) - AutomaticLibraryUpdateModal: deduplicate useAppSettings call (LOW-8) - WebViewReader + translations: expand RTL allowlist and map right->end (M1) - Appbar: prefer insets.top only to avoid layout jump (M4) - serialLock: consolidate writeQueue/mutationQueue duplicate FIFO primitives (M8) Validation: pnpm run type-check, pnpm run test (113 suites, 1663 tests)
- H5: useTimeTracking: == null PK guards, clear chapter-change timer, store+clear 0-delay timeout (fix falsy-0, leaked timer) - M12: move fetchPlugins inside withWriteLock to avoid duplicate fetch - M13: migrate legacy string LAST_USED_PLUGIN to deletion - LOW-7: StatsScreen: mounted guard for Promise.all abort-on-unmount - LOW-9: TTSForegroundService: @VisibleForTesting for test hooks - LOW-10: NativeZipArchive: requireNotNull parentFile for NPE at root / - LOW-4/LOW-5: intentional skip - RTL float override external CSS, numeric ids safe (ponytail: no new abstraction) Validation: pnpm run type-check, pnpm run test (113 suites, 1663 tests)
- Upstream master (getDetailedUpdatesQuery) uses same split: isDownloaded=1 vs updatedTime IS NOT NULL - Downstream fork intentionally matches upstream: overview counts only updates, detail download-only lists all offline chapters (incl. NULL updatedTime) - Add doc comment in ChapterQueries.ts pointing to upstream reference + one-line patch hint for Option A - Add regression test ChapterQueries.updates.test.ts asserting intentional divergence Validation: pnpm run type-check, pnpm run test (114 suites, 1666 tests)
- Enable reading time tracking by default and add dual-mode tracking for manual reading and active TTS playback - Add Settings controls for reading time tracking toggle and inactivity auto-pause interval picker modal - Fix incorrect header string in Overview tab and localize all missing labels across Overview, Time, and Plugins tabs - Enhance Time tab with novel cover thumbnails, tap-to-navigate interaction, and velocity duration safeguards - Make novel rows in Plugins tab interactive with ReaderStack navigation - Validated with type-check, linter, full 1671 unit/integration tests, and wake cycle simulation
- Add TimeTab regression test suite for velocity thresholds and navigation payload - Extract StatsCard into standalone component to optimize test imports - Validated with type-check, linter, Prettier, and full 1674 tests passing
- Enable swipeEnabled across Reader settings TabViews for left/right navigation - Claim Slider responder on touch start to prevent native ViewPager2 cancellation - Wrap SettingsReaderScreen TabView in BottomSheetView for gesture hierarchy - Update Slider unit test suite for touch-start claim verification - Validated with jest (116 suites, 1674 tests passed) and tsc (zero errors)
- add in-chapter search, rtl support, and reading analytics to features screen - update readme with reading analytics, search, rtl, and background updates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR: Comprehensive Upstream Feature Integration, Analytics Overhaul & Architectural Hardening (110 Commits)
1. Executive Summary
This PR integrates all remaining high-value features, security updates, stability fixes, and UX modernizations from upstream
lnreader/lnreaderinto our production-hardened fork, while strictly preserving our core architectural pillars:scaleDimension()anduseScaledDimensions()density scaling tokens.Across 110 commits, this release delivers 5 major upstream feature pillars, unified visible/TTS cleanup, Material You / MD3 theme overhaul, Kitsu tracker support, remote backup DoH routing & security hardening, in-app features documentation, and multi-pass adversarial audit remediations.
2. Architectural Context — Why Selective Porting
A direct
git mergefrom upstream is structurally impossible due to four fundamental architectural divergences:All upstream features and fixes were selectively re-engineered to fit our robust architecture, followed by multi-agent adversarial audits to eliminate regressions.
3. Major Features & Capabilities Added
3.1. In-Chapter Text Search (Upstream lnreader#1877)
window.readerSearchengine with batched DOM scanning (80 chunks/tick) and live<mark>highlighting.<mark>tags are strictly contained inside paragraph text nodes, guaranteeing that paragraph indexing andwindow.tts.getTextNodes()remain 100% stable.ReaderSearchbar.tsxwith occurrence counters, next/previous match steppers, hardware back button dismissal, and auto-scroll to match.3.2. RTL Language & Layout Support (Upstream lnreader#1717)
ar), Hebrew (he), Persian (fa), and Urdu (ur) locales.padding-inline-start,padding-inline-end,margin-inline-start).'start'text alignment resolution that mirrors seamlessly without breaking custom user alignments.TopTabBar.tsxensuring indicator animations respect RTL constraints without jumping.3.3. Reading Time Tracking & Inactivity Detection (Upstream lnreader#1899)
ReadingSessiontable with cascading foreign keys and compound indexes ((novelId, startTime)).useTimeTracking.ts): Accurately tracks active manual reading time with foreground/background app state listeners.3.4. Analytics & Statistics Overhaul (Upstream lnreader#1919)
StatsQueries.tscalculating total read time, daily averages, completion rates, and reading velocity.react-native-svgwith zero-division math protections (NaNguard on empty libraries).3.5. Scheduled Background Library Updates
ServiceManager.3.6. Unified Visible-Text & TTS Cleanup Ruleset (Issue #19)
applyTo: 'tts' | 'visible' | 'both').U+200B) to protect paragraph indexing. Toggle-off restores pristine DOM state from cached snapshots without requiring page reloads.3.7. Material 3 Theme & Modern UI Suite
@pchmn/expo-material3-theme) with graceful fallbacks.@react-native-community/sliderwith modern MD3 Slider; hardened horizontal gesture claiming (shouldClaimPanResponder) to prevent swallowing vertical sheet scrolls and eliminated release flicker.TopTabBarindicators, bottom sheets (surfaceContainerLow/High), and outside-tap dismissibleMenu.3.8. Trackers & Download Enhancements
4. Stability, Security & Hardening Fixes
4.1. Database Integrity & Migrations
juliandaytriggers on all installs; narrows chapter update triggers to ignore high-frequency per-paragraph TTS progress saves.isEnabled).ReadingSessiontable with cascading cleanup.txnobject, restoring full atomicity for migrations and backup restores.deleteDownloadswithWHERE id IN (...)(preventing mass deletion) and fixed parameter passing indeleteReadChaptersFromDb.CAST(page AS INTEGER)across chapter queries and pagination.4.2. Security & Network Hardening
NativeFile.kt.4.3. Upstream Compatibility Waves
5. Verification & Test Coverage
5.1. Automated Verification Gates
tsc --noEmitwith zero errorsTTSAudioManager.refill.test.ts5.2. Manual QA Smoke Checklist
applyTo: 'both'→ verify live reader text and spoken audio both reflect the rule.6. Chronological Commit Log (110 Commits)
7. How to Test & Review This PR