rcgit

/ karakeep
follow (on) | order: default date topo
Age Commit message Author Files +/-
fix: Fix Amazon product image extraction on amazon.com URLs (#2108)
The metascraper-amazon package extracts the first .a-dynamic-image
element, which on amazon.com is often the Prime logo instead of the
product image. This works fine on amazon.co.uk where the product
image appears first in the DOM.
Created a custom metascraper plugin that uses more specific selectors
(#landingImage, #imgTagWrapperId, #imageBlock) to target the actual
product image. By placing this plugin before metascraperAmazon() in
the chain, we fix image extraction while preserving all other Amazon
metadata (title, brand, description).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Randall Hand 2 -0/+79
feat: use reddit API for metadata extraction. Fixes #1853 #1883 Mohamed Bassem 4 -33/+346
fix: use GET requests for the content type request Mohamed Bassem 1 -1/+1
release(cli): Bump CLI version to 0.29.1 Mohamed Bassem 1 -1/+1
deps: Upgrade nextjs to 15.3.8 Mohamed Bassem 2 -22/+22
deps: Upgrade nextjs to 15.3.7 Mohamed Bassem 2 -22/+22
feat: make asset preprocessing worker timeout configurable
- Added ASSET_PREPROCESSING_JOB_TIMEOUT_SEC environment variable with default of 60 seconds (increased from hardcoded 30 seconds)
- Updated worker to use the configurable timeout from serverConfig
- Added documentation for the new configuration option
Claude 3 -1/+4
feat(cli): Add ability to list users for the admin in the CLI Mohamed Bassem 2 -0/+91
fix: check import quota before importing bookmarks (#2232)
* feat: check import quota before importing bookmarks
Add quota validation before bookmark import to prevent users from
exceeding their bookmark limits. The implementation includes:
- New QuotaService.canImportBookmarks() method to check if user can import N bookmarks
- New tRPC checkImportQuota procedure for client-side quota validation
- Updated useBookmarkImport hook to parse files and check quota before import
- Added error banner in ImportExport component to display quota errors
- Optimized file parsing to avoid reading the file twice
The quota check displays remaining bookmarks and provides clear error
messages when the import would exceed the user's quota.
* fix
* some fixes
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 3 -3/+54
build: fix typecheck error in query explainer Mohamed Bassem 1 -0/+10
fix: migrate to metascraper-x from metascraper-twitter Mohamed Bassem 3 -297/+16
feat: add is:broken search qualifier for broken links (#2225)
Add a new search qualifier `is:broken` that allows users to filter bookmarks
with broken or failed links. This matches the functionality on the broken links
settings page, where a link is considered broken if:
- crawlStatus is "failure"
- crawlStatusCode is less than 200
- crawlStatusCode is greater than 299
The qualifier supports negation with `-is:broken` to find working links.
Changes:
- Add brokenLinks matcher type definition
- Update search query parser to handle is:broken qualifier
- Implement query execution logic for broken links filtering
- Add autocomplete support with translations
- Add parser tests
- Update search query language documentation
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 7 -0/+60
feat: spread feed fetch scheduling deterministically over the hour (#2227)
Previously, all RSS feeds were fetched at the top of each hour (minute 0),
which could cause load spikes. This change spreads feed fetches evenly
throughout the hour using a deterministic hash of the feed ID.
Each feed is assigned a target minute (0-59) based on its ID hash, ensuring
consistent scheduling across restarts while distributing the load evenly.
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 1 -0/+31
fix: better extraction for youtube thumbnails. #2204 Mohamed Bassem 3 -18/+241
deps: Upgrade nextjs to 15.3.6 Mohamed Bassem 2 -55/+55
feat: add a notification badge for list invitations Mohamed Bassem 2 -0/+27
fix: regen turnstile token on signup resubmission Mohamed Bassem 1 -1/+14
feat(landing): Add more features to the homepage Mohamed Bassem 1 -8/+47
feat: add support for turnstile on signup Mohamed Bassem 8 -0/+165
release: cli, mcp and sdk Mohamed Bassem 3 -3/+3
release(extension): Release version 1.2.8 Mohamed Bassem 1 -1/+1
release(mobile): Bump mobile version to 1.8.3 Mohamed Bassem 1 -3/+3
i18n: fix en_US translation Mohamed Bassem 1 -57/+57
i18n: Sync weblate translations
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: OpenAI <noreply-mt-openai@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ar/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/cs/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/da/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/de/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/el/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/en_US/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/es/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/fa/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/fi/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/fr/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ga/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/gl/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/hr/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/hu/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/it/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ja/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ko/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/nl/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/pl/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/pt/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ru/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/sk/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/sl/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/sv/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/tr/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/uk/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/vi/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/zh_Hant/
Translation: Karakeep/Karakeep
Hosted Weblate 31 -62/+3286
feat: autocomplete search terms (#2178)
* refactor(web): split search autocomplete logic
* some improvements
* restructure the code
* fix typesafety
* add feed suggestions
* fix
Mohamed Bassem 4 -61/+629
feat: Add automated bookmark backup feature (#2182)
* feat: Add automated bookmark backup system
Implements a comprehensive automated backup feature for user bookmarks with the following capabilities:
Database Schema:
- Add backupSettings table to store user backup preferences (enabled, frequency, retention)
- Add backups table to track backup records with status and metadata
- Add BACKUP asset type for storing compressed backup files
- Add migration 0066_add_backup_tables.sql
Background Workers:
- Implement BackupSchedulingWorker cron job (runs daily at midnight UTC)
- Create BackupWorker to process individual backup jobs
- Deterministic scheduling spreads backup jobs across 24 hours based on user ID hash
- Support for daily and weekly backup frequencies
- Automated retention cleanup to delete old backups based on user settings
Export & Compression:
- Reuse existing export functionality for bookmark data
- Compress exports using Node.js built-in zlib (gzip level 9)
- Store compressed backups as assets with proper metadata
- Track backup size and bookmark count for statistics
tRPC API:
- backups.getSettings - Retrieve user backup configuration
- backups.updateSettings - Update backup preferences
- backups.list - List all user backups with metadata
- backups.get - Get specific backup details
- backups.delete - Delete a backup
- backups.download - Download backup file (base64 encoded)
- backups.triggerBackup - Manually trigger backup creation
UI Components:
- BackupSettings component with configuration form
- Enable/disable automatic backups toggle
- Frequency selection (daily/weekly)
- Retention period configuration (1-365 days)
- Backup list table with download and delete actions
- Manual backup trigger button
- Display backup stats (size, bookmark count, status)
- Added backups page to settings navigation
Technical Details:
- Uses Restate queue system for distributed job processing
- Implements idempotency keys to prevent duplicate backups
- Background worker concurrency: 2 jobs at a time
- 10-minute timeout for large backup exports
- Proper error handling and logging throughout
- Type-safe implementation with Zod schemas
* refactor: simplify backup settings and asset handling
- Move backup settings from separate table to user table columns
- Update BackupSettings model to use static methods with users table
- Remove download mutation in favor of direct asset links
- Implement proper quota checks using QuotaService.checkStorageQuota
- Update UI to use new property names and direct asset downloads
- Update shared types to match new schema
Key changes:
- backupSettingsTable removed, settings now in users table
- Backup downloads use direct /api/assets/{id} links
- Quota properly validated before creating backup assets
- Cleaner separation of concerns in tRPC models
* migration
* use zip instead of gzip
* fix drizzle
* fix settings
* streaming json
* remove more dead code
* add e2e tests
* return backup
* poll for backups
* more fixes
* more fixes
* fix test
* fix UI
* fix delete asset
* fix ui
* redirect for backup download
* cleanups
* fix idempotency
* fix tests
* add ratelimit
* add error handling for background backups
* i18n
* model changes
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 32 -8/+5697
fix: fix react errors in signin and signup forms Mohamed Bassem 2 -0/+10
fix: separate shared lists in the sidebar (#2180)
* fix: separate shared lists in the sidebar
* fix sub
* i18n
Mohamed Bassem 4 -31/+237
fix: correctly render asset extracted text in the edit bookmark dialog. fixes… Mohamed Bassem 1 -4/+24
fix: lazy load js-tiktoken in prompts module (#2176)
* feat: lazy load tiktoken to reduce memory footprint
The js-tiktoken module loads a large encoding dictionary into memory
immediately on import. This change defers the loading of the encoding
until it's actually needed by using a lazy getter pattern.
This reduces memory usage for processes that import this module but
don't actually use the token encoding functions.
* fix: use createRequire for lazy tiktoken import in ES module
The previous implementation used bare require() which fails at runtime
in ES modules (ReferenceError: require is not defined). This fixes it
by using createRequire from Node's 'module' package, which creates a
require function that works in ES module contexts.
* refactor: convert tiktoken lazy loading to async dynamic imports
Changed from createRequire to async import() for lazy loading tiktoken,
making buildTextPrompt and buildSummaryPrompt async. This is cleaner for
ES modules and properly defers the large tiktoken encoding data until
it's actually needed.
Updated all callers to await these async functions:
- packages/trpc/routers/bookmarks.ts
- apps/workers/workers/inference/tagging.ts
- apps/workers/workers/inference/summarize.ts
- apps/web/components/settings/AISettings.tsx (converted to useEffect)
* feat: add untruncated prompt builders for UI previews
Added buildTextPromptUntruncated and buildSummaryPromptUntruncated
functions that don't require token counting or truncation. These are
synchronous and don't load tiktoken, making them perfect for UI
previews where exact token limits aren't needed.
Updated AISettings.tsx to use these untruncated versions, eliminating
the need for useEffect/useState and avoiding unnecessary tiktoken
loading in the browser.
* fix
* fix
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 5 -37/+110
fix: fix colors in invitation form Mohamed Bassem 2 -7/+7
fix: hide archived checkbox in shared lists Mohamed Bassem 1 -1/+1
feat: improve font and colors of sidebar items Mohamed Bassem 2 -11/+16
fix: Propagate group ids in queue calls (#2177)
* fix: Propagate group ids
* fix tests
Mohamed Bassem 11 -37/+103
fix(mcp): propagate parent id to createList call. fixes: #2144 Mohamed Bassem 1 -1/+2
feat(mobile): proper handling for shared list permissions (#2165)
* feat(mobile): Restrict bookmark editing in shared lists
Apply the same ownership-based restrictions that exist in the web app
to the mobile app. Users can now only edit, delete, and manage their
own bookmarks, even when viewing them in shared lists.
Changes:
- BottomActions: Hide edit actions (lists, tags, info, delete) for non-owners
- BookmarkCard: Hide favorite button and action menu for non-owners
- Info page: Make title, notes, tags, and lists read-only for non-owners
- NotePreview: Hide "Edit Notes" button for non-owners
All restrictions are based on comparing the current user ID (from useWhoAmI)
with the bookmark's userId field.
* some fixes
* make tags non clickable for collaborators
* add leave list
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 6 -146/+279
feat(mobile): Add highlights page to mobile app (#2156)
* feat: Add highlights page to mobile app
This commit adds a new highlights page to the mobile app where users can
view all their highlights with the following features:
- HighlightCard component: Displays individual highlights with colored borders,
  text, optional notes, timestamps, and a link to the source bookmark
- HighlightList component: Renders a scrollable list of highlights with
  pull-to-refresh and infinite scroll pagination
- UpdatingHighlightList component: Handles data fetching using tRPC infinite
  queries with automatic cache invalidation
- New /dashboard/highlights route with large header title
- Added navigation link in Settings tab under "App Settings"
All components follow the existing mobile app patterns and integrate with
the existing highlights API.
* make it a tab
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 4 -1/+276
feat: A better looking 404 page Mohamed Bassem 1 -2/+41
fix: hide manage collaborators option for smart lists Mohamed Bassem 1 -1/+1
fix: Hide shared lists where user is a viewer in Manage Lists dialog (#2164)
Users with viewer role cannot add/remove bookmarks from lists, so these lists should not appear in the Manage Lists dialog across all platforms (web, mobile, and extension).
Changes:
- Web: Updated BookmarkListSelector to filter out viewer lists
- Mobile: Updated manage_lists.tsx to filter out viewer lists
- Extension: Updated ListsSelector to filter out viewer lists
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 3 -27/+38
feat(mobile): Add AI summary field to mobile bookmark info (#2157)
* feat: Add AI summary field to mobile bookmark info page
Add a new AI summary section to the mobile bookmark info page that allows users to:
- Generate AI summaries for link bookmarks
- View existing summaries with expand/collapse functionality
- Regenerate summaries with the refresh button
- Delete summaries
The implementation is inspired by the web app's AI summary feature and includes:
- Purple-themed styling to match the AI branding
- Loading states for all actions
- Toast notifications for success/error feedback
- Support for dark mode
- Only displays for LINK type bookmarks
The summary is rendered using markdown and appears prominently in the bookmark info page,
positioned between the title editor and tags section.
* refactor: Simplify AI summary styling to match normal fields
Remove purple border and background from the AI summary display to make it
look more like a standard field. The summary now uses the default card
background from InfoSection, making it visually consistent with other
fields on the page.
The purple "Summarize with AI" button is retained for the generate action.
* make the expand button more clear
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 1 -1/+153
feat(mobile): Add tags screen to mobile app (#2163)
* feat: Add tags screen to mobile app
Add a new Tags tab to the mobile app that displays all tags sorted by usage.
The screen includes:
- Paginated tag list with infinite scroll
- Display of tag names and bookmark counts
- Pull-to-refresh functionality
- Navigation to individual tag detail screens
- Empty state and loading indicators
This brings tag browsing functionality to the mobile app, similar to the
existing Lists tab.
* feat: Add search functionality to mobile tags screen
Add a search input to the tags screen that allows users to filter tags
by name. The search includes:
- Debounced search input (300ms delay) to reduce API calls
- Real-time filtering as the user types
- Sort by relevance when searching, by usage when not searching
- Smooth animated clear button
This enhances the tags browsing experience by making it easy to find
specific tags in a large collection.
* format
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 2 -1/+148
feat: Add notes feature to highlights (#2154)
* feat: Add note-taking functionality to highlights
This commit adds the ability to add and edit notes on highlights, allowing users to capture their thoughts alongside highlighted text.
Changes:
- Updated zUpdateHighlightSchema to include optional note field
- Modified Highlight.update() method to persist notes to database
- Added note button (MessageSquare icon) beside color picker in highlight menu
- Implemented note dialog with textarea for adding/editing notes
- Updated Highlight interface to include optional note field
- Modified ReaderView to pass notes through create and update operations
- Enhanced HighlightCard to display notes below highlighted text
The note button appears alongside the color picker for both new and existing highlights. Notes are displayed in a smaller, muted font below the highlighted text in the HighlightCard component.
* refactor: Convert highlight UI to inline form
Changed the highlight creation/editing interface from a modal dialog to an inline form for a more streamlined user experience.
Changes:
- Replaced ColorPickerMenu and Dialog with a unified HighlightForm component
- Form now displays color selector and note textarea together inline
- Added labels for "Color" and "Note" sections
- Textarea is now optional and inline (placeholder: "Add a note (optional)...")
- Consolidated Save and Cancel buttons in the form
- Delete button appears only for existing highlights
- Removed MessageSquare icon - notes are now always visible in the form
- Simplified state management by removing separate dialog state
The form appears in a popover when text is selected or an existing highlight is clicked, showing both color options and note input in a single 320px wide form.
* fixes
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 6 -48/+111
feat(mobile): Add smart list creation in mobile app (#2153)
* feat: Add smart list creation and display in mobile app
This commit adds support for creating and displaying smart lists in the mobile application:
- Enhanced list creation screen to support both manual and smart list types
- Added type selector with manual/smart toggle buttons
- Implemented conditional search query input for smart lists
- Added query validation to ensure smart lists have valid queries
- Improved error handling to display validation errors from the backend
- Added visual indicators (sparkle icon) for smart lists in the lists tab
- Implemented smart list query display in list detail view with sparkle badge
- Enhanced UI with contextual help text for smart list queries
The implementation follows the web app pattern while adapting the UI for mobile best practices.
* fixes
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 2 -4/+69
feat: Add search bar to highlights page (#2155)
* feat: Add search bar to All highlights page
This commit adds a search bar to the "All highlights page" that allows users to search their highlights by text content or notes.
Changes:
- Added search method to Highlight model with SQL LIKE query on text and note fields
- Added search endpoint to highlights router with pagination support
- Updated AllHighlights component to include search input with debouncing
- Search input includes clear button and search icon
- Maintains existing infinite scroll pagination for search results
Technical details:
- Uses SQL ilike for case-insensitive search
- 300ms debounce to reduce API calls
- Conditionally uses search or getAll endpoint based on search query
* fix db query
* small fixes
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 3 -41/+156
fix: hide collaborator emails from non-owners (#2160)
* feat: Hide collaborator emails from non-owners in shared lists
Implemented privacy protection for collaborator emails in shared lists.
Non-owners (viewers and editors) can no longer see email addresses of
the list owner or other collaborators. Only the list owner can view
all email addresses.
Changes:
- Modified List.getCollaborators() to return empty strings for emails
  when the requester is not the owner
- Updated ManageCollaboratorsModal UI to conditionally display email
  fields only when they are not empty
- Added comprehensive test to verify email privacy for non-owners while
  ensuring owners can still see all emails
This follows existing privacy patterns in the codebase (similar to how
pending invitation names are masked as "Pending User").
* make the email field nullable
* fix tests
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 4 -10/+109
feat: Add invitation approval for shared lists (#2152)
* feat: Add invitation approval system for collaborative lists
- Add database schema changes to support pending invitations
  - Add status field (pending/accepted/declined) to listCollaborators
  - Add invitedAt and invitedEmail fields for tracking
  - Add index on status for efficient queries
- Update List model with invitation workflow methods
  - Modify addCollaboratorByEmail to create pending invitations
  - Add acceptInvitation() for users to accept invites
  - Add declineInvitation() for users to decline invites
  - Add revokeInvitation() for owners to revoke pending invites
  - Add getPendingInvitations() to get user's pending invites
- Implement privacy protection for pending invitations
  - Mask user names as "Pending User" until invitation is accepted
  - Only show email to list owner for pending invitations
- Update getSharedWithUser to only include accepted collaborations
  - Ensures lists only appear after invitation is accepted
* feat: Add tRPC procedures and email notifications for list invitations
- Add new tRPC procedures for invitation workflow
  - acceptInvitation: Allow users to accept pending invitations
  - declineInvitation: Allow users to decline invitations
  - revokeInvitation: Allow owners to revoke pending invitations
  - getPendingInvitations: Get all pending invitations for current user
- Update getCollaborators output schema
  - Add status, invitedAt fields to collaborator objects
  - Support privacy-masked user info for pending invitations
- Add sendListInvitationEmail function
  - Email notification when user is invited to collaborate
  - Includes list name, inviter name, and link to view invitation
  - Gracefully handles missing SMTP configuration
- Integrate email sending into invitation workflow
  - Send email when new invitation is created
  - Send email when declined invitation is renewed
  - Catch and log errors without failing the invitation
* feat: Add UI for list invitation approval workflow
- Update ManageCollaboratorsModal to support pending invitations
  - Show "Pending" badge for pending invitations
  - Add revoke button for owners to cancel pending invitations
  - Update success message to reflect invitation sent
  - Disable role change and remove buttons for pending invitations
- Create PendingInvitationsCard component
  - Display all pending invitations for the current user
  - Show list name, description, inviter, and role
  - Provide Accept and Decline buttons
  - Auto-hide when no pending invitations exist
- Add PendingInvitationsCard to lists page
  - Show at the top of the lists page
  - Only renders when user has pending invitations
* fix: Add missing translation keys and fix TypeScript errors
- Add translation keys for invitation system
  - lists.collaborators.invitation_sent
  - lists.collaborators.pending
  - lists.collaborators.revoke
  - lists.collaborators.invitation_revoked
  - lists.collaborators.failed_to_revoke
  - lists.invitations.* (all invitation-related keys)
- Fix TypeScript errors in email sending
  - Handle optional user.name with fallback to 'A user'
* wip
* fixes
* more fixes
* fix revoke
* more improvements
* comment fix
* fix email url
* fix schemas
* split pending invites into components
* more fixes
* test
* test fixes
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 13 -346/+4874
fix: add a way to allowlist all domains from ip validation Mohamed Bassem 2 -6/+10
fix: use kbd for editor card Mohamed Bassem 5 -36/+58
feat: Add collaborative lists (#2146)
* feat: Add collaborative lists backend implementation
This commit implements the core backend functionality for collaborative
lists, allowing multiple users to share and interact with bookmark lists.
Database changes:
- Add listCollaborators table to track users with access to lists and
  their roles (viewer/editor)
- Add addedBy field to bookmarksInLists to track who added bookmarks
- Add relations for collaborative list functionality
Access control updates:
- Update List model to support role-based access (owner/editor/viewer)
- Add methods to check and enforce permissions for list operations
- Update Bookmark model to allow access through collaborative lists
- Modify bookmark queries to include bookmarks from collaborative lists
List collaboration features:
- Add/remove/update collaborators
- Get list of collaborators
- Get lists shared with current user
- Only manual lists can have collaborators
tRPC procedures:
- addCollaborator: Add a user as a collaborator to a list
- removeCollaborator: Remove a collaborator from a list
- updateCollaboratorRole: Change a collaborator's role
- getCollaborators: Get all collaborators for a list
- getSharedWithMe: Get all lists shared with the current user
- cloneBookmark: Clone a bookmark to the current user's collection
Implementation notes:
- Editors can add/remove bookmarks from the list (must own the bookmark)
- Viewers can only view bookmarks in the list
- Only the list owner can manage collaborators and list metadata
- Smart lists cannot have collaborators (only manual lists)
- Users cannot edit bookmarks they don't own, even in shared lists
* feat: Add collaborative lists frontend UI
This commit implements the frontend user interface for collaborative lists,
allowing users to view shared bookmarks and manage list collaborators.
New pages:
- /dashboard/shared: Shows bookmarks from lists shared with the user
  - Displays bookmarks from all collaborative lists
  - Uses SharedBookmarks component
  - Shows empty state when no lists are shared
Navigation:
- Added "Shared with you" link to sidebar with Users icon
- Positioned after "Home" in main navigation
- Available in both desktop and mobile sidebar
Collaborator management:
- ManageCollaboratorsModal component for managing list collaborators
  - Add collaborators by user ID with viewer/editor role
  - View current collaborators with their roles
  - Update collaborator roles inline
  - Remove collaborators
  - Shows empty state when no collaborators
- Integrated into ListOptions dropdown menu
- Accessible via "Manage Collaborators" menu item
Components created:
- SharedBookmarks.tsx: Server component fetching shared lists/bookmarks
- ManageCollaboratorsModal.tsx: Client component with tRPC mutations
- /dashboard/shared/page.tsx: Route for shared bookmarks page
UI features:
- Role selector for viewer/editor permissions
- Real-time collaborator list updates
- Toast notifications for success/error states
- Loading states for async operations
- Responsive design matching existing UI patterns
Implementation notes:
- Uses existing tRPC endpoints (getSharedWithMe, getCollaborators, etc.)
- Follows established modal patterns from ShareListModal
- Integrates seamlessly with existing list UI
- Currently uses user ID for adding collaborators (email lookup TBD)
* fix typecheck
* add collaborator by email
* add shared list in the sidebar
* fix perm issue
* hide UI components from non list owners
* list leaving
* fix shared bookmarks showing up in homepage
* fix getBookmark access check
* e2e tests
* hide user specific fields from shared lists
* simplify bookmark perm checks
* disable editable fields in bookmark preview
* hide lists if they don't have options
* fix list ownership
* fix highlights
* move tests to trpc
* fix alignment of leave list
* make tag lists unclickable
* allow editors to remove from list
* add a badge for shared lists
* remove bookmarks of user when they're removed from a list
* fix tests
* show owner in the manage collab modal
* fix hasCollab
* drop shared with you
* i18n
* beta badge
* correctly invalidate caches on collab change
* reduce unnecessary changes
* Add ratelimits
* stop manually removing bookmarks on remove
* some fixes
* fixes
* remove unused function
* improve tests
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 40 -596/+6705
deps: upgrade hono and playwright Mohamed Bassem 3 -153/+160
deps: Upgrade typescript to 5.9 Mohamed Bassem 7 -161/+161
fix: fix hydration error in admin user list Mohamed Bassem 1 -7/+9
feat: import from mymind (#2138)
* feat: add mymind importer support
This commit adds support for importing bookmarks from mymind CSV exports.
Changes:
- Added mymind to ImportSource type in parsers.ts
- Implemented parseMymindBookmarkFile() to parse mymind CSV format
- Added mymind case to parseImportFile() switch statement
- Added mymind import card to ImportExport UI component
- Added English translation for mymind import description
- Added comprehensive test for mymind CSV parsing
The mymind CSV format includes:
- WebPages (URLs with optional notes)
- Notes (text content without URLs)
- Tags (comma-separated)
- Created timestamps (ISO format)
Fixes #654
* format
* use zod for parsing
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 4 -1/+163
feat: add Prometheus counter for HTTP status codes (#2117)
* feat: add Prometheus counter for crawler status codes
Add a new Prometheus metric to track HTTP status codes encountered
during crawling operations. This helps monitor crawler health and
identify patterns in response codes (e.g., 200 OK, 404 Not Found, etc.).
Changes:
- Add crawlerStatusCodeCounter in metrics.ts with status_code label
- Instrument crawlerWorker.ts to track status codes after page crawling
- Counter increments for each crawl with the corresponding HTTP status code
The metric is exposed at the /metrics endpoint and follows the naming
convention: karakeep_crawler_status_codes_total
* fix: update counter name to follow Prometheus conventions
Change metric name from "karakeep_crawler_status_codes" to
"karakeep_crawler_status_codes_total" to comply with Prometheus
naming best practices for counter metrics.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 2 -1/+13
fix(mobile): upgrade react-native-pdf to v7 to fix page alignment MohamedBassem 3 -66/+9
fix(mobile): fix app memory page size compatibility (#2135)
* fix(mobile): Add 16KB memory page size support for Android
Updates to support Google Play's requirement for 16KB memory page sizes:
- Update Expo SDK from 53.0.11 to 53.0.19
- Update expo-image from 2.2.0 to 2.4.0
- Update React Native from 0.79.3 to 0.79.5
- Configure expo-build-properties with:
  - compileSdkVersion: 35
  - targetSdkVersion: 35
  - buildToolsVersion: 34.0.0
  - ndkVersion: 27.1.12297006 (r27 with 16KB support)
These changes ensure all native libraries are compiled with proper
alignment for 16KB page sizes as required by Android 15+ devices.
Fixes Google Play rejection: "Your app does not support 16 KB memory page sizes"
* some fixes
* more fixes
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 4 -398/+351
release(mobile): Bump mobile version to 1.8.2 Mohamed Bassem 1 -3/+3
fix: remove incorrect array destructuring in mobile search (#2124)
The search was crashing because of incorrect array destructuring on
the useDebounce hook return value. useDebounce returns a string, not
an array, so using `const [query] = useDebounce(...)` caused query
to be undefined when the search string was empty.
This resulted in passing { text: undefined } to the tRPC endpoint,
which failed Zod validation expecting a string.
Fixed by removing the array destructuring: const query = useDebounce(...)
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 1 -1/+1
feat: correct default prom metrics from web and worker containers Mohamed Bassem 2 -0/+2
fix: fix crash in crawler on invalid URL in matchesNoProxy Mohamed Bassem 1 -3/+9
feat: add crawler domain rate limiting (#2115) Mohamed Bassem 5 -32/+121
refactor: Allow runner functions to return results to onComplete Mohamed Bassem 8 -36/+32
feat(extension): Add custom header support for extension (#2111)
Fixes #1287
Mohamed Bassem 6 -7/+204
feat: Add bookmark sources statistics section (#2110)
* feat: add bookmark sources statistics to usage stats page
Add a new section to the usage statistics page that displays stats about
bookmark sources (mobile, extension, web, API, CLI, etc).
Changes:
- Add bookmarksBySource field to user stats response schema
- Implement backend query to fetch bookmarks grouped by source
- Add new "Bookmark Sources" card to stats page UI
- Add helper function to format source names for display
* refactor: use stricter enum type for bookmark sources in stats API
Replace generic string type with zBookmarkSourceSchema enum for better
type safety and autocomplete. This ensures the API contract matches the
database schema definition.
Changes:
- Import and use zBookmarkSourceSchema in user stats response
- Define BookmarkSource type alias in frontend
- Update formatSourceName to use stricter type and return non-nullable
- Remove fallback case since all enum values are now handled
* refactor: use shared BookmarkSource type and add i18n support
- Replace local BookmarkSource type with canonical type from shared package
  using z.infer<typeof zBookmarkSourceSchema>
- Add translation support for "Bookmark Sources" title and empty state
- Add bookmark_sources.title and bookmark_sources.empty keys to English
  locale file
This ensures type consistency across the codebase and prepares for
future localization of the bookmark sources feature.
* fix icons
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 5 -1/+146
feat: Add page titles (#2109)
* feat: add Next.js metadata titles to dynamic and settings pages
Add page titles using Next.js metadata API for better SEO and user experience:
- List pages: Show list name in format "<name> | Karakeep"
- Tag pages: Show tag name in format "<name> | Karakeep"
- Admin pages: Add titles for overview, users, and background jobs pages
- Settings pages: Add titles for all settings pages (API keys, AI, feeds, import, info, webhooks, subscription, rules, stats, assets, broken links)
For client components (rules, stats, assets, broken-links), created layout.tsx files to export metadata since metadata can only be exported from server components.
* feat: add Next.js metadata titles to dashboard pages
Add page titles using Next.js metadata API to archive, favourites, highlights, and all tags pages:
- Archive page: Show "Archive | Karakeep"
- Favourites page: Show "Favourites | Karakeep"
- Highlights page: Show "Highlights | Karakeep"
- All Tags page: Show "All Tags | Karakeep"
Improves SEO and user experience across all dashboard browsing pages.
* refactor: use i18n translations for dashboard page titles
Convert hardcoded page titles to use translations via generateMetadata:
- Archive page: Uses common.archive translation
- Favourites page: Uses lists.favourites translation
- Highlights page: Uses common.highlights translation
- All Tags page: Uses tags.all_tags translation
Improves localization support across dashboard pages.
* feat: add i18n translations to admin and settings page titles
Convert hardcoded page titles to use translations via generateMetadata:
- Admin Overview: Uses admin.admin_settings translation
- AI Settings: Uses settings.ai.ai_settings translation
- API Keys: Uses settings.api_keys.api_keys translation
- Feed Settings: Uses settings.feeds.rss_subscriptions translation
- Import/Export: Uses settings.import.import_export translation
- Account Info: Uses settings.info.user_info translation
- Subscription: Uses settings.subscription.subscription translation
- Webhooks: Uses settings.webhooks.webhooks translation
Improves localization support across admin and settings pages.
* revert accidental commit
* more translations
* more fixes
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 20 -0/+247
feat: add failed_permanent metric for worker monitoring (#2107)
* feat: add last failure timestamp metric for worker monitoring
Add a Prometheus Gauge metric to track the timestamp of the last failure
for each worker. This complements the existing failed job counter by
providing visibility into when failures last occurred for monitoring and
alerting purposes.
Changes:
- Added workerLastFailureGauge metric in metrics.ts
- Updated all 9 workers to set the gauge on failure:
  - crawler, feed, webhook, assetPreProcessing
  - inference, adminMaintenance, ruleEngine
  - video, search
* refactor: track both all failures and permanent failures with counter
Remove the gauge metric and use the existing counter to track both:
- All failures (including retry attempts): status="failed"
- Permanent failures (retries exhausted): status="failed_permanent"
This provides better visibility into retry behavior and permanent vs
temporary failures without adding a separate metric.
Changes:
- Removed workerLastFailureGauge from metrics.ts
- Updated all 9 workers to track failed_permanent when numRetriesLeft == 0
- Maintained existing failed counter for all failure attempts
* style: format worker files with prettier
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 9 -0/+32
release(extension): Release version 1.7.1 Mohamed Bassem 1 -1/+1
release(mobile): Bump mobile version to 1.8.1 Mohamed Bassem 1 -3/+3
fix: standardize US English translations to professional tone
Remove informal/casual language ('wanna', 'mate', 'dude', 'ain't', 'lil')
and replace with standard professional English. This maintains consistency
with other language variants and the overall professional tone of the application.
Mohamed Bassem 1 -24/+24
i18n: Sync weblate translations
Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Co-authored-by: Hamid Jamali <hamid1375jamali@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Kachelkaiser <kachelkaiser@htpst.de>
Co-authored-by: OpenAI <noreply-mt-openai@weblate.org>
Co-authored-by: Thomas K <t.kristner@gmail.com>
Co-authored-by: hb k <hbk0424@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ar/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/cs/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/da/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/de/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/el/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/en_US/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/es/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/fa/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/fi/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/fr/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ga/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/gl/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/hr/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/hu/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/it/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ja/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ko/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/nl/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/pl/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/pt/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/ru/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/sk/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/sl/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/sv/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/tr/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/uk/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/vi/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/karakeep/karakeep/zh_Hant/
Translation: Karakeep/Karakeep
Hosted Weblate 31 -205/+3808
feat(extension): Allow writing notes directly in the extension (#2104)
* feat(extension): add notes editor to bookmark hoarded screen
Adds the ability to directly add and edit notes for bookmarks in the browser extension's hoarded screen (the page shown after saving a bookmark).
Changes:
- Created Textarea UI component for the browser extension
- Created NoteEditor component that uses useUpdateBookmark hook
- Added Notes section to BookmarkSavedPage, displayed between the header and tags
- Notes auto-save when the user clicks away from the textarea (onBlur)
- Shows saving state and error messages to the user
This brings feature parity with the web app's notes functionality.
* add explicit button
* more fixes
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 3 -0/+132
fix(mobile): fix default address not correctly stored in settings MohamedBassem 2 -3/+3
feat(mobile): add custom headers configuration in sign-in screen (#2103)
* feat(mobile): add custom headers configuration in sign-in screen
Add ability for mobile app users to configure custom HTTP headers that are
sent with every API request. This enables users to add authentication headers,
proxy headers, or other custom headers required by their server setup.
Changes:
- Add customHeaders field to mobile app settings schema
- Create CustomHeadersModal component for managing headers
- Update sign-in screen with link to configure custom headers
- Modify tRPC provider to merge custom headers with Authorization header
The custom headers are stored securely in the app settings and persist
across sessions.
* fix keyboard
* add custom headers to other callsites
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 8 -5/+252
feat: Add what's new modal in the sidebar (#2099)
* Refactor sidebar release modal to use React Query
* fixes
* fix manual server override
Mohamed Bassem 3 -13/+262
feat: Add support for user uploaded files (#2100)
* feat: add user file upload support for bookmarks
Add a new "user-uploaded" asset type that allows users to upload and
attach their own files to bookmarks from the attachment box in the
bookmark preview page.
Changes:
- Add USER_UPLOADED asset type to database schema
- Add userUploaded to zAssetTypesSchema for type safety
- Update attachment permissions to allow attaching/detaching user files
- Add fileName field to asset schema for displaying custom filenames
- Add "Upload File" button in AttachmentBox component
- Display actual filename for user-uploaded files
- Allow any file type for user uploads (respects existing upload limits)
- Add Upload icon for user-uploaded files
Fixes #1863 related asset attachment improvements
* fix: ensure fileName is returned and remove edit button for user uploads
- Fix attachAsset mutation to fetch and return complete asset with fileName
  instead of just returning the input (which lacks fileName)
- Remove replace/edit button for user-uploaded files - users can only
  delete and re-upload instead
- This ensures the filename displays correctly in the UI immediately
  after upload
Fixes fileName propagation issue for user-uploaded assets
* fix asset file name
* remove filename from attach asset api
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mohamed Bassem 10 -31/+101
fix: metascraper logo to go through proxy if one configured. fixes #1863 Mohamed Bassem 1 -1/+14
feat(extension): add tab bookmark badge indicator (#1745)
* feat: add tab bookmark count badge indicator
- implement getApiClient function to create and cache TRPC client
- add tab activation listener to check bookmark count
- display badge with count and appropriate color based on results
- handle errors by showing error indicator in badge
* feat: add show count badge setting to extension
- Add showCountBadge setting to settings schema and default values
- Implement toggle button in OptionsPage for count badge visibility
- Modify background script to respect showCountBadge setting
- Add logging for archive count check in background script
Closes #486
* feat(background): refactor tab badge update logic
- Extract badge setting logic into reusable `setBadge` function
- Create `getTabCount` function to fetch bookmark count and existence
- Implement `checkAndUpdateIcon` function to centralize icon update logic
- Add support for tab updates via `chrome.tabs.onUpdated` listener
- Improve error handling with consistent badge display
* feat(background): implement badge caching system
- Add badge cache initialization and periodic cleanup
- Implement cache get/set operations for badge status
- Update setBadge function to use cached values when available
- Modify badge display logic to check cache before making API calls
* feat(badgeCache): add debug logging for cache operations
- Add console logs to track cache initialization, purging, and operations
- Move debug log in checkAndUpdateIcon to better position
* feat: add badge refresh on bookmark creation and deletion
- implement message types for badge refresh communication
- update background script to handle REFRESH_BADGE messages
- modify SavePage to send message on successful bookmark creation
- modify BookmarkSavedPage to send message on successful deletion
- add clearBadgeStatusSWR utility function import and usage
* perf(badge-cache): decrease purge alarm interval
The badge cache purge alarm was previously set to run every 60
minutes. This change reduces the interval to 10 minutes to ensure
more frequent cache cleanup and better memory management.
* feat(background): clean up API client and badge cache on invalid settings
- add cleanupApiClient function to trpc utils
- modify checkSettingsState to handle async operations
- clear API client and badge status when settings are invalid
- update settings subscription to handle async operations
* feat: reset settings to include showCountBadge flag when logout
When deleting API key, ensure showCountBadge is also reset to false to
maintain consistent state in the options page configuration.
* refactor: use BOOKMARK_REFRESH_BADGE instead of separate created/deleted types
* perf(badgeCache): replace alarm-based purge with on-demand expiration check
- Remove periodic alarm system for cache purging
- Add lastPurgeTimestamp tracking for efficient cache maintenance
- Update manifest to remove unnecessary alarms permission
- Modify background script to use new on-demand purge mechanism
- Clean up related alarm listener and initialization code
* feat: Replace count badge button with toggle switch
- add new Switch component based on Radix UI
- update OptionsPage to use Switch for count badge setting
* feat: Add horizontal rule separator in options page
- Add `<hr />` element between sections for better visual separation
- Improve UI organization in the OptionsPage component
* feat(badgeCache): implement persistent last purge timestamp storage
- Replace in-memory timestamp with chrome.storage persistence
- Add getter/setter functions for last purge timestamp
- Update checkAndPurgeIfNeeded to use persistent storage
* refactor(badgeCache): Improve type safety and storage utilities
- Add BadgeCacheEntry and BadgeCacheStorage types
- Extract storage operations to dedicated utility functions
- Improve code organization and documentation
- Enhance type safety throughout badge cache operations
* feat(extension): add context menu options to clear cache
- introduce new context menu items for cache management
- add clear current site cache functionality
- add clear all cache functionality
- conditionally show cache menu items based on showCountBadge setting
- pass settings to context menu registration/removal functions
* feat(extension): add configurable badge cache expiration time
- introduce `badgeCacheExpireMs` setting with 1-hour default
- update settings schema and default values
- add input field in OptionsPage for cache time configuration
- modify badgeCache to use dynamic expiration time from settings
- improve cache logging for better debugging visibility
* Revert "feat: reset settings to include showCountBadge flag when logout"
This reverts commit cf071e9dd50f1a1ac0a8dd3b68a4359ecc30c783.
# Conflicts:
#	apps/browser-extension/src/OptionsPage.tsx
* refactor(extension): extract badge cache expiration constant
Extract DEFAULT_BADGE_CACHE_EXPIRE_MS constant to central location in
settings.ts and reuse it across badgeCache.ts and OptionsPage.tsx. Remove
duplicate constant definitions and ensure consistent default value usage.
* refactor(extension): standardize showCountBadge default via shared constant
- introduce DEFAULT_SHOW_COUNT_BADGE in settings schema
- replace hardcoded defaults with constant in schema and OptionsPage
- maintain backward compatibility with existing boolean type
* feat(extension): simplify context menu removal logic
- remove redundant `settings` parameter from `removeContextMenus`
- replace selective menu removal with `chrome.contextMenus.removeAll()`
- update function call to match new signature
* refactor(extension): rename site-related cache terms to page for clarity
- update context menu title from "Clear Current Site Cache" to "Clear Current
  Page Cache"
- rename `clearCurrentSiteCache()` to `clearCurrentPageCache()`
- adjust related comments, logs, and docstrings for consistency
* refactor(extension): improve tab event handler parameter naming
- rename `activeInfo` to `tabActiveInfo` in `onActivated` listener
- rename `changeInfo` to `tabId` in `onUpdated` listener
* refactor(extension): add isHttpUrl utility and refactor server address validation
- introduce reusable `isHttpUrl` function in new `url.ts` utility module
- replace inline protocol check with utility call in NotConfiguredPage
* feat(extension): filter out non-HTTP URLs from badge count updates
- add `isHttpUrl` import and check in badge update validation
- skip badge updates for non-HTTP URLs to prevent invalid requests
* feat(extension): filter out non-HTTP URLs from bookmark creation
Add validation using isHttpUrl utility to ensure only HTTP/HTTPS
URLs are processed when creating bookmarks from current tab.
* chore: remove .ts extension from internal import statements
* feat(extension): validate and trim server address input in NotConfiguredPage
- use trimmed input for validation and state updates
- ensure consistent handling of trailing slashes in server address
* feat(extension): prevent non-HTTP(S) URL bookmark creation with validation
- Add URL validation in background script to filter out non-HTTP(S) URLs
  before creating link-type bookmarks, logging warnings for invalid URLs.
- Enhance SavePage component with explicit error messages for:
  - Missing tab URLs
  - Unsupported URL schemes (non-HTTP(S))
- Improve error display by rendering messages immediately when errors occur
  instead of waiting for status changes.
* feat(extension): clear existing context menus before registration
This ensures no duplicate menu items are created when the extension
reinitializes or settings are updated.
* feat(extension): display "+" suffix for default bookmarks per page count
Add logic to append "+" suffix when badge count matches
DEFAULT_NUM_BOOKMARKS_PER_PAGE to indicate potential overflow.
* fix(extension): ensure API client cleanup on settings state change
Clean up API client before handling settings state to prevent stale
connections when address or API key is missing.
* fix(extension): clear badge text when tab is invalid or incomplete
Ensure badge is reset when URL is non-HTTP or tab status is not complete.
* feat(extension): improve badge revalidation for stale cached data
- simplify badge setting from cached data
- add background revalidation for non-fresh cache
- ensure badge updates when stale cache is detected
* feat(extension): refresh active tab badges after cache clearance
Added logic to update badge icons for all active tabs when clearing
the badge status cache, ensuring UI consistency across the extension.
* feat: add null checks for tab URL and ID in REFRESH_BADGE handler
Add defensive programming to prevent runtime errors when processing
REFRESH_BADGE messages with missing or invalid tab properties.
* feat(extension): replace badge status SWR clear with full cache refresh
Replace selective SWR badge status clearing with a complete cache refresh
to ensure consistent badge state across all active tabs. Updates the
`clearBadgeStatusSWR()` call to use the more comprehensive `clearAllCache()`
method and improves related documentation.
* feat(extension): add validation & error handling for API client
- add null check and error throw in `getTabCount` when API client fails
- ensure badge is cleared when API client is unavailable
- refactor `getApiClient` to use destructured settings
- fix potential undefined access in TRPC client initialization
* feat(extension): replace isExisted with exactMatch for precise bookmark info
- modify getTabCount to return exactMatch instead of isExisted
- update BadgeCacheEntry type to use ZBookmark|null for exactMatch
- adjust setBadge and setBadgeStatusSWR to handle new exactMatch format
- ensure backward compatibility by converting exactMatch to boolean
* refactor(background): rename getTabCount to getBookmarkStatusForUrl
- improve function naming to better reflect return value
- update JSDoc to clarify return object structure
- adjust all function calls to use new name
* feat(extension): add "View page in Karakeep" context menu option
- introduce new `VIEW_PAGE_IN_KARAKEEP` menu item for extension action
- extend `handleContextMenuClick` to support optional tab parameter
- add `searchCurrentUrl` function to handle URL-based searches
- implement exact match and search fallback logic with proper URL encoding
- ensure error handling and validation for invalid URLs
* feat(extension): reorder menu items and extend page context support
- Move 'Add to Karakeep' menu creation before conditional block
- Add 'page' context to 'View this page in Karakeep' menu item
* feat(extension): add toggle to enable/disable badge caching
- introduce `useBadgeCache` setting in schema and defaults
- add switch control in OptionsPage to toggle cache usage
- conditionally render cache expire time input based on toggle
- make badge cache operations respect the toggle setting
- hide cache-related context menu items when caching disabled
- skip cache operations in background when disabled
- prevent cache checks and purges when caching is off
* fix(extension): handle cache miss in bookmark search flow
Previously, the search flow would silently fail (no-op) when the cache missed.
Now, it falls back to fetching the bookmark status directly from the server
when no cached data is available. Also refactored to avoid redundant settings
fetch and improve code readability.
* refactor(badge): implement generic cache utility and refactor badge cache
* Remove dedicated cache type definitions in favor of generic solution
* Create reusable cache utility with L1/L2 (memory/storage) support
* Simplify badge cache implementation using new generic cache
* Remove redundant SWR-specific functions and consolidate logic
* Improve type safety and error handling in cache operations
* Eliminate deprecated cache management functions and types
* refactor(extension): replace custom cache with TanStack Query for badge status
- Remove custom SWR cache implementation
- Add TanStack Query persistence with Chrome storage
- Update badge status logic to use QueryClient
- Add storage persister utility for Chrome
- Update TRPC client initialization with QueryClient
- Add required TanStack Query persistence dependencies
* fix(extension): add missing `useBadgeCache` config and refactor cache logic
- restore accidentally removed `useBadgeCache` setting from refactor
- update cache invalidation logic to include `useBadgeCache` changes
- modify QueryClient config to respect `useBadgeCache` toggle
- improve settings comparison logic for better reuse detection
* fix(extension): use dynamic key for TanStack query cache persistence
Previously used hardcoded string 'TANSTACK_QUERY_CACHE_KEY' instead of the
defined constant, which could lead to inconsistent storage access.
* fix(cache): propagate fetch errors to avoid caching failed badge status
Previously, API errors would return an empty status, causing cache to store
invalid results. Now errors are thrown so the cache treats them as misses.
* fix(extension): guard chrome storage and respect cache disable setting
- use `globalThis.chrome` to avoid runtime errors in non-extension contexts
- skip persistence when `useBadgeCache=false` and clear existing cache
- add `maxAge` and `buster` to prevent stale/incompatible data restoration
* refactor(badgeCache): remove redundant null check for searchBookmarks data
Remove unnecessary if (!data) guard since searchBookmarks query is guaranteed
to return a non-nullable response due to its Zod schema. Use direct access to
data.bookmarks and simplify empty state check with bookmarksLength.
* fix(badgeCache): throw error on misconfiguration instead of caching empty
Prevent cache poisoning by throwing when API client is not configured.
This ensures setup errors are visible rather than silently cached as 0.
* fix(badgeCache): add fallback to fetchBadgeStatus when QueryClient missing
Prevents null returns by falling back to direct fetch when QueryClient
is unavailable, ensuring badge remains responsive.
* feat(extension): add yellow badge for URLs ignoring anchor and trailing slash
- implement partial URL matching logic in badge status calculation
- introduce `BadgeMatchType` enum for different match scenarios
- update badge color scheme (green=exact, yellow=partial, red=none)
- refactor badge status interface and setBadge function signature
- handle edge cases for null badge status in error scenarios
* feat: support partial bookmark matches in badge status check
- use partial match fallback when exact match is unavailable
- update target URL generation to handle both match types
- ensure consistent bookmark ID reference in preview URL
* refactor: improve error handling and badge status logic
* wrap `removeContextMenus()` in try-catch block to prevent crashes
  when context menus API fails
* simplify badge setting logic by removing redundant status check
* fix `getBadgeStatus()` return type to always resolve with `BadgeStatus`
* update import path for `urlsMatchIgnoringAnchorAndTrailingSlash`
* clarify comments for URL matching logic and edge cases
* perf: parallelize active-tab badge refresh after cache clear
Avoid serial waits across windows/tabs by using Promise.all to process
active tab IDs concurrently. Replaces nested loops with flatMap and
filter for cleaner extraction of active tab IDs.
* fix(badge): isolate cache config to badge queries only
Move cache time configuration from global QueryClient to badge-specific
queries to prevent unintended caching in other query operations.
* fix: Invalid configuration check should verify if either field is missing.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* fix(trpc): include address in cache buster to isolate persisted caches
Prevents restoring stale data from a different server after switching
address by scoping the cache buster to the current backend address.
* feat(trpc): ensure proper client cleanup on config changes
- add client removal from persistent storage when address/apiKey invalid
- ensure cache wipe when switching context with address/apiKey changes
- simplify persister creation by using default chrome.storage.local
- make storage parameter optional in createChromeStorage
* fix bad merge
* simplify badge by dropping the count
* more fixes
* more fix
---------
Co-authored-by: Mohamed Bassem <me@mbassem.com>
qixing-jk 14 -142/+827
fix: restore image size in grid layout Mohamed Bassem 1 -2/+2
deps: Upgrade react-query to 5.90 MohamedBassem 12 -93/+93
feat: Support inline toggling for todos. fixes #1931 (#1933)
* [1931] Can now chain the creation of todos from the quick add form
* [1931] Can now toggle todos from the masonry view + added a custom renderer for inputs of type checkbox (required to remove the readonly default attribute)
* handle nested lists and case
---------
Co-authored-by: Cédric <cedric.marinot@elosi.com>
Co-authored-by: Mohamed Bassem <me@mbassem.com>
Cédric 3 -1/+85
fix: fix monolith to respect crawler proxy Mohamed Bassem 1 -0/+9
feat(rss): Add import tags from RSS feed categories (#2031)
* feat(feeds): Add import tags from RSS feed categories
- Add importTags boolean field to rssFeedsTable schema (default: false)
- Create database migration 0063_add_import_tags_to_feeds.sql
- Update zod schemas (zFeedSchema, zNewFeedSchema, zUpdateFeedSchema) to include importTags
- Update Feed model to handle importTags in create and update methods
- Update feedWorker to:
  - Read title and categories from RSS parser
  - Attach categories as tags to bookmarks when importTags is enabled
  - Log warnings if tag attachment fails
Resolves #1996
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
* feat(web): Add importTags option to feed settings UI
- Add importTags toggle to FeedsEditorDialog (create feed)
- Add importTags toggle to EditFeedDialog (edit feed)
- Display as a bordered switch control with descriptive text
- Defaults to false for new feeds
Co-authored-by: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
* fix migration
* remove extra migration
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
Mohamed Bassem 8 -0/+2596
fix: fix crash in search input when query contains a percent. fixes #1941 Mohamed Bassem 1 -1/+1
feat: Add view options to show tag/title and control image fit. Fixes #1960 Mohamed Bassem 6 -29/+214
refactor: improve the userLocalSetting server functions Mohamed Bassem 1 -27/+14
feat: Make search job timeout configurable Mohamed Bassem 4 -3/+8
feat: display notes on bookmark card (#2083)
* feat: display notes on bookmark card
* apply styling
* include mobile impl
* apply pr comments
* add display options menu into PR
* put it under app setting
* cleanup
* address pr comments
* change the default for show notes to false
* make the in-card note font lighter
---------
Co-authored-by: Mohamed Bassem <me@mbassem.com>
xuatz 13 -25/+268
fix: Stricter SSRF validation (#2082)
* fix: Stricter SSRF validation
* skip dns resolution if running in proxy context
* more fixes
* Add LRU cache
* change the env variable for internal hostnames
* make dns resolution timeout configerable
* upgrade ipaddr
* handle ipv6
* handle proxy bypass for request interceptor
Mohamed Bassem 10 -135/+602
fix: correctly handle composition in search input. fixes #2048 Mohamed Bassem 1 -1/+21
fix: More memory optimizations for crawler worker. #1748 Mohamed Bassem 1 -26/+43
fix: fix screenshot filepath in crawler Mohamed Bassem 1 -1/+1
fix: Respect abort signal in admin maintenance jobs Mohamed Bassem 3 -1/+11
deps: Upgrade metascraper plugins Mohamed Bassem 2 -132/+148
deps: Upgrade metascraper-readability 5.49.6 Mohamed Bassem 2 -33/+434
feat: Allow configuring inline asset size threshold Mohamed Bassem 5 -31/+32
feat: Add admin maintenance job to migrate large inline HTML (#2071)
* Add admin maintenance job to migrate large inline HTML
* add cursor
* more fixes
Mohamed Bassem 8 -4/+218
refactor: generalize tidy assets queue into admin maintenance (#2059)
* refactor: generalize admin maintenance queue
* more fixes
Mohamed Bassem 10 -159/+227
feat: Add source field to track bookmark creation sources (#2037)
* feat: Add source field to track bookmark creation sources
Add a new 'source' field to the bookmarks table to track where bookmarks
were created from. Possible values: api, web, cli, mobile, singlefile, rss.
Changes:
- Add source field to bookmarks table schema
- Update Zod schemas to include source field
- Update tRPC createBookmark procedure to store source
- Update all callsites to pass appropriate source value:
  - api: Default to "api" if not provided
  - singlefile: Set to "singlefile"
  - rss: Set to "rss" in feedWorker
  - cli: Set to "cli"
  - mobile: Set to "mobile" in all mobile app bookmark creation
  - browser-extension: Set to "web"
  - web: Set to "web" in all web app bookmark creation
- Create migration file for database schema change
Fixes #2036
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
* feat: Add extension source type for browser extension
- Add 'extension' to bookmark source enum
- Update browser extension to use 'extension' instead of 'web'
Co-authored-by: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
* fix CI
* fix CI
* fix the migration file
* add import source
* make source nullish
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
Mohamed Bassem 16 -12/+2650
feat: support passing multiple proxy values (#2039)
* feat: support passing multiple proxy values
* fix typo
* trim and filter
Mohamed Bassem 4 -36/+60
next