From 41a4f6f48deb7689bb8dbb0b87463dcb4ae397da Mon Sep 17 00:00:00 2001 From: HueByte Date: Tue, 24 Feb 2026 22:08:54 +0000 Subject: [PATCH] deploy: 5d61266fd7a42a16c5b9892c12e1e06d01108efa --- api/client-articles/index.html | 2 +- .../EchoHub.Client.AppOrchestrator.html | 2 +- ...choHub.Client.Commands.CommandHandler.html | 2 +- ...EchoHub.Client.Commands.CommandResult.html | 2 +- api/client/EchoHub.Client.Commands.html | 2 +- .../EchoHub.Client.Config.AccountPreset.html | 2 +- .../EchoHub.Client.Config.ClientConfig.html | 2 +- .../EchoHub.Client.Config.ConfigManager.html | 2 +- ...oHub.Client.Config.NotificationConfig.html | 2 +- .../EchoHub.Client.Config.SavedServer.html | 2 +- api/client/EchoHub.Client.Config.html | 2 +- .../EchoHub.Client.Services.ApiClient.html | 2 +- .../EchoHub.Client.Services.AsyncRunner.html | 2 +- ....Client.Services.AudioPlaybackService.html | 2 +- .../EchoHub.Client.Services.BackupInfo.html | 2 +- ...ient.Services.ClientEncryptionService.html | 2 +- ...Hub.Client.Services.EchoHubConnection.html | 2 +- ...ent.Services.NotificationSoundService.html | 2 +- .../EchoHub.Client.Services.PathSetup.html | 2 +- ...b.Client.Services.UpdateBackupService.html | 2 +- ...EchoHub.Client.Services.UpdateChecker.html | 2 +- api/client/EchoHub.Client.Services.html | 2 +- api/client/EchoHub.Client.Themes.Theme.html | 2 +- .../EchoHub.Client.Themes.ThemeColors.html | 2 +- .../EchoHub.Client.Themes.ThemeManager.html | 2 +- api/client/EchoHub.Client.Themes.html | 2 +- .../EchoHub.Client.UI.Chat.ChatColors.html | 2 +- .../EchoHub.Client.UI.Chat.ChatLine.html | 2 +- ...EchoHub.Client.UI.Chat.ChatListSource.html | 2 +- ...Hub.Client.UI.Chat.ChatMessageManager.html | 2 +- .../EchoHub.Client.UI.Chat.ChatSegment.html | 2 +- api/client/EchoHub.Client.UI.Chat.html | 2 +- ...b.Client.UI.Dialogs.AudioPlayerDialog.html | 2 +- ...hoHub.Client.UI.Dialogs.ConnectDialog.html | 2 +- ...Client.UI.Dialogs.ConnectDialogResult.html | 2 +- ...Client.UI.Dialogs.CreateChannelDialog.html | 2 +- ...Client.UI.Dialogs.CreateChannelResult.html | 2 +- ...hoHub.Client.UI.Dialogs.ProfileAction.html | 2 +- ...b.Client.UI.Dialogs.ProfileEditDialog.html | 2 +- ...b.Client.UI.Dialogs.ProfileEditResult.html | 2 +- ...b.Client.UI.Dialogs.ProfileViewDialog.html | 2 +- ...choHub.Client.UI.Dialogs.StatusDialog.html | 2 +- ....Client.UI.Dialogs.StatusDialogResult.html | 2 +- ...Client.UI.Dialogs.UpdateConfirmDialog.html | 2 +- ...lient.UI.Dialogs.UpdateProgressDialog.html | 2 +- api/client/EchoHub.Client.UI.Dialogs.html | 2 +- ...EchoHub.Client.UI.Helpers.EmojiHelper.html | 2 +- ...oHub.Client.UI.Helpers.HexColorHelper.html | 2 +- api/client/EchoHub.Client.UI.Helpers.html | 2 +- ...ient.UI.ListSources.ChannelListSource.html | 2 +- ....Client.UI.ListSources.UserListSource.html | 2 +- api/client/EchoHub.Client.UI.ListSources.html | 2 +- api/client/EchoHub.Client.UI.MainWindow.html | 2 +- api/client/EchoHub.Client.UI.html | 2 +- api/client/EchoHub.Client.html | 2 +- api/core-articles/index.html | 2 +- .../EchoHub.Core.Constants.HubConstants.html | 2 +- ...ub.Core.Constants.ValidationConstants.html | 2 +- api/core/EchoHub.Core.Constants.html | 2 +- ...choHub.Core.Contracts.ChannelListItem.html | 2 +- ...choHub.Core.Contracts.IChannelService.html | 2 +- ...hoHub.Core.Contracts.IChatBroadcaster.html | 2 +- .../EchoHub.Core.Contracts.IChatService.html | 2 +- ...EchoHub.Core.Contracts.IEchoHubClient.html | 2 +- ...e.Contracts.IMessageEncryptionService.html | 2 +- .../EchoHub.Core.Contracts.IUserService.html | 2 +- api/core/EchoHub.Core.Contracts.html | 2 +- api/core/EchoHub.Core.DTOs.ApiResponse-1.html | 2 +- api/core/EchoHub.Core.DTOs.ApiResponse.html | 2 +- .../EchoHub.Core.DTOs.AssignRoleRequest.html | 2 +- ...choHub.Core.DTOs.AvatarUploadResponse.html | 2 +- api/core/EchoHub.Core.DTOs.BanRequest.html | 2 +- api/core/EchoHub.Core.DTOs.ChannelDto.html | 2 +- api/core/EchoHub.Core.DTOs.ChannelError.html | 2 +- ...oHub.Core.DTOs.ChannelOperationResult.html | 2 +- ...choHub.Core.DTOs.CreateChannelRequest.html | 2 +- api/core/EchoHub.Core.DTOs.EmbedDto.html | 2 +- ...hoHub.Core.DTOs.EncryptionKeyResponse.html | 2 +- api/core/EchoHub.Core.DTOs.ErrorResponse.html | 2 +- .../EchoHub.Core.DTOs.JoinChannelResult.html | 2 +- api/core/EchoHub.Core.DTOs.KickRequest.html | 2 +- api/core/EchoHub.Core.DTOs.LoginRequest.html | 2 +- api/core/EchoHub.Core.DTOs.LoginResponse.html | 2 +- api/core/EchoHub.Core.DTOs.MessageDto.html | 2 +- api/core/EchoHub.Core.DTOs.MuteRequest.html | 2 +- ...EchoHub.Core.DTOs.PaginatedResponse-1.html | 2 +- .../EchoHub.Core.DTOs.RefreshRequest.html | 2 +- .../EchoHub.Core.DTOs.RegisterRequest.html | 2 +- .../EchoHub.Core.DTOs.SendMessageRequest.html | 2 +- .../EchoHub.Core.DTOs.SendUrlRequest.html | 2 +- .../EchoHub.Core.DTOs.ServerStatusDto.html | 2 +- ...choHub.Core.DTOs.UpdateProfileRequest.html | 2 +- ...EchoHub.Core.DTOs.UpdateStatusRequest.html | 2 +- .../EchoHub.Core.DTOs.UpdateTopicRequest.html | 2 +- api/core/EchoHub.Core.DTOs.UserDto.html | 2 +- api/core/EchoHub.Core.DTOs.UserError.html | 2 +- ...EchoHub.Core.DTOs.UserOperationResult.html | 2 +- .../EchoHub.Core.DTOs.UserPresenceDto.html | 2 +- .../EchoHub.Core.DTOs.UserProfileDto.html | 2 +- api/core/EchoHub.Core.DTOs.html | 2 +- api/core/EchoHub.Core.Models.Channel.html | 2 +- ...EchoHub.Core.Models.ChannelMembership.html | 2 +- api/core/EchoHub.Core.Models.Message.html | 2 +- api/core/EchoHub.Core.Models.MessageType.html | 2 +- .../EchoHub.Core.Models.RefreshToken.html | 2 +- api/core/EchoHub.Core.Models.ServerRole.html | 2 +- api/core/EchoHub.Core.Models.User.html | 2 +- api/core/EchoHub.Core.Models.UserStatus.html | 2 +- api/core/EchoHub.Core.Models.html | 2 +- api/index.html | 2 +- api/server-articles/index.html | 2 +- .../EchoHub.Server.Irc.IrcBroadcaster.html | 2 +- ...choHub.Server.Irc.IrcClientConnection.html | 2 +- .../EchoHub.Server.Irc.IrcCommandHandler.html | 2 +- .../EchoHub.Server.Irc.IrcGatewayService.html | 2 +- .../EchoHub.Server.Irc.IrcMessage.html | 2 +- ...choHub.Server.Irc.IrcMessageFormatter.html | 2 +- .../EchoHub.Server.Irc.IrcNumericReply.html | 2 +- .../EchoHub.Server.Irc.IrcOptions.html | 2 +- ...hoHub.Server.Irc.IrcServiceExtensions.html | 2 +- api/server-irc/EchoHub.Server.Irc.html | 2 +- .../EchoHub.Server.Auth.JwtTokenService.html | 2 +- api/server/EchoHub.Server.Auth.html | 2 +- ...Hub.Server.Controllers.AuthController.html | 2 +- ...Server.Controllers.ChannelsController.html | 2 +- ...ub.Server.Controllers.FilesController.html | 2 +- ...rver.Controllers.ModerationController.html | 2 +- ...b.Server.Controllers.ServerController.html | 2 +- ...ub.Server.Controllers.UsersController.html | 2 +- api/server/EchoHub.Server.Controllers.html | 2 +- .../EchoHub.Server.Data.EchoHubDbContext.html | 2 +- ...Data.Migrations.AddAttachmentFileSize.html | 2 +- ...er.Data.Migrations.AddChannelIsPublic.html | 2 +- ....Data.Migrations.AddChannelMembership.html | 2 +- ....Data.Migrations.AddEncryptionSupport.html | 2 +- ...erver.Data.Migrations.AddMessageEmbed.html | 2 +- ...er.Data.Migrations.AddModerationRoles.html | 2 +- ....Server.Data.Migrations.InitialCreate.html | 2 +- .../EchoHub.Server.Data.Migrations.html | 2 +- api/server/EchoHub.Server.Data.html | 2 +- api/server/EchoHub.Server.Hubs.ChatHub.html | 2 +- api/server/EchoHub.Server.Hubs.html | 2 +- ...choHub.Server.Services.ChannelService.html | 2 +- .../EchoHub.Server.Services.ChatService.html | 2 +- ...ub.Server.Services.FileCleanupService.html | 2 +- ...ub.Server.Services.FileStorageService.html | 2 +- ....Server.Services.FileValidationHelper.html | 2 +- ...b.Server.Services.ImageToAsciiService.html | 2 +- ...oHub.Server.Services.LinkEmbedService.html | 2 +- ...ver.Services.MessageEncryptionService.html | 2 +- ...Server.Services.MuteExpirationService.html | 2 +- ...hoHub.Server.Services.PresenceTracker.html | 2 +- ...erver.Services.ServerDirectoryService.html | 2 +- ...ub.Server.Services.SignalRBroadcaster.html | 2 +- .../EchoHub.Server.Services.UserService.html | 2 +- api/server/EchoHub.Server.Services.html | 2 +- ...Hub.Server.Setup.DataMigrationService.html | 2 +- .../EchoHub.Server.Setup.DatabaseSetup.html | 2 +- .../EchoHub.Server.Setup.FirstRunSetup.html | 2 +- api/server/EchoHub.Server.Setup.html | 2 +- articles/architecture.html | 2 +- articles/configuration.html | 424 ++++++++++++++++++ articles/docker.html | 71 +-- articles/encryption.html | 2 +- articles/getting-started.html | 6 +- articles/notification-sounds.html | 2 +- articles/toc.html | 3 + articles/toc.json | 2 +- changelog/index.html | 2 +- changelog/v0.1.0.html | 2 +- changelog/v0.1.1.html | 2 +- changelog/v0.2.0.html | 2 +- changelog/v0.2.1.html | 2 +- changelog/v0.2.2.html | 2 +- changelog/v0.2.3.html | 2 +- changelog/v0.2.4.html | 2 +- changelog/v0.2.5.html | 2 +- changelog/v0.2.6.html | 2 +- changelog/v0.2.7.html | 2 +- changelog/v0.2.8.html | 2 +- flows/authentication.html | 148 +----- flows/channels.html | 125 +----- flows/connection.html | 133 +----- flows/flows.html | 2 +- flows/media.html | 108 +---- flows/messaging.html | 160 +------ flows/moderation.html | 49 +- index.html | 2 +- index.json | 21 +- manifest.json | 10 + public/main.css | 14 +- todo.html | 2 +- 192 files changed, 643 insertions(+), 987 deletions(-) create mode 100644 articles/configuration.html diff --git a/api/client-articles/index.html b/api/client-articles/index.html index 09a0c01..eb28283 100644 --- a/api/client-articles/index.html +++ b/api/client-articles/index.html @@ -119,7 +119,7 @@ diff --git a/api/client/EchoHub.Client.AppOrchestrator.html b/api/client/EchoHub.Client.AppOrchestrator.html index 12326b3..9f447a7 100644 --- a/api/client/EchoHub.Client.AppOrchestrator.html +++ b/api/client/EchoHub.Client.AppOrchestrator.html @@ -275,7 +275,7 @@ Wires UI events to service calls and connection events to UI updates.

diff --git a/api/client/EchoHub.Client.Commands.CommandHandler.html b/api/client/EchoHub.Client.Commands.CommandHandler.html index 9864e0b..6f8148a 100644 --- a/api/client/EchoHub.Client.Commands.CommandHandler.html +++ b/api/client/EchoHub.Client.Commands.CommandHandler.html @@ -938,7 +938,7 @@ Class CommandHandler
- +
diff --git a/api/client/EchoHub.Client.Commands.CommandResult.html b/api/client/EchoHub.Client.Commands.CommandResult.html index f5052c8..a870e1a 100644 --- a/api/client/EchoHub.Client.Commands.CommandResult.html +++ b/api/client/EchoHub.Client.Commands.CommandResult.html @@ -652,7 +652,7 @@ Class CommandResult
- +
diff --git a/api/client/EchoHub.Client.Commands.html b/api/client/EchoHub.Client.Commands.html index 795df40..f6fec53 100644 --- a/api/client/EchoHub.Client.Commands.html +++ b/api/client/EchoHub.Client.Commands.html @@ -122,7 +122,7 @@ Classes diff --git a/api/client/EchoHub.Client.Config.AccountPreset.html b/api/client/EchoHub.Client.Config.AccountPreset.html index 77b808a..63c54d0 100644 --- a/api/client/EchoHub.Client.Config.AccountPreset.html +++ b/api/client/EchoHub.Client.Config.AccountPreset.html @@ -295,7 +295,7 @@ Class AccountPreset
- +
diff --git a/api/client/EchoHub.Client.Config.ClientConfig.html b/api/client/EchoHub.Client.Config.ClientConfig.html index 52100b2..542225c 100644 --- a/api/client/EchoHub.Client.Config.ClientConfig.html +++ b/api/client/EchoHub.Client.Config.ClientConfig.html @@ -326,7 +326,7 @@ Class ClientConfig
- +
diff --git a/api/client/EchoHub.Client.Config.ConfigManager.html b/api/client/EchoHub.Client.Config.ConfigManager.html index fae51ec..a856006 100644 --- a/api/client/EchoHub.Client.Config.ConfigManager.html +++ b/api/client/EchoHub.Client.Config.ConfigManager.html @@ -296,7 +296,7 @@ Class ConfigManager
- +
diff --git a/api/client/EchoHub.Client.Config.NotificationConfig.html b/api/client/EchoHub.Client.Config.NotificationConfig.html index 733990e..56757cf 100644 --- a/api/client/EchoHub.Client.Config.NotificationConfig.html +++ b/api/client/EchoHub.Client.Config.NotificationConfig.html @@ -295,7 +295,7 @@ Class NotificationConfig
- +
diff --git a/api/client/EchoHub.Client.Config.SavedServer.html b/api/client/EchoHub.Client.Config.SavedServer.html index 2148284..2b017ea 100644 --- a/api/client/EchoHub.Client.Config.SavedServer.html +++ b/api/client/EchoHub.Client.Config.SavedServer.html @@ -388,7 +388,7 @@ Class SavedServer
- +
diff --git a/api/client/EchoHub.Client.Config.html b/api/client/EchoHub.Client.Config.html index f63a479..8c61ef5 100644 --- a/api/client/EchoHub.Client.Config.html +++ b/api/client/EchoHub.Client.Config.html @@ -134,7 +134,7 @@ Classes diff --git a/api/client/EchoHub.Client.Services.ApiClient.html b/api/client/EchoHub.Client.Services.ApiClient.html index def1502..6b85df8 100644 --- a/api/client/EchoHub.Client.Services.ApiClient.html +++ b/api/client/EchoHub.Client.Services.ApiClient.html @@ -1311,7 +1311,7 @@ Used by EchoHubConnection for SignalR token provider.

diff --git a/api/client/EchoHub.Client.Services.AsyncRunner.html b/api/client/EchoHub.Client.Services.AsyncRunner.html index f4583b4..3c3bbfe 100644 --- a/api/client/EchoHub.Client.Services.AsyncRunner.html +++ b/api/client/EchoHub.Client.Services.AsyncRunner.html @@ -213,7 +213,7 @@ Runs async work on a background thread and routes exceptions to the UI.

diff --git a/api/client/EchoHub.Client.Services.AudioPlaybackService.html b/api/client/EchoHub.Client.Services.AudioPlaybackService.html index a1f6fa0..d0fb426 100644 --- a/api/client/EchoHub.Client.Services.AudioPlaybackService.html +++ b/api/client/EchoHub.Client.Services.AudioPlaybackService.html @@ -467,7 +467,7 @@ Class AudioPlaybackService
- +
diff --git a/api/client/EchoHub.Client.Services.BackupInfo.html b/api/client/EchoHub.Client.Services.BackupInfo.html index 1e65766..254f59f 100644 --- a/api/client/EchoHub.Client.Services.BackupInfo.html +++ b/api/client/EchoHub.Client.Services.BackupInfo.html @@ -652,7 +652,7 @@ Class BackupInfo
- +
diff --git a/api/client/EchoHub.Client.Services.ClientEncryptionService.html b/api/client/EchoHub.Client.Services.ClientEncryptionService.html index f1d0d7e..0d1fd1d 100644 --- a/api/client/EchoHub.Client.Services.ClientEncryptionService.html +++ b/api/client/EchoHub.Client.Services.ClientEncryptionService.html @@ -450,7 +450,7 @@ so messages are encrypted end-to-end between client and server.

diff --git a/api/client/EchoHub.Client.Services.EchoHubConnection.html b/api/client/EchoHub.Client.Services.EchoHubConnection.html index c815024..0e8f88c 100644 --- a/api/client/EchoHub.Client.Services.EchoHubConnection.html +++ b/api/client/EchoHub.Client.Services.EchoHubConnection.html @@ -958,7 +958,7 @@ Class EchoHubConnection
- +
diff --git a/api/client/EchoHub.Client.Services.NotificationSoundService.html b/api/client/EchoHub.Client.Services.NotificationSoundService.html index 0339cea..d78dd42 100644 --- a/api/client/EchoHub.Client.Services.NotificationSoundService.html +++ b/api/client/EchoHub.Client.Services.NotificationSoundService.html @@ -332,7 +332,7 @@ Class NotificationSoundService
- +
diff --git a/api/client/EchoHub.Client.Services.PathSetup.html b/api/client/EchoHub.Client.Services.PathSetup.html index 9c9e222..48e77af 100644 --- a/api/client/EchoHub.Client.Services.PathSetup.html +++ b/api/client/EchoHub.Client.Services.PathSetup.html @@ -203,7 +203,7 @@ On Linux/macOS: appends an export line to shell profile files.

diff --git a/api/client/EchoHub.Client.Services.UpdateBackupService.html b/api/client/EchoHub.Client.Services.UpdateBackupService.html index 41171d2..64ebf15 100644 --- a/api/client/EchoHub.Client.Services.UpdateBackupService.html +++ b/api/client/EchoHub.Client.Services.UpdateBackupService.html @@ -357,7 +357,7 @@ This method does not return — it calls Environment.Exit(0).

diff --git a/api/client/EchoHub.Client.Services.UpdateChecker.html b/api/client/EchoHub.Client.Services.UpdateChecker.html index 8882de2..d9dbc80 100644 --- a/api/client/EchoHub.Client.Services.UpdateChecker.html +++ b/api/client/EchoHub.Client.Services.UpdateChecker.html @@ -328,7 +328,7 @@ Class UpdateChecker
- +
diff --git a/api/client/EchoHub.Client.Services.html b/api/client/EchoHub.Client.Services.html index 667ef8f..0641c38 100644 --- a/api/client/EchoHub.Client.Services.html +++ b/api/client/EchoHub.Client.Services.html @@ -162,7 +162,7 @@ Backup location: ~/.echohub/update-backup/

