Skip to content

Service Layer

The service layer in src/services/ encapsulates all business logic, keeping components and stores thin. Services interact with Supabase directly and are consumed by Pinia stores and composables.

Architecture

Service Facade

src/services/index.ts exports a unified services object that provides access to all service instances:

typescript
services.messages   // CoreMessageService
services.posts      // CorePostService
services.profiles   // CoreProfileService
services.interactions // CoreInteractionService

This facade pattern keeps imports clean and allows swapping implementations.

Core Services (src/services/core/)

Core services handle pure local database operations with no federation side effects. Federation is triggered automatically by database triggers after the local operation succeeds.

ServiceResponsibilities
CoreMessageServiceSend/edit/delete messages, reactions, pagination, encryption decision
CorePostServiceCreate/edit/delete posts, favorites, reblogs, bookmarks, timeline queries
CoreProfileServiceProfile CRUD, avatar/banner updates
CoreInteractionServiceFollow/unfollow, block/unblock, mute/unmute, relationship queries

All core services:

  • Use AuthContextService for the current user context
  • Are singletons via getInstance()
  • Validate inputs strictly before database calls
  • Return typed results (e.g., SendMessageData, CreatePostData, FollowResult)

Message Send Flow

Feature Services

Higher-level services that may coordinate multiple core services or external integrations:

ServicePurpose
PostServiceWraps CorePostService, adds ActivityPub context
MessageServiceWraps CoreMessageService, adds thread/DM logic
InteractionServiceWraps CoreInteractionService
ActivityPubServiceTimeline queries, federation interactions, follows
AdminServiceSystem stats, user management, federation management
InviteServiceServer invite creation and validation
SearchServiceMessage and user search
ThreadServiceThread messages (bypasses encryption, sent as plaintext)
FileServiceFile upload and management
TrendingServiceTrending hashtags and posts
NotificationServiceNotification delivery and management
ProfileServiceFull profile operations including federation triggers

Encryption Services (src/services/encryption/)

ServicePurpose
MegolmServiceLow-level Megolm session management (create, encrypt, decrypt)
MegolmMessageEncryptionServiceHigh-level message encryption/decryption singleton
RecoveryKeyServiceMnemonic derivation, key wrapping, recovery
SecureSessionKeyStoreIndexedDB storage for non-extractable CryptoKeys
MegolmKeyBackupServiceServer-side key backup and restore
WebRTCEncryptionServiceSignal Protocol encryption for WebRTC streams

Federation Services (src/services/federation/)

ServicePurpose
FederationActivityServiceActivityPub activity creation and delivery
FederationServerServiceFederated server discovery and management
FederationDecisionServicePolicy decisions for federation (trust, blocking)

Infrastructure Services

ServicePurpose
AuthContextServiceCached auth user/profile ID resolution (singleton)
RealtimeConnectionManagerSupabase Realtime wrapper with auto-reconnect
userDataServiceCached user profile lookups with presence tracking
ServiceWorkerManagerPWA service worker and push notification management
LoggingServiceStructured logging with configurable levels
AppInitServiceApplication boot sequence and route-aware initialization
SessionHeartbeatPeriodic session keepalive
StatePersistenceState serialization to localStorage

Voice/Video Services

ServicePurpose
webrtcManagerMode switching between SFU (LiveKit) and P2P
livekitWebRTCLiveKit SFU integration with E2EE support
unifiedWebRTCP2P mesh via Supabase Realtime signaling
SpatialAudio2D spatial audio positioning via Web Audio API
VoiceSettingsServiceDevice selection and audio settings
DMCallSignalingDM call setup and teardown

Patterns

Singleton Access

Most services use a getInstance() static method:

typescript
const messageService = CoreMessageService.getInstance()

Local-First with Federation Triggers

Services write to the local database only. Federation is handled by PostgreSQL triggers that call queue_federation_job(), which feeds the pg-boss job queue consumed by the federation backend. This ensures local operations are fast and federation failures don't block the user.

Request Deduplication

RequestDeduplicator (src/utils/requestDeduplicator.ts) prevents duplicate concurrent requests for the same resource, used by userDataService and other services that may receive rapid repeated calls.


Note: This page is protected from auto-generation. Edit the content in docs-source/guide/architecture/services.md and run npm run docs:generate-guide to update.

Released under the AGPL-3.0 License.