* fix(mobile): respect archiveDisplayBehaviour setting in lists and tags
The mobile app was not respecting the user's archiveDisplayBehaviour
setting when displaying bookmarks in home, tags, and lists views. This
fix adds the user settings query to these views and applies the setting
to filter archived bookmarks accordingly.
- When archiveDisplayBehaviour is "show", archived bookmarks are included
- When archiveDisplayBehaviour is "hide", archived bookmarks are filtered out
- Applied to home screen, tags view, and lists view
This brings the mobile app in line with the web app's behavior.
refactor(mobile): extract archive filter logic to shared hook
Created a reusable `useArchiveFilter` hook to centralize the logic for
determining whether to show archived bookmarks based on user settings.
This eliminates code duplication across home, tags, and lists views.
Benefits:
- Single source of truth for archive filtering logic
- Easier to maintain and update
- Consistent behavior across all bookmark views
- Cleaner component code
* fix
* revert the fix for home tab
---------
Co-authored-by: Claude <noreply@anthropic.com>
Introduces a dedicated `checkUrl` tRPC endpoint that directly queries the
database for URL existence instead of going through the full search pipeline.
The endpoint uses the same LIKE matching semantics as the `url:` search
qualifier, then normalizes URLs (stripping hash fragments and trailing slashes)
for exact comparison server-side. This replaces the browser extension's
previous approach of calling searchBookmarks with `url:` and filtering
client-side.
Previously, typing a search term with no matching autocomplete suggestions
would show a "No suggestions" empty state dropdown. Now the popover is
simply hidden when there are no recommendations to display.
https://claude.ai/code/session_015C4Kvd3NYqTJFmhAvomd27
* feat: add synchronized reading progress for bookmarks
Track and restore reading position in reader mode across web and mobile.
Uses text character offsets (matching the highlights pattern) to find
the first visible paragraph and scroll back to it on return.
- Add readingProgressOffset field to bookmarkLinks table
- Add updateReadingProgress tRPC mutation
- Create shared useReadingProgress hook with auto-save on unload
- Integrate in web full-screen reader (/reader/[bookmarkId])
- Integrate in mobile reader mode via WebView injectedJavaScript
- Only tracks progress for bookmark owners
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* it works
* align mobile functions
* fmt
* use generator for webview js fns, remove empty index.ts
* revert comments
* move shared fns into core
* address pr review
* watch core too
* address some pr comments
* fix race condition and jump when scrolling
* fix dead code and error handling, simplify some duplicate logic
* move reading progress to separate table
* remove arbitrary >100 char threshold for updates to progress
* only allow reading progress for link bookmarks, error on others
* add tests
* add tests for shared access reading progress
* simplify reading-progress hooks, visibility checks, remove char threshold on mobile
* remove unnecessary restoration lock
* remove unnecessary exports from reading-progress-core
* move position restoration to onload, more deterministic
* cleanup effects
* Update packages/shared-react/hooks/reading-progress.ts
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* fix function signatures in generated js comment
* remove verbose comments
* add percentage progress fallback
* address comments
* some code dedupe and simplification
* missed one
* Remove lastKnownPositionRef
* remove unnecessary reading-progress-core test
* update savePosition comment
* drop the esbuild generated code
* re-add the db migrations
* wire the mobile dom with the reading progress
* banner for reading progress instead of hiding content
* dedup code from reader view and preview page
* more simplifications
* add a sticky progress bar tracker at the top
* more code simplification
* rename test
* extract reading progress into its own handler
* more polish
* fix scroll behavior of full page bookmark preview
* more polish
* fix pnpm-lock
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Mohamed Bassem <me@mbassem.com>
* feat: add OAuth auto-redirect functionality
Add OAUTH_AUTO_REDIRECT environment variable to automatically redirect
users to the OAuth provider when both password authentication is disabled
and an OAuth provider is configured.
Changes:
- Add OAUTH_AUTO_REDIRECT config in packages/shared/config.ts
- Create OAuthAutoRedirect component for client-side redirect logic
- Update SignInForm to include auto-redirect functionality
- Add oauthAutoRedirect to client config context
- Document new environment variable in configuration docs
This improves user experience by eliminating unnecessary clicks when
OAuth is the only available authentication method.
Fixes #1189
Co-authored-by: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
* review comments
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
* feat(mobile): make the bookmark edit UIs look more native
* fix: dont invalidate getBookmark query on bookmark deletion
* feat: add list definitions and memberships to JSON export and backup
Include list definitions (name, icon, type, hierarchy) and per-bookmark
list memberships in both the JSON export endpoint and backup worker output.
The parser is updated to convert list data back into folder paths on import.
Streaming memory bounds are preserved by fetching memberships per batch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* more fixes
* more fixes
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): make the bookmark edit UIs look more native
* fix: dont invalidate getBookmark query on bookmark deletion
* feat: run metascraper & readability parsing in a subprocess
Extract HTML parsing (metascraper metadata extraction + readability
content extraction) into a separate Node.js subprocess. This prevents
OOM crashes in the parser from killing the entire worker process.
The subprocess communicates via JSON over stdin/stdout, and all log
output is redirected to stderr. Two new config vars control the
subprocess heap size (CRAWLER_PARSE_MAX_OLD_SPACE_SIZE_MB, default
512MB) and timeout (CRAWLER_PARSE_TIMEOUT_SEC, default 60s).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix format
* some fixes
* some fixes
* some fixes
* last fix
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Previously, sharing a PDF from the mobile app would share the asset URL
as a link. This changes the behavior to download the PDF first and share
it as an actual file (matching how images are already shared), with the
correct MIME type and UTI set for proper PDF handling on both platforms.
https://claude.ai/code/session_01VCeeCc64xyZsfEs9T3aQwc
* feat(crawler): write metadata to DB early for faster user feedback
Split the single DB transaction in crawlAndParseUrl into two phases:
- Phase 1: Write metadata (title, description, favicon, author, etc.)
immediately after extraction, before downloading assets
- Phase 2: Write content and asset references after all assets are
stored (banner image, screenshot, pdf, html content)
This gives users near-instant feedback with bookmark metadata while
the slower asset downloads and uploads happen in the background.
https://claude.ai/code/session_013vKTXDcb5CEve3WMszQJmZ
* fix(crawler): move crawledAt to phase 2 DB write
crawledAt should only be set once all assets are fully stored, not
during the early metadata write.
https://claude.ai/code/session_013vKTXDcb5CEve3WMszQJmZ
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add source filter to query language
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* autocomplete source
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When a bookmark is deleted before the rule engine worker processes its
event, the worker would throw an error, triggering failure metrics,
error logging, and retries. This changes both the worker and
RuleEngine.forBookmark to gracefully skip processing with an info log
instead.
Co-authored-by: Claude <noreply@anthropic.com>
Track the time from bookmark creation to crawl completion as a histogram
(karakeep_bookmark_crawl_latency_seconds). This measures the end-to-end
latency users experience when adding bookmarks via extension, web, etc.
Excludes recrawls (crawledAt already set) and imports (low priority jobs).
https://claude.ai/code/session_019jTGGXGWzK9C5aTznQhdgz
Co-authored-by: Claude <noreply@anthropic.com>
The catch block in processOneBookmark was storing raw error strings via
String(error) in the resultReason field, which is exposed to users through
the getImportSessionResults tRPC route. This could leak internal details
like database constraint errors, file paths, stack traces, or connection
strings.
Replace String(error) with getSafeErrorMessage() that only allows through:
- TRPCError client errors (designed to be user-facing)
- Known safe validation messages from the import worker
- A generic fallback for all other errors
The full error is still logged server-side for debugging.
https://claude.ai/code/session_01F1NHE9dqio5LJ177vmSCvt
Co-authored-by: Claude <noreply@anthropic.com>
* feat(ocr): add LLM-based OCR support alongside Tesseract
Add support for using configured LLM inference providers (OpenAI or Ollama)
for OCR text extraction from images as an alternative to Tesseract.
Changes:
- Add OCR_USE_LLM environment variable flag (default: false)
- Add buildOCRPrompt function for LLM-based text extraction
- Add readImageTextWithLLM function in asset preprocessing worker
- Update extractAndSaveImageText to route between Tesseract and LLM OCR
- Update documentation with the new configuration option
When OCR_USE_LLM is enabled, the system uses the configured inference model
to extract text from images. If no inference provider is configured, it
falls back to Tesseract.
https://claude.ai/code/session_01Y7h7kDAmqXKXEWDmWbVkDs
* format
---------
Co-authored-by: Claude <noreply@anthropic.com>
* refactor(web): centralize next-auth client-side utilities
Create lib/auth/client.ts to re-export all next-auth/react APIs (useSession,
signIn, signOut, SessionProvider) from a single location. This prepares
for future auth provider replacement by isolating the next-auth dependency.
https://claude.ai/code/session_01RLLL6SquzmegG6wKHdT3Fm
* format
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(cli): Add search subcommand to bookmarks
Add a new search subcommand that uses the searchBookmarks API endpoint.
The command supports:
- Full-text search with advanced query matchers (tag:, is:, list:, etc.)
- Pagination with --all flag to fetch all results
- Sorting by relevance, ascending, or descending order
- Optional full content inclusion with --include-content
- Configurable result limit per page
Example usage:
bookmarks search "is:fav tag:important"
bookmarks search "kotlin" --sort-order desc --limit 20
bookmarks search "title:api" --include-content --all
* fixes + format
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Fix User-Agent key and accept more permissive content types
Some feeds are Content-Type application/xml only and will respond with a 406 error to responses with a header of content type application/rss+xml. This change allows for the more permissive content types application/xml and text/xml to be accepted
Also fixes UserAgent with correct User-Agent
* Fix: Remote trailing whitespace in feedWorker.ts
Fix formatting on HTTP Header for RSS Accceptable Content-Types introduced in commit 6896392
* format