diff --git a/api/client/EchoHub.Client.Themes.Theme.html b/api/client/EchoHub.Client.Themes.Theme.html index cfff283..3f0f42e 100644 --- a/api/client/EchoHub.Client.Themes.Theme.html +++ b/api/client/EchoHub.Client.Themes.Theme.html @@ -357,7 +357,7 @@ Class Theme
- +
diff --git a/api/client/EchoHub.Client.Themes.ThemeColors.html b/api/client/EchoHub.Client.Themes.ThemeColors.html index 7233aeb..1ee1cdf 100644 --- a/api/client/EchoHub.Client.Themes.ThemeColors.html +++ b/api/client/EchoHub.Client.Themes.ThemeColors.html @@ -326,7 +326,7 @@ Class ThemeColors
- +
diff --git a/api/client/EchoHub.Client.Themes.ThemeManager.html b/api/client/EchoHub.Client.Themes.ThemeManager.html index b110162..fc5ea1c 100644 --- a/api/client/EchoHub.Client.Themes.ThemeManager.html +++ b/api/client/EchoHub.Client.Themes.ThemeManager.html @@ -301,7 +301,7 @@ Class ThemeManager
- +
diff --git a/api/client/EchoHub.Client.Themes.html b/api/client/EchoHub.Client.Themes.html index 9487b9e..2c3390c 100644 --- a/api/client/EchoHub.Client.Themes.html +++ b/api/client/EchoHub.Client.Themes.html @@ -126,7 +126,7 @@ Classes diff --git a/api/client/EchoHub.Client.UI.Chat.ChatColors.html b/api/client/EchoHub.Client.UI.Chat.ChatColors.html index e23b079..3df7e9f 100644 --- a/api/client/EchoHub.Client.UI.Chat.ChatColors.html +++ b/api/client/EchoHub.Client.UI.Chat.ChatColors.html @@ -547,7 +547,7 @@ Non-special text uses the provided default color.

diff --git a/api/client/EchoHub.Client.UI.Chat.ChatLine.html b/api/client/EchoHub.Client.UI.Chat.ChatLine.html index 3b7dcd4..6bf208a 100644 --- a/api/client/EchoHub.Client.UI.Chat.ChatLine.html +++ b/api/client/EchoHub.Client.UI.Chat.ChatLine.html @@ -705,7 +705,7 @@ Continuation lines are indented with the specified number of spaces.

diff --git a/api/client/EchoHub.Client.UI.Chat.ChatListSource.html b/api/client/EchoHub.Client.UI.Chat.ChatListSource.html index 02aec20..2253e33 100644 --- a/api/client/EchoHub.Client.UI.Chat.ChatListSource.html +++ b/api/client/EchoHub.Client.UI.Chat.ChatListSource.html @@ -667,7 +667,7 @@ Class ChatListSource
- +
diff --git a/api/client/EchoHub.Client.UI.Chat.ChatMessageManager.html b/api/client/EchoHub.Client.UI.Chat.ChatMessageManager.html index 33ae767..bd60cc3 100644 --- a/api/client/EchoHub.Client.UI.Chat.ChatMessageManager.html +++ b/api/client/EchoHub.Client.UI.Chat.ChatMessageManager.html @@ -698,7 +698,7 @@ so the UI layer can refresh.

diff --git a/api/client/EchoHub.Client.UI.Chat.ChatSegment.html b/api/client/EchoHub.Client.UI.Chat.ChatSegment.html index aaec48f..b59bd11 100644 --- a/api/client/EchoHub.Client.UI.Chat.ChatSegment.html +++ b/api/client/EchoHub.Client.UI.Chat.ChatSegment.html @@ -619,7 +619,7 @@ Class ChatSegment
- +
diff --git a/api/client/EchoHub.Client.UI.Chat.html b/api/client/EchoHub.Client.UI.Chat.html index 1f4d113..354aabd 100644 --- a/api/client/EchoHub.Client.UI.Chat.html +++ b/api/client/EchoHub.Client.UI.Chat.html @@ -141,7 +141,7 @@ so the UI layer can refresh.

diff --git a/api/client/EchoHub.Client.UI.Dialogs.AudioPlayerDialog.html b/api/client/EchoHub.Client.UI.Dialogs.AudioPlayerDialog.html index 18806f8..88233db 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.AudioPlayerDialog.html +++ b/api/client/EchoHub.Client.UI.Dialogs.AudioPlayerDialog.html @@ -236,7 +236,7 @@ Class AudioPlayerDialog
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.ConnectDialog.html b/api/client/EchoHub.Client.UI.Dialogs.ConnectDialog.html index d81c44f..5f7ae17 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.ConnectDialog.html +++ b/api/client/EchoHub.Client.UI.Dialogs.ConnectDialog.html @@ -241,7 +241,7 @@ Returns the result, or null if cancelled.

diff --git a/api/client/EchoHub.Client.UI.Dialogs.ConnectDialogResult.html b/api/client/EchoHub.Client.UI.Dialogs.ConnectDialogResult.html index bd8d012..db84606 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.ConnectDialogResult.html +++ b/api/client/EchoHub.Client.UI.Dialogs.ConnectDialogResult.html @@ -759,7 +759,7 @@ Class ConnectDialogResult
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.CreateChannelDialog.html b/api/client/EchoHub.Client.UI.Dialogs.CreateChannelDialog.html index 8523866..86b7622 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.CreateChannelDialog.html +++ b/api/client/EchoHub.Client.UI.Dialogs.CreateChannelDialog.html @@ -235,7 +235,7 @@ Class CreateChannelDialog
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html b/api/client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html index 93b59d5..33fa451 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html +++ b/api/client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html @@ -652,7 +652,7 @@ Class CreateChannelResult
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.ProfileAction.html b/api/client/EchoHub.Client.UI.Dialogs.ProfileAction.html index 4990ce1..b2ba111 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.ProfileAction.html +++ b/api/client/EchoHub.Client.UI.Dialogs.ProfileAction.html @@ -149,7 +149,7 @@ Enum ProfileAction
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.ProfileEditDialog.html b/api/client/EchoHub.Client.UI.Dialogs.ProfileEditDialog.html index 4ce1e7d..e6e7f07 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.ProfileEditDialog.html +++ b/api/client/EchoHub.Client.UI.Dialogs.ProfileEditDialog.html @@ -247,7 +247,7 @@ Class ProfileEditDialog
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.ProfileEditResult.html b/api/client/EchoHub.Client.UI.Dialogs.ProfileEditResult.html index 7e9c0a3..d3c30b2 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.ProfileEditResult.html +++ b/api/client/EchoHub.Client.UI.Dialogs.ProfileEditResult.html @@ -759,7 +759,7 @@ Class ProfileEditResult
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.ProfileViewDialog.html b/api/client/EchoHub.Client.UI.Dialogs.ProfileViewDialog.html index 5172905..f0b4e35 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.ProfileViewDialog.html +++ b/api/client/EchoHub.Client.UI.Dialogs.ProfileViewDialog.html @@ -279,7 +279,7 @@ Returns the action the user selected.

diff --git a/api/client/EchoHub.Client.UI.Dialogs.StatusDialog.html b/api/client/EchoHub.Client.UI.Dialogs.StatusDialog.html index 45bb9f5..2f65ff2 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.StatusDialog.html +++ b/api/client/EchoHub.Client.UI.Dialogs.StatusDialog.html @@ -241,7 +241,7 @@ Class StatusDialog
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.StatusDialogResult.html b/api/client/EchoHub.Client.UI.Dialogs.StatusDialogResult.html index 26995a5..2b3b61b 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.StatusDialogResult.html +++ b/api/client/EchoHub.Client.UI.Dialogs.StatusDialogResult.html @@ -619,7 +619,7 @@ Class StatusDialogResult
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.UpdateConfirmDialog.html b/api/client/EchoHub.Client.UI.Dialogs.UpdateConfirmDialog.html index 349f25d..0fdf85b 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.UpdateConfirmDialog.html +++ b/api/client/EchoHub.Client.UI.Dialogs.UpdateConfirmDialog.html @@ -239,7 +239,7 @@ Class UpdateConfirmDialog
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.UpdateProgressDialog.html b/api/client/EchoHub.Client.UI.Dialogs.UpdateProgressDialog.html index a492bfc..bbfe54d 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.UpdateProgressDialog.html +++ b/api/client/EchoHub.Client.UI.Dialogs.UpdateProgressDialog.html @@ -291,7 +291,7 @@ Class UpdateProgressDialog
- +
diff --git a/api/client/EchoHub.Client.UI.Dialogs.html b/api/client/EchoHub.Client.UI.Dialogs.html index e1b281f..0d890ba 100644 --- a/api/client/EchoHub.Client.UI.Dialogs.html +++ b/api/client/EchoHub.Client.UI.Dialogs.html @@ -179,7 +179,7 @@ Enums diff --git a/api/client/EchoHub.Client.UI.Helpers.EmojiHelper.html b/api/client/EchoHub.Client.UI.Helpers.EmojiHelper.html index 736c1c7..4de5a5d 100644 --- a/api/client/EchoHub.Client.UI.Helpers.EmojiHelper.html +++ b/api/client/EchoHub.Client.UI.Helpers.EmojiHelper.html @@ -213,7 +213,7 @@ Non-emoji text passes through unchanged.

diff --git a/api/client/EchoHub.Client.UI.Helpers.HexColorHelper.html b/api/client/EchoHub.Client.UI.Helpers.HexColorHelper.html index 00fd781..ab34cfb 100644 --- a/api/client/EchoHub.Client.UI.Helpers.HexColorHelper.html +++ b/api/client/EchoHub.Client.UI.Helpers.HexColorHelper.html @@ -249,7 +249,7 @@ Returns fallback if parsing fails.

diff --git a/api/client/EchoHub.Client.UI.Helpers.html b/api/client/EchoHub.Client.UI.Helpers.html index f1f2379..d247dc5 100644 --- a/api/client/EchoHub.Client.UI.Helpers.html +++ b/api/client/EchoHub.Client.UI.Helpers.html @@ -126,7 +126,7 @@ so we replace them with fixed-width ASCII shortcodes for display only.

diff --git a/api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html b/api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html index 2d1a075..83ce409 100644 --- a/api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html +++ b/api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html @@ -546,7 +546,7 @@ Active channel gets a > indicator, unread channels are bright with a count ba diff --git a/api/client/EchoHub.Client.UI.ListSources.UserListSource.html b/api/client/EchoHub.Client.UI.ListSources.UserListSource.html index d58ed90..6aa15b0 100644 --- a/api/client/EchoHub.Client.UI.ListSources.UserListSource.html +++ b/api/client/EchoHub.Client.UI.ListSources.UserListSource.html @@ -577,7 +577,7 @@ Class UserListSource
- +
diff --git a/api/client/EchoHub.Client.UI.ListSources.html b/api/client/EchoHub.Client.UI.ListSources.html index b8d327a..909dcc0 100644 --- a/api/client/EchoHub.Client.UI.ListSources.html +++ b/api/client/EchoHub.Client.UI.ListSources.html @@ -125,7 +125,7 @@ Active channel gets a > indicator, unread channels are bright with a count ba diff --git a/api/client/EchoHub.Client.UI.MainWindow.html b/api/client/EchoHub.Client.UI.MainWindow.html index b6399f7..5e35116 100644 --- a/api/client/EchoHub.Client.UI.MainWindow.html +++ b/api/client/EchoHub.Client.UI.MainWindow.html @@ -1882,7 +1882,7 @@ Call after theme changes to refresh colors.

diff --git a/api/client/EchoHub.Client.UI.html b/api/client/EchoHub.Client.UI.html index 0aaf7fd..58a3793 100644 --- a/api/client/EchoHub.Client.UI.html +++ b/api/client/EchoHub.Client.UI.html @@ -119,7 +119,7 @@ Classes diff --git a/api/client/EchoHub.Client.html b/api/client/EchoHub.Client.html index 12380fc..7cfe5ee 100644 --- a/api/client/EchoHub.Client.html +++ b/api/client/EchoHub.Client.html @@ -120,7 +120,7 @@ Wires UI events to service calls and connection events to UI updates.

