aboutsummaryrefslogtreecommitdiffstats
path: root/apps (follow)
Commit message (Collapse)AuthorAgeFilesLines
* feat: add notes to the bookmark edit dialogMohamed Bassem2025-12-251-0/+21
|
* fix(cli): migrate bookmark source in migration commandMohamed Bassem2025-12-251-0/+1
|
* fix: preserve failure count when rescheduling rate limited domains (#2303)Mohamed Bassem2025-12-251-38/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * fix: preserve retry count when rate-limited jobs are rescheduled Previously, when a domain was rate-limited in the crawler worker, the job would be re-enqueued as a new job, which reset the failure count. This meant rate-limited jobs could retry indefinitely without respecting the max retry limit. This commit introduces a RateLimitRetryError exception that signals the queue system to retry the job after a delay without counting it as a failed attempt. The job is retried within the same invocation, preserving the original retry count. Changes: - Add RateLimitRetryError class to shared/queueing.ts - Update crawler worker to throw RateLimitRetryError instead of re-enqueuing - Update Restate queue service to handle RateLimitRetryError with delay - Update Liteque queue wrapper to handle RateLimitRetryError with delay This ensures that rate-limited jobs respect the configured retry limits while still allowing for delayed retries when domains are rate-limited. * refactor: use liteque's native RetryAfterError for rate limiting Instead of manually handling retries in a while loop, translate RateLimitRetryError to liteque's native RetryAfterError. This is cleaner and lets liteque handle the retry logic using its built-in mechanism. * test: add tests for RateLimitRetryError handling in restate queue Added comprehensive tests to verify that: 1. RateLimitRetryError delays retry appropriately 2. Rate-limited retries don't count against the retry limit 3. Jobs can be rate-limited more times than the retry limit 4. Regular errors still respect the retry limit These tests ensure the queue correctly handles rate limiting without exhausting retry attempts. * lint & format * fix: prevent onError callback for RateLimitRetryError Fixed two issues with RateLimitRetryError handling in restate queue: 1. RateLimitRetryError now doesn't trigger the onError callback since it's not a real error - it's an expected rate limiting behavior 2. Check for RateLimitRetryError in runWorkerLogic before calling onError, ensuring the instanceof check works correctly before the error gets further wrapped by restate Updated tests to verify onError is not called for rate limit retries. * fix: catch RateLimitRetryError before ctx.run wraps it Changed approach to use a discriminated union instead of throwing and catching RateLimitRetryError. Now we catch the error inside the ctx.run callback before it gets wrapped by restate's TerminalError, and return a RunResult type that indicates success, rate limit, or error. This fixes the issue where instanceof checks would fail because ctx.run wraps all errors in TerminalError. * more fixes * rename error name --------- Co-authored-by: Claude <noreply@anthropic.com>
* feat: show bookmark owner icon in shared lists (#2277)Mohamed Bassem2025-12-245-46/+164
| | | | | | | | | | | | | | | | | | | | | | * feat: Add owner icon to bookmarks in shared lists Display a small icon showing the bookmark owner's name and email on hover when viewing bookmarks from other users in shared lists. The icon appears in the top-right corner of bookmark cards across all layout types (grid, list, compact). Changes: - Add user field to ZBookmark type to include owner name and email - Update bookmark queries to fetch user information via join - Create BookmarkOwnerIcon component with tooltip showing owner details - Integrate owner indicator into BookmarkLayoutAdaptingCard for all layouts - Only show icon for bookmarks not owned by current user * use icons in more places * remove tooltip providers * fix non list context --------- Co-authored-by: Claude <noreply@anthropic.com>
* feat: add support for user avatars (#2296)Mohamed Bassem2025-12-2410-4/+297
| | | | | | | | | | | * feat: add support for user avatars * more fixes * more fixes * more fixes * more fixes
* feat: add a warning about viewing archives inline. fixes #2286Mohamed Bassem2025-12-223-1/+33
|
* feat: Add user settings to disable auto tagging/summarization (#2275)Mohamed Bassem2025-12-226-1/+149
| | | | | | | | | | | | | | | | | | | | | | | | | | * feat: Add per-user settings to disable auto-tagging and auto-summarization This commit adds user-level controls for AI features when they are enabled on the server. Users can now toggle auto-tagging and auto-summarization on/off from the AI Settings page. Changes: - Added autoTaggingEnabled and autoSummarizationEnabled fields to user table - Updated user settings schemas and API endpoints to handle new fields - Modified inference workers to check user preferences before processing - Added toggle switches to AI Settings page (only visible when server has features enabled) - Generated database migration for new fields - Exposed enableAutoTagging and enableAutoSummarization in client config The settings default to null (use server default). When explicitly set to false, the user's bookmarks will skip the respective AI processing. * revert migration * i18n --------- Co-authored-by: Claude <noreply@anthropic.com>
* feat(mobile): Convert server address editing to modal in mobile app (#2290)Mohamed Bassem2025-12-223-84/+257
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * feat: Convert server address editing to modal in mobile app Changed the server address editing experience from an inline button to a modal dialog. This improves UX by forcing users to explicitly save or cancel their changes rather than forgetting to click a save button. Changes: - Created ServerAddressModal component following the CustomHeadersModal pattern - Updated signin page to use the modal instead of inline editing - Enhanced settings page to allow changing server address (was previously read-only) - Added validation and error handling within the modal - Made the settings page server address clickable with visual feedback This resolves the issue where users forget to click the save button after editing the server address. * refactor: Convert server address to screen modal Changed from React Native Modal to Expo Router screen modal presentation. This provides a better native experience with proper navigation stack integration. Changes: - Created server-address.tsx as a screen route with modal presentation - Registered the route in root _layout.tsx - Updated signin.tsx to navigate to the screen modal instead of opening RN modal - Reverted settings page to original (no server address editing from settings) - Removed ServerAddressModal component (no longer needed) Benefits: - Native modal presentation with proper animations - Better integration with the navigation stack - Cleaner separation of concerns * merge the custom headers inside the server-add screen * fix the look of the address UI --------- Co-authored-by: Claude <noreply@anthropic.com>
* fix: optimize tagging db queries (#2287)Mohamed Bassem2025-12-221-18/+18
| | | | | | | | | * fix: optimize tagging db queries * review * parallel queries * refactoring
* feat(mobile): Show shared lists under a subsectionMohamed Bassem2025-12-201-8/+66
|
* fix(mobile): Fix title line clamp to 2 linesMohamed Bassem2025-12-201-4/+9
|
* fix(mobile): Add loading spinner to mobile list button (#2283)Mohamed Bassem2025-12-201-25/+51
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * fix: add loading spinner to manage lists buttons in mobile app Adds visual feedback when adding/removing bookmarks from lists on the manage lists page. The checkbox is replaced with an ActivityIndicator while the operation is in progress, preventing multiple taps and improving UX when the server is slow. Changes: - Track isPending and variables from add/remove mutations - Add isListLoading helper to check if a specific list is loading - Show ActivityIndicator instead of Checkbox during operations - Disable Pressable interaction while loading * fix: add loading spinner to manage tags page in mobile app Adds visual feedback when adding/removing tags on the manage tags page. A spinner appears on the specific tag being modified, replacing the check/plus icon during the network request. Only the tag being modified is disabled and dimmed to prevent multiple taps. Changes: - Track isPending and variables from updateTags mutation - Add isTagLoading helper to check if a specific tag is loading - Show ActivityIndicator on the specific tag being modified - Only disable the tag item that's loading * revert the change in the tags --------- Co-authored-by: Claude <noreply@anthropic.com>
* feat: add server version display to mobile app settings (#2276)Mohamed Bassem2025-12-202-0/+43
| | | | | | | | - Created useServerVersion hook to fetch server version from /api/version - Display both app version (from expo-constants) and server version - Added version info at the bottom of settings page - Server version shows loading state and handles errors gracefully Co-authored-by: Claude <noreply@anthropic.com>
* fix: add authentication checks to settings layout (#2274)Mohamed Bassem2025-12-201-2/+24
| | | | | | | | | | | | | | | | | The settings layout was missing authentication checks, causing server errors when unauthenticated users tried to access any settings page. This fix adds: - Session verification via getServerAuthSession() - Redirect to "/" if no session exists - Proper error handling with tryCatch wrapper - Redirect to "/logout" for NOT_FOUND or UNAUTHORIZED errors This brings the settings layout in line with the auth patterns used in dashboard, admin, and reader layouts. Fixes #2242 Co-authored-by: Claude <noreply@anthropic.com>
* fix: only trigger search autocomplete on first search charMohamed Bassem2025-12-201-2/+7
|
* feat(landing): remove waitlist link. fixes #2270Mohamed Bassem2025-12-192-5/+5
|
* fix: collapse reader settings by defaultMohamed Bassem2025-12-181-186/+209
|
* feat: Add unified reader settings with local overrides (#2230)Evan Simkowitz2025-12-1520-185/+1484
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Add initial impl * fix some format inconsistencies, add indicator in user settings when local is out of sync * Fix sliders in user settings, unify constants and formatting * address CodeRabbit suggestions * add mobile implementation * address coderabbit nitpicks * fix responsiveness of the reader settings popover * Move more of the web UI strings to i18n * update translations for more coverage * remove duplicate logic/definitions * fix android font family * add shared reading setting hook between web and mobile * unify reader settings context for both web and mobile * remove unused export * address coderabbit suggestions * fix tests
* fix: Fix Amazon product image extraction on amazon.com URLs (#2108)Randall Hand2025-12-142-0/+79
| | | | | | | | | | | | | | | | 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>
* feat: use reddit API for metadata extraction. Fixes #1853 #1883Mohamed Bassem2025-12-133-33/+343
|
* fix: use GET requests for the content type requestMohamed Bassem2025-12-131-1/+1
|
* release(cli): Bump CLI version to 0.29.1Mohamed Bassem2025-12-131-1/+1
|
* deps: Upgrade nextjs to 15.3.8Mohamed Bassem2025-12-121-1/+1
|
* deps: Upgrade nextjs to 15.3.7Mohamed Bassem2025-12-111-1/+1
|
* feat: make asset preprocessing worker timeout configurableClaude2025-12-101-1/+1
| | | | | | - 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
* feat(cli): Add ability to list users for the admin in the CLIMohamed Bassem2025-12-082-0/+91
|
* fix: check import quota before importing bookmarks (#2232)Mohamed Bassem2025-12-082-3/+53
| | | | | | | | | | | | | | | | | | | | | | | * 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>
* build: fix typecheck error in query explainerMohamed Bassem2025-12-081-0/+10
|
* fix: migrate to metascraper-x from metascraper-twitterMohamed Bassem2025-12-082-3/+3
|
* feat: add is:broken search qualifier for broken links (#2225)Mohamed Bassem2025-12-082-0/+8
| | | | | | | | | | | | | | | | | | | | 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>
* feat: spread feed fetch scheduling deterministically over the hour (#2227)Mohamed Bassem2025-12-081-0/+31
| | | | | | | | | | 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>
* fix: better extraction for youtube thumbnails. #2204Mohamed Bassem2025-12-072-0/+14
|
* deps: Upgrade nextjs to 15.3.6Mohamed Bassem2025-12-031-1/+1
|
* feat: add a notification badge for list invitationsMohamed Bassem2025-11-302-0/+27
|
* fix: regen turnstile token on signup resubmissionMohamed Bassem2025-11-301-1/+14
|
* feat(landing): Add more features to the homepageMohamed Bassem2025-11-301-8/+47
|
* feat: add support for turnstile on signupMohamed Bassem2025-11-303-0/+44
|
* release: cli, mcp and sdkMohamed Bassem2025-11-292-2/+2
|
* release(extension): Release version 1.2.8Mohamed Bassem2025-11-291-1/+1
|
* release(mobile): Bump mobile version to 1.8.3Mohamed Bassem2025-11-291-3/+3
|
* i18n: fix en_US translationMohamed Bassem2025-11-291-57/+57
|
* i18n: Sync weblate translationsHosted Weblate2025-11-2931-62/+3286
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* feat: autocomplete search terms (#2178)Mohamed Bassem2025-11-294-61/+629
| | | | | | | | | | | | | * refactor(web): split search autocomplete logic * some improvements * restructure the code * fix typesafety * add feed suggestions * fix
* feat: Add automated bookmark backup feature (#2182)Mohamed Bassem2025-11-299-0/+1071
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* fix: fix react errors in signin and signup formsMohamed Bassem2025-11-282-0/+10
|
* fix: separate shared lists in the sidebar (#2180)Mohamed Bassem2025-11-284-31/+237
| | | | | | | * fix: separate shared lists in the sidebar * fix sub * i18n
* fix: correctly render asset extracted text in the edit bookmark dialog. ↵Mohamed Bassem2025-11-281-4/+24
| | | | fixes #2181
* fix: lazy load js-tiktoken in prompts module (#2176)Mohamed Bassem2025-11-283-10/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* fix: fix colors in invitation formMohamed Bassem2025-11-272-7/+7
|
* fix: hide archived checkbox in shared listsMohamed Bassem2025-11-271-1/+1
|