4.4 KiB
core:data
Room database, DataStore preferences, EncryptedSharedPreferences for tokens, and all repository implementations. This is the coordination layer between network and local storage.
What This Module Provides
- Room database (
db/LibreChatDatabase.kt): 6 entities, 6 DAOs, version 1,exportSchema = true. - Entities:
ConversationEntity,MessageEntity,FileEntity,AgentEntity,PresetEntity,ConversationTagEntity. Complex fields (lists, nested objects) stored as JSON strings viaConverters. - DAOs:
ConversationDao,MessageDao,FileDao,AgentDao,PresetDao,ConversationTagDao. Read methods returnFlow<T>for reactive observation. - DataStore:
ServerDataStore(server URL prefs),SettingsDataStore(user preferences). - Token storage (
datastore/TokenDataStore.kt): ImplementsTokenManagerfrom:core:networkusingEncryptedSharedPreferenceswith AES-256. UsesMutexto ensure only one refresh runs at a time when multiple 401s arrive concurrently. - Repositories (
repository/): Interface + Impl for each domain:AuthRepository,ConversationRepository,MessageRepository,ChatRepository,FileRepository,AgentRepository,PresetRepository,PromptRepository,TagRepository,ShareRepository,ConfigRepository,UserRepository,SettingsRepository. - Entity mappers (
db/mapper/EntityMapper.kt): Convert between Room entities and domain models. - Sync manager (
sync/ConversationSyncManager.kt): Orchestrates cache invalidation.
Key Patterns
Repository: Interface + Impl
interface ConversationRepository {
fun observeConversations(...): Flow<Result<List<Conversation>>>
suspend fun updateTitle(id: String, title: String): Result<Conversation>
}
All impls take constructor parameters (api, dao, mapper, dispatcher) wired via Koin named qualifiers.
Read-Through Cache
- Emit cached data from Room immediately (first page).
- Fetch fresh data from network via API service.
- Upsert into Room. The Room
Flowauto-emits the updated list. - On network error, the cached data remains visible; error is surfaced separately.
Token Refresh with Mutex
private val refreshMutex = Mutex()
override suspend fun refreshAccessToken(): Boolean = refreshMutex.withLock {
// Single refresh attempt, all concurrent callers wait on this lock
}
Wrap EncryptedSharedPreferences in try/catch -- some OEM devices have broken Keystore implementations. On KeyStoreException, clear tokens and force re-login.
DataModule Bindings
DataModule.kt defines a Koin module { } that binds repository interfaces to their implementations via singleOf(::Impl) bind Interface::class and provides the Room database, DAOs, and DataStore instances.
Room TypeConverters
Converters.kt handles JSON serialization for complex Room fields: List<String>, MessageContentPart lists, Feedback, FileReference lists, etc. Uses the same Json instance from the Koin graph.
Rules
- Dependencies:
:core:network,:core:model,:core:common, Room, DataStore, security-crypto, Ktor, kotlinx-serialization, Timber, Koin. - Convention plugins:
librechat.mobile.library+librechat.mobile.koin+librechat.mobile.room+librechat.kotlin.serialization. - Repositories must use
safeApiCallfrom:core:commonfor all network calls. - Entities are internal to this module -- feature modules work with domain models from
:core:model. - All DAO read methods that the UI observes should return
Flow, not suspend functions.
New Repositories (Round 2)
MemoryRepository/MemoryRepositoryImpl— wrapsMemoriesApifor memory CRUD + preferencesMcpRepository/McpRepositoryImpl— wrapsMcpApifor server CRUD, tools, connection status, reinitialize- Both bound in
DataModule.ktviasingleOf - Both use
safeApiCall— no local caching (server is sole source of truth for memories and MCP) - Gotcha: Memory delete/update use
keyas identifier (not a separate ID field) - Gotcha: MCP server operations use
serverNameas identifier
New Repositories (Round 3)
BannerRepository/BannerRepositoryImpl— wrapsBannerApifor fetching server bannersAgentRepository.getAgentsPaginated()— server-side paginated agent fetch, maps response toPaginatedAgentsdomain model- Both bound in
DataModule.ktviasingleOf, both usesafeApiCall, no local caching