diff --git a/api/core-articles/index.html b/api/core-articles/index.html index d3169ad..aecb84e 100644 --- a/api/core-articles/index.html +++ b/api/core-articles/index.html @@ -115,7 +115,7 @@ diff --git a/api/core/EchoHub.Core.Constants.HubConstants.html b/api/core/EchoHub.Core.Constants.HubConstants.html index 1b5ec20..64fe4d3 100644 --- a/api/core/EchoHub.Core.Constants.HubConstants.html +++ b/api/core/EchoHub.Core.Constants.HubConstants.html @@ -682,7 +682,7 @@ Class HubConstants
- +
diff --git a/api/core/EchoHub.Core.Constants.ValidationConstants.html b/api/core/EchoHub.Core.Constants.ValidationConstants.html index 8730594..1aa468e 100644 --- a/api/core/EchoHub.Core.Constants.ValidationConstants.html +++ b/api/core/EchoHub.Core.Constants.ValidationConstants.html @@ -567,7 +567,7 @@ public static Regex UsernameRegex() diff --git a/api/core/EchoHub.Core.Constants.html b/api/core/EchoHub.Core.Constants.html index 6887ce8..b78ecc8 100644 --- a/api/core/EchoHub.Core.Constants.html +++ b/api/core/EchoHub.Core.Constants.html @@ -122,7 +122,7 @@ Classes diff --git a/api/core/EchoHub.Core.Contracts.ChannelListItem.html b/api/core/EchoHub.Core.Contracts.ChannelListItem.html index 4b0b0ae..85ae4b9 100644 --- a/api/core/EchoHub.Core.Contracts.ChannelListItem.html +++ b/api/core/EchoHub.Core.Contracts.ChannelListItem.html @@ -652,7 +652,7 @@ Class ChannelListItem
- +
diff --git a/api/core/EchoHub.Core.Contracts.IChannelService.html b/api/core/EchoHub.Core.Contracts.IChannelService.html index 605dc27..e289cc7 100644 --- a/api/core/EchoHub.Core.Contracts.IChannelService.html +++ b/api/core/EchoHub.Core.Contracts.IChannelService.html @@ -441,7 +441,7 @@ Interface IChannelService
- +
diff --git a/api/core/EchoHub.Core.Contracts.IChatBroadcaster.html b/api/core/EchoHub.Core.Contracts.IChatBroadcaster.html index eb087c0..2ee6028 100644 --- a/api/core/EchoHub.Core.Contracts.IChatBroadcaster.html +++ b/api/core/EchoHub.Core.Contracts.IChatBroadcaster.html @@ -562,7 +562,7 @@ Interface IChatBroadcaster
- +
diff --git a/api/core/EchoHub.Core.Contracts.IChatService.html b/api/core/EchoHub.Core.Contracts.IChatService.html index 26097cf..34ec523 100644 --- a/api/core/EchoHub.Core.Contracts.IChatService.html +++ b/api/core/EchoHub.Core.Contracts.IChatService.html @@ -568,7 +568,7 @@ Interface IChatService
- +
diff --git a/api/core/EchoHub.Core.Contracts.IEchoHubClient.html b/api/core/EchoHub.Core.Contracts.IEchoHubClient.html index 06bc4c9..d2bd040 100644 --- a/api/core/EchoHub.Core.Contracts.IEchoHubClient.html +++ b/api/core/EchoHub.Core.Contracts.IEchoHubClient.html @@ -551,7 +551,7 @@ Interface IEchoHubClient
- +
diff --git a/api/core/EchoHub.Core.Contracts.IMessageEncryptionService.html b/api/core/EchoHub.Core.Contracts.IMessageEncryptionService.html index 77e7216..9075f28 100644 --- a/api/core/EchoHub.Core.Contracts.IMessageEncryptionService.html +++ b/api/core/EchoHub.Core.Contracts.IMessageEncryptionService.html @@ -320,7 +320,7 @@ Interface IMessageEncryptionService
- +
diff --git a/api/core/EchoHub.Core.Contracts.IUserService.html b/api/core/EchoHub.Core.Contracts.IUserService.html index d826386..b75b1e0 100644 --- a/api/core/EchoHub.Core.Contracts.IUserService.html +++ b/api/core/EchoHub.Core.Contracts.IUserService.html @@ -370,7 +370,7 @@ Interface IUserService
- +
diff --git a/api/core/EchoHub.Core.Contracts.html b/api/core/EchoHub.Core.Contracts.html index 11008fc..b82289c 100644 --- a/api/core/EchoHub.Core.Contracts.html +++ b/api/core/EchoHub.Core.Contracts.html @@ -146,7 +146,7 @@ Interfaces diff --git a/api/core/EchoHub.Core.DTOs.ApiResponse-1.html b/api/core/EchoHub.Core.DTOs.ApiResponse-1.html index 454b4cc..b365896 100644 --- a/api/core/EchoHub.Core.DTOs.ApiResponse-1.html +++ b/api/core/EchoHub.Core.DTOs.ApiResponse-1.html @@ -692,7 +692,7 @@ Class ApiResponse<T>
- +
diff --git a/api/core/EchoHub.Core.DTOs.ApiResponse.html b/api/core/EchoHub.Core.DTOs.ApiResponse.html index 85dd74f..90b9050 100644 --- a/api/core/EchoHub.Core.DTOs.ApiResponse.html +++ b/api/core/EchoHub.Core.DTOs.ApiResponse.html @@ -652,7 +652,7 @@ Class ApiResponse
- +
diff --git a/api/core/EchoHub.Core.DTOs.AssignRoleRequest.html b/api/core/EchoHub.Core.DTOs.AssignRoleRequest.html index 04d39de..acfee34 100644 --- a/api/core/EchoHub.Core.DTOs.AssignRoleRequest.html +++ b/api/core/EchoHub.Core.DTOs.AssignRoleRequest.html @@ -617,7 +617,7 @@ Class AssignRoleRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.AvatarUploadResponse.html b/api/core/EchoHub.Core.DTOs.AvatarUploadResponse.html index bb334aa..dd35982 100644 --- a/api/core/EchoHub.Core.DTOs.AvatarUploadResponse.html +++ b/api/core/EchoHub.Core.DTOs.AvatarUploadResponse.html @@ -582,7 +582,7 @@ Class AvatarUploadResponse
- +
diff --git a/api/core/EchoHub.Core.DTOs.BanRequest.html b/api/core/EchoHub.Core.DTOs.BanRequest.html index 4f866a5..f520570 100644 --- a/api/core/EchoHub.Core.DTOs.BanRequest.html +++ b/api/core/EchoHub.Core.DTOs.BanRequest.html @@ -582,7 +582,7 @@ Class BanRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.ChannelDto.html b/api/core/EchoHub.Core.DTOs.ChannelDto.html index c98a492..bfd86cd 100644 --- a/api/core/EchoHub.Core.DTOs.ChannelDto.html +++ b/api/core/EchoHub.Core.DTOs.ChannelDto.html @@ -757,7 +757,7 @@ Class ChannelDto
- +
diff --git a/api/core/EchoHub.Core.DTOs.ChannelError.html b/api/core/EchoHub.Core.DTOs.ChannelError.html index b9904dd..7148428 100644 --- a/api/core/EchoHub.Core.DTOs.ChannelError.html +++ b/api/core/EchoHub.Core.DTOs.ChannelError.html @@ -154,7 +154,7 @@ Enum ChannelError
- +
diff --git a/api/core/EchoHub.Core.DTOs.ChannelOperationResult.html b/api/core/EchoHub.Core.DTOs.ChannelOperationResult.html index 39faa69..3820512 100644 --- a/api/core/EchoHub.Core.DTOs.ChannelOperationResult.html +++ b/api/core/EchoHub.Core.DTOs.ChannelOperationResult.html @@ -757,7 +757,7 @@ Class ChannelOperationResult
- +
diff --git a/api/core/EchoHub.Core.DTOs.CreateChannelRequest.html b/api/core/EchoHub.Core.DTOs.CreateChannelRequest.html index cd145c7..ff8b95c 100644 --- a/api/core/EchoHub.Core.DTOs.CreateChannelRequest.html +++ b/api/core/EchoHub.Core.DTOs.CreateChannelRequest.html @@ -652,7 +652,7 @@ Class CreateChannelRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.EmbedDto.html b/api/core/EchoHub.Core.DTOs.EmbedDto.html index 36f4fcb..90ea912 100644 --- a/api/core/EchoHub.Core.DTOs.EmbedDto.html +++ b/api/core/EchoHub.Core.DTOs.EmbedDto.html @@ -757,7 +757,7 @@ Class EmbedDto
- +
diff --git a/api/core/EchoHub.Core.DTOs.EncryptionKeyResponse.html b/api/core/EchoHub.Core.DTOs.EncryptionKeyResponse.html index 39a6c68..2c081af 100644 --- a/api/core/EchoHub.Core.DTOs.EncryptionKeyResponse.html +++ b/api/core/EchoHub.Core.DTOs.EncryptionKeyResponse.html @@ -582,7 +582,7 @@ Class EncryptionKeyResponse
- +
diff --git a/api/core/EchoHub.Core.DTOs.ErrorResponse.html b/api/core/EchoHub.Core.DTOs.ErrorResponse.html index 99cd847..e23d71c 100644 --- a/api/core/EchoHub.Core.DTOs.ErrorResponse.html +++ b/api/core/EchoHub.Core.DTOs.ErrorResponse.html @@ -617,7 +617,7 @@ Class ErrorResponse
- +
diff --git a/api/core/EchoHub.Core.DTOs.JoinChannelResult.html b/api/core/EchoHub.Core.DTOs.JoinChannelResult.html index c61a3e6..fab53e8 100644 --- a/api/core/EchoHub.Core.DTOs.JoinChannelResult.html +++ b/api/core/EchoHub.Core.DTOs.JoinChannelResult.html @@ -652,7 +652,7 @@ Class JoinChannelResult
- +
diff --git a/api/core/EchoHub.Core.DTOs.KickRequest.html b/api/core/EchoHub.Core.DTOs.KickRequest.html index c2f5832..67484a4 100644 --- a/api/core/EchoHub.Core.DTOs.KickRequest.html +++ b/api/core/EchoHub.Core.DTOs.KickRequest.html @@ -582,7 +582,7 @@ Class KickRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.LoginRequest.html b/api/core/EchoHub.Core.DTOs.LoginRequest.html index 153daba..6c190d5 100644 --- a/api/core/EchoHub.Core.DTOs.LoginRequest.html +++ b/api/core/EchoHub.Core.DTOs.LoginRequest.html @@ -617,7 +617,7 @@ Class LoginRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.LoginResponse.html b/api/core/EchoHub.Core.DTOs.LoginResponse.html index 3bf8fb9..8b167ae 100644 --- a/api/core/EchoHub.Core.DTOs.LoginResponse.html +++ b/api/core/EchoHub.Core.DTOs.LoginResponse.html @@ -757,7 +757,7 @@ Class LoginResponse
- +
diff --git a/api/core/EchoHub.Core.DTOs.MessageDto.html b/api/core/EchoHub.Core.DTOs.MessageDto.html index dd16975..11718ac 100644 --- a/api/core/EchoHub.Core.DTOs.MessageDto.html +++ b/api/core/EchoHub.Core.DTOs.MessageDto.html @@ -932,7 +932,7 @@ Class MessageDto
- +
diff --git a/api/core/EchoHub.Core.DTOs.MuteRequest.html b/api/core/EchoHub.Core.DTOs.MuteRequest.html index 5d43231..8a17a42 100644 --- a/api/core/EchoHub.Core.DTOs.MuteRequest.html +++ b/api/core/EchoHub.Core.DTOs.MuteRequest.html @@ -617,7 +617,7 @@ Class MuteRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.PaginatedResponse-1.html b/api/core/EchoHub.Core.DTOs.PaginatedResponse-1.html index beb16c6..cded478 100644 --- a/api/core/EchoHub.Core.DTOs.PaginatedResponse-1.html +++ b/api/core/EchoHub.Core.DTOs.PaginatedResponse-1.html @@ -692,7 +692,7 @@ Class PaginatedResponse<T>
- +
diff --git a/api/core/EchoHub.Core.DTOs.RefreshRequest.html b/api/core/EchoHub.Core.DTOs.RefreshRequest.html index 4a02c61..63dc51a 100644 --- a/api/core/EchoHub.Core.DTOs.RefreshRequest.html +++ b/api/core/EchoHub.Core.DTOs.RefreshRequest.html @@ -582,7 +582,7 @@ Class RefreshRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.RegisterRequest.html b/api/core/EchoHub.Core.DTOs.RegisterRequest.html index 94d953d..b3dbbb5 100644 --- a/api/core/EchoHub.Core.DTOs.RegisterRequest.html +++ b/api/core/EchoHub.Core.DTOs.RegisterRequest.html @@ -652,7 +652,7 @@ Class RegisterRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.SendMessageRequest.html b/api/core/EchoHub.Core.DTOs.SendMessageRequest.html index 9a6c9d2..6a5240e 100644 --- a/api/core/EchoHub.Core.DTOs.SendMessageRequest.html +++ b/api/core/EchoHub.Core.DTOs.SendMessageRequest.html @@ -617,7 +617,7 @@ Class SendMessageRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.SendUrlRequest.html b/api/core/EchoHub.Core.DTOs.SendUrlRequest.html index e3cc6d0..13d12e3 100644 --- a/api/core/EchoHub.Core.DTOs.SendUrlRequest.html +++ b/api/core/EchoHub.Core.DTOs.SendUrlRequest.html @@ -582,7 +582,7 @@ Class SendUrlRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.ServerStatusDto.html b/api/core/EchoHub.Core.DTOs.ServerStatusDto.html index f7217b7..5a5608c 100644 --- a/api/core/EchoHub.Core.DTOs.ServerStatusDto.html +++ b/api/core/EchoHub.Core.DTOs.ServerStatusDto.html @@ -687,7 +687,7 @@ Class ServerStatusDto
- +
diff --git a/api/core/EchoHub.Core.DTOs.UpdateProfileRequest.html b/api/core/EchoHub.Core.DTOs.UpdateProfileRequest.html index 7ea0245..0cec87f 100644 --- a/api/core/EchoHub.Core.DTOs.UpdateProfileRequest.html +++ b/api/core/EchoHub.Core.DTOs.UpdateProfileRequest.html @@ -652,7 +652,7 @@ Class UpdateProfileRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.UpdateStatusRequest.html b/api/core/EchoHub.Core.DTOs.UpdateStatusRequest.html index fc30bcf..06cc505 100644 --- a/api/core/EchoHub.Core.DTOs.UpdateStatusRequest.html +++ b/api/core/EchoHub.Core.DTOs.UpdateStatusRequest.html @@ -617,7 +617,7 @@ Class UpdateStatusRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.UpdateTopicRequest.html b/api/core/EchoHub.Core.DTOs.UpdateTopicRequest.html index 34e98e5..5cedf75 100644 --- a/api/core/EchoHub.Core.DTOs.UpdateTopicRequest.html +++ b/api/core/EchoHub.Core.DTOs.UpdateTopicRequest.html @@ -582,7 +582,7 @@ Class UpdateTopicRequest
- +
diff --git a/api/core/EchoHub.Core.DTOs.UserDto.html b/api/core/EchoHub.Core.DTOs.UserDto.html index b902a78..0fe3ae1 100644 --- a/api/core/EchoHub.Core.DTOs.UserDto.html +++ b/api/core/EchoHub.Core.DTOs.UserDto.html @@ -757,7 +757,7 @@ Class UserDto
- +
diff --git a/api/core/EchoHub.Core.DTOs.UserError.html b/api/core/EchoHub.Core.DTOs.UserError.html index b99e184..e7475b8 100644 --- a/api/core/EchoHub.Core.DTOs.UserError.html +++ b/api/core/EchoHub.Core.DTOs.UserError.html @@ -154,7 +154,7 @@ Enum UserError
- +
diff --git a/api/core/EchoHub.Core.DTOs.UserOperationResult.html b/api/core/EchoHub.Core.DTOs.UserOperationResult.html index 8245026..d6f9a85 100644 --- a/api/core/EchoHub.Core.DTOs.UserOperationResult.html +++ b/api/core/EchoHub.Core.DTOs.UserOperationResult.html @@ -757,7 +757,7 @@ Class UserOperationResult
- +
diff --git a/api/core/EchoHub.Core.DTOs.UserPresenceDto.html b/api/core/EchoHub.Core.DTOs.UserPresenceDto.html index 48b45c1..f823d66 100644 --- a/api/core/EchoHub.Core.DTOs.UserPresenceDto.html +++ b/api/core/EchoHub.Core.DTOs.UserPresenceDto.html @@ -757,7 +757,7 @@ Class UserPresenceDto
- +
diff --git a/api/core/EchoHub.Core.DTOs.UserProfileDto.html b/api/core/EchoHub.Core.DTOs.UserProfileDto.html index 9e5faa5..1aefe82 100644 --- a/api/core/EchoHub.Core.DTOs.UserProfileDto.html +++ b/api/core/EchoHub.Core.DTOs.UserProfileDto.html @@ -932,7 +932,7 @@ Class UserProfileDto
- +
diff --git a/api/core/EchoHub.Core.DTOs.html b/api/core/EchoHub.Core.DTOs.html index dded302..f32b668 100644 --- a/api/core/EchoHub.Core.DTOs.html +++ b/api/core/EchoHub.Core.DTOs.html @@ -245,7 +245,7 @@ Enums diff --git a/api/core/EchoHub.Core.Models.Channel.html b/api/core/EchoHub.Core.Models.Channel.html index 260046e..e37bd5f 100644 --- a/api/core/EchoHub.Core.Models.Channel.html +++ b/api/core/EchoHub.Core.Models.Channel.html @@ -419,7 +419,7 @@ Class Channel
- +
diff --git a/api/core/EchoHub.Core.Models.ChannelMembership.html b/api/core/EchoHub.Core.Models.ChannelMembership.html index 4a41441..fcd0a4b 100644 --- a/api/core/EchoHub.Core.Models.ChannelMembership.html +++ b/api/core/EchoHub.Core.Models.ChannelMembership.html @@ -295,7 +295,7 @@ Class ChannelMembership
- +
diff --git a/api/core/EchoHub.Core.Models.Message.html b/api/core/EchoHub.Core.Models.Message.html index f7cf63d..049a4c8 100644 --- a/api/core/EchoHub.Core.Models.Message.html +++ b/api/core/EchoHub.Core.Models.Message.html @@ -574,7 +574,7 @@ Class Message
- +
diff --git a/api/core/EchoHub.Core.Models.MessageType.html b/api/core/EchoHub.Core.Models.MessageType.html index 93bebb8..ec8c8a5 100644 --- a/api/core/EchoHub.Core.Models.MessageType.html +++ b/api/core/EchoHub.Core.Models.MessageType.html @@ -151,7 +151,7 @@ Enum MessageType
- +
diff --git a/api/core/EchoHub.Core.Models.RefreshToken.html b/api/core/EchoHub.Core.Models.RefreshToken.html index e241e6b..f41e545 100644 --- a/api/core/EchoHub.Core.Models.RefreshToken.html +++ b/api/core/EchoHub.Core.Models.RefreshToken.html @@ -512,7 +512,7 @@ Class RefreshToken
- +
diff --git a/api/core/EchoHub.Core.Models.ServerRole.html b/api/core/EchoHub.Core.Models.ServerRole.html index 56572f8..6e2a4cf 100644 --- a/api/core/EchoHub.Core.Models.ServerRole.html +++ b/api/core/EchoHub.Core.Models.ServerRole.html @@ -151,7 +151,7 @@ Enum ServerRole
- +
diff --git a/api/core/EchoHub.Core.Models.User.html b/api/core/EchoHub.Core.Models.User.html index edf4618..71b32ef 100644 --- a/api/core/EchoHub.Core.Models.User.html +++ b/api/core/EchoHub.Core.Models.User.html @@ -667,7 +667,7 @@ Class User
- +
diff --git a/api/core/EchoHub.Core.Models.UserStatus.html b/api/core/EchoHub.Core.Models.UserStatus.html index 849fd68..ca2f6ed 100644 --- a/api/core/EchoHub.Core.Models.UserStatus.html +++ b/api/core/EchoHub.Core.Models.UserStatus.html @@ -151,7 +151,7 @@ Enum UserStatus
- +
diff --git a/api/core/EchoHub.Core.Models.html b/api/core/EchoHub.Core.Models.html index 825affc..b337a6b 100644 --- a/api/core/EchoHub.Core.Models.html +++ b/api/core/EchoHub.Core.Models.html @@ -149,7 +149,7 @@ Enums diff --git a/api/index.html b/api/index.html index 51c2bb9..d3808bf 100644 --- a/api/index.html +++ b/api/index.html @@ -118,7 +118,7 @@ diff --git a/api/server-articles/index.html b/api/server-articles/index.html index ede3d7a..2d93c4b 100644 --- a/api/server-articles/index.html +++ b/api/server-articles/index.html @@ -120,7 +120,7 @@ diff --git a/api/server-irc/EchoHub.Server.Irc.IrcBroadcaster.html b/api/server-irc/EchoHub.Server.Irc.IrcBroadcaster.html index 0af861f..1170558 100644 --- a/api/server-irc/EchoHub.Server.Irc.IrcBroadcaster.html +++ b/api/server-irc/EchoHub.Server.Irc.IrcBroadcaster.html @@ -637,7 +637,7 @@ Class IrcBroadcaster
- +
diff --git a/api/server-irc/EchoHub.Server.Irc.IrcClientConnection.html b/api/server-irc/EchoHub.Server.Irc.IrcClientConnection.html index 7750738..10595d2 100644 --- a/api/server-irc/EchoHub.Server.Irc.IrcClientConnection.html +++ b/api/server-irc/EchoHub.Server.Irc.IrcClientConnection.html @@ -903,7 +903,7 @@ Class IrcClientConnection
- +
diff --git a/api/server-irc/EchoHub.Server.Irc.IrcCommandHandler.html b/api/server-irc/EchoHub.Server.Irc.IrcCommandHandler.html index d405ab1..6ff7eb2 100644 --- a/api/server-irc/EchoHub.Server.Irc.IrcCommandHandler.html +++ b/api/server-irc/EchoHub.Server.Irc.IrcCommandHandler.html @@ -252,7 +252,7 @@ Class IrcCommandHandler
- +
diff --git a/api/server-irc/EchoHub.Server.Irc.IrcGatewayService.html b/api/server-irc/EchoHub.Server.Irc.IrcGatewayService.html index cdb5f13..b2b6042 100644 --- a/api/server-irc/EchoHub.Server.Irc.IrcGatewayService.html +++ b/api/server-irc/EchoHub.Server.Irc.IrcGatewayService.html @@ -420,7 +420,7 @@ Class IrcGatewayService
- +
diff --git a/api/server-irc/EchoHub.Server.Irc.IrcMessage.html b/api/server-irc/EchoHub.Server.Irc.IrcMessage.html index bc1ce57..4dc9491 100644 --- a/api/server-irc/EchoHub.Server.Irc.IrcMessage.html +++ b/api/server-irc/EchoHub.Server.Irc.IrcMessage.html @@ -366,7 +366,7 @@ Format: [:prefix] COMMAND [params...] [:trailing]

diff --git a/api/server-irc/EchoHub.Server.Irc.IrcMessageFormatter.html b/api/server-irc/EchoHub.Server.Irc.IrcMessageFormatter.html index 03a4612..9985f63 100644 --- a/api/server-irc/EchoHub.Server.Irc.IrcMessageFormatter.html +++ b/api/server-irc/EchoHub.Server.Irc.IrcMessageFormatter.html @@ -286,7 +286,7 @@ Also passes through content that already uses ANSI codes unchanged.

diff --git a/api/server-irc/EchoHub.Server.Irc.IrcNumericReply.html b/api/server-irc/EchoHub.Server.Irc.IrcNumericReply.html index 6fb2180..437cafe 100644 --- a/api/server-irc/EchoHub.Server.Irc.IrcNumericReply.html +++ b/api/server-irc/EchoHub.Server.Irc.IrcNumericReply.html @@ -1462,7 +1462,7 @@ Class IrcNumericReply
- +
diff --git a/api/server-irc/EchoHub.Server.Irc.IrcOptions.html b/api/server-irc/EchoHub.Server.Irc.IrcOptions.html index a9db3c9..2911ec2 100644 --- a/api/server-irc/EchoHub.Server.Irc.IrcOptions.html +++ b/api/server-irc/EchoHub.Server.Irc.IrcOptions.html @@ -481,7 +481,7 @@ Class IrcOptions
- +
diff --git a/api/server-irc/EchoHub.Server.Irc.IrcServiceExtensions.html b/api/server-irc/EchoHub.Server.Irc.IrcServiceExtensions.html index a7aadc7..2d2d39f 100644 --- a/api/server-irc/EchoHub.Server.Irc.IrcServiceExtensions.html +++ b/api/server-irc/EchoHub.Server.Irc.IrcServiceExtensions.html @@ -208,7 +208,7 @@ Class IrcServiceExtensions
- +
diff --git a/api/server-irc/EchoHub.Server.Irc.html b/api/server-irc/EchoHub.Server.Irc.html index af361f7..39ff709 100644 --- a/api/server-irc/EchoHub.Server.Irc.html +++ b/api/server-irc/EchoHub.Server.Irc.html @@ -153,7 +153,7 @@ Format: [:prefix] COMMAND [params...] [:trailing]

diff --git a/api/server/EchoHub.Server.Auth.JwtTokenService.html b/api/server/EchoHub.Server.Auth.JwtTokenService.html index 5bc0abf..7983885 100644 --- a/api/server/EchoHub.Server.Auth.JwtTokenService.html +++ b/api/server/EchoHub.Server.Auth.JwtTokenService.html @@ -380,7 +380,7 @@ Class JwtTokenService
- +
diff --git a/api/server/EchoHub.Server.Auth.html b/api/server/EchoHub.Server.Auth.html index c67a8e9..c22a8d1 100644 --- a/api/server/EchoHub.Server.Auth.html +++ b/api/server/EchoHub.Server.Auth.html @@ -118,7 +118,7 @@ Classes diff --git a/api/server/EchoHub.Server.Controllers.AuthController.html b/api/server/EchoHub.Server.Controllers.AuthController.html index a8acfc1..1d56454 100644 --- a/api/server/EchoHub.Server.Controllers.AuthController.html +++ b/api/server/EchoHub.Server.Controllers.AuthController.html @@ -363,7 +363,7 @@ public Task<IActionResult> Register(RegisterRequest request) diff --git a/api/server/EchoHub.Server.Controllers.ChannelsController.html b/api/server/EchoHub.Server.Controllers.ChannelsController.html index a6f6025..78b2d37 100644 --- a/api/server/EchoHub.Server.Controllers.ChannelsController.html +++ b/api/server/EchoHub.Server.Controllers.ChannelsController.html @@ -460,7 +460,7 @@ public Task<IActionResult> Upload(string channel, string? size = null)
- +
diff --git a/api/server/EchoHub.Server.Controllers.FilesController.html b/api/server/EchoHub.Server.Controllers.FilesController.html index 21e253e..9632f2f 100644 --- a/api/server/EchoHub.Server.Controllers.FilesController.html +++ b/api/server/EchoHub.Server.Controllers.FilesController.html @@ -249,7 +249,7 @@ public IActionResult GetFile(string fileId) diff --git a/api/server/EchoHub.Server.Controllers.ModerationController.html b/api/server/EchoHub.Server.Controllers.ModerationController.html index 682f33a..263df51 100644 --- a/api/server/EchoHub.Server.Controllers.ModerationController.html +++ b/api/server/EchoHub.Server.Controllers.ModerationController.html @@ -520,7 +520,7 @@ public Task<IActionResult> UnmuteUser(string username) diff --git a/api/server/EchoHub.Server.Controllers.ServerController.html b/api/server/EchoHub.Server.Controllers.ServerController.html index dad1c5c..9e82355 100644 --- a/api/server/EchoHub.Server.Controllers.ServerController.html +++ b/api/server/EchoHub.Server.Controllers.ServerController.html @@ -278,7 +278,7 @@ public Task<IActionResult> GetInfo() diff --git a/api/server/EchoHub.Server.Controllers.UsersController.html b/api/server/EchoHub.Server.Controllers.UsersController.html index 0f546db..cee8ebf 100644 --- a/api/server/EchoHub.Server.Controllers.UsersController.html +++ b/api/server/EchoHub.Server.Controllers.UsersController.html @@ -321,7 +321,7 @@ public Task<IActionResult> UploadAvatar() diff --git a/api/server/EchoHub.Server.Controllers.html b/api/server/EchoHub.Server.Controllers.html index 5a92415..1014062 100644 --- a/api/server/EchoHub.Server.Controllers.html +++ b/api/server/EchoHub.Server.Controllers.html @@ -138,7 +138,7 @@ Classes diff --git a/api/server/EchoHub.Server.Data.EchoHubDbContext.html b/api/server/EchoHub.Server.Data.EchoHubDbContext.html index c009b80..a6f3ac2 100644 --- a/api/server/EchoHub.Server.Data.EchoHubDbContext.html +++ b/api/server/EchoHub.Server.Data.EchoHubDbContext.html @@ -436,7 +436,7 @@ Class EchoHubDbContext
- +
diff --git a/api/server/EchoHub.Server.Data.Migrations.AddAttachmentFileSize.html b/api/server/EchoHub.Server.Data.Migrations.AddAttachmentFileSize.html index 4d77710..f94e906 100644 --- a/api/server/EchoHub.Server.Data.Migrations.AddAttachmentFileSize.html +++ b/api/server/EchoHub.Server.Data.Migrations.AddAttachmentFileSize.html @@ -298,7 +298,7 @@ public class AddAttachmentFileSize : Migration diff --git a/api/server/EchoHub.Server.Data.Migrations.AddChannelIsPublic.html b/api/server/EchoHub.Server.Data.Migrations.AddChannelIsPublic.html index 8b5d914..0178252 100644 --- a/api/server/EchoHub.Server.Data.Migrations.AddChannelIsPublic.html +++ b/api/server/EchoHub.Server.Data.Migrations.AddChannelIsPublic.html @@ -298,7 +298,7 @@ public class AddChannelIsPublic : Migration diff --git a/api/server/EchoHub.Server.Data.Migrations.AddChannelMembership.html b/api/server/EchoHub.Server.Data.Migrations.AddChannelMembership.html index f5532ee..cc6bdbd 100644 --- a/api/server/EchoHub.Server.Data.Migrations.AddChannelMembership.html +++ b/api/server/EchoHub.Server.Data.Migrations.AddChannelMembership.html @@ -298,7 +298,7 @@ public class AddChannelMembership : Migration diff --git a/api/server/EchoHub.Server.Data.Migrations.AddEncryptionSupport.html b/api/server/EchoHub.Server.Data.Migrations.AddEncryptionSupport.html index a56b014..9ed736b 100644 --- a/api/server/EchoHub.Server.Data.Migrations.AddEncryptionSupport.html +++ b/api/server/EchoHub.Server.Data.Migrations.AddEncryptionSupport.html @@ -298,7 +298,7 @@ public class AddEncryptionSupport : Migration diff --git a/api/server/EchoHub.Server.Data.Migrations.AddMessageEmbed.html b/api/server/EchoHub.Server.Data.Migrations.AddMessageEmbed.html index 0a1569e..ce7bc4b 100644 --- a/api/server/EchoHub.Server.Data.Migrations.AddMessageEmbed.html +++ b/api/server/EchoHub.Server.Data.Migrations.AddMessageEmbed.html @@ -298,7 +298,7 @@ public class AddMessageEmbed : Migration diff --git a/api/server/EchoHub.Server.Data.Migrations.AddModerationRoles.html b/api/server/EchoHub.Server.Data.Migrations.AddModerationRoles.html index 5bc044e..934a2ab 100644 --- a/api/server/EchoHub.Server.Data.Migrations.AddModerationRoles.html +++ b/api/server/EchoHub.Server.Data.Migrations.AddModerationRoles.html @@ -298,7 +298,7 @@ public class AddModerationRoles : Migration diff --git a/api/server/EchoHub.Server.Data.Migrations.InitialCreate.html b/api/server/EchoHub.Server.Data.Migrations.InitialCreate.html index c4d2411..14cd3e6 100644 --- a/api/server/EchoHub.Server.Data.Migrations.InitialCreate.html +++ b/api/server/EchoHub.Server.Data.Migrations.InitialCreate.html @@ -298,7 +298,7 @@ public class InitialCreate : Migration diff --git a/api/server/EchoHub.Server.Data.Migrations.html b/api/server/EchoHub.Server.Data.Migrations.html index 1f267a3..b9cb7cb 100644 --- a/api/server/EchoHub.Server.Data.Migrations.html +++ b/api/server/EchoHub.Server.Data.Migrations.html @@ -142,7 +142,7 @@ Classes diff --git a/api/server/EchoHub.Server.Data.html b/api/server/EchoHub.Server.Data.html index 94efb0e..9d5448e 100644 --- a/api/server/EchoHub.Server.Data.html +++ b/api/server/EchoHub.Server.Data.html @@ -118,7 +118,7 @@ Classes diff --git a/api/server/EchoHub.Server.Hubs.ChatHub.html b/api/server/EchoHub.Server.Hubs.ChatHub.html index f991638..b38deb3 100644 --- a/api/server/EchoHub.Server.Hubs.ChatHub.html +++ b/api/server/EchoHub.Server.Hubs.ChatHub.html @@ -507,7 +507,7 @@ public class ChatHub : Hub<IEchoHubClient>, IDisposable diff --git a/api/server/EchoHub.Server.Hubs.html b/api/server/EchoHub.Server.Hubs.html index 213fd37..47db6d1 100644 --- a/api/server/EchoHub.Server.Hubs.html +++ b/api/server/EchoHub.Server.Hubs.html @@ -118,7 +118,7 @@ Classes diff --git a/api/server/EchoHub.Server.Services.ChannelService.html b/api/server/EchoHub.Server.Services.ChannelService.html index 38d2708..0cf2d05 100644 --- a/api/server/EchoHub.Server.Services.ChannelService.html +++ b/api/server/EchoHub.Server.Services.ChannelService.html @@ -518,7 +518,7 @@ Class ChannelService
- +
diff --git a/api/server/EchoHub.Server.Services.ChatService.html b/api/server/EchoHub.Server.Services.ChatService.html index e14fe38..15e154a 100644 --- a/api/server/EchoHub.Server.Services.ChatService.html +++ b/api/server/EchoHub.Server.Services.ChatService.html @@ -653,7 +653,7 @@ Class ChatService
- +
diff --git a/api/server/EchoHub.Server.Services.FileCleanupService.html b/api/server/EchoHub.Server.Services.FileCleanupService.html index b0846b3..0ed164e 100644 --- a/api/server/EchoHub.Server.Services.FileCleanupService.html +++ b/api/server/EchoHub.Server.Services.FileCleanupService.html @@ -249,7 +249,7 @@ Class FileCleanupService
- +
diff --git a/api/server/EchoHub.Server.Services.FileStorageService.html b/api/server/EchoHub.Server.Services.FileStorageService.html index 3e5c15a..5ab0190 100644 --- a/api/server/EchoHub.Server.Services.FileStorageService.html +++ b/api/server/EchoHub.Server.Services.FileStorageService.html @@ -312,7 +312,7 @@ Class FileStorageService
- +
diff --git a/api/server/EchoHub.Server.Services.FileValidationHelper.html b/api/server/EchoHub.Server.Services.FileValidationHelper.html index f5c234a..6530971 100644 --- a/api/server/EchoHub.Server.Services.FileValidationHelper.html +++ b/api/server/EchoHub.Server.Services.FileValidationHelper.html @@ -247,7 +247,7 @@ The stream position is reset to the beginning after validation.

