aboutsummaryrefslogtreecommitdiffstats
path: root/packages/shared (follow)
Commit message (Collapse)AuthorAgeFilesLines
* feat: add "URL Does Not Contain" condition to rule engine (#2280)Mohamed Bassem2025-12-301-0/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * feat: add "URL Does Not Contain" condition to rule engine Add a new condition type `urlDoesNotContain` that allows users to create rules based on URLs that do NOT contain specific strings. This enables more flexible rule configurations, such as: - Automatically adding bookmarks to a "Read Later" list if the URL does not contain "reddit.com" or "youtube.com" Changes: - Added `urlDoesNotContain` condition type to Zod schema - Implemented evaluation logic in RuleEngine - Added UI support in ConditionBuilder component - Added translation key for new condition type - Added test coverage for the new condition Fixes #2259 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Mohamed Bassem <MohamedBassem@users.noreply.github.com> * fix type link --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
* feat: 2025 wrapped (#2322)Mohamed Bassem2025-12-301-0/+67
| | | | | * feat: 2025 wrapped * don't add wrapped for new users
* fix: more tagging tweaksMohamed Bassem2025-12-291-4/+3
|
* fix: change prompt to better recognize error pagesMohamed Bassem2025-12-291-3/+6
|
* refactor: reduce duplication in compare-models toolMohamed Bassem2025-12-291-28/+79
|
* feat: Add open telemetry (#2318)Mohamed Bassem2025-12-291-0/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * feat: add OpenTelemetry tracing infrastructure Introduce distributed tracing capabilities using OpenTelemetry: - Add @opentelemetry packages to shared-server for tracing - Create tracing utility module with span helpers (withSpan, addSpanEvent, etc.) - Add tRPC middleware for automatic span creation on API calls - Initialize tracing in API and workers entry points - Add demo instrumentation to bookmark creation and crawler worker - Add configuration options (OTEL_TRACING_ENABLED, OTEL_EXPORTER_OTLP_ENDPOINT, etc.) - Document tracing configuration in environment variables docs When enabled, traces are collected for tRPC calls, bookmark creation flow, and crawler operations, with support for any OTLP-compatible backend (Jaeger, Tempo, etc.) * refactor: remove tracing from workers for now Keep tracing infrastructure but remove worker instrumentation: - Remove tracing initialization from workers entry point - Remove tracing instrumentation from crawler worker - Fix formatting in tracing files The tracing infrastructure remains available for future use. * add hono and next tracing * remove extra span logging * more fixes * update config * some fixes * upgrade packages * remove unneeded packages --------- Co-authored-by: Claude <noreply@anthropic.com>
* fix: reset tagging status on crawl failure (#2316)Mohamed Bassem2025-12-292-3/+8
| | | | | | | * feat: add the ability to specify a different changelog version * fix: reset tagging status on crawl failure * fix missing crawlStatus in loadMulti
* feat: add the ability to specify a different changelog versionMohamed Bassem2025-12-291-0/+2
|
* feat: add customizable tag styles (#2312)Mohamed Bassem2025-12-273-5/+71
| | | | | | | | | | | | | | | * feat: add customizable tag styles * add tag lang setting * ui settings cleanup * fix migration * change look of the field * more fixes * fix tests
* feat: add Matter import support (#2245)Moondragon852025-12-271-0/+50
| | | | | | | | | | | * Matter import * use zod * fix date parsing --------- Co-authored-by: Mohamed Bassem <me@mbassem.com>
* feat: support archiving as pdf (#2309)Mohamed Bassem2025-12-272-0/+4
| | | | | | | | | | | * feat: support archiving as pdf * add supprot for manually triggering pdf downloads * fix submenu * menu cleanup * fix store pdf
* feat: add OPENAI_PROXY_URL configuration and support for proxy in OpenAI ↵rzxczxc2025-12-272-0/+12
| | | | | | | | | | | | | client (#2231) * Add OPENAI_PROXY_URL configuration and support for proxy in OpenAIInferenceClient * docs: add OPENAI_PROXY_URL configuration for proxy support in OpenAI API requests * format --------- Co-authored-by: Mohamed Bassem <me@mbassem.com>
* fix: preserve failure count when rescheduling rate limited domains (#2303)Mohamed Bassem2025-12-251-0/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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: add support for user avatars (#2296)Mohamed Bassem2025-12-242-0/+2
| | | | | | | | | | | * feat: add support for user avatars * more fixes * more fixes * more fixes * more fixes
* fix: handle empty folder names in HTML bookmark imports (#2300)Mohamed Bassem2025-12-242-1/+85
| | | | | | | | | When importing bookmarks from an HTML file, empty H3 tags (folder names) are now replaced with "Unnamed" to prevent import failures. Fixes #2299 Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Mohamed Bassem <MohamedBassem@users.noreply.github.com>
* feat: Add user settings to disable auto tagging/summarization (#2275)Mohamed Bassem2025-12-222-0/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | * 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: Add unified reader settings with local overrides (#2230)Evan Simkowitz2025-12-152-0/+69
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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
* feat: Add limits on number of rss feeds and webhooks per userMohamed Bassem2025-12-131-0/+6
|
* feat: make asset preprocessing worker timeout configurableClaude2025-12-101-0/+2
| | | | | | - 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
* fix: check import quota before importing bookmarks (#2232)Mohamed Bassem2025-12-081-0/+1
| | | | | | | | | | | | | | | | | | | | | | | * 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>
* feat: add is:broken search qualifier for broken links (#2225)Mohamed Bassem2025-12-083-0/+28
| | | | | | | | | | | | | | | | | | | | 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: add support for turnstile on signupMohamed Bassem2025-11-302-0/+23
|
* feat: Add automated bookmark backup feature (#2182)Mohamed Bassem2025-11-293-0/+28
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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: making serverConfig readonlyMohamed Bassem2025-11-281-1/+3
|
* fix: lazy load js-tiktoken in prompts module (#2176)Mohamed Bassem2025-11-281-26/+100
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* feat: Introduce groupId in restate queue (#2168)Mohamed Bassem2025-11-241-0/+1
| | | | | | | * feat: Introduce groupId in restate queue * add group ids to the interface * use last served timestamp
* feat: Add notes feature to highlights (#2154)Mohamed Bassem2025-11-231-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* feat: Add collaborative lists (#2146)Mohamed Bassem2025-11-172-0/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* feat: import from mymind (#2138)Mohamed Bassem2025-11-152-1/+145
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* feat: add crawler domain rate limiting (#2115)Mohamed Bassem2025-11-092-4/+13
|
* refactor: Allow runner functions to return results to onCompleteMohamed Bassem2025-11-091-5/+5
|
* refactor: Extract ratelimiter into separate plugin (#2112)Mohamed Bassem2025-11-092-0/+42
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * refactor(trpc): extract rate limiter into dedicated plugin Move the rate limiting middleware from the trpc package to the centralized plugins package. This improves code organization by consolidating all plugins in a single location. Changes: - Created packages/plugins/trpc-ratelimit/ plugin - Moved rate limiter from packages/trpc/rateLimit.ts to packages/plugins/trpc-ratelimit/src/index.ts - Added trpc-ratelimit export to plugins package.json - Added @trpc/server dependency to plugins package - Updated trpc package to import from @karakeep/plugins/trpc-ratelimit - Added @karakeep/plugins dependency to trpc package - Removed packages/trpc/plugins/ directory * refactor(plugins): decouple rate limiter from tRPC Refactor the rate limiting plugin to be framework-agnostic, allowing it to be used outside of tRPC contexts. The plugin now has a generic core with a tRPC-specific adapter. Changes: - Renamed trpc-ratelimit to ratelimit plugin - Created generic RateLimiter class with framework-agnostic API - Added checkRateLimit() method that returns allow/deny results - Created separate tRPC adapter (src/trpc.ts) that uses the generic core - Exported both generic (RateLimiter, globalRateLimiter) and tRPC-specific (createRateLimitMiddleware) APIs - Updated trpc package to import from @karakeep/plugins/ratelimit - Updated plugins package.json exports Benefits: - Rate limiter can now be used in any context (HTTP handlers, WebSocket, etc.) - Cleaner separation of concerns - Easy to create adapters for other frameworks - Generic API allows for custom error handling * refactor(plugins): integrate rate limiter with plugin registry Refactor the rate limiting plugin to use the centralized plugin system with PluginManager, making it consistent with other plugins like queue and search providers. Changes: - Added RateLimit plugin type to PluginType enum - Created RateLimitClient interface in packages/shared/ratelimiting.ts - Created RateLimitProvider class implementing PluginProvider - Updated plugin to auto-register with PluginManager on import - Updated tRPC adapter to use getRateLimitClient() from PluginManager - Added ratelimit plugin to loadAllPlugins() in shared-server - Updated shared/plugins.ts with RateLimit type mapping Benefits: - Consistent plugin architecture across the codebase - Rate limiter can be swapped with alternative implementations - Centralized plugin management and logging - Better separation of concerns - Framework-agnostic core with tRPC adapter pattern * refactor(trpc): move rate limit middleware to trpc package Move the tRPC-specific rate limiting middleware from the plugins package to the trpc package, making the plugins package framework-agnostic. Changes: - Moved packages/plugins/ratelimit/src/trpc.ts to packages/trpc/lib/rateLimit.ts - Updated packages/trpc/index.ts to import from local lib/rateLimit - Removed tRPC export from packages/plugins/ratelimit/index.ts - Removed @trpc/server dependency from packages/plugins/package.json Benefits: - plugins package is now framework-agnostic - tRPC-specific code lives in the trpc package where it belongs - Cleaner separation of concerns - Rate limiter plugin can be used in any context without tRPC * refactor(plugins): rename to ratelimit-memory and add tests Rename the rate limiting plugin from "ratelimit" to "ratelimit-memory" to better indicate it's an in-memory implementation. This naming leaves room for future implementations like ratelimit-redis. Also added comprehensive test coverage. Changes: - Renamed packages/plugins/ratelimit to ratelimit-memory - Updated package.json export from ./ratelimit to ./ratelimit-memory - Updated shared-server to import @karakeep/plugins/ratelimit-memory - Added comprehensive unit tests (index.test.ts): - Rate limit enforcement tests - Window expiration tests - Identifier and path isolation tests - Reset functionality tests - Cleanup mechanism tests - Added provider integration tests (provider.test.ts): - PluginProvider interface compliance - Client singleton behavior - End-to-end rate limiting functionality Benefits: - More descriptive plugin name indicating the storage mechanism - Better test coverage ensuring reliability - Easier to add alternative implementations (Redis, etc.) * change the api to only take the key * move the serverConfig check to the trpc * fix lockfile * get rid of the timer --------- Co-authored-by: Claude <noreply@anthropic.com>
* feat: Add bookmark sources statistics section (#2110)Mohamed Bassem2025-11-091-0/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* feat: Add support for user uploaded files (#2100)Mohamed Bassem2025-11-081-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* feat(rss): Add import tags from RSS feed categories (#2031)Mohamed Bassem2025-11-021-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* feat: Make search job timeout configurableMohamed Bassem2025-11-021-0/+2
|
* fix: Stricter SSRF validation (#2082)Mohamed Bassem2025-11-021-1/+24
| | | | | | | | | | | | | | | | | | | * 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
* feat: Allow configuring inline asset size thresholdMohamed Bassem2025-10-261-0/+2
|
* fix(inferance): skip token slicing when content is already witin max lengthMohamed Bassem2025-10-261-0/+3
|
* fix: update OpenAI API to use max_completion_tokens instead of max_tokens ↵Benjamin Michaelis2025-10-252-2/+8
| | | | | | | | | | (#2000) * fix: update OpenAI API to use max_completion_tokens instead of max_tokens The OpenAI API has deprecated max_tokens in favor of max_completion_tokens for newer models. This change updates both text and image model calls. * feat: add support for max_completion_tokens in OpenAI inference configuration
* feat: Add source field to track bookmark creation sources (#2037)Mohamed Bassem2025-10-121-0/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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>
* feat: support passing multiple proxy values (#2039)Mohamed Bassem2025-10-121-2/+18
| | | | | | | * feat: support passing multiple proxy values * fix typo * trim and filter
* feat: Add service dependency checks in the server overview pageMohamed Bassem2025-10-121-0/+8
|
* fix: Correct grammatical errors in prompts (#2020)atsggx2025-10-111-2/+2
| | | Corrected "who's" to "whose" in buildImagePrompt and buildTextPrompt.
* feat: Restate-based queue plugin (#2011)Mohamed Bassem2025-10-051-2/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * WIP: Initial restate integration * add retry * add delay + idempotency * implement concurrency limits * add admin stats * add todos * add id provider * handle onComplete failures * add tests * add pub key and fix logging * add priorities * fail call after retries * more fixes * fix retries left * some refactoring * fix package.json * upgrade sdk * some test cleanups
* feat: Revamp import experience (#2001)Mohamed Bassem2025-10-044-18/+121
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * WIP: import v2 * remove new session button * don't redirect after import * store and lint to root list * models + tests * redesign the progress * simplify the import session for ow * drop status from session schema * split the import session page * i18n * fix test * remove pagination * fix some colors in darkmode * one last fix * add privacy filter * privacy check * fix interactivity of import progress * fix test
* feat: Add tag search and pagination (#1987)Mohamed Bassem2025-09-282-0/+64
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * feat: Add tag search and use in the homepage * use paginated query in the all tags view * wire the load more buttons * add skeleton to all tags page * fix attachedby aggregation * fix loading states * fix hasNextPage * use action buttons for load more buttons * migrate the tags auto complete to the search api * Migrate the tags editor to the new search API * Replace tag merging dialog with tag auto completion * Merge both search and list APIs * fix tags.list * add some tests for the endpoint * add relevance based sorting * change cursor * update the REST API * fix review comments * more fixes * fix lockfile * i18n * fix visible tags
* refactor: Move callsites to liteque to be behind a pluginMohamed Bassem2025-09-145-236/+100
|
* refactor: strongly type the search plugin interfaceMohamed Bassem2025-09-141-3/+19
|
* feat(search): add title search qualifier (#1940)Mohamed Bassem2025-09-133-1/+50
| | | | | | | * fix(search): include link titles in title matcher * docs(search): add title qualifier * docs: remove title qualifier from v0.27 guide