diff --git a/api/server/EchoHub.Server.Services.ImageToAsciiService.html b/api/server/EchoHub.Server.Services.ImageToAsciiService.html index 88a920c..8f2ebbf 100644 --- a/api/server/EchoHub.Server.Services.ImageToAsciiService.html +++ b/api/server/EchoHub.Server.Services.ImageToAsciiService.html @@ -285,7 +285,7 @@ s = small (40x40), m = medium/default (80x80), l = large (120x120).

diff --git a/api/server/EchoHub.Server.Services.LinkEmbedService.html b/api/server/EchoHub.Server.Services.LinkEmbedService.html index 3c29687..30751ec 100644 --- a/api/server/EchoHub.Server.Services.LinkEmbedService.html +++ b/api/server/EchoHub.Server.Services.LinkEmbedService.html @@ -248,7 +248,7 @@ Never throws — all errors are caught internally.

diff --git a/api/server/EchoHub.Server.Services.MessageEncryptionService.html b/api/server/EchoHub.Server.Services.MessageEncryptionService.html index 1c89221..0862ff8 100644 --- a/api/server/EchoHub.Server.Services.MessageEncryptionService.html +++ b/api/server/EchoHub.Server.Services.MessageEncryptionService.html @@ -395,7 +395,7 @@ Class MessageEncryptionService
- +
diff --git a/api/server/EchoHub.Server.Services.MuteExpirationService.html b/api/server/EchoHub.Server.Services.MuteExpirationService.html index ca2b279..dc4a196 100644 --- a/api/server/EchoHub.Server.Services.MuteExpirationService.html +++ b/api/server/EchoHub.Server.Services.MuteExpirationService.html @@ -250,7 +250,7 @@ Class MuteExpirationService
- +
diff --git a/api/server/EchoHub.Server.Services.PresenceTracker.html b/api/server/EchoHub.Server.Services.PresenceTracker.html index ef7efd2..80970ce 100644 --- a/api/server/EchoHub.Server.Services.PresenceTracker.html +++ b/api/server/EchoHub.Server.Services.PresenceTracker.html @@ -595,7 +595,7 @@ so the caller can broadcast departures and force-disconnect connections.

diff --git a/api/server/EchoHub.Server.Services.ServerDirectoryService.html b/api/server/EchoHub.Server.Services.ServerDirectoryService.html index 14d3ebf..8187379 100644 --- a/api/server/EchoHub.Server.Services.ServerDirectoryService.html +++ b/api/server/EchoHub.Server.Services.ServerDirectoryService.html @@ -287,7 +287,7 @@ Class ServerDirectoryService
- +
diff --git a/api/server/EchoHub.Server.Services.SignalRBroadcaster.html b/api/server/EchoHub.Server.Services.SignalRBroadcaster.html index b534454..d642735 100644 --- a/api/server/EchoHub.Server.Services.SignalRBroadcaster.html +++ b/api/server/EchoHub.Server.Services.SignalRBroadcaster.html @@ -637,7 +637,7 @@ Class SignalRBroadcaster
- +
diff --git a/api/server/EchoHub.Server.Services.UserService.html b/api/server/EchoHub.Server.Services.UserService.html index af69c74..29ac265 100644 --- a/api/server/EchoHub.Server.Services.UserService.html +++ b/api/server/EchoHub.Server.Services.UserService.html @@ -443,7 +443,7 @@ Class UserService
- +
diff --git a/api/server/EchoHub.Server.Services.html b/api/server/EchoHub.Server.Services.html index b6123c8..4c64ea2 100644 --- a/api/server/EchoHub.Server.Services.html +++ b/api/server/EchoHub.Server.Services.html @@ -167,7 +167,7 @@ Classes diff --git a/api/server/EchoHub.Server.Setup.DataMigrationService.html b/api/server/EchoHub.Server.Setup.DataMigrationService.html index df3300d..05ffd68 100644 --- a/api/server/EchoHub.Server.Setup.DataMigrationService.html +++ b/api/server/EchoHub.Server.Setup.DataMigrationService.html @@ -246,7 +246,7 @@ Class DataMigrationService
- +
diff --git a/api/server/EchoHub.Server.Setup.DatabaseSetup.html b/api/server/EchoHub.Server.Setup.DatabaseSetup.html index b8b8e8b..9d6d4dd 100644 --- a/api/server/EchoHub.Server.Setup.DatabaseSetup.html +++ b/api/server/EchoHub.Server.Setup.DatabaseSetup.html @@ -208,7 +208,7 @@ Class DatabaseSetup
- +
diff --git a/api/server/EchoHub.Server.Setup.FirstRunSetup.html b/api/server/EchoHub.Server.Setup.FirstRunSetup.html index 70719ff..2b8d4d8 100644 --- a/api/server/EchoHub.Server.Setup.FirstRunSetup.html +++ b/api/server/EchoHub.Server.Setup.FirstRunSetup.html @@ -198,7 +198,7 @@ Class FirstRunSetup
- +
diff --git a/api/server/EchoHub.Server.Setup.html b/api/server/EchoHub.Server.Setup.html index b8e5b21..02cf2fb 100644 --- a/api/server/EchoHub.Server.Setup.html +++ b/api/server/EchoHub.Server.Setup.html @@ -126,7 +126,7 @@ Classes diff --git a/articles/architecture.html b/articles/architecture.html index 1fb2739..503ee2a 100644 --- a/articles/architecture.html +++ b/articles/architecture.html @@ -166,7 +166,7 @@ TUI Client ──► WebSocket ──► ChatHub ─────┘ diff --git a/articles/configuration.html b/articles/configuration.html new file mode 100644 index 0000000..133fc9d --- /dev/null +++ b/articles/configuration.html @@ -0,0 +1,424 @@ + + + + + Configuration | EchoHub Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
Table of Contents
+ +
+
+ +
+
+
+ +
+
+ + + +
+ +
+

Configuration

+ +

EchoHub Server generates an appsettings.json with sensible defaults on first run (including a random JWT secret), so you can launch and start chatting immediately. Tweak things later when you feel like it.

+
+
Note
+

Under the hood, EchoHub Server is built on ASP.NET Core, so it inherits the standard .NET configuration system. If you're familiar with that, everything works exactly as you'd expect. If not — no worries, this page covers everything you need.

+
+

How It Works

+

EchoHub Server loads settings from multiple sources. Each source overrides the previous one, so you can layer defaults with environment-specific values:

+
1. appsettings.json                   (base defaults)
+2. appsettings.{Environment}.json     (e.g. appsettings.Production.json)
+3. Environment variables              (great for Docker / CI)
+4. Command-line arguments             (highest priority)
+
+

The last one wins. If appsettings.json says "Irc:Port": 6667 but you pass --Irc:Port=7000 on the command line, port 7000 is what you get.

+

In practice this means you can leave appsettings.json alone and override just the settings you care about using environment variables or CLI flags — no need to edit JSON files if that's not your thing.

+

Environment Variable Mapping

+

Environment variables use double underscores (__) in place of the JSON nesting. The rule is simple — replace every : (or each level of JSON nesting) with __:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
appsettings.json pathEnvironment variable
Server:NameServer__Name
Irc:EnabledIrc__Enabled
Jwt:SecretJwt__Secret
Serilog:MinimumLevel:DefaultSerilog__MinimumLevel__Default
ConnectionStrings:DefaultConnectionConnectionStrings__DefaultConnection
+

Arrays use numeric indices: Server:Admins:0 becomes Server__Admins__0, Server:Admins:1 becomes Server__Admins__1, and so on.

+

This is why the Docker .env file uses Server__Name=My Server instead of JSON — Docker passes these as environment variables, and the server picks them up automatically.

+

Examples

+

All three of these achieve the same thing — use whichever fits your setup.

+

appsettings.json (direct editing):

+
{
+  "Server": {
+    "Name": "My EchoHub Server",
+    "PublicServer": true
+  }
+}
+
+

Environment variables (Docker, systemd, shell export):

+
export Server__Name="My EchoHub Server"
+export Server__PublicServer=true
+
+

Command-line arguments (quick overrides, highest priority):

+
./EchoHub.Server --Server:Name="My EchoHub Server" --Irc:Enabled=true
+
+

Configuration Reference

+

The full appsettings.json is auto-generated on first run from the example config. Here's every option:

+

General

+ + + + + + + + + + + + + + + + + + + + +
KeyDefaultDescription
Urlshttp://0.0.0.0:5000Listen address and port
AllowedHosts*Allowed host headers (leave * unless you need host filtering)
+

Database

+ + + + + + + + + + + + + + + +
KeyDefaultDescription
ConnectionStrings:DefaultConnection(empty)SQLite connection string. Empty = echohub.db in the app directory
+

Authentication

+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDefaultDescription
Jwt:Secret(auto-generated)Signing key (min 32 chars). Auto-generated on first run
Jwt:IssuerEchoHub.ServerJWT issuer claim
Jwt:AudienceEchoHub.ClientJWT audience claim
+

Access tokens expire after 15 minutes, refresh tokens after 30 days with rotation on each use.

+

Server Identity

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDefaultDescription
Server:NameMy EchoHub ServerDisplay name shown to clients
Server:DescriptionA self-hosted EchoHub chat serverServer description
Server:PublicServerfalseRegister on the public directory
Server:PublicHost(empty)Public hostname for the directory listing (e.g. chat.example.com:5000)
Server:Admins[]Array of admin usernames (e.g. ["alice", "bob"])
+

Encryption

+ + + + + + + + + + + + + + + + + + + + +
KeyDefaultDescription
Encryption:Key(auto-generated)AES key for message encryption in transit
Encryption:EncryptDatabasefalseAlso encrypt message content at rest in SQLite
+

Storage

+ + + + + + + + + + + + + + + + + + + + +
KeyDefaultDescription
Storage:CleanupIntervalHours1How often the cleanup job runs (hours)
Storage:RetentionDays30Days to keep uploaded files before cleanup
+

IRC Gateway

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDefaultDescription
Irc:EnabledfalseEnable the IRC protocol gateway
Irc:Port6667IRC plain-text listen port
Irc:TlsEnabledfalseEnable TLS termination for IRC
Irc:TlsPort6697IRC TLS listen port
Irc:TlsCertPath(empty)Path to a PKCS#12 (.pfx) certificate
Irc:TlsCertPassword(empty)Password for the certificate file
Irc:ServerNameechohubIRC server name in protocol messages
Irc:MotdWelcome to EchoHub IRC Gateway!Message of the day
+

Logging

+

EchoHub uses Serilog for structured logging — console output + daily rolling files with 14-day retention by default.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDefaultDescription
Serilog:MinimumLevel:DefaultInformationGlobal log level (Debug, Information, Warning, Error)
Serilog:MinimumLevel:Override:MicrosoftWarningSuppress noisy framework logs
Serilog:MinimumLevel:Override:Microsoft.AspNetCoreWarningSuppress request pipeline logs
Serilog:MinimumLevel:Override:Microsoft.EntityFrameworkCoreWarningSuppress database query logs
+

Log files are written to logs/echohub-server-YYYY-MM-DD.log. To change the path or retention, edit the Serilog:WriteTo section in appsettings.json.

+

Want more verbose output for debugging? Set the minimum level to Debug:

+
# via environment variable
+export Serilog__MinimumLevel__Default=Debug
+
+# or command line
+./EchoHub.Server --Serilog:MinimumLevel:Default=Debug
+
+ +
+ + + + + +
+ +
+ +
+
+ +
+ + + + diff --git a/articles/docker.html b/articles/docker.html index e828efe..1efea94 100644 --- a/articles/docker.html +++ b/articles/docker.html @@ -102,7 +102,9 @@ docker compose up -d # start the server # dockerfile: EchoHub.Server/Dockerfile

Configuration

-

All settings are configured through the .env file. These are ASP.NET Core environment variables that override appsettings.json.

+

All settings are configured through the .env file. These are environment variables that override appsettings.json — the __ (double underscore) maps to JSON nesting levels. For example, Server__Name overrides the Server:Name key in appsettings.json.

+

See the Configuration guide for the full reference of all available settings and how the override hierarchy works.

+

Common Docker-relevant variables:

@@ -118,81 +120,16 @@ docker compose up -d # start the server - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -271,7 +208,7 @@ docker compose up -d diff --git a/articles/encryption.html b/articles/encryption.html index eda13fb..14307d9 100644 --- a/articles/encryption.html +++ b/articles/encryption.html @@ -235,7 +235,7 @@ diff --git a/articles/getting-started.html b/articles/getting-started.html index 40e8254..42a5bad 100644 --- a/articles/getting-started.html +++ b/articles/getting-started.html @@ -136,8 +136,8 @@ Connect to a server, register an account, and start chatting.

For TLS, set TlsEnabled: true, TlsPort: 6697, and provide a PKCS#12 certificate path.

See the Architecture page for details on how the IRC gateway integrates with the chat service.

Configuration

-

Server configuration is in appsettings.json (auto-generated on first run). See the example config for all available options.

-

To list your server on the public directory, set Server:PublicServer to true and Server:PublicHost to your server's public address.

+

Server configuration is in appsettings.json (auto-generated on first run). You can also use environment variables or command-line arguments to override settings.

+

See the Configuration guide for the full reference and how it all works.

Build from Source

dotnet build src/EchoHub.slnx
 
@@ -162,7 +162,7 @@ Connect to a server, register an account, and start chatting.

diff --git a/articles/notification-sounds.html b/articles/notification-sounds.html index 570f8b1..46f9b29 100644 --- a/articles/notification-sounds.html +++ b/articles/notification-sounds.html @@ -134,7 +134,7 @@ diff --git a/articles/toc.html b/articles/toc.html index e5a41ec..dc29b5a 100644 --- a/articles/toc.html +++ b/articles/toc.html @@ -26,6 +26,9 @@
  • Architecture
  • +
  • + Configuration +
  • Encryption
  • diff --git a/articles/toc.json b/articles/toc.json index 117afda..81e02ea 100644 --- a/articles/toc.json +++ b/articles/toc.json @@ -1,2 +1,2 @@ -{"items":[{"name":"Guides","items":[{"name":"Getting Started","href":"getting-started.html","topicHref":"getting-started.html"},{"name":"Docker","href":"docker.html","topicHref":"docker.html"},{"name":"Architecture","href":"architecture.html","topicHref":"architecture.html"},{"name":"Encryption","href":"encryption.html","topicHref":"encryption.html"},{"name":"Notification Sounds","href":"notification-sounds.html","topicHref":"notification-sounds.html"}]},{"name":"Flows","includedFrom":"~/flows/toc.yml","items":[{"name":"Authentication","href":"../flows/authentication.html","topicHref":"../flows/authentication.html"},{"name":"Connection","href":"../flows/connection.html","topicHref":"../flows/connection.html"},{"name":"Messaging","href":"../flows/messaging.html","topicHref":"../flows/messaging.html"},{"name":"Channels","href":"../flows/channels.html","topicHref":"../flows/channels.html"},{"name":"Moderation","href":"../flows/moderation.html","topicHref":"../flows/moderation.html"},{"name":"Media & Services","href":"../flows/media.html","topicHref":"../flows/media.html"}]}]} +{"items":[{"name":"Guides","items":[{"name":"Getting Started","href":"getting-started.html","topicHref":"getting-started.html"},{"name":"Docker","href":"docker.html","topicHref":"docker.html"},{"name":"Architecture","href":"architecture.html","topicHref":"architecture.html"},{"name":"Configuration","href":"configuration.html","topicHref":"configuration.html"},{"name":"Encryption","href":"encryption.html","topicHref":"encryption.html"},{"name":"Notification Sounds","href":"notification-sounds.html","topicHref":"notification-sounds.html"}]},{"name":"Flows","includedFrom":"~/flows/toc.yml","items":[{"name":"Authentication","href":"../flows/authentication.html","topicHref":"../flows/authentication.html"},{"name":"Connection","href":"../flows/connection.html","topicHref":"../flows/connection.html"},{"name":"Messaging","href":"../flows/messaging.html","topicHref":"../flows/messaging.html"},{"name":"Channels","href":"../flows/channels.html","topicHref":"../flows/channels.html"},{"name":"Moderation","href":"../flows/moderation.html","topicHref":"../flows/moderation.html"},{"name":"Media & Services","href":"../flows/media.html","topicHref":"../flows/media.html"}]}]} diff --git a/changelog/index.html b/changelog/index.html index fd7a532..1c2fc8b 100644 --- a/changelog/index.html +++ b/changelog/index.html @@ -123,7 +123,7 @@ diff --git a/changelog/v0.1.0.html b/changelog/v0.1.0.html index 524cfc7..0b4a6e2 100644 --- a/changelog/v0.1.0.html +++ b/changelog/v0.1.0.html @@ -120,7 +120,7 @@ diff --git a/changelog/v0.1.1.html b/changelog/v0.1.1.html index 836abef..ccb6a2d 100644 --- a/changelog/v0.1.1.html +++ b/changelog/v0.1.1.html @@ -114,7 +114,7 @@ diff --git a/changelog/v0.2.0.html b/changelog/v0.2.0.html index d9fb553..c1f1cb7 100644 --- a/changelog/v0.2.0.html +++ b/changelog/v0.2.0.html @@ -128,7 +128,7 @@ diff --git a/changelog/v0.2.1.html b/changelog/v0.2.1.html index 4004900..f01fa75 100644 --- a/changelog/v0.2.1.html +++ b/changelog/v0.2.1.html @@ -120,7 +120,7 @@ diff --git a/changelog/v0.2.2.html b/changelog/v0.2.2.html index df57c4b..f8ebd6d 100644 --- a/changelog/v0.2.2.html +++ b/changelog/v0.2.2.html @@ -121,7 +121,7 @@ diff --git a/changelog/v0.2.3.html b/changelog/v0.2.3.html index 30f0ed7..28829a1 100644 --- a/changelog/v0.2.3.html +++ b/changelog/v0.2.3.html @@ -201,7 +201,7 @@ diff --git a/changelog/v0.2.4.html b/changelog/v0.2.4.html index a38d2ae..73a439b 100644 --- a/changelog/v0.2.4.html +++ b/changelog/v0.2.4.html @@ -141,7 +141,7 @@ diff --git a/changelog/v0.2.5.html b/changelog/v0.2.5.html index 8a65dab..700d02c 100644 --- a/changelog/v0.2.5.html +++ b/changelog/v0.2.5.html @@ -226,7 +226,7 @@ diff --git a/changelog/v0.2.6.html b/changelog/v0.2.6.html index f1028a4..d64472d 100644 --- a/changelog/v0.2.6.html +++ b/changelog/v0.2.6.html @@ -129,7 +129,7 @@ diff --git a/changelog/v0.2.7.html b/changelog/v0.2.7.html index dfd5c51..3dd5cef 100644 --- a/changelog/v0.2.7.html +++ b/changelog/v0.2.7.html @@ -119,7 +119,7 @@ diff --git a/changelog/v0.2.8.html b/changelog/v0.2.8.html index 6210ff1..bbbf978 100644 --- a/changelog/v0.2.8.html +++ b/changelog/v0.2.8.html @@ -164,7 +164,7 @@ diff --git a/flows/authentication.html b/flows/authentication.html index a7b17ea..5948c72 100644 --- a/flows/authentication.html +++ b/flows/authentication.html @@ -120,58 +120,6 @@ refresh token for "Remember Me" sessions.

    CM->>CM: Wire OnTokensRefreshed for config persistence CM->>CM: Continue to connection setup (see Connection Flow) -

    Code references:

    -
    Display name for your server
    Server__DescriptionA self-hosted EchoHub chat serverServer description
    Server__PublicServerfalseList on the public directory
    Server__PublicHost(empty)Public address for the directory listing
    Server__Admins__0 (empty) Admin username (use __1, __2 for more)
    Jwt__Secret(auto-generated)JWT signing key. Auto-generated on first run
    Encryption__Key(auto-generated)AES encryption key. Auto-generated on first run
    Encryption__EncryptDatabasefalseEncrypt message content in the database
    Storage__CleanupIntervalHours1How often to clean expired uploads
    Storage__RetentionDays30Days to keep uploaded files
    Irc__Enabled false Enable the IRC gateway
    Irc__Port6667IRC plain-text port
    Irc__TlsEnabledfalseEnable IRC over TLS
    Irc__TlsPort6697IRC TLS port
    Irc__ServerNameechohubIRC server name shown to clients
    Irc__MotdWelcome to EchoHub IRC Gateway!Message of the day
    Serilog__MinimumLevel__Default Information Log level (Debug, Warning, etc.)
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Dialog UIsrc/EchoHub.Client/UI/Dialogs/ConnectDialog.csLines 251-268 (register handler)
    Orchestrator entrysrc/EchoHub.Client/AppOrchestrator.csLines 550-592 (HandleConnect)
    ConnectionManager authsrc/EchoHub.Client/Services/ConnectionManager.csLines 74-76 (register branch)
    ApiClient registersrc/EchoHub.Client/Services/ApiClient.csLines 32-43 (RegisterAsync)
    AuthController registersrc/EchoHub.Server/Controllers/AuthController.csLines 28-49
    UserService registersrc/EchoHub.Server/Services/UserService.csLines 20-59 (RegisterUserAsync)
    JWT generationsrc/EchoHub.Server/Auth/JwtTokenService.csLines 30-53 (access), 80-86 (refresh)
    Token persistencesrc/EchoHub.Client/AppOrchestrator.csLines 1039-1053 (SaveServerToConfig)

    User Login

    Returning user authenticates with username/password or a saved refresh token.

    @@ -202,53 +150,6 @@ refresh token for "Remember Me" sessions.

    end API->>API: SetTokens() -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Login button handlersrc/EchoHub.Client/UI/Dialogs/ConnectDialog.csLines 214-249
    Saved token branchsrc/EchoHub.Client/Services/ConnectionManager.csLines 69-71
    Password branchsrc/EchoHub.Client/Services/ConnectionManager.csLines 78-80
    ApiClient loginsrc/EchoHub.Client/Services/ApiClient.csLines 45-56 (LoginAsync)
    AuthController loginsrc/EchoHub.Server/Controllers/AuthController.csLines 51-72
    AuthController refreshsrc/EchoHub.Server/Controllers/AuthController.csLines 74-108
    UserService authenticatesrc/EchoHub.Server/Services/UserService.csLines 61-83

    Token Refresh

    Access tokens expire after 15 minutes. The client auto-refreshes transparently @@ -276,53 +177,6 @@ before requests and on 401 responses. Refresh tokens are rotated on each use.

    -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Proactive checksrc/EchoHub.Client/Services/ApiClient.csLines 110-129 (GetValidTokenAsync)
    Reactive 401 retry (GET)src/EchoHub.Client/Services/ApiClient.csLines 338-358 (AuthenticatedGetAsync)
    Reactive 401 retry (POST/PUT/DELETE)src/EchoHub.Client/Services/ApiClient.csLines 364-384 (AuthenticatedRequestAsync)
    Refresh HTTP callsrc/EchoHub.Client/Services/ApiClient.csLines 58-71 (RefreshTokenAsync)
    SignalR token providersrc/EchoHub.Client/Services/EchoHubConnection.csLine 37 (AccessTokenProvider)
    Server-side rotationsrc/EchoHub.Server/Controllers/AuthController.csLines 74-108
    Token persistence callbacksrc/EchoHub.Client/Services/ConnectionManager.csLines 253-264
    @@ -344,7 +198,7 @@ before requests and on 401 responses. Refresh tokens are rotated on each use.

    - +
    diff --git a/flows/channels.html b/flows/channels.html index 5aad9f8..070436f 100644 --- a/flows/channels.html +++ b/flows/channels.html @@ -116,33 +116,6 @@ connected clients.

    CC-->>Client: 201 Created (ChannelDto) -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Controller endpointsrc/EchoHub.Server/Controllers/ChannelsController.csLines 60-76
    Channel service createsrc/EchoHub.Server/Services/ChannelService.csLines 50-90
    Broadcast updatedsrc/EchoHub.Server/Services/ChatService.csLines 308-309

    Channel Deletion

    Only the channel creator (or admin) can delete a channel. The default channel @@ -162,28 +135,6 @@ is protected.

    ChS-->>CC: Success CC-->>Client: 204 No Content -

    Code references:

    - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Controller endpointsrc/EchoHub.Server/Controllers/ChannelsController.csLines 94-106
    Channel service deletesrc/EchoHub.Server/Services/ChannelService.csLines 119-144

    Joining a Channel

    Both SignalR and IRC clients join channels through ChatService. The presence @@ -221,48 +172,6 @@ broadcasts accordingly.

    CS-->>Entry: (history, error) Entry-->>Client: History messages -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    SignalR hub joinsrc/EchoHub.Server/Hubs/ChatHub.csLines 59-81
    IRC joinsrc/EchoHub.Server.Irc/IrcCommandHandler.csLines 361-414
    ChatService joinsrc/EchoHub.Server/Services/ChatService.csLines 96-135
    Presence joinsrc/EchoHub.Server/Services/PresenceTracker.csLines 58-70
    SignalR broadcastsrc/EchoHub.Server/Services/SignalRBroadcaster.csLines 26-32
    IRC broadcastsrc/EchoHub.Server.Irc/IrcBroadcaster.csLines 34-41

    Leaving a Channel

    sequenceDiagram
    @@ -283,38 +192,6 @@ broadcasts accordingly.

    CS->>IRCB: SendUserLeftAsync(channel, username) end
    -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    SignalR hub leavesrc/EchoHub.Server/Hubs/ChatHub.csLines 83-96
    IRC partsrc/EchoHub.Server.Irc/IrcCommandHandler.csLines 416-435
    ChatService leavesrc/EchoHub.Server/Services/ChatService.csLines 137-143
    Presence leavesrc/EchoHub.Server/Services/PresenceTracker.csLines 72-81
    @@ -336,7 +213,7 @@ broadcasts accordingly.

    diff --git a/flows/connection.html b/flows/connection.html index 50c2902..1bd7a27 100644 --- a/flows/connection.html +++ b/flows/connection.html @@ -117,58 +117,6 @@ event handlers, joins the default channel, and loads history.

    Hub-->>EHC: List<MessageDto> (encrypted) EHC-->>CM: Decrypted history -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Connection orchestrationsrc/EchoHub.Client/Services/ConnectionManager.csLines 58-140 (ConnectAsync)
    EchoHubConnection setupsrc/EchoHub.Client/Services/EchoHubConnection.csLines 29-62 (constructor)
    Handler registrationsrc/EchoHub.Client/Services/EchoHubConnection.csLines 64-122 (RegisterHandlers)
    Hub OnConnectedsrc/EchoHub.Server/Hubs/ChatHub.csLines 31-43
    ChatService connectedsrc/EchoHub.Server/Services/ChatService.csLines 41-57
    PresenceTracker connectsrc/EchoHub.Server/Services/PresenceTracker.csLines 13-29
    Join channel (hub)src/EchoHub.Server/Hubs/ChatHub.csLines 59-81
    Join channel (service)src/EchoHub.Server/Services/ChatService.csLines 96-135

    IRC Client Connection

    IRC clients connect via TCP, authenticate with PASS/NICK/USER or SASL PLAIN, @@ -213,53 +161,6 @@ and auto-join channels. New usernames are auto-registered.

    Note over IRC,CH: Client is now ready for JOIN/PART/PRIVMSG -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    TCP listenersrc/EchoHub.Server.Irc/IrcGatewayService.csLines 45-90 (ExecuteAsync)
    Client handlersrc/EchoHub.Server.Irc/IrcGatewayService.csLines 92-154 (HandleClientAsync)
    Command read loopsrc/EchoHub.Server.Irc/IrcCommandHandler.csLines 40-98 (RunAsync)
    SASL authsrc/EchoHub.Server.Irc/IrcCommandHandler.csLines 136-207 (HandleAuthenticateAsync)
    PASS/NICK/USERsrc/EchoHub.Server.Irc/IrcCommandHandler.csLines 209-267
    Registration completionsrc/EchoHub.Server.Irc/IrcCommandHandler.csLines 268-315 (TryCompleteRegistrationAsync)
    Cleanup on disconnectsrc/EchoHub.Server.Irc/IrcGatewayService.csLines 136-153

    User Disconnect & Presence

    When a client disconnects, the presence tracker determines if the user has any @@ -287,38 +188,6 @@ notified.

    end end -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    SignalR disconnectsrc/EchoHub.Server/Hubs/ChatHub.csLines 45-57
    IRC cleanupsrc/EchoHub.Server.Irc/IrcGatewayService.csLines 136-153
    ChatService disconnectsrc/EchoHub.Server/Services/ChatService.csLines 59-94
    Presence disconnectsrc/EchoHub.Server/Services/PresenceTracker.csLines 31-53
    @@ -340,7 +209,7 @@ notified.

    diff --git a/flows/flows.html b/flows/flows.html index f60ef24..b356a79 100644 --- a/flows/flows.html +++ b/flows/flows.html @@ -95,7 +95,7 @@ diff --git a/flows/media.html b/flows/media.html index 1601ee5..9f11b9d 100644 --- a/flows/media.html +++ b/flows/media.html @@ -111,38 +111,6 @@ and broadcast as a message with a download link.

    CS->>DB: INSERT Message CS->>CS: BroadcastToAllAsync → fan out to clients -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Upload endpointsrc/EchoHub.Server/Controllers/ChannelsController.csLines 108-200
    File validationsrc/EchoHub.Server/Services/FileValidationHelper.csLines 15-82
    File storagesrc/EchoHub.Server/Services/FileStorageService.csLines 1-47
    File downloadsrc/EchoHub.Server/Controllers/FilesController.csLines 22-53

    When a message contains URLs, the server fetches OpenGraph metadata for preview @@ -168,48 +136,6 @@ embeds.

    LE-->>CS: List<EmbedDto> (or null) Note over CS: Attached to MessageDto before broadcast -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Entry pointsrc/EchoHub.Server/Services/LinkEmbedService.csLines 28-51 (TryGetEmbedsAsync)
    URL extractionsrc/EchoHub.Server/Services/LinkEmbedService.csLines 145-160
    Private IP blockingsrc/EchoHub.Server/Services/LinkEmbedService.csLines 162-181
    OG tag parsingsrc/EchoHub.Server/Services/LinkEmbedService.csLines 187-210
    Theme color parsingsrc/EchoHub.Server/Services/LinkEmbedService.csLines 117-143
    ChatService integrationsrc/EchoHub.Server/Services/ChatService.csLines 194-201

    Server Directory Registration

    Public servers register with the EchoHubSpace directory for discoverability.

    @@ -235,38 +161,6 @@ embeds.

    Note over SDS,Dir: Exponential backoff on disconnect (2s → 30s max) -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Service lifecyclesrc/EchoHub.Server/Services/ServerDirectoryService.csLines 29-122
    Registrationsrc/EchoHub.Server/Services/ServerDirectoryService.csLines 195-212
    User count pollingsrc/EchoHub.Server/Services/ServerDirectoryService.csLines 154-187
    Reconnection backoffsrc/EchoHub.Server/Services/ServerDirectoryService.csLines 77-82, 191
    @@ -288,7 +182,7 @@ embeds.

    diff --git a/flows/messaging.html b/flows/messaging.html index 6a8b2d5..f221cf0 100644 --- a/flows/messaging.html +++ b/flows/messaging.html @@ -128,73 +128,6 @@ clients.

    IRCB->>Clients: Send to each IRC conn (skip sender) end -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Input handlersrc/EchoHub.Client/UI/MainWindow.csLines 428-449 (OnInputKeyDown)
    Orchestrator dispatchsrc/EchoHub.Client/AppOrchestrator.csLines 631-661 (HandleMessageSubmitted)
    Client encrypt + sendsrc/EchoHub.Client/Services/EchoHubConnection.csLines 148-153 (SendMessageAsync)
    Hub receivesrc/EchoHub.Server/Hubs/ChatHub.csLines 98-111 (SendMessage)
    ChatService processsrc/EchoHub.Server/Services/ChatService.csLines 145-241 (SendMessageAsync)
    Mute checksrc/EchoHub.Server/Services/ChatService.csLines 177-190
    Link embedssrc/EchoHub.Server/Services/LinkEmbedService.csLines 28-51 (TryGetEmbedsAsync)
    DB insertsrc/EchoHub.Server/Services/ChatService.csLines 208-221
    Broadcast fan-outsrc/EchoHub.Server/Services/ChatService.csLines 311-324 (BroadcastToAllAsync)
    SignalR broadcastsrc/EchoHub.Server/Services/SignalRBroadcaster.csLines 23-24
    IRC broadcastsrc/EchoHub.Server.Irc/IrcBroadcaster.csLines 17-32

    Sending a Message (IRC)

    Messages from IRC clients follow the same ChatService path but enter as @@ -223,38 +156,6 @@ plaintext (no app-layer encryption).

    IRCB->>IRCB: Skip sender (IRC echo suppression) end -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    PRIVMSG handlersrc/EchoHub.Server.Irc/IrcCommandHandler.csLines 437-469
    Channel name conversionsrc/EchoHub.Server.Irc/IrcCommandHandler.csLine 680 (IrcToEchoHubChannel)
    ChatService (shared path)src/EchoHub.Server/Services/ChatService.csLines 145-241
    IRC echo suppressionsrc/EchoHub.Server.Irc/IrcBroadcaster.csLines 25-26

    Receiving a Message (TUI Client)

    When a message arrives via SignalR, the client decrypts it, adds it to the chat @@ -276,33 +177,6 @@ view, and optionally plays a notification sound for @mentions.

    AO->>AO: PlayAsync() notification sound end -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    SignalR handlersrc/EchoHub.Client/Services/EchoHubConnection.csLines 64-71
    Orchestrator receivesrc/EchoHub.Client/AppOrchestrator.csLines 372-383
    @mention detectionsrc/EchoHub.Client/AppOrchestrator.csLines 378-382

    Command Execution

    Slash commands (/status, /nick, /kick, etc.) are parsed client-side and @@ -452,38 +326,6 @@ dispatched to appropriate handlers, which call REST APIs or SignalR methods.

    -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Command detectionsrc/EchoHub.Client/AppOrchestrator.csLines 639-655
    Command dispatchsrc/EchoHub.Client/Commands/CommandHandler.csLines 34-69 (HandleAsync)
    Command handlers wiredsrc/EchoHub.Client/AppOrchestrator.csLines 97-117
    Individual handlerssrc/EchoHub.Client/AppOrchestrator.csLines 122-350
    @@ -505,7 +347,7 @@ dispatched to appropriate handlers, which call REST APIs or SignalR methods.

    diff --git a/flows/moderation.html b/flows/moderation.html index 976326b..7363e5a 100644 --- a/flows/moderation.html +++ b/flows/moderation.html @@ -120,53 +120,6 @@ These actions force-disconnect the target and broadcast the event.

    CS->>IRCB: ForceDisconnectUserAsync(connectionIds, reason) CS->>DB: Set Status=Invisible, LastSeenAt=now -

    Code references:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepFileLocation
    Kick endpointsrc/EchoHub.Server/Controllers/ModerationController.csLines 62-87
    Ban endpointsrc/EchoHub.Server/Controllers/ModerationController.csLines 89-112
    Mute endpointsrc/EchoHub.Server/Controllers/ModerationController.csLines 130-151
    Force disconnectsrc/EchoHub.Server/Controllers/ModerationController.csLines 232-256
    Mute expirationsrc/EchoHub.Server/Services/MuteExpirationService.csLines 22-62
    Mute enforcementsrc/EchoHub.Server/Services/ChatService.csLines 177-190
    Presence force removesrc/EchoHub.Server/Services/PresenceTracker.csLines 161-178
    @@ -188,7 +141,7 @@ These actions force-disconnect the target and broadcast the event.

    diff --git a/index.html b/index.html index b7bdf4a..05fb5b4 100644 --- a/index.html +++ b/index.html @@ -103,7 +103,7 @@ diff --git a/index.json b/index.json index 4454635..59eeafc 100644 --- a/index.json +++ b/index.json @@ -804,10 +804,15 @@ "title": "Architecture | EchoHub Documentation", "summary": "Architecture Overview EchoHub follows a decentralized model where each server is fully independent. There is no central authority or account federation. Users create one account per server. The server exposes two protocol interfaces to the same chat backend: IRC Client ──► TCP :6667 ──► IrcGateway ──┐ ├──► ChatService ──► DB + PresenceTracker TUI Client ──► WebSocket ──► ChatHub ─────┘ Both protocols call into a shared IChatService for business logic. Events fan out to all registered IChatBroadcaster implementations (SignalR and IRC). Components EchoHub.Core Shared library containing: Models: User, Channel, Message, RefreshToken DTOs: Record types for API requests/responses Contracts: IChatService (protocol-agnostic chat operations), IChannelService (channel CRUD and membership), IChatBroadcaster (event fan-out interface), IEchoHubClient (SignalR client interface) Constants: ValidationConstants (shared regex patterns), HubConstants EchoHub.Server ASP.NET Core web application: Controllers: REST API endpoints for auth, channels, users, files, server info Hubs: SignalR ChatHub -- thin adapter delegating to IChatService Auth: JWT token service (15-min access tokens, 30-day refresh tokens) Data: EF Core with SQLite Services: ChatService (core business logic), ChannelService (channel CRUD and membership), SignalRBroadcaster, presence tracking, file storage, image-to-ASCII conversion, FileCleanupService (periodic removal of expired uploads), DataMigrationService (startup schema/data evolution) EchoHub.Server.Irc IRC protocol gateway (separate project for clean separation of concerns): IrcGatewayService: BackgroundService with TCP listener on configured port(s), optional TLS IrcCommandHandler: Per-client IRC command dispatch -- handles CAP/SASL, NICK/USER/PASS, JOIN/PART/PRIVMSG/QUIT, NAMES/TOPIC/WHO/WHOIS/AWAY/LIST/MODE/MOTD IrcBroadcaster: IChatBroadcaster implementation that formats chat events as IRC protocol lines, with echo suppression (IRC convention) IrcMessageFormatter: Converts MessageDto to IRC PRIVMSG lines -- splits long text at word boundaries (~400 byte chunks), sends images as ASCII art line-by-line IRC users authenticate with existing EchoHub accounts via PASS/NICK/USER or SASL PLAIN (BCrypt verification against the database). EchoHub.Client Terminal.Gui v2 TUI application: UI: Main window, dialogs, chat renderer with ANSI color support Services: API client with automatic token refresh, SignalR connection wrapper, audio playback (NetCoreAudio), automatic update checker (AlwaysUpToDate) Themes: 13 built-in color themes (including transparent theme with true terminal transparency) Config: Client configuration management with session persistence (\"Remember Me\" refresh tokens) Communication REST API for authentication, profile management, channel CRUD, file uploads SignalR WebSocket for real-time messaging and presence updates (TUI client) IRC TCP for real-time messaging via standard IRC protocol (IRC clients) JWT tokens passed via query string for SignalR authentication IRC authentication via PASS/SASL PLAIN against BCrypt password hashes Broadcaster Pattern The IChatBroadcaster interface allows multiple protocols to receive chat events: SignalRBroadcaster: Wraps IHubContext, filters out IRC connections IrcBroadcaster: Iterates live IRC connections in a channel, formats events as IRC protocol lines Both are registered in DI and called by ChatService when events occur. This means a message sent from an IRC client appears in the TUI client, and vice versa." }, + "articles/configuration.html": { + "href": "articles/configuration.html", + "title": "Configuration | EchoHub Documentation", + "summary": "Configuration EchoHub Server generates an appsettings.json with sensible defaults on first run (including a random JWT secret), so you can launch and start chatting immediately. Tweak things later when you feel like it. Note Under the hood, EchoHub Server is built on ASP.NET Core, so it inherits the standard .NET configuration system. If you're familiar with that, everything works exactly as you'd expect. If not — no worries, this page covers everything you need. How It Works EchoHub Server loads settings from multiple sources. Each source overrides the previous one, so you can layer defaults with environment-specific values: 1. appsettings.json (base defaults) 2. appsettings.{Environment}.json (e.g. appsettings.Production.json) 3. Environment variables (great for Docker / CI) 4. Command-line arguments (highest priority) The last one wins. If appsettings.json says \"Irc:Port\": 6667 but you pass --Irc:Port=7000 on the command line, port 7000 is what you get. In practice this means you can leave appsettings.json alone and override just the settings you care about using environment variables or CLI flags — no need to edit JSON files if that's not your thing. Environment Variable Mapping Environment variables use double underscores (__) in place of the JSON nesting. The rule is simple — replace every : (or each level of JSON nesting) with __: appsettings.json path Environment variable Server:Name Server__Name Irc:Enabled Irc__Enabled Jwt:Secret Jwt__Secret Serilog:MinimumLevel:Default Serilog__MinimumLevel__Default ConnectionStrings:DefaultConnection ConnectionStrings__DefaultConnection Arrays use numeric indices: Server:Admins:0 becomes Server__Admins__0, Server:Admins:1 becomes Server__Admins__1, and so on. This is why the Docker .env file uses Server__Name=My Server instead of JSON — Docker passes these as environment variables, and the server picks them up automatically. Examples All three of these achieve the same thing — use whichever fits your setup. appsettings.json (direct editing): { \"Server\": { \"Name\": \"My EchoHub Server\", \"PublicServer\": true } } Environment variables (Docker, systemd, shell export): export Server__Name=\"My EchoHub Server\" export Server__PublicServer=true Command-line arguments (quick overrides, highest priority): ./EchoHub.Server --Server:Name=\"My EchoHub Server\" --Irc:Enabled=true Configuration Reference The full appsettings.json is auto-generated on first run from the example config. Here's every option: General Key Default Description Urls http://0.0.0.0:5000 Listen address and port AllowedHosts * Allowed host headers (leave * unless you need host filtering) Database Key Default Description ConnectionStrings:DefaultConnection (empty) SQLite connection string. Empty = echohub.db in the app directory Authentication Key Default Description Jwt:Secret (auto-generated) Signing key (min 32 chars). Auto-generated on first run Jwt:Issuer EchoHub.Server JWT issuer claim Jwt:Audience EchoHub.Client JWT audience claim Access tokens expire after 15 minutes, refresh tokens after 30 days with rotation on each use. Server Identity Key Default Description Server:Name My EchoHub Server Display name shown to clients Server:Description A self-hosted EchoHub chat server Server description Server:PublicServer false Register on the public directory Server:PublicHost (empty) Public hostname for the directory listing (e.g. chat.example.com:5000) Server:Admins [] Array of admin usernames (e.g. [\"alice\", \"bob\"]) Encryption Key Default Description Encryption:Key (auto-generated) AES key for message encryption in transit Encryption:EncryptDatabase false Also encrypt message content at rest in SQLite Storage Key Default Description Storage:CleanupIntervalHours 1 How often the cleanup job runs (hours) Storage:RetentionDays 30 Days to keep uploaded files before cleanup IRC Gateway Key Default Description Irc:Enabled false Enable the IRC protocol gateway Irc:Port 6667 IRC plain-text listen port Irc:TlsEnabled false Enable TLS termination for IRC Irc:TlsPort 6697 IRC TLS listen port Irc:TlsCertPath (empty) Path to a PKCS#12 (.pfx) certificate Irc:TlsCertPassword (empty) Password for the certificate file Irc:ServerName echohub IRC server name in protocol messages Irc:Motd Welcome to EchoHub IRC Gateway! Message of the day Logging EchoHub uses Serilog for structured logging — console output + daily rolling files with 14-day retention by default. Key Default Description Serilog:MinimumLevel:Default Information Global log level (Debug, Information, Warning, Error) Serilog:MinimumLevel:Override:Microsoft Warning Suppress noisy framework logs Serilog:MinimumLevel:Override:Microsoft.AspNetCore Warning Suppress request pipeline logs Serilog:MinimumLevel:Override:Microsoft.EntityFrameworkCore Warning Suppress database query logs Log files are written to logs/echohub-server-YYYY-MM-DD.log. To change the path or retention, edit the Serilog:WriteTo section in appsettings.json. Want more verbose output for debugging? Set the minimum level to Debug: # via environment variable export Serilog__MinimumLevel__Default=Debug # or command line ./EchoHub.Server --Serilog:MinimumLevel:Default=Debug" + }, "articles/docker.html": { "href": "articles/docker.html", "title": "Docker | EchoHub Documentation", - "summary": "Docker Quick Start cp .env.example .env # create your config docker compose up -d # start the server On first run the server automatically generates JWT and encryption keys, creates the database, and seeds a #general channel. Connect with the EchoHub client to http://localhost:5000. Using a Pre-built Image Instead of building locally, you can pull from GHCR. In docker-compose.yml, replace the build block: services: echohub-server: image: ghcr.io/huebyte/echohub-server:latest # build: # context: ./src # dockerfile: EchoHub.Server/Dockerfile Configuration All settings are configured through the .env file. These are ASP.NET Core environment variables that override appsettings.json. Variable Default Description Server__Name My EchoHub Server Display name for your server Server__Description A self-hosted EchoHub chat server Server description Server__PublicServer false List on the public directory Server__PublicHost (empty) Public address for the directory listing Server__Admins__0 (empty) Admin username (use __1, __2 for more) Jwt__Secret (auto-generated) JWT signing key. Auto-generated on first run Encryption__Key (auto-generated) AES encryption key. Auto-generated on first run Encryption__EncryptDatabase false Encrypt message content in the database Storage__CleanupIntervalHours 1 How often to clean expired uploads Storage__RetentionDays 30 Days to keep uploaded files Irc__Enabled false Enable the IRC gateway Irc__Port 6667 IRC plain-text port Irc__TlsEnabled false Enable IRC over TLS Irc__TlsPort 6697 IRC TLS port Irc__ServerName echohub IRC server name shown to clients Irc__Motd Welcome to EchoHub IRC Gateway! Message of the day Serilog__MinimumLevel__Default Information Log level (Debug, Warning, etc.) Persistent Data All server state lives in a single Docker volume mounted at /app/data: /app/data/ ├── appsettings.json # generated config with JWT/encryption keys ├── echohub.db # SQLite database ├── uploads/ # uploaded files and avatars └── logs/ # rolling log files (14-day retention) Backup # stop the server to ensure a consistent snapshot docker compose stop # copy the data volume to a local directory docker cp echohub-server:/app/data ./backup docker compose start IRC Gateway To enable IRC, set these in your .env: Irc__Enabled=true Then uncomment the port in docker-compose.yml: ports: - \"5000:5000\" - \"6697:6697\" # IRC (TLS encrypted, preferred) For TLS, also set: Irc__TlsEnabled=true Irc__TlsCertPath=/app/data/cert.pfx Irc__TlsCertPassword=your_password Mount your certificate into the data volume or bind-mount it directly. IRC users must have an existing EchoHub account. See Getting Started for client connection examples. Updating # if using pre-built images docker compose pull docker compose up -d # if building locally docker compose build docker compose up -d Data persists across updates since it lives in the named volume. Troubleshooting Port already in use -- Another process is using port 5000. Change the host port in docker-compose.yml: ports: - \"8080:5000\" # access via http://localhost:8080 Permission denied on volume -- The container runs as a non-root echohub user (UID 999). If using bind mounts instead of named volumes, ensure the directory is writable. View logs -- Check the container output: docker compose logs -f echohub-server File-based logs are also available inside the volume at /app/data/logs/." + "summary": "Docker Quick Start cp .env.example .env # create your config docker compose up -d # start the server On first run the server automatically generates JWT and encryption keys, creates the database, and seeds a #general channel. Connect with the EchoHub client to http://localhost:5000. Using a Pre-built Image Instead of building locally, you can pull from GHCR. In docker-compose.yml, replace the build block: services: echohub-server: image: ghcr.io/huebyte/echohub-server:latest # build: # context: ./src # dockerfile: EchoHub.Server/Dockerfile Configuration All settings are configured through the .env file. These are environment variables that override appsettings.json — the __ (double underscore) maps to JSON nesting levels. For example, Server__Name overrides the Server:Name key in appsettings.json. See the Configuration guide for the full reference of all available settings and how the override hierarchy works. Common Docker-relevant variables: Variable Default Description Server__Name My EchoHub Server Display name for your server Server__Admins__0 (empty) Admin username (use __1, __2 for more) Irc__Enabled false Enable the IRC gateway Serilog__MinimumLevel__Default Information Log level (Debug, Warning, etc.) Persistent Data All server state lives in a single Docker volume mounted at /app/data: /app/data/ ├── appsettings.json # generated config with JWT/encryption keys ├── echohub.db # SQLite database ├── uploads/ # uploaded files and avatars └── logs/ # rolling log files (14-day retention) Backup # stop the server to ensure a consistent snapshot docker compose stop # copy the data volume to a local directory docker cp echohub-server:/app/data ./backup docker compose start IRC Gateway To enable IRC, set these in your .env: Irc__Enabled=true Then uncomment the port in docker-compose.yml: ports: - \"5000:5000\" - \"6697:6697\" # IRC (TLS encrypted, preferred) For TLS, also set: Irc__TlsEnabled=true Irc__TlsCertPath=/app/data/cert.pfx Irc__TlsCertPassword=your_password Mount your certificate into the data volume or bind-mount it directly. IRC users must have an existing EchoHub account. See Getting Started for client connection examples. Updating # if using pre-built images docker compose pull docker compose up -d # if building locally docker compose build docker compose up -d Data persists across updates since it lives in the named volume. Troubleshooting Port already in use -- Another process is using port 5000. Change the host port in docker-compose.yml: ports: - \"8080:5000\" # access via http://localhost:8080 Permission denied on volume -- The container runs as a non-root echohub user (UID 999). If using bind mounts instead of named volumes, ensure the directory is writable. View logs -- Check the container output: docker compose logs -f echohub-server File-based logs are also available inside the volume at /app/data/logs/." }, "articles/encryption.html": { "href": "articles/encryption.html", @@ -817,7 +822,7 @@ "articles/getting-started.html": { "href": "articles/getting-started.html", "title": "Getting Started | EchoHub Documentation", - "summary": "Getting Started Install the Client Windows (Chocolatey) choco install echohub Linux / macOS curl -sSfL https://raw.githubusercontent.com/HueByte/EchoHub/master/scripts/install.sh | sh To install a specific version or to a custom directory: curl -sSfL .../install.sh | sh -s -- --version 0.2.8 curl -sSfL .../install.sh | sh -s -- --install-dir /opt/echohub Manual Download Grab a self-contained binary from Releases -- no runtime needed. Host a Server Docker The quickest way to host a server: cp .env.example .env docker compose up -d See the Docker guide for configuration, pre-built images, and more. From Source dotnet run --project src/EchoHub.Server Requires .NET 10 SDK. On first run, the server automatically: Creates appsettings.json from the example config Generates a secure JWT secret Creates the SQLite database with a #general channel Usage After installing the client, run echohub (or dotnet run --project src/EchoHub.Client from source). Connect to a server, register an account, and start chatting. Connect via IRC Enable the IRC gateway in the server's appsettings.json: { \"Irc\": { \"Enabled\": true, \"Port\": 6667 } } Then connect with any standard IRC client: irssi -c localhost -p 6667 -w -n IRC users must have an existing EchoHub account. Authentication works via PASS/NICK/USER or SASL PLAIN. Messages flow bidirectionally between IRC and TUI clients. For TLS, set TlsEnabled: true, TlsPort: 6697, and provide a PKCS#12 certificate path. See the Architecture page for details on how the IRC gateway integrates with the chat service. Configuration Server configuration is in appsettings.json (auto-generated on first run). See the example config for all available options. To list your server on the public directory, set Server:PublicServer to true and Server:PublicHost to your server's public address. Build from Source dotnet build src/EchoHub.slnx" + "summary": "Getting Started Install the Client Windows (Chocolatey) choco install echohub Linux / macOS curl -sSfL https://raw.githubusercontent.com/HueByte/EchoHub/master/scripts/install.sh | sh To install a specific version or to a custom directory: curl -sSfL .../install.sh | sh -s -- --version 0.2.8 curl -sSfL .../install.sh | sh -s -- --install-dir /opt/echohub Manual Download Grab a self-contained binary from Releases -- no runtime needed. Host a Server Docker The quickest way to host a server: cp .env.example .env docker compose up -d See the Docker guide for configuration, pre-built images, and more. From Source dotnet run --project src/EchoHub.Server Requires .NET 10 SDK. On first run, the server automatically: Creates appsettings.json from the example config Generates a secure JWT secret Creates the SQLite database with a #general channel Usage After installing the client, run echohub (or dotnet run --project src/EchoHub.Client from source). Connect to a server, register an account, and start chatting. Connect via IRC Enable the IRC gateway in the server's appsettings.json: { \"Irc\": { \"Enabled\": true, \"Port\": 6667 } } Then connect with any standard IRC client: irssi -c localhost -p 6667 -w -n IRC users must have an existing EchoHub account. Authentication works via PASS/NICK/USER or SASL PLAIN. Messages flow bidirectionally between IRC and TUI clients. For TLS, set TlsEnabled: true, TlsPort: 6697, and provide a PKCS#12 certificate path. See the Architecture page for details on how the IRC gateway integrates with the chat service. Configuration Server configuration is in appsettings.json (auto-generated on first run). You can also use environment variables or command-line arguments to override settings. See the Configuration guide for the full reference and how it all works. Build from Source dotnet build src/EchoHub.slnx" }, "articles/notification-sounds.html": { "href": "articles/notification-sounds.html", @@ -887,17 +892,17 @@ "flows/authentication.html": { "href": "flows/authentication.html", "title": "Authentication | EchoHub Documentation", - "summary": "Authentication User Registration A new user creates an account on a server. The client sends credentials via REST, the server hashes the password, issues JWT tokens, and the client stores the refresh token for \"Remember Me\" sessions. sequenceDiagram participant UI as ConnectDialog participant AO as AppOrchestrator participant CM as ConnectionManager participant API as ApiClient participant Auth as AuthController participant US as UserService participant JWT as JwtTokenService participant DB as SQLite UI->>AO: ConnectDialogResult(IsRegister: true) AO->>CM: ConnectAsync(dialogResult) CM->>API: RegisterAsync(username, password) API->>Auth: POST /api/auth/register Auth->>US: RegisterUserAsync(username, password, displayName) US->>US: Validate (regex, length, uniqueness) US->>DB: INSERT User (BCrypt hash) US-->>Auth: UserOperationResult.Success Auth->>JWT: GenerateAccessToken(user) JWT-->>Auth: (token, expiresAt) [15 min] Auth->>JWT: GenerateRefreshToken() JWT-->>Auth: Base64 random (64 bytes) Auth->>DB: INSERT RefreshToken (SHA256 hash) Auth-->>API: LoginResponse API->>API: SetTokens() — store in memory + set Bearer header API-->>CM: LoginResponse CM->>CM: Wire OnTokensRefreshed for config persistence CM->>CM: Continue to connection setup (see Connection Flow) Code references: Step File Location Dialog UI src/EchoHub.Client/UI/Dialogs/ConnectDialog.cs Lines 251-268 (register handler) Orchestrator entry src/EchoHub.Client/AppOrchestrator.cs Lines 550-592 (HandleConnect) ConnectionManager auth src/EchoHub.Client/Services/ConnectionManager.cs Lines 74-76 (register branch) ApiClient register src/EchoHub.Client/Services/ApiClient.cs Lines 32-43 (RegisterAsync) AuthController register src/EchoHub.Server/Controllers/AuthController.cs Lines 28-49 UserService register src/EchoHub.Server/Services/UserService.cs Lines 20-59 (RegisterUserAsync) JWT generation src/EchoHub.Server/Auth/JwtTokenService.cs Lines 30-53 (access), 80-86 (refresh) Token persistence src/EchoHub.Client/AppOrchestrator.cs Lines 1039-1053 (SaveServerToConfig) User Login Returning user authenticates with username/password or a saved refresh token. sequenceDiagram participant UI as ConnectDialog participant CM as ConnectionManager participant API as ApiClient participant Auth as AuthController participant US as UserService participant DB as SQLite alt Saved refresh token (Remember Me) UI->>CM: ConnectDialogResult(SavedRefreshToken: \"...\") CM->>API: LoginWithRefreshTokenAsync() API->>Auth: POST /api/auth/refresh Auth->>DB: Lookup token by SHA256 hash Auth->>DB: Revoke old token, issue new pair Auth-->>API: LoginResponse (rotated tokens) else Username + Password UI->>CM: ConnectDialogResult(IsRegister: false) CM->>API: LoginAsync(username, password) API->>Auth: POST /api/auth/login Auth->>US: AuthenticateUserAsync(username, password) US->>DB: Fetch user, BCrypt.Verify(password, hash) US->>DB: Update LastSeenAt US-->>Auth: UserOperationResult.Success Auth-->>API: LoginResponse end API->>API: SetTokens() Code references: Step File Location Login button handler src/EchoHub.Client/UI/Dialogs/ConnectDialog.cs Lines 214-249 Saved token branch src/EchoHub.Client/Services/ConnectionManager.cs Lines 69-71 Password branch src/EchoHub.Client/Services/ConnectionManager.cs Lines 78-80 ApiClient login src/EchoHub.Client/Services/ApiClient.cs Lines 45-56 (LoginAsync) AuthController login src/EchoHub.Server/Controllers/AuthController.cs Lines 51-72 AuthController refresh src/EchoHub.Server/Controllers/AuthController.cs Lines 74-108 UserService authenticate src/EchoHub.Server/Services/UserService.cs Lines 61-83 Token Refresh Access tokens expire after 15 minutes. The client auto-refreshes transparently before requests and on 401 responses. Refresh tokens are rotated on each use. sequenceDiagram participant SR as SignalR / HTTP Request participant API as ApiClient participant Auth as AuthController participant DB as SQLite participant Config as config.json SR->>API: GetValidTokenAsync() or HTTP 401 API->>API: Token expires within 60s? alt Proactive refresh (SignalR token provider) API->>Auth: POST /api/auth/refresh (old refresh token) else Reactive refresh (HTTP 401 retry) API->>Auth: POST /api/auth/refresh (old refresh token) end Auth->>DB: Lookup by SHA256 hash Auth->>DB: Revoke old refresh token Auth->>DB: INSERT new RefreshToken Auth-->>API: LoginResponse (new token pair) API->>API: SetTokens() — update Bearer header API-->>API: Fire OnTokensRefreshed event API-->>Config: Persist new refresh token (if Remember Me) API->>SR: Retry original request with new token Code references: Step File Location Proactive check src/EchoHub.Client/Services/ApiClient.cs Lines 110-129 (GetValidTokenAsync) Reactive 401 retry (GET) src/EchoHub.Client/Services/ApiClient.cs Lines 338-358 (AuthenticatedGetAsync) Reactive 401 retry (POST/PUT/DELETE) src/EchoHub.Client/Services/ApiClient.cs Lines 364-384 (AuthenticatedRequestAsync) Refresh HTTP call src/EchoHub.Client/Services/ApiClient.cs Lines 58-71 (RefreshTokenAsync) SignalR token provider src/EchoHub.Client/Services/EchoHubConnection.cs Line 37 (AccessTokenProvider) Server-side rotation src/EchoHub.Server/Controllers/AuthController.cs Lines 74-108 Token persistence callback src/EchoHub.Client/Services/ConnectionManager.cs Lines 253-264" + "summary": "Authentication User Registration A new user creates an account on a server. The client sends credentials via REST, the server hashes the password, issues JWT tokens, and the client stores the refresh token for \"Remember Me\" sessions. sequenceDiagram participant UI as ConnectDialog participant AO as AppOrchestrator participant CM as ConnectionManager participant API as ApiClient participant Auth as AuthController participant US as UserService participant JWT as JwtTokenService participant DB as SQLite UI->>AO: ConnectDialogResult(IsRegister: true) AO->>CM: ConnectAsync(dialogResult) CM->>API: RegisterAsync(username, password) API->>Auth: POST /api/auth/register Auth->>US: RegisterUserAsync(username, password, displayName) US->>US: Validate (regex, length, uniqueness) US->>DB: INSERT User (BCrypt hash) US-->>Auth: UserOperationResult.Success Auth->>JWT: GenerateAccessToken(user) JWT-->>Auth: (token, expiresAt) [15 min] Auth->>JWT: GenerateRefreshToken() JWT-->>Auth: Base64 random (64 bytes) Auth->>DB: INSERT RefreshToken (SHA256 hash) Auth-->>API: LoginResponse API->>API: SetTokens() — store in memory + set Bearer header API-->>CM: LoginResponse CM->>CM: Wire OnTokensRefreshed for config persistence CM->>CM: Continue to connection setup (see Connection Flow) User Login Returning user authenticates with username/password or a saved refresh token. sequenceDiagram participant UI as ConnectDialog participant CM as ConnectionManager participant API as ApiClient participant Auth as AuthController participant US as UserService participant DB as SQLite alt Saved refresh token (Remember Me) UI->>CM: ConnectDialogResult(SavedRefreshToken: \"...\") CM->>API: LoginWithRefreshTokenAsync() API->>Auth: POST /api/auth/refresh Auth->>DB: Lookup token by SHA256 hash Auth->>DB: Revoke old token, issue new pair Auth-->>API: LoginResponse (rotated tokens) else Username + Password UI->>CM: ConnectDialogResult(IsRegister: false) CM->>API: LoginAsync(username, password) API->>Auth: POST /api/auth/login Auth->>US: AuthenticateUserAsync(username, password) US->>DB: Fetch user, BCrypt.Verify(password, hash) US->>DB: Update LastSeenAt US-->>Auth: UserOperationResult.Success Auth-->>API: LoginResponse end API->>API: SetTokens() Token Refresh Access tokens expire after 15 minutes. The client auto-refreshes transparently before requests and on 401 responses. Refresh tokens are rotated on each use. sequenceDiagram participant SR as SignalR / HTTP Request participant API as ApiClient participant Auth as AuthController participant DB as SQLite participant Config as config.json SR->>API: GetValidTokenAsync() or HTTP 401 API->>API: Token expires within 60s? alt Proactive refresh (SignalR token provider) API->>Auth: POST /api/auth/refresh (old refresh token) else Reactive refresh (HTTP 401 retry) API->>Auth: POST /api/auth/refresh (old refresh token) end Auth->>DB: Lookup by SHA256 hash Auth->>DB: Revoke old refresh token Auth->>DB: INSERT new RefreshToken Auth-->>API: LoginResponse (new token pair) API->>API: SetTokens() — update Bearer header API-->>API: Fire OnTokensRefreshed event API-->>Config: Persist new refresh token (if Remember Me) API->>SR: Retry original request with new token" }, "flows/channels.html": { "href": "flows/channels.html", "title": "Channels | EchoHub Documentation", - "summary": "Channels Channel Creation Channels are created via the REST API. Public channels are broadcast to all connected clients. sequenceDiagram participant Client as Client (TUI/API) participant CC as ChannelsController participant ChS as ChannelService participant CS as ChatService participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster Client->>CC: POST /api/channels {name, topic, isPublic} CC->>ChS: CreateChannelAsync(creatorId, name, topic, isPublic) ChS->>ChS: Normalize name (lowercase, trim) ChS->>ChS: Validate format (2-100 chars, regex) ChS->>DB: Check duplicate ChS->>DB: INSERT Channel + ChannelMembership (creator auto-added) ChS-->>CC: ChannelDto alt Channel is public CC->>CS: BroadcastChannelUpdatedAsync(channel) CS->>SRB: SendChannelUpdatedAsync(channelDto) SRB->>SRB: Notify all SignalR clients CS->>IRCB: SendChannelUpdatedAsync(channelDto) end CC-->>Client: 201 Created (ChannelDto) Code references: Step File Location Controller endpoint src/EchoHub.Server/Controllers/ChannelsController.cs Lines 60-76 Channel service create src/EchoHub.Server/Services/ChannelService.cs Lines 50-90 Broadcast updated src/EchoHub.Server/Services/ChatService.cs Lines 308-309 Channel Deletion Only the channel creator (or admin) can delete a channel. The default channel is protected. sequenceDiagram participant Client as Client participant CC as ChannelsController participant ChS as ChannelService participant DB as SQLite Client->>CC: DELETE /api/channels/{channel} CC->>ChS: DeleteChannelAsync(channelName, callerId) ChS->>ChS: Reject if default channel ChS->>DB: Lookup channel ChS->>ChS: Verify caller is creator or admin ChS->>DB: DELETE Channel (cascade: messages, memberships) ChS-->>CC: Success CC-->>Client: 204 No Content Code references: Step File Location Controller endpoint src/EchoHub.Server/Controllers/ChannelsController.cs Lines 94-106 Channel service delete src/EchoHub.Server/Services/ChannelService.cs Lines 119-144 Joining a Channel Both SignalR and IRC clients join channels through ChatService. The presence tracker determines if this is a genuinely new join (vs. a second connection) and broadcasts accordingly. sequenceDiagram participant Client as Client (SignalR or IRC) participant Entry as ChatHub / IrcCommandHandler participant CS as ChatService participant ChS as ChannelService participant PT as PresenceTracker participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster Client->>Entry: JoinChannel / JOIN #channel Entry->>CS: JoinChannelAsync(connectionId, userId, username, channel) CS->>ChS: EnsureChannelMembershipAsync(userId, channel) ChS->>DB: INSERT ChannelMembership (if not exists) CS->>PT: JoinChannel(username, channel) PT-->>CS: isNewJoin? alt First connection in this channel CS->>DB: Fetch UserPresenceDto CS->>CS: BroadcastToAllAsync(SendUserJoinedAsync) par CS->>SRB: SendUserJoinedAsync(channel, user, excludeConn) and CS->>IRCB: SendUserJoinedAsync(channel, user) end end CS->>DB: Fetch message history CS-->>Entry: (history, error) Entry-->>Client: History messages Code references: Step File Location SignalR hub join src/EchoHub.Server/Hubs/ChatHub.cs Lines 59-81 IRC join src/EchoHub.Server.Irc/IrcCommandHandler.cs Lines 361-414 ChatService join src/EchoHub.Server/Services/ChatService.cs Lines 96-135 Presence join src/EchoHub.Server/Services/PresenceTracker.cs Lines 58-70 SignalR broadcast src/EchoHub.Server/Services/SignalRBroadcaster.cs Lines 26-32 IRC broadcast src/EchoHub.Server.Irc/IrcBroadcaster.cs Lines 34-41 Leaving a Channel sequenceDiagram participant Client as Client participant Entry as ChatHub / IrcCommandHandler participant CS as ChatService participant PT as PresenceTracker participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster Client->>Entry: LeaveChannel / PART #channel Entry->>CS: LeaveChannelAsync(connectionId, username, channel) CS->>PT: LeaveChannel(username, channel) CS->>CS: BroadcastToAllAsync(SendUserLeftAsync) par CS->>SRB: SendUserLeftAsync(channel, username) and CS->>IRCB: SendUserLeftAsync(channel, username) end Code references: Step File Location SignalR hub leave src/EchoHub.Server/Hubs/ChatHub.cs Lines 83-96 IRC part src/EchoHub.Server.Irc/IrcCommandHandler.cs Lines 416-435 ChatService leave src/EchoHub.Server/Services/ChatService.cs Lines 137-143 Presence leave src/EchoHub.Server/Services/PresenceTracker.cs Lines 72-81" + "summary": "Channels Channel Creation Channels are created via the REST API. Public channels are broadcast to all connected clients. sequenceDiagram participant Client as Client (TUI/API) participant CC as ChannelsController participant ChS as ChannelService participant CS as ChatService participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster Client->>CC: POST /api/channels {name, topic, isPublic} CC->>ChS: CreateChannelAsync(creatorId, name, topic, isPublic) ChS->>ChS: Normalize name (lowercase, trim) ChS->>ChS: Validate format (2-100 chars, regex) ChS->>DB: Check duplicate ChS->>DB: INSERT Channel + ChannelMembership (creator auto-added) ChS-->>CC: ChannelDto alt Channel is public CC->>CS: BroadcastChannelUpdatedAsync(channel) CS->>SRB: SendChannelUpdatedAsync(channelDto) SRB->>SRB: Notify all SignalR clients CS->>IRCB: SendChannelUpdatedAsync(channelDto) end CC-->>Client: 201 Created (ChannelDto) Channel Deletion Only the channel creator (or admin) can delete a channel. The default channel is protected. sequenceDiagram participant Client as Client participant CC as ChannelsController participant ChS as ChannelService participant DB as SQLite Client->>CC: DELETE /api/channels/{channel} CC->>ChS: DeleteChannelAsync(channelName, callerId) ChS->>ChS: Reject if default channel ChS->>DB: Lookup channel ChS->>ChS: Verify caller is creator or admin ChS->>DB: DELETE Channel (cascade: messages, memberships) ChS-->>CC: Success CC-->>Client: 204 No Content Joining a Channel Both SignalR and IRC clients join channels through ChatService. The presence tracker determines if this is a genuinely new join (vs. a second connection) and broadcasts accordingly. sequenceDiagram participant Client as Client (SignalR or IRC) participant Entry as ChatHub / IrcCommandHandler participant CS as ChatService participant ChS as ChannelService participant PT as PresenceTracker participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster Client->>Entry: JoinChannel / JOIN #channel Entry->>CS: JoinChannelAsync(connectionId, userId, username, channel) CS->>ChS: EnsureChannelMembershipAsync(userId, channel) ChS->>DB: INSERT ChannelMembership (if not exists) CS->>PT: JoinChannel(username, channel) PT-->>CS: isNewJoin? alt First connection in this channel CS->>DB: Fetch UserPresenceDto CS->>CS: BroadcastToAllAsync(SendUserJoinedAsync) par CS->>SRB: SendUserJoinedAsync(channel, user, excludeConn) and CS->>IRCB: SendUserJoinedAsync(channel, user) end end CS->>DB: Fetch message history CS-->>Entry: (history, error) Entry-->>Client: History messages Leaving a Channel sequenceDiagram participant Client as Client participant Entry as ChatHub / IrcCommandHandler participant CS as ChatService participant PT as PresenceTracker participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster Client->>Entry: LeaveChannel / PART #channel Entry->>CS: LeaveChannelAsync(connectionId, username, channel) CS->>PT: LeaveChannel(username, channel) CS->>CS: BroadcastToAllAsync(SendUserLeftAsync) par CS->>SRB: SendUserLeftAsync(channel, username) and CS->>IRCB: SendUserLeftAsync(channel, username) end" }, "flows/connection.html": { "href": "flows/connection.html", "title": "Connection | EchoHub Documentation", - "summary": "Connection SignalR Client Connection After authentication, the TUI client establishes a SignalR WebSocket, registers event handlers, joins the default channel, and loads history. sequenceDiagram participant CM as ConnectionManager participant EHC as EchoHubConnection participant Hub as ChatHub participant CS as ChatService participant PT as PresenceTracker participant DB as SQLite CM->>CM: Fetch encryption key (GET /api/server/encryption-key) CM->>EHC: new EchoHubConnection(apiClient, encryption) EHC->>EHC: Build HubConnection (URL + JWT token provider + auto-reconnect) EHC->>EHC: RegisterHandlers() — wire ReceiveMessage, UserJoined, etc. EHC->>Hub: ConnectAsync() → WebSocket handshake Hub->>CS: UserConnectedAsync(connectionId, userId, username) CS->>PT: UserConnected(connectionId, userId, username) CS->>DB: Update user: Status=Online, LastSeenAt=now CM->>CM: Fetch channel list (GET /api/channels) CM->>EHC: JoinChannelAsync(\"general\") EHC->>Hub: InvokeAsync(\"JoinChannel\", \"general\") Hub->>CS: JoinChannelAsync(connectionId, userId, username, \"general\") CS->>DB: EnsureChannelMembership CS->>PT: JoinChannel(username, \"general\") CS->>CS: BroadcastToAllAsync → UserJoined CS->>DB: Fetch message history Hub-->>EHC: List (encrypted) EHC-->>CM: Decrypted history Code references: Step File Location Connection orchestration src/EchoHub.Client/Services/ConnectionManager.cs Lines 58-140 (ConnectAsync) EchoHubConnection setup src/EchoHub.Client/Services/EchoHubConnection.cs Lines 29-62 (constructor) Handler registration src/EchoHub.Client/Services/EchoHubConnection.cs Lines 64-122 (RegisterHandlers) Hub OnConnected src/EchoHub.Server/Hubs/ChatHub.cs Lines 31-43 ChatService connected src/EchoHub.Server/Services/ChatService.cs Lines 41-57 PresenceTracker connect src/EchoHub.Server/Services/PresenceTracker.cs Lines 13-29 Join channel (hub) src/EchoHub.Server/Hubs/ChatHub.cs Lines 59-81 Join channel (service) src/EchoHub.Server/Services/ChatService.cs Lines 96-135 IRC Client Connection IRC clients connect via TCP, authenticate with PASS/NICK/USER or SASL PLAIN, and auto-join channels. New usernames are auto-registered. sequenceDiagram participant IRC as IRC Client participant GW as IrcGatewayService participant CH as IrcCommandHandler participant US as UserService participant CS as ChatService participant PT as PresenceTracker IRC->>GW: TCP connect (:6667 or :6697 TLS) GW->>GW: Accept + create IrcClientConnection GW->>CH: new IrcCommandHandler(connection, services) GW->>CH: RunAsync() — start read loop alt SASL PLAIN IRC->>CH: CAP REQ :sasl CH-->>IRC: CAP ACK :sasl IRC->>CH: AUTHENTICATE PLAIN CH-->>IRC: AUTHENTICATE + IRC->>CH: AUTHENTICATE CH->>US: AuthenticateUserAsync(user, pass) alt Auth fails → auto-register CH->>US: RegisterUserAsync(user, pass) end CH-->>IRC: 903 :SASL authentication successful else PASS/NICK/USER IRC->>CH: PASS IRC->>CH: NICK IRC->>CH: USER 0 * : CH->>US: AuthenticateUserAsync(nick, pass) alt Auth fails → auto-register CH->>US: RegisterUserAsync(nick, pass) end end CH->>CS: UserConnectedAsync(irc-{guid}, userId, username) CS->>PT: UserConnected(irc-{guid}, userId, username) CH-->>IRC: 001-004 RPL_WELCOME burst + MOTD Note over IRC,CH: Client is now ready for JOIN/PART/PRIVMSG Code references: Step File Location TCP listener src/EchoHub.Server.Irc/IrcGatewayService.cs Lines 45-90 (ExecuteAsync) Client handler src/EchoHub.Server.Irc/IrcGatewayService.cs Lines 92-154 (HandleClientAsync) Command read loop src/EchoHub.Server.Irc/IrcCommandHandler.cs Lines 40-98 (RunAsync) SASL auth src/EchoHub.Server.Irc/IrcCommandHandler.cs Lines 136-207 (HandleAuthenticateAsync) PASS/NICK/USER src/EchoHub.Server.Irc/IrcCommandHandler.cs Lines 209-267 Registration completion src/EchoHub.Server.Irc/IrcCommandHandler.cs Lines 268-315 (TryCompleteRegistrationAsync) Cleanup on disconnect src/EchoHub.Server.Irc/IrcGatewayService.cs Lines 136-153 User Disconnect & Presence When a client disconnects, the presence tracker determines if the user has any remaining connections. If not, status is set to Invisible and all channels are notified. sequenceDiagram participant Client as Client participant Entry as ChatHub / IrcGatewayService participant CS as ChatService participant PT as PresenceTracker participant DB as SQLite participant SRB as SignalRBroadcaster Client->>Entry: Disconnect / TCP close Entry->>CS: UserDisconnectedAsync(connectionId) CS->>PT: Get username + channels (before removal) CS->>PT: UserDisconnected(connectionId) PT->>PT: Remove connection from tracking alt No remaining connections for user CS->>DB: Update user: Status=Invisible, LastSeenAt=now loop For each channel user was in CS->>CS: BroadcastToAllAsync(SendUserStatusChangedAsync) CS->>SRB: Notify channel members end end Code references: Step File Location SignalR disconnect src/EchoHub.Server/Hubs/ChatHub.cs Lines 45-57 IRC cleanup src/EchoHub.Server.Irc/IrcGatewayService.cs Lines 136-153 ChatService disconnect src/EchoHub.Server/Services/ChatService.cs Lines 59-94 Presence disconnect src/EchoHub.Server/Services/PresenceTracker.cs Lines 31-53" + "summary": "Connection SignalR Client Connection After authentication, the TUI client establishes a SignalR WebSocket, registers event handlers, joins the default channel, and loads history. sequenceDiagram participant CM as ConnectionManager participant EHC as EchoHubConnection participant Hub as ChatHub participant CS as ChatService participant PT as PresenceTracker participant DB as SQLite CM->>CM: Fetch encryption key (GET /api/server/encryption-key) CM->>EHC: new EchoHubConnection(apiClient, encryption) EHC->>EHC: Build HubConnection (URL + JWT token provider + auto-reconnect) EHC->>EHC: RegisterHandlers() — wire ReceiveMessage, UserJoined, etc. EHC->>Hub: ConnectAsync() → WebSocket handshake Hub->>CS: UserConnectedAsync(connectionId, userId, username) CS->>PT: UserConnected(connectionId, userId, username) CS->>DB: Update user: Status=Online, LastSeenAt=now CM->>CM: Fetch channel list (GET /api/channels) CM->>EHC: JoinChannelAsync(\"general\") EHC->>Hub: InvokeAsync(\"JoinChannel\", \"general\") Hub->>CS: JoinChannelAsync(connectionId, userId, username, \"general\") CS->>DB: EnsureChannelMembership CS->>PT: JoinChannel(username, \"general\") CS->>CS: BroadcastToAllAsync → UserJoined CS->>DB: Fetch message history Hub-->>EHC: List (encrypted) EHC-->>CM: Decrypted history IRC Client Connection IRC clients connect via TCP, authenticate with PASS/NICK/USER or SASL PLAIN, and auto-join channels. New usernames are auto-registered. sequenceDiagram participant IRC as IRC Client participant GW as IrcGatewayService participant CH as IrcCommandHandler participant US as UserService participant CS as ChatService participant PT as PresenceTracker IRC->>GW: TCP connect (:6667 or :6697 TLS) GW->>GW: Accept + create IrcClientConnection GW->>CH: new IrcCommandHandler(connection, services) GW->>CH: RunAsync() — start read loop alt SASL PLAIN IRC->>CH: CAP REQ :sasl CH-->>IRC: CAP ACK :sasl IRC->>CH: AUTHENTICATE PLAIN CH-->>IRC: AUTHENTICATE + IRC->>CH: AUTHENTICATE CH->>US: AuthenticateUserAsync(user, pass) alt Auth fails → auto-register CH->>US: RegisterUserAsync(user, pass) end CH-->>IRC: 903 :SASL authentication successful else PASS/NICK/USER IRC->>CH: PASS IRC->>CH: NICK IRC->>CH: USER 0 * : CH->>US: AuthenticateUserAsync(nick, pass) alt Auth fails → auto-register CH->>US: RegisterUserAsync(nick, pass) end end CH->>CS: UserConnectedAsync(irc-{guid}, userId, username) CS->>PT: UserConnected(irc-{guid}, userId, username) CH-->>IRC: 001-004 RPL_WELCOME burst + MOTD Note over IRC,CH: Client is now ready for JOIN/PART/PRIVMSG User Disconnect & Presence When a client disconnects, the presence tracker determines if the user has any remaining connections. If not, status is set to Invisible and all channels are notified. sequenceDiagram participant Client as Client participant Entry as ChatHub / IrcGatewayService participant CS as ChatService participant PT as PresenceTracker participant DB as SQLite participant SRB as SignalRBroadcaster Client->>Entry: Disconnect / TCP close Entry->>CS: UserDisconnectedAsync(connectionId) CS->>PT: Get username + channels (before removal) CS->>PT: UserDisconnected(connectionId) PT->>PT: Remove connection from tracking alt No remaining connections for user CS->>DB: Update user: Status=Invisible, LastSeenAt=now loop For each channel user was in CS->>CS: BroadcastToAllAsync(SendUserStatusChangedAsync) CS->>SRB: Notify channel members end end" }, "flows/flows.html": { "href": "flows/flows.html", @@ -907,17 +912,17 @@ "flows/media.html": { "href": "flows/media.html", "title": "Media & Services | EchoHub Documentation", - "summary": "Media & Services File Upload Files are uploaded via REST, validated by magic bytes, stored with GUID filenames, and broadcast as a message with a download link. sequenceDiagram participant Client as Client participant CC as ChannelsController participant FV as FileValidationHelper participant FS as FileStorageService participant CS as ChatService participant DB as SQLite Client->>CC: POST /api/channels/{channel}/upload (multipart) CC->>CC: Check file size limits CC->>FV: IsValidImage(stream) — magic byte check FV->>FV: Read header: JPEG(FFD8FF) / PNG(89504E47) / GIF / WebP(RIFF+WEBP) FV-->>CC: true/false CC->>FS: SaveFileAsync(stream, extension) FS->>FS: Generate GUID filename, write to uploads/ FS-->>CC: fileId (GUID) CC->>CC: Determine MessageType (Image/Audio/File) CC->>CS: SendMessageAsync (with file URL + optional ASCII art) CS->>DB: INSERT Message CS->>CS: BroadcastToAllAsync → fan out to clients Code references: Step File Location Upload endpoint src/EchoHub.Server/Controllers/ChannelsController.cs Lines 108-200 File validation src/EchoHub.Server/Services/FileValidationHelper.cs Lines 15-82 File storage src/EchoHub.Server/Services/FileStorageService.cs Lines 1-47 File download src/EchoHub.Server/Controllers/FilesController.cs Lines 22-53 Link Embed Resolution When a message contains URLs, the server fetches OpenGraph metadata for preview embeds. sequenceDiagram participant CS as ChatService participant LE as LinkEmbedService participant Web as External Website CS->>LE: TryGetEmbedsAsync(messageContent) LE->>LE: Extract URLs via regex LE->>LE: Filter: max URLs per message, skip duplicates loop For each URL LE->>LE: Validate: http(s) only, block private IPs LE->>Web: GET URL (timeout + size limit) Web-->>LE: HTML response LE->>LE: Parse og:title, og:description, og:site_name LE->>LE: Parse theme-color meta tag LE->>LE: Fallback to if no og:title end LE-->>CS: List<EmbedDto> (or null) Note over CS: Attached to MessageDto before broadcast Code references: Step File Location Entry point src/EchoHub.Server/Services/LinkEmbedService.cs Lines 28-51 (TryGetEmbedsAsync) URL extraction src/EchoHub.Server/Services/LinkEmbedService.cs Lines 145-160 Private IP blocking src/EchoHub.Server/Services/LinkEmbedService.cs Lines 162-181 OG tag parsing src/EchoHub.Server/Services/LinkEmbedService.cs Lines 187-210 Theme color parsing src/EchoHub.Server/Services/LinkEmbedService.cs Lines 117-143 ChatService integration src/EchoHub.Server/Services/ChatService.cs Lines 194-201 Server Directory Registration Public servers register with the EchoHubSpace directory for discoverability. sequenceDiagram participant SDS as ServerDirectoryService participant Dir as EchoHubSpace Directory participant PT as PresenceTracker SDS->>SDS: Check Server:PublicServer config SDS->>Dir: SignalR connect (echohub.voidcube.cloud/hubs/servers) SDS->>Dir: RegisterServer(name, description, host, userCount) Dir-->>SDS: Registered loop Every 30 seconds SDS->>PT: Get online user count alt Count changed SDS->>Dir: UpdateUserCount(count) end end Dir->>SDS: Ping SDS->>Dir: Heartbeat Note over SDS,Dir: Exponential backoff on disconnect (2s → 30s max) Code references: Step File Location Service lifecycle src/EchoHub.Server/Services/ServerDirectoryService.cs Lines 29-122 Registration src/EchoHub.Server/Services/ServerDirectoryService.cs Lines 195-212 User count polling src/EchoHub.Server/Services/ServerDirectoryService.cs Lines 154-187 Reconnection backoff src/EchoHub.Server/Services/ServerDirectoryService.cs Lines 77-82, 191" + "summary": "Media & Services File Upload Files are uploaded via REST, validated by magic bytes, stored with GUID filenames, and broadcast as a message with a download link. sequenceDiagram participant Client as Client participant CC as ChannelsController participant FV as FileValidationHelper participant FS as FileStorageService participant CS as ChatService participant DB as SQLite Client->>CC: POST /api/channels/{channel}/upload (multipart) CC->>CC: Check file size limits CC->>FV: IsValidImage(stream) — magic byte check FV->>FV: Read header: JPEG(FFD8FF) / PNG(89504E47) / GIF / WebP(RIFF+WEBP) FV-->>CC: true/false CC->>FS: SaveFileAsync(stream, extension) FS->>FS: Generate GUID filename, write to uploads/ FS-->>CC: fileId (GUID) CC->>CC: Determine MessageType (Image/Audio/File) CC->>CS: SendMessageAsync (with file URL + optional ASCII art) CS->>DB: INSERT Message CS->>CS: BroadcastToAllAsync → fan out to clients Link Embed Resolution When a message contains URLs, the server fetches OpenGraph metadata for preview embeds. sequenceDiagram participant CS as ChatService participant LE as LinkEmbedService participant Web as External Website CS->>LE: TryGetEmbedsAsync(messageContent) LE->>LE: Extract URLs via regex LE->>LE: Filter: max URLs per message, skip duplicates loop For each URL LE->>LE: Validate: http(s) only, block private IPs LE->>Web: GET URL (timeout + size limit) Web-->>LE: HTML response LE->>LE: Parse og:title, og:description, og:site_name LE->>LE: Parse theme-color meta tag LE->>LE: Fallback to <title> if no og:title end LE-->>CS: List<EmbedDto> (or null) Note over CS: Attached to MessageDto before broadcast Server Directory Registration Public servers register with the EchoHubSpace directory for discoverability. sequenceDiagram participant SDS as ServerDirectoryService participant Dir as EchoHubSpace Directory participant PT as PresenceTracker SDS->>SDS: Check Server:PublicServer config SDS->>Dir: SignalR connect (echohub.voidcube.cloud/hubs/servers) SDS->>Dir: RegisterServer(name, description, host, userCount) Dir-->>SDS: Registered loop Every 30 seconds SDS->>PT: Get online user count alt Count changed SDS->>Dir: UpdateUserCount(count) end end Dir->>SDS: Ping SDS->>Dir: Heartbeat Note over SDS,Dir: Exponential backoff on disconnect (2s → 30s max)" }, "flows/messaging.html": { "href": "flows/messaging.html", "title": "Messaging | EchoHub Documentation", - "summary": "Messaging Sending a Message (SignalR) A message typed in the TUI travels through encryption, the SignalR hub, ChatService validation, database storage, and fan-out to both SignalR and IRC clients. sequenceDiagram participant UI as MainWindow (TUI) participant AO as AppOrchestrator participant EHC as EchoHubConnection participant Hub as ChatHub participant CS as ChatService participant LE as LinkEmbedService participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster participant Clients as Other Clients UI->>AO: OnMessageSubmitted(channel, text) AO->>AO: IsCommand(text)? → No AO->>EHC: SendMessageAsync(channel, text) EHC->>EHC: Encrypt(text) → ciphertext EHC->>Hub: InvokeAsync(\"SendMessage\", channel, ciphertext) Hub->>CS: SendMessageAsync(userId, username, channel, ciphertext) CS->>CS: Decrypt(ciphertext) → plaintext CS->>CS: Validate (length, newlines, channel exists) CS->>DB: Check mute status CS->>LE: TryGetEmbedsAsync(plaintext) LE->>LE: Extract URLs, fetch OG tags LE-->>CS: List<EmbedDto> (or null) CS->>DB: INSERT Message (encrypted at rest) CS->>CS: Re-encrypt plaintext for transport CS->>CS: Build MessageDto with embeds par Fan-out to all broadcasters CS->>SRB: SendMessageToChannelAsync(channel, dto) SRB->>Clients: HubContext.Group(channel).ReceiveMessage(dto) and CS->>IRCB: SendMessageToChannelAsync(channel, dto) IRCB->>IRCB: Decrypt → format as PRIVMSG lines IRCB->>Clients: Send to each IRC conn (skip sender) end Code references: Step File Location Input handler src/EchoHub.Client/UI/MainWindow.cs Lines 428-449 (OnInputKeyDown) Orchestrator dispatch src/EchoHub.Client/AppOrchestrator.cs Lines 631-661 (HandleMessageSubmitted) Client encrypt + send src/EchoHub.Client/Services/EchoHubConnection.cs Lines 148-153 (SendMessageAsync) Hub receive src/EchoHub.Server/Hubs/ChatHub.cs Lines 98-111 (SendMessage) ChatService process src/EchoHub.Server/Services/ChatService.cs Lines 145-241 (SendMessageAsync) Mute check src/EchoHub.Server/Services/ChatService.cs Lines 177-190 Link embeds src/EchoHub.Server/Services/LinkEmbedService.cs Lines 28-51 (TryGetEmbedsAsync) DB insert src/EchoHub.Server/Services/ChatService.cs Lines 208-221 Broadcast fan-out src/EchoHub.Server/Services/ChatService.cs Lines 311-324 (BroadcastToAllAsync) SignalR broadcast src/EchoHub.Server/Services/SignalRBroadcaster.cs Lines 23-24 IRC broadcast src/EchoHub.Server.Irc/IrcBroadcaster.cs Lines 17-32 Sending a Message (IRC) Messages from IRC clients follow the same ChatService path but enter as plaintext (no app-layer encryption). sequenceDiagram participant IRC as IRC Client participant CH as IrcCommandHandler participant CS as ChatService participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster IRC->>CH: PRIVMSG #channel :Hello world CH->>CH: Parse target + content CH->>CH: IrcToEchoHubChannel(\"#channel\") → \"channel\" CH->>CS: SendMessageAsync(userId, username, \"channel\", \"Hello world\") CS->>CS: Decrypt(\"Hello world\") → passthrough (no $ENC$ prefix) CS->>CS: Validate, check mute, fetch embeds CS->>DB: INSERT Message CS->>CS: Encrypt plaintext for SignalR transport par Fan-out CS->>SRB: SendMessageToChannelAsync (encrypted for SignalR) and CS->>IRCB: SendMessageToChannelAsync (decrypt → PRIVMSG) IRCB->>IRCB: Skip sender (IRC echo suppression) end Code references: Step File Location PRIVMSG handler src/EchoHub.Server.Irc/IrcCommandHandler.cs Lines 437-469 Channel name conversion src/EchoHub.Server.Irc/IrcCommandHandler.cs Line 680 (IrcToEchoHubChannel) ChatService (shared path) src/EchoHub.Server/Services/ChatService.cs Lines 145-241 IRC echo suppression src/EchoHub.Server.Irc/IrcBroadcaster.cs Lines 25-26 Receiving a Message (TUI Client) When a message arrives via SignalR, the client decrypts it, adds it to the chat view, and optionally plays a notification sound for @mentions. sequenceDiagram participant SRB as SignalRBroadcaster participant EHC as EchoHubConnection participant AO as AppOrchestrator participant MM as ChatMessageManager participant UI as MainWindow SRB->>EHC: ReceiveMessage(MessageDto) EHC->>EHC: Decrypt(message.Content) EHC-->>AO: OnMessageReceived(decrypted dto) AO->>AO: InvokeUI (thread-safe) AO->>MM: AddMessage(message) MM->>UI: Render in chat ListView alt Message contains @username AO->>AO: PlayAsync() notification sound end Code references: Step File Location SignalR handler src/EchoHub.Client/Services/EchoHubConnection.cs Lines 64-71 Orchestrator receive src/EchoHub.Client/AppOrchestrator.cs Lines 372-383 @mention detection src/EchoHub.Client/AppOrchestrator.cs Lines 378-382 Command Execution Slash commands (/status, /nick, /kick, etc.) are parsed client-side and dispatched to appropriate handlers, which call REST APIs or SignalR methods. sequenceDiagram participant UI as MainWindow participant AO as AppOrchestrator participant CMD as CommandHandler participant API as ApiClient participant EHC as EchoHubConnection participant Server as Server (API/Hub) UI->>AO: OnMessageSubmitted(channel, \"/kick baduser\") AO->>CMD: IsCommand(\"/kick baduser\")? → true AO->>CMD: HandleAsync(\"/kick baduser\") CMD->>CMD: Parse → command=\"kick\", args=\"baduser\" alt API command (kick, ban, mute, nick, etc.) CMD-->>AO: Fire OnKickRequested(\"baduser\") AO->>API: KickUserAsync(\"baduser\") API->>Server: POST /api/moderation/kick/baduser else Hub command (status, join, leave, etc.) CMD-->>AO: Fire OnSetStatus / OnJoinChannel / etc. AO->>EHC: UpdateStatusAsync() / JoinChannelAsync() / etc. EHC->>Server: SignalR Invoke else Local command (theme, help, quit) CMD-->>AO: Fire OnThemeChanged / etc. AO->>UI: Apply locally (no server call) end AO->>UI: AddSystemMessage(result) Available commands: Command Type Handler /status <status> [message] Hub UpdateStatusAsync /nick <name> API UpdateProfileAsync /color <hex> API UpdateProfileAsync /join <channel> Hub JoinChannelAsync /leave Hub LeaveChannelAsync /topic <text> API UpdateChannelTopicAsync /kick <user> API POST /api/moderation/kick/{user} /ban <user> API POST /api/moderation/ban/{user} /unban <user> API POST /api/moderation/unban/{user} /mute <user> [mins] API POST /api/moderation/mute/{user} /unmute <user> API POST /api/moderation/unmute/{user} /role <user> <role> API PUT /api/moderation/role/{user} /nuke API DELETE /api/channels/{channel}/messages /send <file> API POST /api/channels/{channel}/upload /profile [user] Local Show profile dialog /avatar API POST /api/users/avatar /theme <name> Local ThemeManager.SetTheme() /servers API GET /api/serverdir/servers /users Local Show userlist /help Local Show help text /quit Local Exit application Code references: Step File Location Command detection src/EchoHub.Client/AppOrchestrator.cs Lines 639-655 Command dispatch src/EchoHub.Client/Commands/CommandHandler.cs Lines 34-69 (HandleAsync) Command handlers wired src/EchoHub.Client/AppOrchestrator.cs Lines 97-117 Individual handlers src/EchoHub.Client/AppOrchestrator.cs Lines 122-350" + "summary": "Messaging Sending a Message (SignalR) A message typed in the TUI travels through encryption, the SignalR hub, ChatService validation, database storage, and fan-out to both SignalR and IRC clients. sequenceDiagram participant UI as MainWindow (TUI) participant AO as AppOrchestrator participant EHC as EchoHubConnection participant Hub as ChatHub participant CS as ChatService participant LE as LinkEmbedService participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster participant Clients as Other Clients UI->>AO: OnMessageSubmitted(channel, text) AO->>AO: IsCommand(text)? → No AO->>EHC: SendMessageAsync(channel, text) EHC->>EHC: Encrypt(text) → ciphertext EHC->>Hub: InvokeAsync(\"SendMessage\", channel, ciphertext) Hub->>CS: SendMessageAsync(userId, username, channel, ciphertext) CS->>CS: Decrypt(ciphertext) → plaintext CS->>CS: Validate (length, newlines, channel exists) CS->>DB: Check mute status CS->>LE: TryGetEmbedsAsync(plaintext) LE->>LE: Extract URLs, fetch OG tags LE-->>CS: List<EmbedDto> (or null) CS->>DB: INSERT Message (encrypted at rest) CS->>CS: Re-encrypt plaintext for transport CS->>CS: Build MessageDto with embeds par Fan-out to all broadcasters CS->>SRB: SendMessageToChannelAsync(channel, dto) SRB->>Clients: HubContext.Group(channel).ReceiveMessage(dto) and CS->>IRCB: SendMessageToChannelAsync(channel, dto) IRCB->>IRCB: Decrypt → format as PRIVMSG lines IRCB->>Clients: Send to each IRC conn (skip sender) end Sending a Message (IRC) Messages from IRC clients follow the same ChatService path but enter as plaintext (no app-layer encryption). sequenceDiagram participant IRC as IRC Client participant CH as IrcCommandHandler participant CS as ChatService participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster IRC->>CH: PRIVMSG #channel :Hello world CH->>CH: Parse target + content CH->>CH: IrcToEchoHubChannel(\"#channel\") → \"channel\" CH->>CS: SendMessageAsync(userId, username, \"channel\", \"Hello world\") CS->>CS: Decrypt(\"Hello world\") → passthrough (no $ENC$ prefix) CS->>CS: Validate, check mute, fetch embeds CS->>DB: INSERT Message CS->>CS: Encrypt plaintext for SignalR transport par Fan-out CS->>SRB: SendMessageToChannelAsync (encrypted for SignalR) and CS->>IRCB: SendMessageToChannelAsync (decrypt → PRIVMSG) IRCB->>IRCB: Skip sender (IRC echo suppression) end Receiving a Message (TUI Client) When a message arrives via SignalR, the client decrypts it, adds it to the chat view, and optionally plays a notification sound for @mentions. sequenceDiagram participant SRB as SignalRBroadcaster participant EHC as EchoHubConnection participant AO as AppOrchestrator participant MM as ChatMessageManager participant UI as MainWindow SRB->>EHC: ReceiveMessage(MessageDto) EHC->>EHC: Decrypt(message.Content) EHC-->>AO: OnMessageReceived(decrypted dto) AO->>AO: InvokeUI (thread-safe) AO->>MM: AddMessage(message) MM->>UI: Render in chat ListView alt Message contains @username AO->>AO: PlayAsync() notification sound end Command Execution Slash commands (/status, /nick, /kick, etc.) are parsed client-side and dispatched to appropriate handlers, which call REST APIs or SignalR methods. sequenceDiagram participant UI as MainWindow participant AO as AppOrchestrator participant CMD as CommandHandler participant API as ApiClient participant EHC as EchoHubConnection participant Server as Server (API/Hub) UI->>AO: OnMessageSubmitted(channel, \"/kick baduser\") AO->>CMD: IsCommand(\"/kick baduser\")? → true AO->>CMD: HandleAsync(\"/kick baduser\") CMD->>CMD: Parse → command=\"kick\", args=\"baduser\" alt API command (kick, ban, mute, nick, etc.) CMD-->>AO: Fire OnKickRequested(\"baduser\") AO->>API: KickUserAsync(\"baduser\") API->>Server: POST /api/moderation/kick/baduser else Hub command (status, join, leave, etc.) CMD-->>AO: Fire OnSetStatus / OnJoinChannel / etc. AO->>EHC: UpdateStatusAsync() / JoinChannelAsync() / etc. EHC->>Server: SignalR Invoke else Local command (theme, help, quit) CMD-->>AO: Fire OnThemeChanged / etc. AO->>UI: Apply locally (no server call) end AO->>UI: AddSystemMessage(result) Available commands: Command Type Handler /status <status> [message] Hub UpdateStatusAsync /nick <name> API UpdateProfileAsync /color <hex> API UpdateProfileAsync /join <channel> Hub JoinChannelAsync /leave Hub LeaveChannelAsync /topic <text> API UpdateChannelTopicAsync /kick <user> API POST /api/moderation/kick/{user} /ban <user> API POST /api/moderation/ban/{user} /unban <user> API POST /api/moderation/unban/{user} /mute <user> [mins] API POST /api/moderation/mute/{user} /unmute <user> API POST /api/moderation/unmute/{user} /role <user> <role> API PUT /api/moderation/role/{user} /nuke API DELETE /api/channels/{channel}/messages /send <file> API POST /api/channels/{channel}/upload /profile [user] Local Show profile dialog /avatar API POST /api/users/avatar /theme <name> Local ThemeManager.SetTheme() /servers API GET /api/serverdir/servers /users Local Show userlist /help Local Show help text /quit Local Exit application" }, "flows/moderation.html": { "href": "flows/moderation.html", "title": "Moderation | EchoHub Documentation", - "summary": "Moderation Kick / Ban / Mute Moderators and admins can kick, ban, or mute users via REST API or slash commands. These actions force-disconnect the target and broadcast the event. sequenceDiagram participant Mod as Moderator participant MC as ModerationController participant CS as ChatService participant PT as PresenceTracker participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster Mod->>MC: POST /api/moderation/kick/{user} alt Kick MC->>CS: Get user's channels MC->>CS: BroadcastToAllAsync(SendUserKickedAsync) MC->>CS: ForceDisconnectAndCleanupAsync(user) else Ban MC->>DB: Set user.IsBanned = true MC->>CS: BroadcastToAllAsync(SendUserBannedAsync) MC->>CS: ForceDisconnectAndCleanupAsync(user) else Mute MC->>DB: Set user.IsMuted = true, MutedUntil = now + duration Note over DB: MuteExpirationService auto-unmutes when timer expires end CS->>PT: ForceRemoveUser(username) PT->>PT: Remove from all connections + channels CS->>SRB: ForceDisconnectUserAsync(connectionIds, reason) CS->>IRCB: ForceDisconnectUserAsync(connectionIds, reason) CS->>DB: Set Status=Invisible, LastSeenAt=now Code references: Step File Location Kick endpoint src/EchoHub.Server/Controllers/ModerationController.cs Lines 62-87 Ban endpoint src/EchoHub.Server/Controllers/ModerationController.cs Lines 89-112 Mute endpoint src/EchoHub.Server/Controllers/ModerationController.cs Lines 130-151 Force disconnect src/EchoHub.Server/Controllers/ModerationController.cs Lines 232-256 Mute expiration src/EchoHub.Server/Services/MuteExpirationService.cs Lines 22-62 Mute enforcement src/EchoHub.Server/Services/ChatService.cs Lines 177-190 Presence force remove src/EchoHub.Server/Services/PresenceTracker.cs Lines 161-178" + "summary": "Moderation Kick / Ban / Mute Moderators and admins can kick, ban, or mute users via REST API or slash commands. These actions force-disconnect the target and broadcast the event. sequenceDiagram participant Mod as Moderator participant MC as ModerationController participant CS as ChatService participant PT as PresenceTracker participant DB as SQLite participant SRB as SignalRBroadcaster participant IRCB as IrcBroadcaster Mod->>MC: POST /api/moderation/kick/{user} alt Kick MC->>CS: Get user's channels MC->>CS: BroadcastToAllAsync(SendUserKickedAsync) MC->>CS: ForceDisconnectAndCleanupAsync(user) else Ban MC->>DB: Set user.IsBanned = true MC->>CS: BroadcastToAllAsync(SendUserBannedAsync) MC->>CS: ForceDisconnectAndCleanupAsync(user) else Mute MC->>DB: Set user.IsMuted = true, MutedUntil = now + duration Note over DB: MuteExpirationService auto-unmutes when timer expires end CS->>PT: ForceRemoveUser(username) PT->>PT: Remove from all connections + channels CS->>SRB: ForceDisconnectUserAsync(connectionIds, reason) CS->>IRCB: ForceDisconnectUserAsync(connectionIds, reason) CS->>DB: Set Status=Invisible, LastSeenAt=now" }, "index.html": { "href": "index.html", diff --git a/manifest.json b/manifest.json index 66e45a5..69aae4d 100644 --- a/manifest.json +++ b/manifest.json @@ -2296,6 +2296,16 @@ }, "version": "" }, + { + "type": "Conceptual", + "source_relative_path": "articles/configuration.md", + "output": { + ".html": { + "relative_path": "articles/configuration.html" + } + }, + "version": "" + }, { "type": "Conceptual", "source_relative_path": "articles/docker.md", diff --git a/public/main.css b/public/main.css index ffcce11..abc2acf 100644 --- a/public/main.css +++ b/public/main.css @@ -49,6 +49,7 @@ header.top-navbar { .navbar .navbar-brand svg { height: 28px; width: auto; + margin-right: 0.5em; } .navbar .nav-link { @@ -320,19 +321,6 @@ footer { color: #E6C06E; } -.footer-credit { - color: #484f58; - font-size: 0.85em; -} - -.footer-credit a { - color: #6e7681; -} - -.footer-credit a:hover { - color: #E6C06E; -} - /* --- Scrollbar --- */ ::-webkit-scrollbar { width: 8px; diff --git a/todo.html b/todo.html index 967f203..22b6eef 100644 --- a/todo.html +++ b/todo.html @@ -124,7 +124,7 @@ <footer class="border-top text-secondary"> <div class="container-xxl"> <div class="flex-fill"> - <div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>·</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>·</span><a href='https://echohub.voidcube.cloud'>Website</a><span class='footer-sep'>·</span><span class='footer-credit'>Built with <a href='https://dotnet.github.io/docfx'>DocFX</a></span></div></div> + <div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>·</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>·</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div> </div> </div> </footer>